package net.minecraft.network.syncher; import com.mojang.logging.LogUtils; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.EncoderException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Objects; import javax.annotation.Nullable; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.util.ClassTreeIdRegistry; import org.apache.commons.lang3.ObjectUtils; import org.slf4j.Logger; public class SynchedEntityData { private static final Logger LOGGER = LogUtils.getLogger(); private static final int MAX_ID_VALUE = 254; static final ClassTreeIdRegistry ID_REGISTRY = new ClassTreeIdRegistry(); private final SyncedDataHolder entity; private final SynchedEntityData.DataItem[] itemsById; private boolean isDirty; SynchedEntityData(SyncedDataHolder p_334075_, SynchedEntityData.DataItem[] p_331536_) { this.entity = p_334075_; this.itemsById = p_331536_; } public static EntityDataAccessor defineId(Class p_135354_, EntityDataSerializer p_135355_) { if (LOGGER.isDebugEnabled()) { try { Class oclass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName()); if (!oclass.equals(p_135354_)) { LOGGER.debug("defineId called for: {} from {}", p_135354_, oclass, new RuntimeException()); } } catch (ClassNotFoundException classnotfoundexception) { } } int i = ID_REGISTRY.define(p_135354_); if (i > 254) { throw new IllegalArgumentException("Data value id is too big with " + i + "! (Max is 254)"); } else { return p_135355_.createAccessor(i); } } private SynchedEntityData.DataItem getItem(EntityDataAccessor p_135380_) { return (SynchedEntityData.DataItem)this.itemsById[p_135380_.id()]; } public T get(EntityDataAccessor p_135371_) { return this.getItem(p_135371_).getValue(); } public void set(EntityDataAccessor p_135382_, T p_135383_) { this.set(p_135382_, p_135383_, false); } public void set(EntityDataAccessor p_276368_, T p_276363_, boolean p_276370_) { SynchedEntityData.DataItem dataitem = this.getItem(p_276368_); if (p_276370_ || ObjectUtils.notEqual(p_276363_, dataitem.getValue())) { dataitem.setValue(p_276363_); this.entity.onSyncedDataUpdated(p_276368_); dataitem.setDirty(true); this.isDirty = true; } } public boolean isDirty() { return this.isDirty; } @Nullable public List> packDirty() { if (!this.isDirty) { return null; } else { this.isDirty = false; List> list = new ArrayList<>(); for (SynchedEntityData.DataItem dataitem : this.itemsById) { if (dataitem.isDirty()) { dataitem.setDirty(false); list.add(dataitem.value()); } } return list; } } @Nullable public List> getNonDefaultValues() { List> list = null; for (SynchedEntityData.DataItem dataitem : this.itemsById) { if (!dataitem.isSetToDefault()) { if (list == null) { list = new ArrayList<>(); } list.add(dataitem.value()); } } return list; } public void assignValues(List> p_135357_) { for (SynchedEntityData.DataValue datavalue : p_135357_) { SynchedEntityData.DataItem dataitem = this.itemsById[datavalue.id]; this.assignValue(dataitem, datavalue); this.entity.onSyncedDataUpdated(dataitem.getAccessor()); } this.entity.onSyncedDataUpdated(p_135357_); } private void assignValue(SynchedEntityData.DataItem p_135376_, SynchedEntityData.DataValue p_254484_) { if (!Objects.equals(p_254484_.serializer(), p_135376_.accessor.serializer())) { throw new IllegalStateException( String.format( Locale.ROOT, "Invalid entity data item type for field %d on entity %s: old=%s(%s), new=%s(%s)", p_135376_.accessor.id(), this.entity, p_135376_.value, p_135376_.value.getClass(), p_254484_.value, p_254484_.value.getClass() ) ); } else { p_135376_.setValue((T)p_254484_.value); } } public static class Builder { private final SyncedDataHolder entity; private final SynchedEntityData.DataItem[] itemsById; public Builder(SyncedDataHolder p_334752_) { this.entity = p_334752_; this.itemsById = new SynchedEntityData.DataItem[SynchedEntityData.ID_REGISTRY.getCount(p_334752_.getClass())]; } public SynchedEntityData.Builder define(EntityDataAccessor p_329741_, T p_330016_) { int i = p_329741_.id(); if (i > this.itemsById.length) { throw new IllegalArgumentException("Data value id is too big with " + i + "! (Max is " + this.itemsById.length + ")"); } else if (this.itemsById[i] != null) { throw new IllegalArgumentException("Duplicate id value for " + i + "!"); } else if (EntityDataSerializers.getSerializedId(p_329741_.serializer()) < 0) { throw new IllegalArgumentException("Unregistered serializer " + p_329741_.serializer() + " for " + i + "!"); } else { this.itemsById[p_329741_.id()] = new SynchedEntityData.DataItem<>(p_329741_, p_330016_); return this; } } public SynchedEntityData build() { for (int i = 0; i < this.itemsById.length; i++) { if (this.itemsById[i] == null) { throw new IllegalStateException("Entity " + this.entity.getClass() + " has not defined synched data value " + i); } } return new SynchedEntityData(this.entity, this.itemsById); } } public static class DataItem { final EntityDataAccessor accessor; T value; private final T initialValue; private boolean dirty; public DataItem(EntityDataAccessor p_135394_, T p_135395_) { this.accessor = p_135394_; this.initialValue = p_135395_; this.value = p_135395_; } public EntityDataAccessor getAccessor() { return this.accessor; } public void setValue(T p_135398_) { this.value = p_135398_; } public T getValue() { return this.value; } public boolean isDirty() { return this.dirty; } public void setDirty(boolean p_135402_) { this.dirty = p_135402_; } public boolean isSetToDefault() { return this.initialValue.equals(this.value); } public SynchedEntityData.DataValue value() { return SynchedEntityData.DataValue.create(this.accessor, this.value); } } public record DataValue(int id, EntityDataSerializer serializer, T value) { public static SynchedEntityData.DataValue create(EntityDataAccessor p_254543_, T p_254138_) { EntityDataSerializer entitydataserializer = p_254543_.serializer(); return new SynchedEntityData.DataValue<>(p_254543_.id(), entitydataserializer, entitydataserializer.copy(p_254138_)); } public void write(RegistryFriendlyByteBuf p_328126_) { int i = EntityDataSerializers.getSerializedId(this.serializer); if (i < 0) { throw new EncoderException("Unknown serializer type " + this.serializer); } else { p_328126_.writeByte(this.id); p_328126_.writeVarInt(i); this.serializer.codec().encode(p_328126_, this.value); } } public static SynchedEntityData.DataValue read(RegistryFriendlyByteBuf p_335154_, int p_254356_) { int i = p_335154_.readVarInt(); EntityDataSerializer entitydataserializer = EntityDataSerializers.getSerializer(i); if (entitydataserializer == null) { throw new DecoderException("Unknown serializer type " + i); } else { return read(p_335154_, p_254356_, entitydataserializer); } } private static SynchedEntityData.DataValue read(RegistryFriendlyByteBuf p_333448_, int p_253899_, EntityDataSerializer p_254222_) { return new SynchedEntityData.DataValue<>(p_253899_, p_254222_, p_254222_.codec().decode(p_333448_)); } } }