Random event manager rewrite
Time until next random event now persists across logins Events will no longer spawn while the player has an interface like the bank open Replaced the slurry of random event commands with a singular ::revent admin command Random events now support being associated with multiple skills Random event selection is now more robust Players will no longer get skill-based random events if more than 2.5 minutes have passed since training the skill
This commit is contained in:
@@ -1,29 +1,31 @@
|
||||
import content.global.ame.RandomEventManager
|
||||
import content.global.skill.farming.timers.CropGrowth
|
||||
import core.ServerConstants
|
||||
import core.api.log
|
||||
import core.cache.Cache
|
||||
import core.cache.crypto.ISAACCipher
|
||||
import core.cache.crypto.ISAACPair
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.info.PlayerDetails
|
||||
import core.game.node.entity.player.info.Rights
|
||||
import core.game.node.entity.player.link.IronmanMode
|
||||
import core.game.node.item.Item
|
||||
import core.net.IoSession
|
||||
import core.net.packet.IoBuffer
|
||||
import org.rs09.consts.Items
|
||||
import core.ServerConstants
|
||||
import core.api.log
|
||||
import core.game.interaction.ScriptProcessor
|
||||
import core.game.node.Node
|
||||
import core.game.node.entity.combat.equipment.WeaponInterface
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.skill.SkillBonus
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.player.VarpManager
|
||||
import core.game.node.entity.player.info.PlayerDetails
|
||||
import core.game.node.entity.player.info.Rights
|
||||
import core.game.node.entity.player.info.login.PlayerSaveParser
|
||||
import core.game.node.entity.player.info.login.PlayerSaver
|
||||
import core.game.node.entity.player.link.IronmanMode
|
||||
import core.game.node.entity.player.link.SavedData
|
||||
import core.game.node.entity.player.link.quest.QuestRepository
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.GroundItem
|
||||
import core.game.node.item.Item
|
||||
import core.game.shops.Shop
|
||||
import core.game.shops.ShopItem
|
||||
import core.tools.SystemLogger
|
||||
import core.game.system.config.ConfigParser
|
||||
import core.game.system.config.ServerConfigParser
|
||||
import core.game.system.timer.TimerRegistry
|
||||
import core.game.system.timer.impl.AntiMacro
|
||||
import core.game.system.timer.impl.Disease
|
||||
import core.game.system.timer.impl.Poison
|
||||
import core.game.world.GameWorld
|
||||
@@ -31,10 +33,11 @@ import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.repository.Repository
|
||||
import core.game.world.update.UpdateSequence
|
||||
import core.net.IoSession
|
||||
import core.net.packet.IoBuffer
|
||||
import core.net.packet.PacketProcessor
|
||||
import core.tools.Log
|
||||
import org.rs09.consts.Scenery
|
||||
import java.io.Closeable
|
||||
import org.rs09.consts.Items
|
||||
import java.net.URI
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
@@ -85,6 +88,7 @@ object TestUtils {
|
||||
TimerRegistry.registerTimer(Poison())
|
||||
TimerRegistry.registerTimer(Disease())
|
||||
TimerRegistry.registerTimer(CropGrowth())
|
||||
TimerRegistry.registerTimer(AntiMacro())
|
||||
}
|
||||
|
||||
fun loadFile(path: String) : URI? {
|
||||
@@ -111,12 +115,17 @@ object TestUtils {
|
||||
|
||||
class MockPlayer(name: String) : Player(PlayerDetails(name)), AutoCloseable {
|
||||
var hasInit = false
|
||||
init {
|
||||
init { configureBasicProperties(); flagTutComplete(false); init(); flagTutComplete(true) }
|
||||
|
||||
fun configureBasicProperties() {
|
||||
this.details.session = MockSession()
|
||||
this.location = ServerConstants.HOME_LOCATION
|
||||
this.properties.attackStyle = WeaponInterface.AttackStyle(0, WeaponInterface.BONUS_CRUSH)
|
||||
init()
|
||||
this.setAttribute("tutorial:complete", true)
|
||||
}
|
||||
|
||||
fun flagTutComplete(complete: Boolean) {
|
||||
this.setAttribute("/save:tutorial:complete", complete)
|
||||
this.setAttribute("/save:rules:confirmed", complete)
|
||||
}
|
||||
|
||||
override fun update() {
|
||||
@@ -140,6 +149,37 @@ class MockPlayer(name: String) : Player(PlayerDetails(name)), AutoCloseable {
|
||||
RegionManager.move(this)
|
||||
this.playerFlags.lastSceneGraph = location
|
||||
}
|
||||
|
||||
fun relog(ticksToWait: Int = -1) {
|
||||
val json = PlayerSaver(this).populate()
|
||||
val parse = PlayerSaveParser(this)
|
||||
parse.saveFile = json
|
||||
|
||||
close()
|
||||
timers.clearTimers()
|
||||
inventory.clear()
|
||||
bank.clear()
|
||||
equipment.clear()
|
||||
skills = Skills(this)
|
||||
savedData = SavedData(this)
|
||||
questRepository = QuestRepository(this)
|
||||
varpManager = VarpManager(this)
|
||||
varpMap.clear()
|
||||
saveVarp.clear()
|
||||
scripts = ScriptProcessor(this)
|
||||
clearAttributes()
|
||||
hasInit = false
|
||||
|
||||
if (ticksToWait > 0) TestUtils.advanceTicks(ticksToWait, false)
|
||||
|
||||
configureBasicProperties()
|
||||
parse.parseData()
|
||||
init()
|
||||
}
|
||||
|
||||
override fun debug(string: String?) {
|
||||
log (this::class.java, Log.DEBUG, "[$name] -> Received Debug: $string")
|
||||
}
|
||||
}
|
||||
|
||||
class MockSession : IoSession(null, null) {
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
package content
|
||||
|
||||
import TestUtils
|
||||
import content.global.ame.RandomEventManager
|
||||
import core.game.node.item.Item
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.rs09.consts.Items
|
||||
import content.global.ame.RandomEventNPC
|
||||
import core.game.world.GameWorld
|
||||
|
||||
class RandomEventManagerTests {
|
||||
init {
|
||||
TestUtils.preTestSetup()
|
||||
}
|
||||
|
||||
@Test fun loginShouldEnableManager() {
|
||||
val p = TestUtils.getMockPlayer("Bill")
|
||||
RandomEventManager().login(p)
|
||||
val manager = content.global.ame.RandomEventManager.getInstance(p)
|
||||
Assertions.assertNotNull(manager)
|
||||
Assertions.assertEquals(true, manager!!.enabled)
|
||||
}
|
||||
|
||||
@Test fun loginShouldSetNextSpawn() {
|
||||
val p = TestUtils.getMockPlayer("Bill")
|
||||
RandomEventManager().login(p)
|
||||
val manager = content.global.ame.RandomEventManager.getInstance(p)
|
||||
Assertions.assertNotNull(manager)
|
||||
Assertions.assertEquals(true, manager!!.nextSpawn > GameWorld.ticks)
|
||||
}
|
||||
|
||||
@Test fun shouldSpawnRandomEventWithinMAXTICKSGivenNoRestrictions() {
|
||||
val p = TestUtils.getMockPlayer("Bill")
|
||||
p.setAttribute("tutorial:complete", true) //tutorial has to be complete to spawn randoms
|
||||
RandomEventManager.MIN_DELAY_TICKS = 10
|
||||
RandomEventManager.MAX_DELAY_TICKS = 20
|
||||
RandomEventManager().login(p)
|
||||
TestUtils.advanceTicks(RandomEventManager.MAX_DELAY_TICKS + 5)
|
||||
RandomEventManager.MIN_DELAY_TICKS = 3000
|
||||
RandomEventManager.MAX_DELAY_TICKS = 9000
|
||||
Assertions.assertNotNull(p.getAttribute("re-npc", null))
|
||||
}
|
||||
|
||||
@Test fun teleportAndNotePunishmentShouldNotAffectAlreadyNotedItems() {
|
||||
val p = TestUtils.getMockPlayer("Shitforbrains")
|
||||
p.setAttribute("tutorial:complete", true)
|
||||
RandomEventManager().login(p)
|
||||
|
||||
p.inventory.add(Item(Items.RAW_SHARK_384, 1000))
|
||||
content.global.ame.RandomEventManager.getInstance(p)?.fireEvent()
|
||||
p.getAttribute<RandomEventNPC>("re-npc")!!.noteAndTeleport()
|
||||
|
||||
Assertions.assertEquals(1000, p.inventory.getAmount(Items.RAW_SHARK_384))
|
||||
}
|
||||
|
||||
@Test fun teleportAndNotePunishmentShouldNoteNotableUnnotedItems() {
|
||||
val p = TestUtils.getMockPlayer("shitforbrains2")
|
||||
p.setAttribute("tutorial:complete", true)
|
||||
RandomEventManager().login(p)
|
||||
|
||||
p.inventory.add(Item(4151, 5))
|
||||
content.global.ame.RandomEventManager.getInstance(p)?.fireEvent()
|
||||
p.getAttribute<RandomEventNPC>("re-npc")!!.noteAndTeleport()
|
||||
|
||||
Assertions.assertEquals(5, p.inventory.getAmount(4152))
|
||||
Assertions.assertEquals(0, p.inventory.getAmount(4151))
|
||||
}
|
||||
|
||||
@Test fun teleportAndNotePunishmentShouldNotAffectUnnotableItems() {
|
||||
val p = TestUtils.getMockPlayer("shitforbrains3")
|
||||
p.setAttribute("tutorial:complete", true)
|
||||
RandomEventManager().login(p)
|
||||
|
||||
p.inventory.add(Item(Items.AIR_RUNE_556, 30))
|
||||
content.global.ame.RandomEventManager.getInstance(p)?.fireEvent()
|
||||
p.getAttribute<RandomEventNPC>("re-npc")!!.noteAndTeleport()
|
||||
|
||||
Assertions.assertEquals(30, p.inventory.getAmount(Items.AIR_RUNE_556))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
package content
|
||||
|
||||
import TestUtils
|
||||
import content.global.ame.RandomEventNPC
|
||||
import content.global.ame.RandomEvents
|
||||
import core.api.*
|
||||
import core.game.system.timer.impl.AntiMacro
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.zone.impl.WildernessZone
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.rs09.consts.Items
|
||||
import org.rs09.consts.NPCs
|
||||
|
||||
class RandomEventTests {
|
||||
init {
|
||||
TestUtils.preTestSetup()
|
||||
}
|
||||
|
||||
@Test fun loginShouldRegisterRandomEventTimer() {
|
||||
TestUtils.getMockPlayer("antimacroAutoRegister").use { p ->
|
||||
Assertions.assertNotNull(getTimer<AntiMacro>(p))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun loginShouldSetNextSpawn() {
|
||||
TestUtils.getMockPlayer("antimacroautosetsnextspawnifunset").use { p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null.")
|
||||
Assertions.assertNotEquals(getWorldTicks(), timer.nextExecution)
|
||||
Assertions.assertEquals(true, timer.nextExecution - getWorldTicks() >= AntiMacro.MIN_DELAY_TICKS)
|
||||
Assertions.assertEquals(true, timer.nextExecution - getWorldTicks() <= AntiMacro.MAX_DELAY_TICKS)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun remainingDelayShouldPersistRelog() {
|
||||
TestUtils.getMockPlayer("antimacrotimeremainingpersists").use { p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null.")
|
||||
timer.nextExecution = getWorldTicks() + 666
|
||||
p.relog(ticksToWait = 100)
|
||||
Assertions.assertEquals(getWorldTicks() + 666, getTimer<AntiMacro>(p)!!.nextExecution)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun delayShouldBeRestartedOnceDepleted() {
|
||||
TestUtils.getMockPlayer("delayrestartoncedepleted").use { p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null.")
|
||||
TestUtils.advanceTicks(2, false)
|
||||
timer.nextExecution = 5 //run in 5 ticks
|
||||
TestUtils.advanceTicks(5, false)
|
||||
Assertions.assertEquals(true, timer.nextExecution - getWorldTicks() >= AntiMacro.MIN_DELAY_TICKS)
|
||||
Assertions.assertEquals(true, timer.nextExecution - getWorldTicks() <= AntiMacro.MAX_DELAY_TICKS)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun shouldSpawnRandomEventGivenNoRestrictions() {
|
||||
TestUtils.getMockPlayer("antimacroshouldspawnrandom").use {p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null!")
|
||||
TestUtils.advanceTicks(5, false)
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
TestUtils.advanceTicks(10, false)
|
||||
Assertions.assertNotNull(p.getAttribute(AntiMacro.EVENT_NPC, null))
|
||||
Assertions.assertEquals(true, p.getAttribute<RandomEventNPC>(AntiMacro.EVENT_NPC).isActive)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun teleportAndNotePunishmentShouldNotAffectAlreadyNotedItems() {
|
||||
TestUtils.getMockPlayer("teleportpunishment1").use {p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null!")
|
||||
TestUtils.advanceTicks(5, false)
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
TestUtils.advanceTicks(10, false)
|
||||
|
||||
addItem(p, Items.RAW_SHARK_384, 1000)
|
||||
getAttribute<RandomEventNPC?>(p, AntiMacro.EVENT_NPC, null)!!.noteAndTeleport()
|
||||
|
||||
Assertions.assertEquals(1000, amountInInventory(p, Items.RAW_SHARK_384))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun teleportAndNotePunishmentShouldNoteNotableUnnotedItems() {
|
||||
TestUtils.getMockPlayer("teleportpunishment2").use {p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null!")
|
||||
TestUtils.advanceTicks(5, false)
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
TestUtils.advanceTicks(10, false)
|
||||
|
||||
addItem(p, Items.ABYSSAL_WHIP_4151, 5)
|
||||
getAttribute<RandomEventNPC?>(p, AntiMacro.EVENT_NPC, null)!!.noteAndTeleport()
|
||||
|
||||
Assertions.assertEquals(5, amountInInventory(p, Items.ABYSSAL_WHIP_4152))
|
||||
Assertions.assertEquals(0, amountInInventory(p, Items.ABYSSAL_WHIP_4151))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun teleportAndNotePunishmentShouldNotAffectUnnotableItems() {
|
||||
TestUtils.getMockPlayer("teleportpunishment3").use {p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer is null!")
|
||||
TestUtils.advanceTicks(5, false)
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
TestUtils.advanceTicks(10, false)
|
||||
|
||||
addItem(p, Items.AIR_RUNE_556, 30)
|
||||
getAttribute<RandomEventNPC?>(p, AntiMacro.EVENT_NPC, null)!!.noteAndTeleport()
|
||||
|
||||
Assertions.assertEquals(30, amountInInventory(p, Items.AIR_RUNE_556))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun randomEventShouldNotSpawnInEventRestrictedArea() {
|
||||
|
||||
TestUtils.getMockPlayer("antimacronospawninrestrictedzone").use { p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer was null!")
|
||||
TestUtils.advanceTicks(5, false)
|
||||
|
||||
//Wilderness is Random Event restricted
|
||||
WildernessZone.getInstance().configure()
|
||||
val loc = Location.create(3131, 3595)
|
||||
p.location = loc
|
||||
|
||||
Assertions.assertEquals(loc, p.location)
|
||||
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
TestUtils.advanceTicks(10, false)
|
||||
Assertions.assertNull(AntiMacro.getEventNpc(p))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun randomEventShouldNotSpawnIfOneAlreadyActive() {
|
||||
TestUtils.getMockPlayer("antimacronospawnifalreadyhas").use { p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer was null!")
|
||||
TestUtils.advanceTicks(5, false)
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
TestUtils.advanceTicks(10, false)
|
||||
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||
|
||||
val previousEvent = AntiMacro.getEventNpc(p)
|
||||
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
TestUtils.advanceTicks(10, false)
|
||||
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||
Assertions.assertEquals(previousEvent, AntiMacro.getEventNpc(p))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun randomEventShouldSpawnIfCurrentOneIsInactive() {
|
||||
TestUtils.getMockPlayer("antimacrospawnifcurrentinactive").use { p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer was null!")
|
||||
TestUtils.advanceTicks(5, false)
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
TestUtils.advanceTicks(10, false)
|
||||
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||
|
||||
val previousEvent = AntiMacro.getEventNpc(p)
|
||||
AntiMacro.terminateEventNpc(p)
|
||||
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
TestUtils.advanceTicks(10, false)
|
||||
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||
Assertions.assertNotEquals(previousEvent, AntiMacro.getEventNpc(p))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun randomEventSystemShouldSupportPauseAndUnpause() {
|
||||
TestUtils.getMockPlayer("antimacropause").use { p ->
|
||||
val timer = getTimer<AntiMacro>(p) ?: Assertions.fail("AntiMacro timer was null!")
|
||||
TestUtils.advanceTicks(5, false)
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
|
||||
AntiMacro.pause(p)
|
||||
TestUtils.advanceTicks(10, false)
|
||||
Assertions.assertNull(AntiMacro.getEventNpc(p))
|
||||
|
||||
AntiMacro.unpause(p)
|
||||
timer.nextExecution = getWorldTicks() + 5
|
||||
TestUtils.advanceTicks(10, false)
|
||||
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun shouldBeAbleToForceRandomEvent() {
|
||||
TestUtils.getMockPlayer("antimacroforcerand").use { p ->
|
||||
TestUtils.advanceTicks(5, false)
|
||||
AntiMacro.forceEvent(p)
|
||||
TestUtils.advanceTicks(1, false)
|
||||
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun shouldBeAbleToForceSpecificRandomEvent() {
|
||||
TestUtils.getMockPlayer("antimacroforcespecific").use { p ->
|
||||
TestUtils.advanceTicks(5, false)
|
||||
AntiMacro.forceEvent(p, RandomEvents.TREE_SPIRIT)
|
||||
TestUtils.advanceTicks(1, false)
|
||||
Assertions.assertNotNull(AntiMacro.getEventNpc(p))
|
||||
Assertions.assertEquals(NPCs.TREE_SPIRIT_438, AntiMacro.getEventNpc(p)?.originalId)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun parseAntiMacroCommandArgsShouldReturnExpectedValues() {
|
||||
val testData = arrayOf(
|
||||
Triple("revent -p test", "test", null),
|
||||
Triple("revent -p test ", "test", null),
|
||||
Triple("revent -p test -e certer ", "test", RandomEvents.CERTER),
|
||||
Triple("revent -p test_user -e Sandwich lady", "test_user", RandomEvents.SANDWICH_LADY),
|
||||
Triple("revent -p test user -e sandwich Lady ", "test_user", RandomEvents.SANDWICH_LADY),
|
||||
Triple("revent -e sandwich Lady -p test user ", "test_user", RandomEvents.SANDWICH_LADY),
|
||||
Triple("revent test", "test", null),
|
||||
Triple("revent test -e sAndwich Lady", "test", RandomEvents.SANDWICH_LADY)
|
||||
)
|
||||
|
||||
for ((commandStr, expectedUser, expectedEvent) in testData) {
|
||||
val (resultUser, resultEvent) = AntiMacro.parseCommandArgs(commandStr, "revent")
|
||||
Assertions.assertEquals(expectedUser, resultUser)
|
||||
Assertions.assertEquals(expectedEvent, resultEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user