diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/object/LoungeOrientation.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/object/LoungeOrientation.kt index e518b6bd..69b7cf58 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/object/LoungeOrientation.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/object/LoungeOrientation.kt @@ -1,11 +1,12 @@ package ru.dbotthepony.kstarbound.defs.`object` import ru.dbotthepony.kstarbound.json.builder.IStringSerializable +import ru.dbotthepony.kstarbound.world.entities.HumanoidActorEntity // int32_t -enum class LoungeOrientation(override val jsonName: String) : IStringSerializable { - NONE("none"), - SIT("sit"), - LAY("lay"), - STAND("stand"); +enum class LoungeOrientation(override val jsonName: String, val humanoidState: HumanoidActorEntity.HumanoidState) : IStringSerializable { + NONE("none", HumanoidActorEntity.HumanoidState.IDLE), + SIT("sit", HumanoidActorEntity.HumanoidState.SIT), + LAY("lay", HumanoidActorEntity.HumanoidState.LAY), + STAND("stand", HumanoidActorEntity.HumanoidState.IDLE); } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/NPCBindings.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/NPCBindings.kt index 02141353..d00015b2 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/NPCBindings.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/NPCBindings.kt @@ -102,7 +102,7 @@ fun provideNPCBindings(self: NPCEntity, lua: LuaEnvironment) { val anchorIndex = oAnchorIndex?.toInt() ?: 0 val entity = self.world.entities[loungeable.toInt()] as? LoungeableEntity - if (entity == null || anchorIndex !in 0 until entity.sitPositions.size || entity.entitiesLoungingIn(anchorIndex).isNotEmpty()) { + if (entity == null || anchorIndex !in 0 until entity.anchors.size || entity.entitiesLoungingIn(anchorIndex).isNotEmpty()) { returnBuffer.setTo(false) } else { self.movement.anchorNetworkState = AnchorNetworkState(loungeable.toInt(), anchorIndex) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/serverbound/EntityInteractPacket.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/serverbound/EntityInteractPacket.kt index 21f1eb7c..5bd210fe 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/serverbound/EntityInteractPacket.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/network/packets/serverbound/EntityInteractPacket.kt @@ -28,7 +28,7 @@ class EntityInteractPacket(val request: InteractRequest, val id: UUID) : IServer override suspend fun play(connection: ServerConnection) { if (request.target >= 0) { - connection.enqueue { + connection.enqueueAndSuspend { connection.send(EntityInteractResultPacket((entities[request.target] as? InteractiveEntity)?.interact(request) ?: InteractAction.NONE, id, request.source)) } } else { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/ActorMovementController.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/ActorMovementController.kt index f6ea0a9e..0ab0a63a 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/ActorMovementController.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/ActorMovementController.kt @@ -69,7 +69,7 @@ class ActorMovementController() : MovementController() { if (networkState != null) { val entity = world.entities[networkState.entityID] as? LoungeableEntity ?: throw InvalidArgumentException("${networkState.entityID} is not a valid entity or not a loungeable one") - state = entity.anchor(networkState.positionIndex) ?: throw IllegalArgumentException("Anchor with index ${networkState.positionIndex} of $entity is either invalid or disabled") + state = entity.anchors.getOrNull(networkState.positionIndex) ?: throw IllegalArgumentException("Anchor with index ${networkState.positionIndex} of $entity is either invalid or disabled") } if (state == null && this.anchorState?.exitBottomPosition != null) { @@ -344,7 +344,7 @@ class ActorMovementController() : MovementController() { if (anchorNetworkState == null) this.anchorState = null else - this.anchorState = (world.entities[anchorNetworkState.entityID] as? LoungeableEntity)?.anchor(anchorNetworkState.positionIndex) + this.anchorState = (world.entities[anchorNetworkState.entityID] as? LoungeableEntity)?.anchors?.getOrNull(anchorNetworkState.positionIndex) super.tickRemote(delta) } @@ -355,7 +355,7 @@ class ActorMovementController() : MovementController() { val anchorNetworkState = anchorNetworkState if (anchorNetworkState != null) { - state = (world.entities[anchorNetworkState.entityID] as? LoungeableEntity)?.anchor(anchorNetworkState.positionIndex) + state = (world.entities[anchorNetworkState.entityID] as? LoungeableEntity)?.anchors?.getOrNull(anchorNetworkState.positionIndex) } if (state == null) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/AnchorState.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/AnchorState.kt index 33044a49..326245a2 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/AnchorState.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/AnchorState.kt @@ -1,9 +1,9 @@ package ru.dbotthepony.kstarbound.world.entities import com.google.gson.JsonElement -import com.google.gson.JsonObject import ru.dbotthepony.kstarbound.client.render.RenderLayer import ru.dbotthepony.kstarbound.defs.actor.PersistentStatusEffect +import ru.dbotthepony.kstarbound.defs.`object`.LoungeOrientation import ru.dbotthepony.kstarbound.math.vector.Vector2d import ru.dbotthepony.kstarbound.world.Direction @@ -21,23 +21,15 @@ data class AnchorState( override val angle: Double ) : IAnchorState -// int32_t -enum class LoungeOrientation(val humanoidState: HumanoidActorEntity.HumanoidState) { - NONE(HumanoidActorEntity.HumanoidState.IDLE), - SIT(HumanoidActorEntity.HumanoidState.SIT), - LAY(HumanoidActorEntity.HumanoidState.LAY), - STAND(HumanoidActorEntity.HumanoidState.IDLE); -} - data class LoungeAnchorState( override val position: Vector2d, override val exitBottomPosition: Vector2d?, override val direction: Direction, override val angle: Double, val orientation: LoungeOrientation = LoungeOrientation.NONE, - val loungeRenderLayer: RenderLayer, + val loungeRenderLayer: RenderLayer.Point, val controllable: Boolean = false, - val statusEffects: List = listOf(), + val statusEffects: Set = setOf(), val effectEmitters: Set = setOf(), val emote: String? = null, val dance: String? = null, diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/api/LoungeableEntity.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/api/LoungeableEntity.kt index 311e64ac..1726a9ef 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/api/LoungeableEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/api/LoungeableEntity.kt @@ -1,19 +1,18 @@ package ru.dbotthepony.kstarbound.world.entities.api -import ru.dbotthepony.kstarbound.math.vector.Vector2d import ru.dbotthepony.kstarbound.world.entities.ActorEntity import ru.dbotthepony.kstarbound.world.entities.IAnchorState interface LoungeableEntity { - val sitPositions: List + val anchors: List + + /** + * Determines entities currently lounging in this entity + */ + fun entitiesLoungingIn(): List /** * Determines entities currently lounging at specified anchor index */ fun entitiesLoungingIn(index: Int): List - - /** - * Returns anchor information with given index, or null if index is invalid - */ - fun anchor(index: Int): IAnchorState? } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/LoungeableObject.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/LoungeableObject.kt index c3482020..3950f07a 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/LoungeableObject.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/LoungeableObject.kt @@ -3,6 +3,7 @@ package ru.dbotthepony.kstarbound.world.entities.tile import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableSet import com.google.gson.JsonArray +import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonPrimitive import com.google.gson.reflect.TypeToken @@ -11,6 +12,7 @@ import ru.dbotthepony.kommons.util.Either import ru.dbotthepony.kstarbound.math.vector.Vector2d import ru.dbotthepony.kstarbound.Registry import ru.dbotthepony.kstarbound.Starbound +import ru.dbotthepony.kstarbound.client.render.RenderLayer import ru.dbotthepony.kstarbound.defs.InteractAction import ru.dbotthepony.kstarbound.defs.InteractRequest import ru.dbotthepony.kstarbound.defs.actor.PersistentStatusEffect @@ -23,6 +25,7 @@ import ru.dbotthepony.kstarbound.world.Direction import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNIT import ru.dbotthepony.kstarbound.world.entities.ActorEntity import ru.dbotthepony.kstarbound.world.entities.IAnchorState +import ru.dbotthepony.kstarbound.world.entities.LoungeAnchorState import ru.dbotthepony.kstarbound.world.entities.api.LoungeableEntity import java.lang.Math.toRadians @@ -31,67 +34,100 @@ class LoungeableObject(config: Registry.Entry) : WorldObject(c isInteractive = true } - override val sitPositions = ArrayList() + override val anchors = ArrayList() - var sitFlipDirection = false - private set - var sitOrientation = LoungeOrientation.NONE - private set - var sitAngle = 0.0 - private set var sitCoverImage = "" private set var sitFlipImages = false private set - val sitStatusEffects = ObjectArraySet() - val sitEffectEmitters = ObjectArraySet() - - var sitEmote: String? = null - private set - var sitDance: String? = null - private set - var sitArmorCosmeticOverrides: JsonObject = JsonObject() - private set - var sitCursorOverride: String? = null - private set - private fun updateSitParams() { - orientation ?: return + anchors.clear() + val orientation = orientation ?: return + + val sitPositionsList = ArrayList() + + val sitDir = orientation.directionAffinity ?: Direction.LEFT - sitPositions.clear() val sitPosition = lookupProperty("sitPosition") val sitPositions = lookupProperty("sitPositions") if (!sitPosition.isJsonNull) { - this.sitPositions.add(vectors.fromJsonTree(sitPosition) / PIXELS_IN_STARBOUND_UNIT) + sitPositionsList.add(vectors.fromJsonTree(sitPosition) / PIXELS_IN_STARBOUND_UNIT * sitDir.normal) } else if (!sitPositions.isJsonNull) { - vectorsList.fromJsonTree(sitPositions).forEach { this.sitPositions.add(it / PIXELS_IN_STARBOUND_UNIT) } + vectorsList.fromJsonTree(sitPositions).forEach { sitPositionsList.add(it / PIXELS_IN_STARBOUND_UNIT * sitDir.normal) } } - sitFlipDirection = lookupProperty("sitFlipDirection") { JsonPrimitive(false) }.asBoolean - sitOrientation = LoungeOrientation.entries.valueOf(lookupProperty("sitOrientation") { JsonPrimitive("sit") }.asString) - sitAngle = toRadians(lookupProperty("sitAngle") { JsonPrimitive(0.0) }.asDouble) + val sitFlipDirection = lookupProperty("sitFlipDirection") { JsonPrimitive(false) }.asBoolean + val sitOrientation = LoungeOrientation.entries.valueOf(lookupProperty("sitOrientation") { JsonPrimitive("sit") }.asString) + var sitAngle = toRadians(lookupProperty("sitAngle") { JsonPrimitive(0.0) }.asDouble) sitCoverImage = lookupProperty("sitCoverImage") { JsonPrimitive("") }.asString sitFlipImages = lookupProperty("flipImages") { JsonPrimitive(false) }.asBoolean - sitStatusEffects.clear() + if (sitDir == Direction.LEFT) { + sitAngle *= -1f + } + + val sitStatusEffects = ObjectArraySet() sitStatusEffects.addAll(statusEffects.fromJsonTree(lookupProperty("sitStatusEffects") { JsonArray() })) - sitEffectEmitters.clear() + val sitEffectEmitters = ObjectArraySet() lookupProperty("sitEffectEmitters") { JsonArray() }.asJsonArray.forEach { sitEffectEmitters.add(it.asString) } - sitEmote = lookupProperty("sitEmote").coalesceNull?.asString - sitDance = lookupProperty("sitDance").coalesceNull?.asString - sitArmorCosmeticOverrides = lookupProperty("sitArmorCosmeticOverrides") { JsonObject() } as JsonObject - sitCursorOverride = lookupProperty("sitCursorOverride").coalesceNull?.asString + val sitEmote = lookupProperty("sitEmote").coalesceNull?.asString + val sitDance = lookupProperty("sitDance").coalesceNull?.asString + val sitArmorCosmeticOverrides = lookupProperty("sitArmorCosmeticOverrides") { JsonObject() } as JsonObject + val sitCursorOverride = lookupProperty("sitCursorOverride").coalesceNull?.asString + + for ((i, pos) in sitPositionsList.withIndex()) { + val anchor = LoungeAnchorState( + position = pos, + exitBottomPosition = pos.copy(y = yTilePosition.toDouble() + volumeBoundingBox.mins.y), + direction = if (sitFlipDirection) sitDir.opposite else sitDir, + angle = sitAngle, + orientation = sitOrientation, + // Layer all anchored entities one above the object layer, in top to bottom + // order based on the anchor index. + loungeRenderLayer = RenderLayer.Object.point(i.toLong()), + controllable = false, + emote = sitEmote, + dance = sitDance, + armorCosmeticOverrides = LinkedHashMap().also { for ((k, v) in sitArmorCosmeticOverrides.entrySet()) { it[k] = v } }, + cursorOverride = sitCursorOverride, + statusEffects = sitStatusEffects, + effectEmitters = sitEffectEmitters + ) + + anchors.add(anchor) + } } override fun entitiesLoungingIn(index: Int): List { - TODO("Not yet implemented") + if (index !in anchors.indices) return listOf() + val result = ArrayList() + + world.entityIndex.iterate(metaBoundingBox, { + if (it is ActorEntity) { + val state = it.movement.anchorNetworkState + + if (state != null && state.entityID == entityID && state.positionIndex == index) { + result.add(it) + } + } + }) + + return result } - override fun anchor(index: Int): IAnchorState? { - TODO("Not yet implemented") + override fun entitiesLoungingIn(): List { + val result = ArrayList() + + world.entityIndex.iterate(metaBoundingBox, { + if (it is ActorEntity && it.movement.anchorNetworkState?.entityID == entityID) { + result.add(it) + } + }) + + return result } override fun parametersUpdated() { @@ -107,12 +143,12 @@ class LoungeableObject(config: Registry.Entry) : WorldObject(c override fun interact(request: InteractRequest): InteractAction { val upstream = super.interact(request) - if (upstream.type == InteractAction.Type.NONE && sitPositions.isNotEmpty()) { + if (upstream.type == InteractAction.Type.NONE && anchors.isNotEmpty()) { val interactOffset = if (direction.isRight) position - request.targetPos else request.targetPos - position var index = 0 - for (i in 1 until sitPositions.size) { - if ((sitPositions[i] + interactOffset).length < (sitPositions[index] + interactOffset).length) { + for (i in 1 until anchors.size) { + if ((anchors[i].position + interactOffset).length < (anchors[index].position + interactOffset).length) { index = i } }