001    package net.minecraft.entity;
002    
003    import cpw.mods.fml.relauncher.Side;
004    import cpw.mods.fml.relauncher.SideOnly;
005    import java.io.DataInputStream;
006    import java.io.DataOutputStream;
007    import java.io.IOException;
008    import java.util.ArrayList;
009    import java.util.HashMap;
010    import java.util.Iterator;
011    import java.util.List;
012    import java.util.Map;
013    import java.util.concurrent.locks.ReadWriteLock;
014    import java.util.concurrent.locks.ReentrantReadWriteLock;
015    import net.minecraft.crash.CrashReport;
016    import net.minecraft.crash.CrashReportCategory;
017    import net.minecraft.item.ItemStack;
018    import net.minecraft.network.packet.Packet;
019    import net.minecraft.util.ChunkCoordinates;
020    import net.minecraft.util.ReportedException;
021    
022    public class DataWatcher
023    {
024        private boolean field_92035_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 field_75694_d = 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.field_75694_d.writeLock().lock();
056                this.watchedObjects.put(Integer.valueOf(par1), var4);
057                this.field_75694_d.writeLock().unlock();
058                this.field_92035_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.field_75694_d.writeLock().lock();
069            this.watchedObjects.put(Integer.valueOf(par1), var3);
070            this.field_75694_d.writeLock().unlock();
071            this.field_92035_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.field_75694_d.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.field_75694_d.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.field_75694_d.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.field_75694_d.readLock().unlock();
207            }
208    
209            this.objectChanged = false;
210            return var1;
211        }
212    
213        public void writeWatchableObjects(DataOutputStream par1DataOutputStream) throws IOException
214        {
215            this.field_75694_d.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.field_75694_d.readLock().unlock();
225            par1DataOutputStream.writeByte(127);
226        }
227    
228        public List func_75685_c()
229        {
230            ArrayList var1 = null;
231            this.field_75694_d.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.field_75694_d.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.field_75694_d.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.field_75694_d.writeLock().unlock();
348        }
349    
350        public boolean func_92034_d()
351        {
352            return this.field_92035_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    }