package net.minecraft.server; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.koloboke.collect.map.hash.HashObjIntMap; import com.koloboke.collect.map.hash.HashObjIntMaps; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.EncoderException; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.annotation.Nullable; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; // Paper import org.apache.commons.lang3.ObjectUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class DataWatcher { private static final Logger a = LogManager.getLogger(); private static final Map, Integer> b = HashObjIntMaps.newMutableMap(255); private static final HashObjIntMap> entityTypeToIdMap() { return (HashObjIntMap>) b; }// Akarin private final Entity c; private final Map> d = new ConcurrentHashMap>(255); // Paper // Akarin private final ReadWriteLock e = new ReentrantReadWriteLock(); private boolean f = true; private boolean g; public DataWatcher(Entity entity) { this.c = entity; } public static DataWatcherObject a(Class oclass, DataWatcherSerializer datawatcherserializer) { if (DataWatcher.a.isDebugEnabled()) { try { Class oclass1 = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName()); if (!oclass1.equals(oclass)) { DataWatcher.a.debug("defineId called for: {} from {}", oclass, oclass1, new RuntimeException()); } } catch (ClassNotFoundException classnotfoundexception) { ; } } // Akarin start int i = entityTypeToIdMap().getOrDefault(oclass, -1); if (i != -1) { i = i + 1; // Akarin end } else { int j = 0; Class oclass2 = oclass; while (oclass2 != Entity.class) { oclass2 = oclass2.getSuperclass(); // Akarin start int superId = entityTypeToIdMap().getOrDefault(oclass2, -1); if (superId != -1) { j = superId + 1; // Akarin end break; } } i = j; } if (i > 254) { throw new IllegalArgumentException("Data value id is too big with " + i + "! (Max is " + 254 + ")"); } else { DataWatcher.b.put(oclass, i); return datawatcherserializer.a(i); } } public void register(DataWatcherObject datawatcherobject, T t0) { int i = datawatcherobject.a(); if (i > 254) { throw new IllegalArgumentException("Data value id is too big with " + i + "! (Max is " + 254 + ")"); } else if (this.d.containsKey(i)) { throw new IllegalArgumentException("Duplicate id value for " + i + "!"); } else if (DataWatcherRegistry.b(datawatcherobject.b()) < 0) { throw new IllegalArgumentException("Unregistered serializer " + datawatcherobject.b() + " for " + i + "!"); } else { this.registerObject(datawatcherobject, t0); } } private void registerObject(DataWatcherObject datawatcherobject, T t0) { DataWatcher.Item datawatcher_item = new DataWatcher.Item<>(datawatcherobject, t0); //this.e.writeLock().lock(); // Akarin this.d.put(datawatcherobject.a(), datawatcher_item); this.f = false; //this.e.writeLock().unlock(); // Akarin } private DataWatcher.Item b(DataWatcherObject datawatcherobject) { //this.e.readLock().lock(); // Akarin DataWatcher.Item datawatcher_item; try { datawatcher_item = (DataWatcher.Item) this.d.get(datawatcherobject.a()); } catch (Throwable throwable) { CrashReport crashreport = CrashReport.a(throwable, "Getting synched entity data"); CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Synched entity data"); crashreportsystemdetails.a("Data ID", (Object) datawatcherobject); throw new ReportedException(crashreport); } //this.e.readLock().unlock(); // Akarin return datawatcher_item; } public T get(DataWatcherObject datawatcherobject) { return this.b(datawatcherobject).b(); } public void set(DataWatcherObject datawatcherobject, T t0) { DataWatcher.Item datawatcher_item = this.b(datawatcherobject); if (ObjectUtils.notEqual(t0, datawatcher_item.b())) { datawatcher_item.a(t0); this.c.a(datawatcherobject); datawatcher_item.a(true); this.g = true; } } // CraftBukkit start - add method from above public void markDirty(DataWatcherObject datawatcherobject) { this.b(datawatcherobject).a(true); this.g = true; } // CraftBukkit end public boolean a() { return this.g; } public static void a(List> list, PacketDataSerializer packetdataserializer) throws IOException { if (list != null) { int i = 0; for (int j = list.size(); i < j; ++i) { a(packetdataserializer, (DataWatcher.Item) list.get(i)); } } packetdataserializer.writeByte(255); } @Nullable public List> b() { List> list = null; if (this.g) { //this.e.readLock().lock(); // Akarin Iterator iterator = this.d.values().iterator(); while (iterator.hasNext()) { DataWatcher.Item datawatcher_item = (DataWatcher.Item) iterator.next(); if (datawatcher_item.c()) { datawatcher_item.a(false); if (list == null) { list = Lists.newArrayList(); } list.add(datawatcher_item.d()); } } //this.e.readLock().unlock(); // Akarin } this.g = false; return list; } public void a(PacketDataSerializer packetdataserializer) throws IOException { //this.e.readLock().lock(); // Akarin Iterator iterator = this.d.values().iterator(); while (iterator.hasNext()) { DataWatcher.Item datawatcher_item = (DataWatcher.Item) iterator.next(); a(packetdataserializer, datawatcher_item); } //this.e.readLock().unlock(); // Akarin packetdataserializer.writeByte(255); } @Nullable public List> c() { List> list = null; //this.e.readLock().lock(); // Akarin DataWatcher.Item datawatcher_item; for (Iterator iterator = this.d.values().iterator(); iterator.hasNext(); list.add(datawatcher_item.d())) { datawatcher_item = (DataWatcher.Item) iterator.next(); if (list == null) { list = Lists.newArrayList(); } } //this.e.readLock().unlock(); // Akarin return list; } private static void a(PacketDataSerializer packetdataserializer, DataWatcher.Item datawatcher_item) throws IOException { DataWatcherObject datawatcherobject = datawatcher_item.a(); int i = DataWatcherRegistry.b(datawatcherobject.b()); if (i < 0) { throw new EncoderException("Unknown serializer type " + datawatcherobject.b()); } else { packetdataserializer.writeByte(datawatcherobject.a()); packetdataserializer.d(i); datawatcherobject.b().a(packetdataserializer, datawatcher_item.b()); } } @Nullable public static List> b(PacketDataSerializer packetdataserializer) throws IOException { ArrayList arraylist = null; short short0; while ((short0 = packetdataserializer.readUnsignedByte()) != 255) { if (arraylist == null) { arraylist = Lists.newArrayList(); } int i = packetdataserializer.g(); DataWatcherSerializer datawatcherserializer = DataWatcherRegistry.a(i); if (datawatcherserializer == null) { throw new DecoderException("Unknown serializer type " + i); } arraylist.add(a(packetdataserializer, short0, datawatcherserializer)); } return arraylist; } private static DataWatcher.Item a(PacketDataSerializer packetdataserializer, int i, DataWatcherSerializer datawatcherserializer) { return new DataWatcher.Item<>(datawatcherserializer.a(i), datawatcherserializer.a(packetdataserializer)); } public boolean d() { return this.f; } public void e() { this.g = false; //this.e.readLock().lock(); // Akarin Iterator iterator = this.d.values().iterator(); while (iterator.hasNext()) { DataWatcher.Item datawatcher_item = (DataWatcher.Item) iterator.next(); datawatcher_item.a(false); } //this.e.readLock().unlock(); // Akarin } public static class Item { private final DataWatcherObject a; private T b; private boolean c; public Item(DataWatcherObject datawatcherobject, T t0) { this.a = datawatcherobject; this.b = t0; this.c = true; } public DataWatcherObject a() { return this.a; } public void a(T t0) { this.b = t0; } public T b() { return this.b; } public boolean c() { return this.c; } public void a(boolean flag) { this.c = flag; } public DataWatcher.Item d() { return new DataWatcher.Item<>(this.a, this.a.b().a(this.b)); } } }