fix entity attribute stuff

This commit is contained in:
Bixilon 2021-10-24 16:35:33 +02:00
parent 2008dcba18
commit 34f15d2baf
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 71 additions and 43 deletions

View File

@ -26,8 +26,8 @@ import de.bixilon.minosoft.data.registries.AABB
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
import de.bixilon.minosoft.data.registries.effects.StatusEffect
import de.bixilon.minosoft.data.registries.effects.attributes.StatusEffectAttribute
import de.bixilon.minosoft.data.registries.effects.attributes.StatusEffectAttributeInstance
import de.bixilon.minosoft.data.registries.effects.attributes.EntityAttribute
import de.bixilon.minosoft.data.registries.effects.attributes.EntityAttributeModifier
import de.bixilon.minosoft.data.registries.effects.attributes.StatusEffectOperations
import de.bixilon.minosoft.data.registries.enchantment.Enchantment
import de.bixilon.minosoft.data.registries.entities.EntityType
@ -72,7 +72,7 @@ abstract class Entity(
protected val random = Random
open val equipment: MutableMap<EquipmentSlots, ItemStack> = mutableMapOf()
val activeStatusEffects: MutableMap<StatusEffect, StatusEffectInstance> = synchronizedMapOf()
val attributes: MutableMap<ResourceLocation, MutableMap<UUID, StatusEffectAttributeInstance>> = synchronizedMapOf()
val attributes: MutableMap<ResourceLocation, EntityAttribute> = synchronizedMapOf()
val id: Int?
get() = connection.world.entities.getId(this)
@ -154,28 +154,30 @@ abstract class Entity(
activeStatusEffects.remove(effect)
}
fun getAttributeValue(attribute: ResourceLocation, baseValue: Double = entityType.attributes[attribute] ?: 1.0): Double {
fun getAttributeValue(name: ResourceLocation, baseValue: Double? = null): Double {
// ToDo: Check order and verify value
var ret = baseValue
val attribute = attributes[name]
val realBaseValue = baseValue ?: attribute?.baseValue ?: 1.0
var ret = realBaseValue
fun addToValue(statusEffectAttribute: StatusEffectAttribute, amplifier: Int) {
val instanceValue = statusEffectAttribute.amount * amplifier
when (statusEffectAttribute.operation) {
fun addToValue(modifier: EntityAttributeModifier, amplifier: Int) {
val instanceValue = modifier.amount * amplifier
when (modifier.operation) {
StatusEffectOperations.MULTIPLY_TOTAL -> ret *= 1.0 + instanceValue
StatusEffectOperations.ADDITION -> ret += instanceValue
StatusEffectOperations.MULTIPLY_BASE -> ret += baseValue * (instanceValue + 1.0)
StatusEffectOperations.MULTIPLY_BASE -> ret += realBaseValue * (instanceValue + 1.0)
}
}
attributes[attribute]?.let {
for (instance in it.values) {
addToValue(instance.statusEffectAttribute, instance.amplifier)
attribute?.let {
for (instance in it.modifiers.values) {
addToValue(instance, 1)
}
}
for (statusEffect in activeStatusEffects.values) {
for ((instanceResourceLocation, instance) in statusEffect.statusEffect.attributes) {
if (instanceResourceLocation != attribute) {
if (instanceResourceLocation != name) {
continue
}
addToValue(instance, statusEffect.amplifier)

View File

@ -30,7 +30,7 @@ import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.effects.DefaultStatusEffects
import de.bixilon.minosoft.data.registries.effects.attributes.DefaultStatusEffectAttributeNames
import de.bixilon.minosoft.data.registries.effects.attributes.DefaultStatusEffectAttributes
import de.bixilon.minosoft.data.registries.effects.attributes.StatusEffectAttributeInstance
import de.bixilon.minosoft.data.registries.effects.attributes.EntityAttribute
import de.bixilon.minosoft.data.registries.enchantment.DefaultEnchantments
import de.bixilon.minosoft.data.registries.items.DefaultItems
import de.bixilon.minosoft.data.registries.items.Item
@ -133,10 +133,10 @@ class LocalPlayerEntity(
if (value == field) {
return
}
attributes[DefaultStatusEffectAttributeNames.GENERIC_MOVEMENT_SPEED]?.remove(DefaultStatusEffectAttributes.SPRINT_SPEED_BOOST.uuid)
attributes[DefaultStatusEffectAttributeNames.GENERIC_MOVEMENT_SPEED]?.modifiers?.remove(DefaultStatusEffectAttributes.SPRINT_SPEED_BOOST.uuid)
if (value) {
attributes.getOrPut(DefaultStatusEffectAttributeNames.GENERIC_MOVEMENT_SPEED) { synchronizedMapOf() }[DefaultStatusEffectAttributes.SPRINT_SPEED_BOOST.uuid] = StatusEffectAttributeInstance(DefaultStatusEffectAttributes.SPRINT_SPEED_BOOST, 1)
attributes.getOrPut(DefaultStatusEffectAttributeNames.GENERIC_MOVEMENT_SPEED) { EntityAttribute() }.modifiers[DefaultStatusEffectAttributes.SPRINT_SPEED_BOOST.uuid] = DefaultStatusEffectAttributes.SPRINT_SPEED_BOOST
}
field = value
}

View File

@ -13,7 +13,7 @@
package de.bixilon.minosoft.data.registries.effects
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.effects.attributes.StatusEffectAttribute
import de.bixilon.minosoft.data.registries.effects.attributes.EntityAttributeModifier
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.data.registries.registries.registry.RegistryItem
import de.bixilon.minosoft.data.registries.registries.registry.ResourceLocationDeserializer
@ -32,8 +32,8 @@ data class StatusEffect(
val category: StatusEffectCategories,
override val translationKey: ResourceLocation?,
val color: RGBColor,
val attributes: Map<ResourceLocation, StatusEffectAttribute>,
val uuidAttributes: Map<UUID, StatusEffectAttribute>,
val attributes: Map<ResourceLocation, EntityAttributeModifier>,
val uuidAttributes: Map<UUID, EntityAttributeModifier>,
) : RegistryItem(), Translatable {
override fun toString(): String {
@ -42,12 +42,12 @@ data class StatusEffect(
companion object : ResourceLocationDeserializer<StatusEffect> {
override fun deserialize(registries: Registries?, resourceLocation: ResourceLocation, data: Map<String, Any>): StatusEffect {
val attributes: MutableMap<ResourceLocation, StatusEffectAttribute> = mutableMapOf()
val uuidAttributes: MutableMap<UUID, StatusEffectAttribute> = mutableMapOf()
val attributes: MutableMap<ResourceLocation, EntityAttributeModifier> = mutableMapOf()
val uuidAttributes: MutableMap<UUID, EntityAttributeModifier> = mutableMapOf()
data["attributes"]?.compoundCast()?.let {
for ((key, value) in it) {
val attribute = StatusEffectAttribute.deserialize(value.asCompound())
val attribute = EntityAttributeModifier.deserialize(value.asCompound())
attributes[ResourceLocation.getResourceLocation(key).fix()] = attribute
uuidAttributes[attribute.uuid] = attribute
}

View File

@ -16,5 +16,5 @@ package de.bixilon.minosoft.data.registries.effects.attributes
import de.bixilon.minosoft.util.KUtil.asUUID
object DefaultStatusEffectAttributes {
val SPRINT_SPEED_BOOST = StatusEffectAttribute("Sprinting speed boost", "662A6B8D-DA3E-4C1C-8813-96EA6097278D".asUUID(), 0.30000001192092896, StatusEffectOperations.MULTIPLY_TOTAL)
val SPRINT_SPEED_BOOST = EntityAttributeModifier("Sprinting speed boost", "662A6B8D-DA3E-4C1C-8813-96EA6097278D".asUUID(), 0.30000001192092896, StatusEffectOperations.MULTIPLY_TOTAL)
}

View File

@ -13,7 +13,17 @@
package de.bixilon.minosoft.data.registries.effects.attributes
class StatusEffectAttributeInstance(
val statusEffectAttribute: StatusEffectAttribute,
val amplifier: Int,
)
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import java.util.*
data class EntityAttribute(
var baseValue: Double = 1.0,
val modifiers: MutableMap<UUID, EntityAttributeModifier> = synchronizedMapOf(),
) {
fun merge(other: EntityAttribute) {
baseValue = other.baseValue
for ((key, modifier) in other.modifiers) {
modifiers[key] = modifier
}
}
}

View File

@ -16,7 +16,7 @@ import de.bixilon.minosoft.util.KUtil.unsafeCast
import de.bixilon.minosoft.util.Util
import java.util.*
data class StatusEffectAttribute(
data class EntityAttributeModifier(
val name: String,
val uuid: UUID,
val amount: Double,
@ -27,8 +27,8 @@ data class StatusEffectAttribute(
}
companion object {
fun deserialize(data: Map<String, Any>): StatusEffectAttribute {
return StatusEffectAttribute(
fun deserialize(data: Map<String, Any>): EntityAttributeModifier {
return EntityAttributeModifier(
name = data["name"].unsafeCast(),
uuid = Util.getUUIDFromString(data["uuid"].unsafeCast()),
amount = data["amount"].unsafeCast(),

View File

@ -26,6 +26,8 @@ import de.bixilon.minosoft.util.KUtil.decide
import de.bixilon.minosoft.util.KUtil.unsafeCast
import de.bixilon.minosoft.util.MMath.ceil
import glm_.vec2.Vec2i
import java.lang.Float.max
import java.lang.Float.min
class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Pollable {
private val witherStatusEffect = hudRenderer.connection.registries.statusEffectRegistry[DefaultStatusEffects.WITHER]
@ -234,13 +236,15 @@ class HotbarHealthElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Poll
val wither = witherStatusEffect?.let { player.activeStatusEffects[it] != null } ?: false
val frozen = player.ticksFrozen > 0
val absorptionsAmount = max(0.0f, player.playerAbsorptionHearts) // ToDo: This is (probably) calculated as effect instance
val maxHealth = max(0.0f, player.getAttributeValue(DefaultStatusEffectAttributeNames.GENERIC_MAX_HEALTH).toFloat())
var health = player.healthCondition.hp
if (health > 0.0f && health < 0.5f) {
health = 0.5f
}
val absorptionsAmount = player.playerAbsorptionHearts // ToDo: This is (probably) calculated as effect instance
val maxHealth = player.getAttributeValue(DefaultStatusEffectAttributeNames.GENERIC_MAX_HEALTH).toFloat()
health = min(health, maxHealth)
if (this.hardcode == hardcode && this.poison == poison && this.wither == wither && this.frozen == frozen && this.health == health && this.absorptionsAmount == absorptionsAmount && this.maxHealth == maxHealth) {
return false

View File

@ -13,8 +13,10 @@
package de.bixilon.minosoft.protocol.packets.s2c.play
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.effects.attributes.StatusEffectAttribute
import de.bixilon.minosoft.data.registries.effects.attributes.EntityAttribute
import de.bixilon.minosoft.data.registries.effects.attributes.EntityAttributeModifier
import de.bixilon.minosoft.data.registries.effects.attributes.StatusEffectOperations
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_14W04A
@ -26,34 +28,44 @@ import java.util.*
class EntityEffectAttributesS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
val entityId: Int = buffer.readEntityId()
val attributes: Map<ResourceLocation, StatusEffectAttribute>
val attributes: Map<ResourceLocation, EntityAttribute>
init {
val attributes: MutableMap<ResourceLocation, StatusEffectAttribute> = mutableMapOf()
val count: Int = if (buffer.versionId < V_21W08A) {
val attributes: MutableMap<ResourceLocation, EntityAttribute> = mutableMapOf()
val attributeCount: Int = if (buffer.versionId < V_21W08A) {
buffer.readInt()
} else {
buffer.readVarInt()
}
for (i in 0 until count) {
for (i in 0 until attributeCount) {
val key: ResourceLocation = buffer.readResourceLocation()
val value: Double = buffer.readDouble() // ToDo: For what is this?
val listLength: Int = if (buffer.versionId < V_14W04A) {
val baseValue: Double = buffer.readDouble()
val attribute = EntityAttribute(baseValue = baseValue)
val modifierCount: Int = if (buffer.versionId < V_14W04A) {
buffer.readUnsignedShort()
} else {
buffer.readVarInt()
}
for (ii in 0 until listLength) {
for (ii in 0 until modifierCount) {
val uuid: UUID = buffer.readUUID()
val amount: Double = buffer.readDouble()
val operation = StatusEffectOperations[buffer.readUnsignedByte()]
// ToDo: modifiers
attributes[key] = StatusEffectAttribute("", uuid, amount, operation)
attribute.modifiers[uuid] = EntityAttributeModifier(key.toString(), uuid, amount, operation)
}
attributes[key] = attribute
}
this.attributes = attributes.toMap()
}
override fun handle(connection: PlayConnection) {
connection.world.entities[entityId]?.let {
for ((key, attribute) in this.attributes) {
it.attributes.getOrPut(key) { EntityAttribute(baseValue = it.entityType.attributes[key] ?: 1.0) }.merge(attribute)
}
}
}
override fun log() {
Log.log(LogMessageType.NETWORK_PACKETS_IN, LogLevels.VERBOSE) { "Entity effect attributes (entityId=$entityId, attributes=$attributes)" }
}