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