PageRenderTime 27ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/SevenBits/mcpatcher
Java | 204 lines | 181 code | 23 blank | 0 comment | 26 complexity | 6e62f8ac6654865a9dc386a32b8efcb1 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 com.prupe.mcpatcher.mal.biome.BiomeAPI;
  6. import net.minecraft.src.Entity;
  7. import net.minecraft.src.EntityLivingBase;
  8. import net.minecraft.src.NBTTagCompound;
  9. import net.minecraft.src.ResourceLocation;
  10. import java.lang.ref.Reference;
  11. import java.lang.ref.ReferenceQueue;
  12. import java.lang.ref.WeakReference;
  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. static void init() {
  34. }
  35. public static ResourceLocation randomTexture(EntityLivingBase entity, ResourceLocation texture) {
  36. if (texture == null || !texture.getPath().endsWith(".png")) {
  37. return texture;
  38. }
  39. String key = texture.toString() + ":" + entity.entityId;
  40. ResourceLocation newTexture = cache.get(key);
  41. if (newTexture == null) {
  42. ExtraInfo info = ExtraInfo.getInfo(entity);
  43. MobRuleList list = MobRuleList.get(texture);
  44. newTexture = list.getSkin(info.skin, info.origX, info.origY, info.origZ, info.origBiome);
  45. cache.put(key, newTexture);
  46. logger.finer("entity %s using %s (cache: %d)", entity, newTexture, cache.size());
  47. if (cache.size() > 250) {
  48. while (cache.size() > 200) {
  49. cache.remove(cache.keySet().iterator().next());
  50. }
  51. }
  52. }
  53. return newTexture;
  54. }
  55. public static ResourceLocation randomTexture(Entity entity, ResourceLocation texture) {
  56. if (entity instanceof EntityLivingBase) {
  57. return randomTexture((EntityLivingBase) entity, texture);
  58. } else {
  59. return texture;
  60. }
  61. }
  62. public static final class ExtraInfo {
  63. private static final String SKIN_TAG = "randomMobsSkin";
  64. private static final String ORIG_X_TAG = "origX";
  65. private static final String ORIG_Y_TAG = "origY";
  66. private static final String ORIG_Z_TAG = "origZ";
  67. private static final long MULTIPLIER = 0x5deece66dL;
  68. private static final long ADDEND = 0xbL;
  69. private static final long MASK = (1L << 48) - 1;
  70. private static final HashMap<Integer, ExtraInfo> allInfo = new HashMap<Integer, ExtraInfo>();
  71. private static final HashMap<WeakReference<EntityLivingBase>, ExtraInfo> allRefs = new HashMap<WeakReference<EntityLivingBase>, ExtraInfo>();
  72. private static final ReferenceQueue<EntityLivingBase> refQueue = new ReferenceQueue<EntityLivingBase>();
  73. private final int entityId;
  74. private final HashSet<WeakReference<EntityLivingBase>> references;
  75. private final long skin;
  76. private final int origX;
  77. private final int origY;
  78. private final int origZ;
  79. private Integer origBiome;
  80. ExtraInfo(EntityLivingBase entity) {
  81. this(entity, getSkinId(entity.entityId), (int) entity.posX, (int) entity.posY, (int) entity.posZ);
  82. }
  83. ExtraInfo(EntityLivingBase entity, long skin, int origX, int origY, int origZ) {
  84. entityId = entity.entityId;
  85. references = new HashSet<WeakReference<EntityLivingBase>>();
  86. this.skin = skin;
  87. this.origX = origX;
  88. this.origY = origY;
  89. this.origZ = origZ;
  90. }
  91. private void setBiome() {
  92. if (origBiome == null) {
  93. origBiome = BiomeAPI.getBiomeIDAt(BiomeAPI.getWorld(), origX, origY, origZ);
  94. }
  95. }
  96. @Override
  97. public String toString() {
  98. return String.format("%s{%d, %d, %d, %d, %d, %s}", getClass().getSimpleName(), entityId, skin, origX, origY, origZ, origBiome);
  99. }
  100. private static void clearUnusedReferences() {
  101. synchronized (allInfo) {
  102. Reference<? extends EntityLivingBase> ref;
  103. while ((ref = refQueue.poll()) != null) {
  104. ExtraInfo info = allRefs.get(ref);
  105. if (info != null) {
  106. info.references.remove(ref);
  107. if (info.references.isEmpty()) {
  108. logger.finest("removing unused ref %d", info.entityId);
  109. allInfo.remove(info.entityId);
  110. }
  111. }
  112. allRefs.remove(ref);
  113. }
  114. }
  115. }
  116. static ExtraInfo getInfo(EntityLivingBase entity) {
  117. ExtraInfo info;
  118. synchronized (allInfo) {
  119. clearUnusedReferences();
  120. info = allInfo.get(entity.entityId);
  121. if (info == null) {
  122. info = new ExtraInfo(entity);
  123. putInfo(entity, info);
  124. }
  125. boolean found = false;
  126. for (WeakReference<EntityLivingBase> ref : info.references) {
  127. if (ref.get() == entity) {
  128. found = true;
  129. break;
  130. }
  131. }
  132. if (!found) {
  133. WeakReference<EntityLivingBase> reference = new WeakReference<EntityLivingBase>(entity, refQueue);
  134. info.references.add(reference);
  135. allRefs.put(reference, info);
  136. logger.finest("added ref #%d for %d (%d entities)", info.references.size(), entity.entityId, allInfo.size());
  137. }
  138. info.setBiome();
  139. }
  140. return info;
  141. }
  142. static void putInfo(EntityLivingBase entity, ExtraInfo info) {
  143. synchronized (allInfo) {
  144. allInfo.put(entity.entityId, info);
  145. }
  146. }
  147. static void clearInfo() {
  148. synchronized (allInfo) {
  149. allInfo.clear();
  150. }
  151. }
  152. private static long getSkinId(int entityId) {
  153. long n = entityId;
  154. n = n ^ (n << 16) ^ (n << 32) ^ (n << 48);
  155. n = MULTIPLIER * n + ADDEND;
  156. n = MULTIPLIER * n + ADDEND;
  157. n &= MASK;
  158. return (n >> 32) ^ n;
  159. }
  160. public static void readFromNBT(EntityLivingBase entity, NBTTagCompound nbt) {
  161. long skin = nbt.getLong(SKIN_TAG);
  162. if (skin != 0L) {
  163. int x = nbt.getInteger(ORIG_X_TAG);
  164. int y = nbt.getInteger(ORIG_Y_TAG);
  165. int z = nbt.getInteger(ORIG_Z_TAG);
  166. putInfo(entity, new ExtraInfo(entity, skin, x, y, z));
  167. }
  168. }
  169. public static void writeToNBT(EntityLivingBase entity, NBTTagCompound nbt) {
  170. synchronized (allInfo) {
  171. ExtraInfo info = allInfo.get(entity.entityId);
  172. if (info != null) {
  173. nbt.setLong(SKIN_TAG, info.skin);
  174. nbt.setInteger(ORIG_X_TAG, info.origX);
  175. nbt.setInteger(ORIG_Y_TAG, info.origY);
  176. nbt.setInteger(ORIG_Z_TAG, info.origZ);
  177. }
  178. }
  179. }
  180. }
  181. }