001package net.minecraft.entity;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005import java.io.DataInputStream;
006import java.io.DataOutputStream;
007import java.io.IOException;
008import java.util.ArrayList;
009import java.util.HashMap;
010import java.util.Iterator;
011import java.util.List;
012import java.util.Map;
013import java.util.concurrent.locks.ReadWriteLock;
014import java.util.concurrent.locks.ReentrantReadWriteLock;
015import net.minecraft.crash.CrashReport;
016import net.minecraft.crash.CrashReportCategory;
017import net.minecraft.item.ItemStack;
018import net.minecraft.network.packet.Packet;
019import net.minecraft.util.ChunkCoordinates;
020import net.minecraft.util.ReportedException;
021
022public class DataWatcher
023{
024    private boolean field_92086_a = true;
025    private static final HashMap dataTypes = new HashMap();
026    private final Map watchedObjects = new HashMap();
027
028    /** true if one or more object was changed */
029    private boolean objectChanged;
030    private ReadWriteLock lock = new ReentrantReadWriteLock();
031
032    /**
033     * adds a new object to dataWatcher to watch, to update an already existing object see updateObject. Arguments: data
034     * Value Id, Object to add
035     */
036    public void addObject(int par1, Object par2Obj)
037    {
038        Integer var3 = (Integer)dataTypes.get(par2Obj.getClass());
039
040        if (var3 == null)
041        {
042            throw new IllegalArgumentException("Unknown data type: " + par2Obj.getClass());
043        }
044        else if (par1 > 31)
045        {
046            throw new IllegalArgumentException("Data value id is too big with " + par1 + "! (Max is " + 31 + ")");
047        }
048        else if (this.watchedObjects.containsKey(Integer.valueOf(par1)))
049        {
050            throw new IllegalArgumentException("Duplicate id value for " + par1 + "!");
051        }
052        else
053        {
054            WatchableObject var4 = new WatchableObject(var3.intValue(), par1, par2Obj);
055            this.lock.writeLock().lock();
056            this.watchedObjects.put(Integer.valueOf(par1), var4);
057            this.lock.writeLock().unlock();
058            this.field_92086_a = false;
059        }
060    }
061
062    /**
063     * Add a new object for the DataWatcher to watch, using the specified data type.
064     */
065    public void addObjectByDataType(int par1, int par2)
066    {
067        WatchableObject var3 = new WatchableObject(par2, par1, (Object)null);
068        this.lock.writeLock().lock();
069        this.watchedObjects.put(Integer.valueOf(par1), var3);
070        this.lock.writeLock().unlock();
071        this.field_92086_a = false;
072    }
073
074    /**
075     * gets the bytevalue of a watchable object
076     */
077    public byte getWatchableObjectByte(int par1)
078    {
079        return ((Byte)this.getWatchedObject(par1).getObject()).byteValue();
080    }
081
082    public short getWatchableObjectShort(int par1)
083    {
084        return ((Short)this.getWatchedObject(par1).getObject()).shortValue();
085    }
086
087    /**
088     * gets a watchable object and returns it as a Integer
089     */
090    public int getWatchableObjectInt(int par1)
091    {
092        return ((Integer)this.getWatchedObject(par1).getObject()).intValue();
093    }
094
095    /**
096     * gets a watchable object and returns it as a String
097     */
098    public String getWatchableObjectString(int par1)
099    {
100        return (String)this.getWatchedObject(par1).getObject();
101    }
102
103    /**
104     * Get a watchable object as an ItemStack.
105     */
106    public ItemStack getWatchableObjectItemStack(int par1)
107    {
108        return (ItemStack)this.getWatchedObject(par1).getObject();
109    }
110
111    /**
112     * is threadsafe, unless it throws an exception, then
113     */
114    private WatchableObject getWatchedObject(int par1)
115    {
116        this.lock.readLock().lock();
117        WatchableObject var2;
118
119        try
120        {
121            var2 = (WatchableObject)this.watchedObjects.get(Integer.valueOf(par1));
122        }
123        catch (Throwable var6)
124        {
125            CrashReport var4 = CrashReport.makeCrashReport(var6, "Getting synched entity data");
126            CrashReportCategory var5 = var4.makeCategory("Synched entity data");
127            var5.addCrashSection("Data ID", Integer.valueOf(par1));
128            throw new ReportedException(var4);
129        }
130
131        this.lock.readLock().unlock();
132        return var2;
133    }
134
135    /**
136     * updates an already existing object
137     */
138    public void updateObject(int par1, Object par2Obj)
139    {
140        WatchableObject var3 = this.getWatchedObject(par1);
141
142        if (!par2Obj.equals(var3.getObject()))
143        {
144            var3.setObject(par2Obj);
145            var3.setWatched(true);
146            this.objectChanged = true;
147        }
148    }
149
150    public void func_82708_h(int par1)
151    {
152        WatchableObject.setWatchableObjectWatched(this.getWatchedObject(par1), true);
153        this.objectChanged = true;
154    }
155
156    public boolean hasChanges()
157    {
158        return this.objectChanged;
159    }
160
161    /**
162     * writes every object in passed list to dataoutputstream, terminated by 0x7F
163     */
164    public static void writeObjectsInListToStream(List par0List, DataOutputStream par1DataOutputStream) throws IOException
165    {
166        if (par0List != null)
167        {
168            Iterator var2 = par0List.iterator();
169
170            while (var2.hasNext())
171            {
172                WatchableObject var3 = (WatchableObject)var2.next();
173                writeWatchableObject(par1DataOutputStream, var3);
174            }
175        }
176
177        par1DataOutputStream.writeByte(127);
178    }
179
180    public List unwatchAndReturnAllWatched()
181    {
182        ArrayList var1 = null;
183
184        if (this.objectChanged)
185        {
186            this.lock.readLock().lock();
187            Iterator var2 = this.watchedObjects.values().iterator();
188
189            while (var2.hasNext())
190            {
191                WatchableObject var3 = (WatchableObject)var2.next();
192
193                if (var3.isWatched())
194                {
195                    var3.setWatched(false);
196
197                    if (var1 == null)
198                    {
199                        var1 = new ArrayList();
200                    }
201
202                    var1.add(var3);
203                }
204            }
205
206            this.lock.readLock().unlock();
207        }
208
209        this.objectChanged = false;
210        return var1;
211    }
212
213    public void writeWatchableObjects(DataOutputStream par1DataOutputStream) throws IOException
214    {
215        this.lock.readLock().lock();
216        Iterator var2 = this.watchedObjects.values().iterator();
217
218        while (var2.hasNext())
219        {
220            WatchableObject var3 = (WatchableObject)var2.next();
221            writeWatchableObject(par1DataOutputStream, var3);
222        }
223
224        this.lock.readLock().unlock();
225        par1DataOutputStream.writeByte(127);
226    }
227
228    public List func_75685_c()
229    {
230        ArrayList var1 = null;
231        this.lock.readLock().lock();
232        WatchableObject var3;
233
234        for (Iterator var2 = this.watchedObjects.values().iterator(); var2.hasNext(); var1.add(var3))
235        {
236            var3 = (WatchableObject)var2.next();
237
238            if (var1 == null)
239            {
240                var1 = new ArrayList();
241            }
242        }
243
244        this.lock.readLock().unlock();
245        return var1;
246    }
247
248    private static void writeWatchableObject(DataOutputStream par0DataOutputStream, WatchableObject par1WatchableObject) throws IOException
249    {
250        int var2 = (par1WatchableObject.getObjectType() << 5 | par1WatchableObject.getDataValueId() & 31) & 255;
251        par0DataOutputStream.writeByte(var2);
252
253        switch (par1WatchableObject.getObjectType())
254        {
255            case 0:
256                par0DataOutputStream.writeByte(((Byte)par1WatchableObject.getObject()).byteValue());
257                break;
258            case 1:
259                par0DataOutputStream.writeShort(((Short)par1WatchableObject.getObject()).shortValue());
260                break;
261            case 2:
262                par0DataOutputStream.writeInt(((Integer)par1WatchableObject.getObject()).intValue());
263                break;
264            case 3:
265                par0DataOutputStream.writeFloat(((Float)par1WatchableObject.getObject()).floatValue());
266                break;
267            case 4:
268                Packet.writeString((String)par1WatchableObject.getObject(), par0DataOutputStream);
269                break;
270            case 5:
271                ItemStack var4 = (ItemStack)par1WatchableObject.getObject();
272                Packet.writeItemStack(var4, par0DataOutputStream);
273                break;
274            case 6:
275                ChunkCoordinates var3 = (ChunkCoordinates)par1WatchableObject.getObject();
276                par0DataOutputStream.writeInt(var3.posX);
277                par0DataOutputStream.writeInt(var3.posY);
278                par0DataOutputStream.writeInt(var3.posZ);
279        }
280    }
281
282    public static List readWatchableObjects(DataInputStream par0DataInputStream) throws IOException
283    {
284        ArrayList var1 = null;
285
286        for (byte var2 = par0DataInputStream.readByte(); var2 != 127; var2 = par0DataInputStream.readByte())
287        {
288            if (var1 == null)
289            {
290                var1 = new ArrayList();
291            }
292
293            int var3 = (var2 & 224) >> 5;
294            int var4 = var2 & 31;
295            WatchableObject var5 = null;
296
297            switch (var3)
298            {
299                case 0:
300                    var5 = new WatchableObject(var3, var4, Byte.valueOf(par0DataInputStream.readByte()));
301                    break;
302                case 1:
303                    var5 = new WatchableObject(var3, var4, Short.valueOf(par0DataInputStream.readShort()));
304                    break;
305                case 2:
306                    var5 = new WatchableObject(var3, var4, Integer.valueOf(par0DataInputStream.readInt()));
307                    break;
308                case 3:
309                    var5 = new WatchableObject(var3, var4, Float.valueOf(par0DataInputStream.readFloat()));
310                    break;
311                case 4:
312                    var5 = new WatchableObject(var3, var4, Packet.readString(par0DataInputStream, 64));
313                    break;
314                case 5:
315                    var5 = new WatchableObject(var3, var4, Packet.readItemStack(par0DataInputStream));
316                    break;
317                case 6:
318                    int var6 = par0DataInputStream.readInt();
319                    int var7 = par0DataInputStream.readInt();
320                    int var8 = par0DataInputStream.readInt();
321                    var5 = new WatchableObject(var3, var4, new ChunkCoordinates(var6, var7, var8));
322            }
323
324            var1.add(var5);
325        }
326
327        return var1;
328    }
329
330    @SideOnly(Side.CLIENT)
331    public void updateWatchedObjectsFromList(List par1List)
332    {
333        this.lock.writeLock().lock();
334        Iterator var2 = par1List.iterator();
335
336        while (var2.hasNext())
337        {
338            WatchableObject var3 = (WatchableObject)var2.next();
339            WatchableObject var4 = (WatchableObject)this.watchedObjects.get(Integer.valueOf(var3.getDataValueId()));
340
341            if (var4 != null)
342            {
343                var4.setObject(var3.getObject());
344            }
345        }
346
347        this.lock.writeLock().unlock();
348    }
349
350    public boolean func_92085_d()
351    {
352        return this.field_92086_a;
353    }
354
355    static
356    {
357        dataTypes.put(Byte.class, Integer.valueOf(0));
358        dataTypes.put(Short.class, Integer.valueOf(1));
359        dataTypes.put(Integer.class, Integer.valueOf(2));
360        dataTypes.put(Float.class, Integer.valueOf(3));
361        dataTypes.put(String.class, Integer.valueOf(4));
362        dataTypes.put(ItemStack.class, Integer.valueOf(5));
363        dataTypes.put(ChunkCoordinates.class, Integer.valueOf(6));
364    }
365}