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