Random Events should now spawn correctly

Fixed an issue that was causing tick event hooks to not fire
This commit is contained in:
Ceikry
2022-05-16 12:22:29 +00:00
committed by Ryan
parent 8835799230
commit 07065c7e79
8 changed files with 67 additions and 9 deletions
@@ -2,6 +2,7 @@ package core.game.node.entity;
import api.events.Event; import api.events.Event;
import api.events.EventHook; import api.events.EventHook;
import api.events.TickEvent;
import core.game.content.holiday.HolidayEvent; import core.game.content.holiday.HolidayEvent;
import core.game.interaction.DestinationFlag; import core.game.interaction.DestinationFlag;
import core.game.node.Node; import core.game.node.Node;
@@ -216,6 +217,7 @@ public abstract class Entity extends Node {
* This methods gets called before the {@link #update()} method. * This methods gets called before the {@link #update()} method.
*/ */
public void tick() { public void tick() {
dispatch(new TickEvent(GameWorld.getTicks()));
skills.pulse(); skills.pulse();
walkingQueue.update(); walkingQueue.update();
updateMasks.prepare(this); updateMasks.prepare(this);
@@ -70,6 +70,9 @@ public final class WalkingQueue {
boolean isPlayer = entity instanceof Player; boolean isPlayer = entity instanceof Player;
this.walkDir = -1; this.walkDir = -1;
this.runDir = -1; this.runDir = -1;
if(entity.getLocation() == null) {
return;
}
if (updateTeleport()) { if (updateTeleport()) {
return; return;
} }
+1 -1
View File
@@ -13,4 +13,4 @@ data class InteractionEvent(val target: Node, val option: String) : Event
data class ButtonClickedEvent(val iface: Int, val buttonId: Int) : Event data class ButtonClickedEvent(val iface: Int, val buttonId: Int) : Event
data class UsedWithEvent(val used: Int, val with: Int) : Event data class UsedWithEvent(val used: Int, val with: Int) : Event
data class SelfDeath(val killer: Entity) : Event data class SelfDeath(val killer: Entity) : Event
data class TickEvent(val source: Entity) : Event data class TickEvent(val worldTicks: Int) : Event
@@ -14,9 +14,6 @@ import rs09.game.system.SystemLogger
import rs09.game.world.GameWorld import rs09.game.world.GameWorld
import kotlin.random.Random import kotlin.random.Random
private const val AVG_DELAY_TICKS = 6000 // 60 minutes
private const val MIN_DELAY_TICKS = AVG_DELAY_TICKS / 2
private const val MAX_DELAY_TICKS = MIN_DELAY_TICKS + AVG_DELAY_TICKS // window of 60 min centered on 60 min (30 to 90 min)
class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<TickEvent> { class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<TickEvent> {
var event: RandomEventNPC? = null var event: RandomEventNPC? = null
var enabled: Boolean = false var enabled: Boolean = false
@@ -47,7 +44,7 @@ class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<
return return
} }
if (getAttribute<RandomEventNPC?>(player, "re-npc", null) != null) return if (getAttribute<RandomEventNPC?>(player, "re-npc", null) != null) return
val currentAction = player.pulseManager.current.toString() val currentAction = player.pulseManager.current?.toString() ?: "None"
val ame: RandomEvents = if(currentAction.contains("WoodcuttingSkillPulse") && Random.nextBoolean()){ val ame: RandomEvents = if(currentAction.contains("WoodcuttingSkillPulse") && Random.nextBoolean()){
RandomEvents.TREE_SPIRIT RandomEvents.TREE_SPIRIT
} else if(currentAction.contains("FishingPulse") && Random.nextBoolean()){ } else if(currentAction.contains("FishingPulse") && Random.nextBoolean()){
@@ -62,6 +59,7 @@ class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<
event = ame.npc.create(player,ame.loot,ame.type) event = ame.npc.create(player,ame.loot,ame.type)
if (event!!.spawnLocation == null) { if (event!!.spawnLocation == null) {
nextSpawn = GameWorld.ticks + 3000 nextSpawn = GameWorld.ticks + 3000
SystemLogger.logWarn("Tried to spawn random event for ${player.username} but spawn location was null!")
return return
} }
event!!.init() event!!.init()
@@ -74,6 +72,10 @@ class RandomEventManager(val player: Player? = null) : LoginListener, EventHook<
} }
companion object { companion object {
const val AVG_DELAY_TICKS = 6000 // 60 minutes
const val MIN_DELAY_TICKS = AVG_DELAY_TICKS / 2
const val MAX_DELAY_TICKS = MIN_DELAY_TICKS + AVG_DELAY_TICKS // window of 60 min centered on 60 min (30 to 90 min)
@JvmStatic fun getInstance(player: Player): RandomEventManager? @JvmStatic fun getInstance(player: Player): RandomEventManager?
{ {
return getAttribute(player, "random-manager", null) return getAttribute(player, "random-manager", null)
@@ -9,6 +9,7 @@ import core.tools.RandomFunction
import org.rs09.consts.Items import org.rs09.consts.Items
import rs09.game.content.ame.RandomEventNPC import rs09.game.content.ame.RandomEventNPC
import rs09.game.content.global.WeightBasedTable import rs09.game.content.global.WeightBasedTable
import java.lang.Integer.max
val ids = 2463..2468 val ids = 2463..2468
@@ -18,7 +19,7 @@ class EvilChickenNPC(override var loot: WeightBasedTable? = null) : RandomEventN
override fun init() { override fun init() {
super.init() super.init()
val index = (player.properties.combatLevel / 20) - 1 val index = max(0, (player.properties.combatLevel / 20) - 1)
val id = ids.toList()[index] val id = ids.toList()[index]
this.transform(id) this.transform(id)
this.attack(player) this.attack(player)
@@ -38,7 +38,7 @@ class UpdateSequence
playersList = renderablePlayers playersList = renderablePlayers
npcList = Repository.renderableNpcs npcList = Repository.renderableNpcs
lobbyList!!.map{ PacketRepository.send(ClearMinimapFlag::class.java, PlayerContext(it)) } lobbyList!!.map{ PacketRepository.send(ClearMinimapFlag::class.java, PlayerContext(it)) }
playersList!!.forEach(Player::tick) renderablePlayers.forEach(Player::tick)
npcList!!.forEach(NPC::tick) npcList!!.forEach(NPC::tick)
} }
+16 -2
View File
@@ -11,18 +11,21 @@ import org.rs09.consts.Items
import rs09.ServerConstants import rs09.ServerConstants
import rs09.game.content.global.shops.Shop import rs09.game.content.global.shops.Shop
import rs09.game.content.global.shops.ShopItem import rs09.game.content.global.shops.ShopItem
import rs09.game.system.SystemLogger
import rs09.game.system.config.ConfigParser import rs09.game.system.config.ConfigParser
import rs09.game.system.config.ServerConfigParser import rs09.game.system.config.ServerConfigParser
import rs09.game.world.GameWorld import rs09.game.world.GameWorld
import rs09.game.world.repository.Repository import rs09.game.world.repository.Repository
import rs09.game.world.update.UpdateSequence
import java.nio.ByteBuffer import java.nio.ByteBuffer
object TestUtils { object TestUtils {
fun getMockPlayer(name: String, ironman: IronmanMode = IronmanMode.NONE): Player { fun getMockPlayer(name: String, ironman: IronmanMode = IronmanMode.NONE): Player {
val p = Player(PlayerDetails(name)) val p = MockPlayer(name)
p.details.session = MockSession()
p.ironmanManager.mode = ironman p.ironmanManager.mode = ironman
Repository.addPlayer(p) Repository.addPlayer(p)
//Update sequence has a separate list of players for some reason...
UpdateSequence.renderablePlayers.add(p)
return p return p
} }
@@ -53,12 +56,23 @@ object TestUtils {
} }
fun advanceTicks(amount: Int) { fun advanceTicks(amount: Int) {
SystemLogger.logInfo("Advancing ticks by $amount.")
for(i in 0 until amount) { for(i in 0 until amount) {
GameWorld.majorUpdateWorker.handleTickActions() GameWorld.majorUpdateWorker.handleTickActions()
} }
} }
} }
class MockPlayer(name: String) : Player(PlayerDetails(name)) {
init {
this.details.session = MockSession()
}
override fun update() {
//do nothing. This is for rendering stuff. We don't render a mock player. Not until the spaghetti is less spaghetti.
}
}
class MockSession : IoSession(null, null) { class MockSession : IoSession(null, null) {
val receivedPackets = ArrayList<Packet>() val receivedPackets = ArrayList<Packet>()
var disconnected = false var disconnected = false
@@ -0,0 +1,36 @@
package content
import TestUtils
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import rs09.game.world.GameWorld
class RandomEventManager {
companion object {init {
TestUtils.preTestSetup()
}}
@Test fun loginShouldEnableManager() {
val p = TestUtils.getMockPlayer("Bill")
rs09.game.content.ame.RandomEventManager().login(p)
val manager = rs09.game.content.ame.RandomEventManager.getInstance(p)
Assertions.assertNotNull(manager)
Assertions.assertEquals(true, manager!!.enabled)
}
@Test fun loginShouldSetNextSpawn() {
val p = TestUtils.getMockPlayer("Bill")
rs09.game.content.ame.RandomEventManager().login(p)
val manager = rs09.game.content.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
rs09.game.content.ame.RandomEventManager().login(p)
TestUtils.advanceTicks(rs09.game.content.ame.RandomEventManager.MAX_DELAY_TICKS + 5)
Assertions.assertNotNull(p.getAttribute("re-npc", null))
}
}