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