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