PageRenderTime 36ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/newcode/src/com/prupe/mcpatcher/mob/MobRandomizer.java

https://bitbucket.org/Freso/mcpatcher
Java | 221 lines | 198 code | 23 blank | 0 comment | 31 complexity | 7513877a6cbc1d1f7216d5b58896f2b8 MD5 | raw file
  1. package com.prupe.mcpatcher.mob;
  2. import com.prupe.mcpatcher.MCLogger;
  3. import com.prupe.mcpatcher.MCPatcherUtils;
  4. import com.prupe.mcpatcher.TexturePackChangeHandler;
  5. import net.minecraft.src.Entity;
  6. import net.minecraft.src.EntityLivingBase;
  7. import net.minecraft.src.NBTTagCompound;
  8. import net.minecraft.src.ResourceLocation;
  9. import java.lang.ref.Reference;
  10. import java.lang.ref.ReferenceQueue;
  11. import java.lang.ref.WeakReference;
  12. import java.lang.reflect.Method;
  13. import java.util.HashMap;
  14. import java.util.HashSet;
  15. import java.util.LinkedHashMap;
  16. public class MobRandomizer {
  17. private static final MCLogger logger = MCLogger.getLogger(MCPatcherUtils.RANDOM_MOBS);
  18. private static final LinkedHashMap<String, ResourceLocation> cache = new LinkedHashMap<String, ResourceLocation>();
  19. static {
  20. TexturePackChangeHandler.register(new TexturePackChangeHandler(MCPatcherUtils.RANDOM_MOBS, 2) {
  21. @Override
  22. public void beforeChange() {
  23. cache.clear();
  24. }
  25. @Override
  26. public void afterChange() {
  27. MobRuleList.clear();
  28. MobOverlay.reset();
  29. LineRenderer.reset();
  30. }
  31. });
  32. }
  33. public static ResourceLocation randomTexture(EntityLivingBase entity, ResourceLocation texture) {
  34. if (texture == null || !texture.getPath().endsWith(".png")) {
  35. return texture;
  36. }
  37. String key = texture.toString() + ":" + entity.entityId;
  38. ResourceLocation newTexture = cache.get(key);
  39. if (newTexture == null) {
  40. ExtraInfo info = ExtraInfo.getInfo(entity);
  41. MobRuleList list = MobRuleList.get(texture);
  42. newTexture = list.getSkin(info.skin, info.origX, info.origY, info.origZ, info.origBiome);
  43. cache.put(key, newTexture);
  44. logger.finer("entity %s using %s (cache: %d)", entity, newTexture, cache.size());
  45. if (cache.size() > 250) {
  46. while (cache.size() > 200) {
  47. cache.remove(cache.keySet().iterator().next());
  48. }
  49. }
  50. }
  51. return newTexture;
  52. }
  53. public static ResourceLocation randomTexture(Entity entity, ResourceLocation texture) {
  54. if (entity instanceof EntityLivingBase) {
  55. return randomTexture((EntityLivingBase) entity, texture);
  56. } else {
  57. return texture;
  58. }
  59. }
  60. public static final class ExtraInfo {
  61. private static final String SKIN_TAG = "randomMobsSkin";
  62. private static final String ORIG_X_TAG = "origX";
  63. private static final String ORIG_Y_TAG = "origY";
  64. private static final String ORIG_Z_TAG = "origZ";
  65. private static final long MULTIPLIER = 0x5deece66dL;
  66. private static final long ADDEND = 0xbL;
  67. private static final long MASK = (1L << 48) - 1;
  68. private static Method getBiomeNameAt;
  69. private static final HashMap<Integer, ExtraInfo> allInfo = new HashMap<Integer, ExtraInfo>();
  70. private static final HashMap<WeakReference<EntityLivingBase>, ExtraInfo> allRefs = new HashMap<WeakReference<EntityLivingBase>, ExtraInfo>();
  71. private static final ReferenceQueue<EntityLivingBase> refQueue = new ReferenceQueue<EntityLivingBase>();
  72. private final int entityId;
  73. private final HashSet<WeakReference<EntityLivingBase>> references;
  74. private final long skin;
  75. private final int origX;
  76. private final int origY;
  77. private final int origZ;
  78. private String origBiome;
  79. static {
  80. try {
  81. Class<?> biomeHelperClass = Class.forName(MCPatcherUtils.BIOME_HELPER_CLASS);
  82. getBiomeNameAt = biomeHelperClass.getDeclaredMethod("getBiomeNameAt", Integer.TYPE, Integer.TYPE, Integer.TYPE);
  83. getBiomeNameAt.setAccessible(true);
  84. } catch (Throwable e) {
  85. }
  86. if (getBiomeNameAt == null) {
  87. logger.warning("biome integration failed");
  88. } else {
  89. logger.fine("biome integration active");
  90. }
  91. }
  92. ExtraInfo(EntityLivingBase entity) {
  93. this(entity, getSkinId(entity.entityId), (int) entity.posX, (int) entity.posY, (int) entity.posZ);
  94. }
  95. ExtraInfo(EntityLivingBase entity, long skin, int origX, int origY, int origZ) {
  96. entityId = entity.entityId;
  97. references = new HashSet<WeakReference<EntityLivingBase>>();
  98. this.skin = skin;
  99. this.origX = origX;
  100. this.origY = origY;
  101. this.origZ = origZ;
  102. }
  103. private void setBiome() {
  104. if (origBiome == null && getBiomeNameAt != null) {
  105. try {
  106. origBiome = (String) getBiomeNameAt.invoke(null, origX, origY, origZ);
  107. } catch (Throwable e) {
  108. getBiomeNameAt = null;
  109. e.printStackTrace();
  110. }
  111. }
  112. }
  113. @Override
  114. public String toString() {
  115. return String.format("%s{%d, %d, %d, %d, %d, %s}", getClass().getSimpleName(), entityId, skin, origX, origY, origZ, origBiome);
  116. }
  117. private static void clearUnusedReferences() {
  118. synchronized (allInfo) {
  119. Reference<? extends EntityLivingBase> ref;
  120. while ((ref = refQueue.poll()) != null) {
  121. ExtraInfo info = allRefs.get(ref);
  122. if (info != null) {
  123. info.references.remove(ref);
  124. if (info.references.isEmpty()) {
  125. logger.finest("removing unused ref %d", info.entityId);
  126. allInfo.remove(info.entityId);
  127. }
  128. }
  129. allRefs.remove(ref);
  130. }
  131. }
  132. }
  133. static ExtraInfo getInfo(EntityLivingBase entity) {
  134. ExtraInfo info;
  135. synchronized (allInfo) {
  136. clearUnusedReferences();
  137. info = allInfo.get(entity.entityId);
  138. if (info == null) {
  139. info = new ExtraInfo(entity);
  140. putInfo(entity, info);
  141. }
  142. boolean found = false;
  143. for (WeakReference<EntityLivingBase> ref : info.references) {
  144. if (ref.get() == entity) {
  145. found = true;
  146. break;
  147. }
  148. }
  149. if (!found) {
  150. WeakReference<EntityLivingBase> reference = new WeakReference<EntityLivingBase>(entity, refQueue);
  151. info.references.add(reference);
  152. allRefs.put(reference, info);
  153. logger.finest("added ref #%d for %d (%d entities)", info.references.size(), entity.entityId, allInfo.size());
  154. }
  155. info.setBiome();
  156. }
  157. return info;
  158. }
  159. static void putInfo(EntityLivingBase entity, ExtraInfo info) {
  160. synchronized (allInfo) {
  161. allInfo.put(entity.entityId, info);
  162. }
  163. }
  164. static void clearInfo() {
  165. synchronized (allInfo) {
  166. allInfo.clear();
  167. }
  168. }
  169. private static long getSkinId(int entityId) {
  170. long n = entityId;
  171. n = n ^ (n << 16) ^ (n << 32) ^ (n << 48);
  172. n = MULTIPLIER * n + ADDEND;
  173. n = MULTIPLIER * n + ADDEND;
  174. n &= MASK;
  175. return (n >> 32) ^ n;
  176. }
  177. public static void readFromNBT(EntityLivingBase entity, NBTTagCompound nbt) {
  178. long skin = nbt.getLong(SKIN_TAG);
  179. if (skin != 0L) {
  180. int x = nbt.getInteger(ORIG_X_TAG);
  181. int y = nbt.getInteger(ORIG_Y_TAG);
  182. int z = nbt.getInteger(ORIG_Z_TAG);
  183. putInfo(entity, new ExtraInfo(entity, skin, x, y, z));
  184. }
  185. }
  186. public static void writeToNBT(EntityLivingBase entity, NBTTagCompound nbt) {
  187. synchronized (allInfo) {
  188. ExtraInfo info = allInfo.get(entity.entityId);
  189. if (info != null) {
  190. nbt.setLong(SKIN_TAG, info.skin);
  191. nbt.setInteger(ORIG_X_TAG, info.origX);
  192. nbt.setInteger(ORIG_Y_TAG, info.origY);
  193. nbt.setInteger(ORIG_Z_TAG, info.origZ);
  194. }
  195. }
  196. }
  197. }
  198. }