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 }