Skip to content

Commit

Permalink
Make GameObject an EventDispatcher and re-add Registered and Unregist…
Browse files Browse the repository at this point in the history
…ered events for it
  • Loading branch information
GregHib committed Feb 26, 2024
1 parent 55ce7e3 commit b539c42
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,8 @@ import world.gregs.voidps.engine.entity.character.Character
import world.gregs.voidps.engine.entity.character.npc.NPC
import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.engine.entity.item.floor.FloorItem
import world.gregs.voidps.engine.event.Event
import world.gregs.voidps.engine.event.Priority
import world.gregs.voidps.engine.event.on
import world.gregs.voidps.engine.event.onWorld
import world.gregs.voidps.engine.event.onFloorItem
import world.gregs.voidps.engine.event.onCharacter
import world.gregs.voidps.engine.event.onNPC
import world.gregs.voidps.engine.event.wildcardEquals
import world.gregs.voidps.engine.entity.obj.GameObject
import world.gregs.voidps.engine.event.*

object Registered : Event

Expand Down Expand Up @@ -39,6 +33,10 @@ fun floorItemSpawn(block: suspend Registered.(FloorItem) -> Unit) {
onFloorItem<Registered>(block = block)
}

fun objectSpawn(block: suspend Registered.(GameObject) -> Unit) {
onObject<Registered>(block = block)
}

