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