/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.logging.LogUtils * io.netty.handler.codec.DecoderException * io.netty.handler.codec.EncoderException * org.apache.commons.lang3.ObjectUtils * org.jspecify.annotations.Nullable * org.slf4j.Logger */ 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 net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializer; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SyncedDataHolder; import net.minecraft.util.ClassTreeIdRegistry; import org.apache.commons.lang3.ObjectUtils; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public class SynchedEntityData { private static final Logger LOGGER = LogUtils.getLogger(); private static final int MAX_ID_VALUE = 254; private static final ClassTreeIdRegistry ID_REGISTRY = new ClassTreeIdRegistry(); private final SyncedDataHolder entity; private final DataItem[] itemsById; private boolean isDirty; private SynchedEntityData(SyncedDataHolder entity, DataItem[] itemsById) { this.entity = entity; this.itemsById = itemsById; } public static EntityDataAccessor defineId(Class clazz, EntityDataSerializer type) { int id; if (LOGGER.isDebugEnabled()) { try { Class aClass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName()); if (!aClass.equals(clazz)) { LOGGER.debug("defineId called for: {} from {}", new Object[]{clazz, aClass, new RuntimeException()}); } } catch (ClassNotFoundException aClass) { // empty catch block } } if ((id = ID_REGISTRY.define(clazz)) > 254) { throw new IllegalArgumentException("Data value id is too big with " + id + "! (Max is 254)"); } return type.createAccessor(id); } private DataItem getItem(EntityDataAccessor accessor) { return this.itemsById[accessor.id()]; } public T get(EntityDataAccessor accessor) { return this.getItem(accessor).getValue(); } public void set(EntityDataAccessor accessor, T value) { this.set(accessor, value, false); } public void set(EntityDataAccessor accessor, T value, boolean forceDirty) { DataItem dataItem = this.getItem(accessor); if (forceDirty || ObjectUtils.notEqual(value, dataItem.getValue())) { dataItem.setValue(value); this.entity.onSyncedDataUpdated(accessor); dataItem.setDirty(true); this.isDirty = true; } } public boolean isDirty() { return this.isDirty; } public @Nullable List> packDirty() { if (!this.isDirty) { return null; } this.isDirty = false; ArrayList result = new ArrayList(); for (DataItem dataItem : this.itemsById) { if (!dataItem.isDirty()) continue; dataItem.setDirty(false); result.add(dataItem.value()); } return result; } public @Nullable List> getNonDefaultValues() { ArrayList result = null; for (DataItem dataItem : this.itemsById) { if (dataItem.isSetToDefault()) continue; if (result == null) { result = new ArrayList(); } result.add(dataItem.value()); } return result; } public void assignValues(List> items) { for (DataValue item : items) { DataItem dataItem = this.itemsById[item.id]; this.assignValue(dataItem, item); this.entity.onSyncedDataUpdated(dataItem.getAccessor()); } this.entity.onSyncedDataUpdated(items); } private void assignValue(DataItem dataItem, DataValue item) { if (!Objects.equals(item.serializer(), dataItem.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)", dataItem.accessor.id(), this.entity, dataItem.value, dataItem.value.getClass(), item.value, item.value.getClass())); } dataItem.setValue(item.value); } public static class DataItem { private final EntityDataAccessor accessor; private T value; private final T initialValue; private boolean dirty; public DataItem(EntityDataAccessor accessor, T initialValue) { this.accessor = accessor; this.initialValue = initialValue; this.value = initialValue; } public EntityDataAccessor getAccessor() { return this.accessor; } public void setValue(T value) { this.value = value; } public T getValue() { return this.value; } public boolean isDirty() { return this.dirty; } public void setDirty(boolean dirty) { this.dirty = dirty; } public boolean isSetToDefault() { return this.initialValue.equals(this.value); } public DataValue value() { return DataValue.create(this.accessor, this.value); } } public record DataValue(int id, EntityDataSerializer serializer, T value) { public static DataValue create(EntityDataAccessor accessor, T value) { EntityDataSerializer serializer = accessor.serializer(); return new DataValue(accessor.id(), serializer, serializer.copy(value)); } public void write(RegistryFriendlyByteBuf output) { int serializerId = EntityDataSerializers.getSerializedId(this.serializer); if (serializerId < 0) { throw new EncoderException("Unknown serializer type " + String.valueOf(this.serializer)); } output.writeByte(this.id); output.writeVarInt(serializerId); this.serializer.codec().encode(output, this.value); } public static DataValue read(RegistryFriendlyByteBuf input, int id) { int type = input.readVarInt(); EntityDataSerializer serializer = EntityDataSerializers.getSerializer(type); if (serializer == null) { throw new DecoderException("Unknown serializer type " + type); } return DataValue.read(input, id, serializer); } private static DataValue read(RegistryFriendlyByteBuf input, int id, EntityDataSerializer serializer) { return new DataValue(id, serializer, serializer.codec().decode(input)); } } public static class Builder { private final SyncedDataHolder entity; private final @Nullable DataItem[] itemsById; public Builder(SyncedDataHolder entity) { this.entity = entity; this.itemsById = new DataItem[ID_REGISTRY.getCount(entity.getClass())]; } public Builder define(EntityDataAccessor accessor, T value) { int id = accessor.id(); if (id > this.itemsById.length) { throw new IllegalArgumentException("Data value id is too big with " + id + "! (Max is " + this.itemsById.length + ")"); } if (this.itemsById[id] != null) { throw new IllegalArgumentException("Duplicate id value for " + id + "!"); } if (EntityDataSerializers.getSerializedId(accessor.serializer()) < 0) { throw new IllegalArgumentException("Unregistered serializer " + String.valueOf(accessor.serializer()) + " for " + id + "!"); } this.itemsById[accessor.id()] = new DataItem(accessor, value); return this; } public SynchedEntityData build() { for (int i = 0; i < this.itemsById.length; ++i) { if (this.itemsById[i] != null) continue; throw new IllegalStateException("Entity " + String.valueOf(this.entity.getClass()) + " has not defined synched data value " + i); } return new SynchedEntityData(this.entity, this.itemsById); } } }