fun worldSpawn(block: suspend () -> Unit) {
onWorld<Registered> {
block.invoke()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,8 @@ import world.gregs.voidps.engine.entity.character.Character
import world.gregs.voidps.engine.entity.character.npc.NPC
import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.engine.entity.item.floor.FloorItem
import world.gregs.voidps.engine.event.Event
import world.gregs.voidps.engine.event.Priority
import world.gregs.voidps.engine.event.on
import world.gregs.voidps.engine.event.onFloorItem
import world.gregs.voidps.engine.event.onCharacter
import world.gregs.voidps.engine.event.onNPC
import world.gregs.voidps.engine.entity.obj.GameObject
import world.gregs.voidps.engine.event.*

object Unregistered : Event

Expand All @@ -28,3 +24,7 @@ fun characterDespawn(block: suspend Unregistered.(Character) -> Unit) {
fun floorItemDespawn(block: suspend Unregistered.(FloorItem) -> Unit) {
onFloorItem<Unregistered>(block = block)
}

fun objectDespawn(block: suspend Unregistered.(GameObject) -> Unit) {
onObject<Unregistered>(block = block)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package world.gregs.voidps.engine.entity.obj

import org.koin.mp.KoinPlatformTools
import world.gregs.voidps.cache.definition.data.ObjectDefinition
import world.gregs.voidps.engine.client.update.batch.ZoneBatchUpdates
import world.gregs.voidps.engine.data.definition.AnimationDefinitions
import world.gregs.voidps.engine.data.definition.ObjectDefinitions
import world.gregs.voidps.engine.entity.Entity
import world.gregs.voidps.engine.event.EventDispatcher
import world.gregs.voidps.engine.get
import world.gregs.voidps.network.encode.zone.ObjectAnimation
import world.gregs.voidps.type.Distance
Expand All @@ -14,7 +16,7 @@ import world.gregs.voidps.type.Tile
* Interactive Object
*/
@JvmInline
value class GameObject(internal val packed: Long) : Entity {
value class GameObject(internal val packed: Long) : Entity, EventDispatcher {

constructor(id: Int, x: Int, y: Int, level: Int, shape: Int, rotation: Int) : this(pack(id, x, y, level, shape, rotation))

Expand Down Expand Up @@ -53,7 +55,11 @@ value class GameObject(internal val packed: Long) : Entity {
)

override fun toString(): String {
return "GameObject(id=$id, intId=$intId, tile=$tile, shape=$shape, rotation=$rotation)"
return if (KoinPlatformTools.defaultContext().getOrNull() == null) {
"GameObject(intId=$intId, tile=$tile, shape=$shape, rotation=$rotation)"
} else {
"GameObject(id=$id, intId=$intId, tile=$tile, shape=$shape, rotation=$rotation)"
}
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import world.gregs.voidps.cache.definition.data.ObjectDefinition
import world.gregs.voidps.engine.client.ui.chat.toInt
import world.gregs.voidps.engine.client.update.batch.ZoneBatchUpdates
import world.gregs.voidps.engine.data.definition.ObjectDefinitions
import world.gregs.voidps.engine.entity.Registered
import world.gregs.voidps.engine.entity.Unregistered
import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.engine.get
import world.gregs.voidps.engine.map.collision.GameObjectCollision
Expand All @@ -19,6 +21,7 @@ import world.gregs.voidps.type.Zone
* "original" objects refer to those [set] on game load from the cache or map file
* "temporary" objects are [add]ed or [remove]ed with a reset timer
* "permanent" objects are [add]ed or [remove]ed without a reset timer (but don't persist after server restart)
* Note: [Registered] and [Unregistered] events are only emitted for temporary and permanent objects, original objects that are added or removed do not emit events.
* @param storeUnused store non-interactive and objects without configs for debugging and content dev (uses ~240MB more ram).
*/
class GameObjects(
Expand Down Expand Up @@ -63,15 +66,17 @@ class GameObjects(
}
size++
} else {
// Remove original (if exists)
map.add(obj, REPLACED)
if (original > 0 && !replaced(original)) {
val originalObj = GameObject(id(original), obj.x, obj.y, obj.level, shape(original), rotation(original))
batches.add(obj.tile.zone, ObjectRemoval(obj.tile.id, originalObj.shape, originalObj.rotation))
if (collision) {
collisions.modify(originalObj, add = false)
if (replaced(original)) {
// Remove replacements (if exists)
val current = replacements[obj.index]
if (current != null) {
val currentObj = remove(current, obj, collision)
currentObj.emit(Unregistered)
}
size--
} else if (original > 0) {
// Remove original (if exists)
remove(original, obj, collision)
}

// Add replacement
Expand All @@ -81,9 +86,20 @@ class GameObjects(
collisions.modify(obj, add = true)
}
size++
obj.emit(Registered)
}
}

private fun remove(objectValue: Int, obj: GameObject, collision: Boolean): GameObject {
val gameObject = GameObject(id(objectValue), obj.x, obj.y, obj.level, shape(objectValue), rotation(objectValue))
batches.add(obj.tile.zone, ObjectRemoval(obj.tile.id, gameObject.shape, gameObject.rotation))
if (collision) {
collisions.modify(gameObject, add = false)
}
size--
return gameObject
}

/**
* Sets the original placement of a game object
*/
Expand Down Expand Up @@ -130,6 +146,7 @@ class GameObjects(
collisions.modify(obj, add = false)
}
size--
obj.emit(Unregistered)
// Re-add original (if exists)
map.remove(obj, REPLACED)
if (original > 1) {
Expand All @@ -154,7 +171,15 @@ class GameObjects(
/**
* Replaces [original] object with [id], optionally reverting after [ticks]
*/
fun replace(original: GameObject, id: String, tile: Tile = original.tile, shape: Int = original.shape, rotation: Int = original.rotation, ticks: Int = NEVER, collision: Boolean = true): GameObject {
fun replace(
original: GameObject,
id: String,
tile: Tile = original.tile,
shape: Int = original.shape,
rotation: Int = original.rotation,
ticks: Int = NEVER,
collision: Boolean = true
): GameObject {
val replacement = GameObject(definitions.get(id).id, tile, shape, rotation)
replace(original, replacement, ticks, collision)
return replacement
Expand Down Expand Up @@ -334,12 +359,14 @@ class GameObjects(
private const val REPLACED = 0x1

private fun empty(value: Int) = value == -1 || value == 0

/**
* Value represents an objects id, shape and rotation plus and extra bit for whether the object has been [REPLACED] or removed.
*/
internal fun value(replaced: Boolean, id: Int, shape: Int, rotation: Int): Int {
return replaced.toInt() or (rotation shl 1) + (shape shl 3) + (id shl 8)
}

private fun id(value: Int): Int = value shr 8 and 0x1ffff
private fun shape(value: Int): Int = value shr 3 and 0x1f
private fun rotation(value: Int): Int = value shr 1 and 0x3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import world.gregs.voidps.engine.entity.character.Character
import world.gregs.voidps.engine.entity.character.npc.NPC
import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.engine.entity.item.floor.FloorItem
import world.gregs.voidps.engine.entity.obj.GameObject
import kotlin.coroutines.CoroutineContext
import kotlin.reflect.KClass

Expand Down Expand Up @@ -88,6 +89,11 @@ class EventStore : CoroutineScope {
}
var events = EventStore()
private set

fun setEvents(eventStore: EventStore) {
this.events = eventStore
}

private val parents = Object2ObjectOpenHashMap(mapOf(
Character::class to listOf(Player::class.simpleName, NPC::class.simpleName)
))
Expand Down Expand Up @@ -115,4 +121,7 @@ inline fun <reified E : Event> onFloorItem(noinline condition: E.(FloorItem) ->
addEvent(condition, priority, block)

inline fun <reified E : Event> onWorld(noinline condition: E.(World) -> Boolean = { true }, priority: Priority = Priority.MEDIUM, noinline block: suspend E.(World) -> Unit) =
addEvent(condition, priority, block)

inline fun <reified E : Event> onObject(noinline condition: E.(GameObject) -> Boolean = { true }, priority: Priority = Priority.MEDIUM, noinline block: suspend E.(GameObject) -> Unit) =
addEvent(condition, priority, block)
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package world.gregs.voidps.engine.entity.obj

import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import io.mockk.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import world.gregs.voidps.cache.definition.data.ObjectDefinition
import world.gregs.voidps.engine.client.update.batch.ZoneBatchUpdates
import world.gregs.voidps.engine.data.definition.ObjectDefinitions
import world.gregs.voidps.engine.entity.Registered
import world.gregs.voidps.engine.entity.Unregistered
import world.gregs.voidps.engine.event.EventStore
import world.gregs.voidps.type.Tile
import world.gregs.voidps.network.encode.zone.ObjectAddition
import world.gregs.voidps.network.encode.zone.ObjectRemoval
Expand All @@ -20,6 +21,7 @@ class GameObjectsTest {

private lateinit var objects: GameObjects
private lateinit var updates: ZoneBatchUpdates
private lateinit var events: EventStore

@BeforeEach
fun setup() {
Expand All @@ -29,6 +31,8 @@ class GameObjectsTest {
every { definitions.get("test2") } returns ObjectDefinition(456)
updates = mockk(relaxed = true)
objects = GameObjects(mockk(relaxed = true), updates, definitions, storeUnused = true)
events = spyk(EventStore())
EventStore.setEvents(events)
}

@Test
Expand All @@ -42,6 +46,9 @@ class GameObjectsTest {
assertNull(objects.getLayer(Tile(10, 10, 1), ObjectLayer.GROUND))
objects.clear()
assertNull(objects.getLayer(obj.tile, ObjectLayer.GROUND))
verify(exactly = 0) {
events.emit(obj, any())
}
}

@Test
Expand All @@ -57,6 +64,9 @@ class GameObjectsTest {
verify {
updates.add(obj.tile.zone, ObjectRemoval(tile = obj.tile.id, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 1))
}
verify(exactly = 0) {
events.emit(obj, any())
}
}

@Test
Expand All @@ -70,8 +80,10 @@ class GameObjectsTest {
objects.reset(obj.tile.zone)
assertNull(objects.getLayer(obj.tile, ObjectLayer.GROUND))
assertFalse(objects.contains(obj))
verify {
verifyOrder {
updates.add(obj.tile.zone, ObjectAddition(tile = obj.tile.id, id = 1234, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 1))
events.emit(obj, Registered)
events.emit(obj, Unregistered)
}
}

Expand All @@ -93,10 +105,13 @@ class GameObjectsTest {
assertNull(objects.getLayer(obj.tile, ObjectLayer.GROUND))
assertFalse(objects.contains(obj))
assertFalse(objects.contains(override))
verify {
verifyOrder {
updates.add(obj.tile.zone, ObjectAddition(tile = obj.tile.id, id = 1234, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 1))
events.emit(obj, Registered)
updates.add(obj.tile.zone, ObjectAddition(tile = obj.tile.id, id = 4321, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 0))
events.emit(override, Registered)
updates.add(obj.tile.zone, ObjectRemoval(tile = obj.tile.id, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 0))
events.emit(override, Unregistered)
}
}

Expand All @@ -112,10 +127,12 @@ class GameObjectsTest {
objects.remove(obj)
assertEquals(original, objects.getLayer(obj.tile, ObjectLayer.GROUND))

verify {
verifyOrder {
updates.add(obj.tile.zone, ObjectRemoval(tile = obj.tile.id, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 1))
updates.add(obj.tile.zone, ObjectAddition(tile = obj.tile.id, id = 1234, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 0))
events.emit(obj, Registered)
updates.add(obj.tile.zone, ObjectRemoval(tile = obj.tile.id, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 0))
events.emit(obj, Unregistered)
updates.add(obj.tile.zone, ObjectAddition(tile = obj.tile.id, id = 123, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 1))
}
}
Expand All @@ -136,12 +153,19 @@ class GameObjectsTest {
objects.remove(override)
assertEquals(original, objects.getLayer(obj.tile, ObjectLayer.GROUND))

verify {
verifyOrder {
// Add 1234
updates.add(obj.tile.zone, ObjectRemoval(tile = obj.tile.id, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 1))
updates.add(obj.tile.zone, ObjectAddition(tile = obj.tile.id, id = 1234, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 0))
events.emit(obj, Registered)
// Add 4321
updates.add(obj.tile.zone, ObjectRemoval(tile = obj.tile.id, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 0))
events.emit(obj, Unregistered)
updates.add(obj.tile.zone, ObjectAddition(tile = obj.tile.id, id = 4321, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 0))
events.emit(override, Registered)
// Remove 4321
updates.add(obj.tile.zone, ObjectRemoval(tile = obj.tile.id, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 0))
events.emit(override, Unregistered)
updates.add(obj.tile.zone, ObjectAddition(tile = obj.tile.id, id = 123, type = ObjectShape.CENTRE_PIECE_STRAIGHT, rotation = 1))
}
}
Expand All @@ -154,6 +178,10 @@ class GameObjectsTest {
objects.timers.run()
}
assertFalse(objects.contains(obj))
verifyOrder {
events.emit(obj, Registered)
events.emit(obj, Unregistered)
}
}

@Test
Expand All @@ -166,6 +194,11 @@ class GameObjectsTest {
objects.timers.run()
}
assertTrue(objects.contains(obj))
verifyOrder {
events.emit(obj, Registered)
events.emit(obj, Unregistered)
events.emit(obj, Registered)
}
}

@Test
Expand All @@ -180,6 +213,12 @@ class GameObjectsTest {
}
assertTrue(objects.contains(obj))
assertFalse(objects.contains(replacement))
verifyOrder {
events.emit(obj, Registered)
events.emit(obj, Unregistered)
events.emit(replacement, Registered)
events.emit(obj, Registered)
}
}

@Test
Expand All @@ -194,5 +233,9 @@ class GameObjectsTest {
}
assertTrue(objects.contains(original))
assertFalse(objects.contains(replacement))
verifyOrder {
events.emit(replacement, Registered)
events.emit(replacement, Unregistered)
}
}
}

0 comments on commit b539c42

Please sign in to comment.