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