package net.minecraft.entity;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ReportedException;
import net.minecraft.util.Rotations;
import org.apache.commons.lang3.ObjectUtils;
public class DataWatcher
{
private final Entity owner;
/** When isBlank is true the DataWatcher is not watching any objects */
private boolean isBlank = true;
private static final Map dataTypes = Maps.newHashMap();
private final Map watchedObjects = Maps.newHashMap();
/** true if one or more object was changed */
private boolean objectChanged;
private ReadWriteLock lock = new ReentrantReadWriteLock();
private static final String __OBFID = "CL_00001559";
public DataWatcher(Entity owner)
{
this.owner = owner;
}
/**
* adds a new object to dataWatcher to watch, to update an already existing object see updateObject. Arguments: data
* Value Id, Object to add
*/
public void addObject(int id, Object object)
{
Integer var3 = (Integer)dataTypes.get(object.getClass());
if (var3 == null)
{
throw new IllegalArgumentException("Unknown data type: " + object.getClass());
}
else if (id > 31)
{
throw new IllegalArgumentException("Data value id is too big with " + id + "! (Max is " + 31 + ")");
}
else if (this.watchedObjects.containsKey(Integer.valueOf(id)))
{
throw new IllegalArgumentException("Duplicate id value for " + id + "!");
}
else
{
DataWatcher.WatchableObject var4 = new DataWatcher.WatchableObject(var3.intValue(), id, object);
this.lock.writeLock().lock();
this.watchedObjects.put(Integer.valueOf(id), var4);
this.lock.writeLock().unlock();
this.isBlank = false;
}
}
/**
* Add a new object for the DataWatcher to watch, using the specified data type.
*/
public void addObjectByDataType(int id, int type)
{
DataWatcher.WatchableObject var3 = new DataWatcher.WatchableObject(type, id, (Object)null);
this.lock.writeLock().lock();
this.watchedObjects.put(Integer.valueOf(id), var3);
this.lock.writeLock().unlock();
this.isBlank = false;
}
/**
* gets the bytevalue of a watchable object
*/
public byte getWatchableObjectByte(int id)
{
return ((Byte)this.getWatchedObject(id).getObject()).byteValue();
}
public short getWatchableObjectShort(int id)
{
return ((Short)this.getWatchedObject(id).getObject()).shortValue();
}
/**
* gets a watchable object and returns it as a Integer
*/
public int getWatchableObjectInt(int id)
{
return ((Integer)this.getWatchedObject(id).getObject()).intValue();
}
public float getWatchableObjectFloat(int id)
{
return ((Float)this.getWatchedObject(id).getObject()).floatValue();
}
/**
* gets a watchable object and returns it as a String
*/
public String getWatchableObjectString(int id)
{
return (String)this.getWatchedObject(id).getObject();
}
/**
* Get a watchable object as an ItemStack.
*/
public ItemStack getWatchableObjectItemStack(int id)
{
return (ItemStack)this.getWatchedObject(id).getObject();
}
/**
* is threadsafe, unless it throws an exception, then
*/
private DataWatcher.WatchableObject getWatchedObject(int id)
{
this.lock.readLock().lock();
DataWatcher.WatchableObject var2;
try
{
var2 = (DataWatcher.WatchableObject)this.watchedObjects.get(Integer.valueOf(id));
}
catch (Throwable var6)
{
CrashReport var4 = CrashReport.makeCrashReport(var6, "Getting synched entity data");
CrashReportCategory var5 = var4.makeCategory("Synched entity data");
var5.addCrashSection("Data ID", Integer.valueOf(id));
throw new ReportedException(var4);
}
this.lock.readLock().unlock();
return var2;
}
public Rotations getWatchableObjectRotations(int id)
{
return (Rotations)this.getWatchedObject(id).getObject();
}
/**
* updates an already existing object
*/
public void updateObject(int id, Object newData)
{
DataWatcher.WatchableObject var3 = this.getWatchedObject(id);
if (ObjectUtils.notEqual(newData, var3.getObject()))
{
var3.setObject(newData);
this.owner.func_145781_i(id);
var3.setWatched(true);
this.objectChanged = true;
}
}
public void setObjectWatched(int id)
{
this.getWatchedObject(id).watched = true;
this.objectChanged = true;
}
/**
* true if one or more object was changed
*/
public boolean hasObjectChanged()
{
return this.objectChanged;
}
/**
* Writes the list of watched objects (entity attribute of type {byte, short, int, float, string, ItemStack,
* ChunkCoordinates}) to the specified PacketBuffer
*/
public static void writeWatchedListToPacketBuffer(List objectsList, PacketBuffer buffer) throws IOException
{
if (objectsList != null)
{
Iterator var2 = objectsList.iterator();
while (var2.hasNext())
{
DataWatcher.WatchableObject var3 = (DataWatcher.WatchableObject)var2.next();
writeWatchableObjectToPacketBuffer(buffer, var3);
}
}
buffer.writeByte(127);
}
public List getChanged()
{
ArrayList var1 = null;
if (this.objectChanged)
{
this.lock.readLock().lock();
Iterator var2 = this.watchedObjects.values().iterator();
while (var2.hasNext())
{
DataWatcher.WatchableObject var3 = (DataWatcher.WatchableObject)var2.next();
if (var3.isWatched())
{
var3.setWatched(false);
if (var1 == null)
{
var1 = Lists.newArrayList();
}
var1.add(var3);
}
}
this.lock.readLock().unlock();
}
this.objectChanged = false;
return var1;
}
public void writeTo(PacketBuffer buffer) throws IOException
{
this.lock.readLock().lock();
Iterator var2 = this.watchedObjects.values().iterator();
while (var2.hasNext())
{
DataWatcher.WatchableObject var3 = (DataWatcher.WatchableObject)var2.next();
writeWatchableObjectToPacketBuffer(buffer, var3);
}
this.lock.readLock().unlock();
buffer.writeByte(127);
}
public List getAllWatched()
{
ArrayList var1 = null;
this.lock.readLock().lock();
DataWatcher.WatchableObject var3;
for (Iterator var2 = this.watchedObjects.values().iterator(); var2.hasNext(); var1.add(var3))
{
var3 = (DataWatcher.WatchableObject)var2.next();
if (var1 == null)
{
var1 = Lists.newArrayList();
}
}
this.lock.readLock().unlock();
return var1;
}
/**
* Writes a watchable object (entity attribute of type {byte, short, int, float, string, ItemStack,
* ChunkCoordinates}) to the specified PacketBuffer
*/
private static void writeWatchableObjectToPacketBuffer(PacketBuffer buffer, DataWatcher.WatchableObject object) throws IOException
{
int var2 = (object.getObjectType() << 5 | object.getDataValueId() & 31) & 255;
buffer.writeByte(var2);
switch (object.getObjectType())
{
case 0:
buffer.writeByte(((Byte)object.getObject()).byteValue());
break;
case 1:
buffer.writeShort(((Short)object.getObject()).shortValue());
break;
case 2:
buffer.writeInt(((Integer)object.getObject()).intValue());
break;
case 3:
buffer.writeFloat(((Float)object.getObject()).floatValue());
break;
case 4:
buffer.writeString((String)object.getObject());
break;
case 5:
ItemStack var3 = (ItemStack)object.getObject();
buffer.writeItemStackToBuffer(var3);
break;
case 6:
BlockPos var4 = (BlockPos)object.getObject();
buffer.writeInt(var4.getX());
buffer.writeInt(var4.getY());
buffer.writeInt(var4.getZ());
break;
case 7:
Rotations var5 = (Rotations)object.getObject();
buffer.writeFloat(var5.func_179415_b());
buffer.writeFloat(var5.func_179416_c());
buffer.writeFloat(var5.func_179413_d());
}
}
/**
* Reads a list of watched objects (entity attribute of type {byte, short, int, float, string, ItemStack,
* ChunkCoordinates}) from the supplied PacketBuffer
*/
public static List readWatchedListFromPacketBuffer(PacketBuffer buffer) throws IOException
{
ArrayList var1 = null;
for (byte var2 = buffer.readByte(); var2 != 127; var2 = buffer.readByte())
{
if (var1 == null)
{
var1 = Lists.newArrayList();
}
int var3 = (var2 & 224) >> 5;
int var4 = var2 & 31;
DataWatcher.WatchableObject var5 = null;
switch (var3)
{
case 0:
var5 = new DataWatcher.WatchableObject(var3, var4, Byte.valueOf(buffer.readByte()));
break;
case 1:
var5 = new DataWatcher.WatchableObject(var3, var4, Short.valueOf(buffer.readShort()));
break;
case 2:
var5 = new DataWatcher.WatchableObject(var3, var4, Integer.valueOf(buffer.readInt()));
break;
case 3:
var5 = new DataWatcher.WatchableObject(var3, var4, Float.valueOf(buffer.readFloat()));
break;
case 4:
var5 = new DataWatcher.WatchableObject(var3, var4, buffer.readStringFromBuffer(32767));
break;
case 5:
var5 = new DataWatcher.WatchableObject(var3, var4, buffer.readItemStackFromBuffer());
break;
case 6:
int var6 = buffer.readInt();
int var7 = buffer.readInt();
int var8 = buffer.readInt();
var5 = new DataWatcher.WatchableObject(var3, var4, new BlockPos(var6, var7, var8));
break;
case 7:
float var9 = buffer.readFloat();
float var10 = buffer.readFloat();
float var11 = buffer.readFloat();
var5 = new DataWatcher.WatchableObject(var3, var4, new Rotations(var9, var10, var11));
}
var1.add(var5);
}
return var1;
}
public boolean getIsBlank()
{
return this.isBlank;
}
public void func_111144_e()
{
this.objectChanged = false;
}
static
{
dataTypes.put(Byte.class, Integer.valueOf(0));
dataTypes.put(Short.class, Integer.valueOf(1));
dataTypes.put(Integer.class, Integer.valueOf(2));
dataTypes.put(Float.class, Integer.valueOf(3));
dataTypes.put(String.class, Integer.valueOf(4));
dataTypes.put(ItemStack.class, Integer.valueOf(5));
dataTypes.put(BlockPos.class, Integer.valueOf(6));
dataTypes.put(Rotations.class, Integer.valueOf(7));
}
public static class WatchableObject
{
private final int objectType;
private final int dataValueId;
private Object watchedObject;
private boolean watched;
private static final String __OBFID = "CL_00001560";
public WatchableObject(int type, int id, Object object)
{
this.dataValueId = id;
this.watchedObject = object;
this.objectType = type;
this.watched = true;
}
public int getDataValueId()
{
return this.dataValueId;
}
public void setObject(Object object)
{
this.watchedObject = object;
}
public Object getObject()
{
return this.watchedObject;
}
public int getObjectType()
{
return this.objectType;
}
public boolean isWatched()
{
return this.watched;
}
public void setWatched(boolean watched)
{
this.watched = watched;
}
}
}