Implement entitiesLoungingIn

This commit is contained in:
DBotThePony 2024-12-01 11:26:12 +07:00
parent 918b6ff95f
commit 9947138eac
Signed by: DBot
GPG Key ID: DCC23B5715498507
7 changed files with 94 additions and 66 deletions

View File

@ -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);
}

View File

@ -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)

View File

@ -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 {

View File

@ -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) {

View File

@ -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<PersistentStatusEffect> = listOf(),
val statusEffects: Set<PersistentStatusEffect> = setOf(),
val effectEmitters: Set<String> = setOf(),
val emote: String? = null,
val dance: String? = null,

View File

@ -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<Vector2d>
val anchors: List<IAnchorState>
/**
* Determines entities currently lounging in this entity
*/
fun entitiesLoungingIn(): List<ActorEntity>
/**
* Determines entities currently lounging at specified anchor index
*/
fun entitiesLoungingIn(index: Int): List<ActorEntity>
/**
* Returns anchor information with given index, or null if index is invalid
*/
fun anchor(index: Int): IAnchorState?
}

View File

@ -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<ObjectDefinition>) : WorldObject(c
isInteractive = true
}
override val sitPositions = ArrayList<Vector2d>()
override val anchors = ArrayList<LoungeAnchorState>()
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<PersistentStatusEffect>()
val sitEffectEmitters = ObjectArraySet<String>()
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<Vector2d>()
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<PersistentStatusEffect>()
sitStatusEffects.addAll(statusEffects.fromJsonTree(lookupProperty("sitStatusEffects") { JsonArray() }))
sitEffectEmitters.clear()
val sitEffectEmitters = ObjectArraySet<String>()
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<String, JsonElement>().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<ActorEntity> {
TODO("Not yet implemented")
if (index !in anchors.indices) return listOf()
val result = ArrayList<ActorEntity>()
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<ActorEntity> {
val result = ArrayList<ActorEntity>()
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<ObjectDefinition>) : 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
}
}