| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| package cpw.mods.fml.common.registry; |
| |
| import java.util.BitSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.logging.log4j.Level; |
| |
| import net.minecraft.entity.Entity; |
| import net.minecraft.entity.EntityList; |
| import net.minecraft.entity.EntityLiving; |
| import net.minecraft.entity.EntityTracker; |
| import net.minecraft.entity.EnumCreatureType; |
| import net.minecraft.world.biome.BiomeGenBase; |
| import net.minecraft.world.biome.BiomeGenBase.SpawnListEntry; |
| |
| import com.google.common.base.Function; |
| import com.google.common.collect.ArrayListMultimap; |
| import com.google.common.collect.BiMap; |
| import com.google.common.collect.HashBiMap; |
| import com.google.common.collect.ListMultimap; |
| import com.google.common.collect.Maps; |
| import com.google.common.primitives.UnsignedBytes; |
| |
| import cpw.mods.fml.common.FMLCommonHandler; |
| import cpw.mods.fml.common.FMLLog; |
| import cpw.mods.fml.common.Loader; |
| import cpw.mods.fml.common.ModContainer; |
| import cpw.mods.fml.common.network.internal.FMLMessage.EntitySpawnMessage; |
| |
| import net.minecraft.world.biome.BiomeGenBase.SpawnListEntry; |
| public class EntityRegistry |
| { |
| public class EntityRegistration |
| { |
| private Class entityClass; |
| private ModContainer container; |
| private String entityName; |
| private int modId; |
| private int trackingRange; |
| private int updateFrequency; |
| private boolean sendsVelocityUpdates; |
| private Function <entityspawnmessage, entity="">customSpawnCallback; |
| private boolean usesVanillaSpawning; |
| public EntityRegistration(ModContainer mc, Class entityClass, String entityName, int id, int trackingRange, int updateFrequency, boolean sendsVelocityUpdates) |
| { |
| this.container = mc; |
| this.entityClass = entityClass; |
| this.entityName = entityName; |
| this.modId = id; |
| this.trackingRange = trackingRange; |
| this.updateFrequency = updateFrequency; |
| this.sendsVelocityUpdates = sendsVelocityUpdates; |
| } |
| public Class getEntityClass() |
| { |
| return entityClass; |
| } |
| public ModContainer getContainer() |
| { |
| return container; |
| } |
| public String getEntityName() |
| { |
| return entityName; |
| } |
| public int getModEntityId() |
| { |
| return modId; |
| } |
| public int getTrackingRange() |
| { |
| return trackingRange; |
| } |
| public int getUpdateFrequency() |
| { |
| return updateFrequency; |
| } |
| public boolean sendsVelocityUpdates() |
| { |
| return sendsVelocityUpdates; |
| } |
| |
| public boolean usesVanillaSpawning() |
| { |
| return usesVanillaSpawning; |
| } |
| public boolean hasCustomSpawning() |
| { |
| return customSpawnCallback != null; |
| } |
| public Entity doCustomSpawning(EntitySpawnMessage spawnMsg) throws Exception |
| { |
| return customSpawnCallback.apply(spawnMsg); |
| } |
| public void setCustomSpawning(Function <entityspawnmessage, entity="">callable, boolean usesVanillaSpawning) |
| { |
| this.customSpawnCallback = callable; |
| this.usesVanillaSpawning = usesVanillaSpawning; |
| } |
| } |
| |
| private static final EntityRegistry INSTANCE = new EntityRegistry(); |
| |
| private BitSet availableIndicies; |
| private ListMultimap <modcontainer, entityregistration="">entityRegistrations = ArrayListMultimap.create(); |
| private Map <string,modcontainer>entityNames = Maps.newHashMap(); |
| private BiMap<class<? extends="" entity="">, EntityRegistration> entityClassRegistrations = HashBiMap.create(); |
| public static EntityRegistry instance() |
| { |
| return INSTANCE; |
| } |
| |
| private EntityRegistry() |
| { |
| availableIndicies = new BitSet(256); |
| availableIndicies.set(1,255); |
| for (Object id : EntityList.IDtoClassMapping.keySet()) |
| { |
| availableIndicies.clear((Integer)id); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public static void registerModEntity(Class entityClass, String entityName, int id, Object mod, int trackingRange, int updateFrequency, boolean sendsVelocityUpdates) |
| { |
| instance().doModEntityRegistration(entityClass, entityName, id, mod, trackingRange, updateFrequency, sendsVelocityUpdates); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private void doModEntityRegistration(Class entityClass, String entityName, int id, Object mod, int trackingRange, int updateFrequency, boolean sendsVelocityUpdates) |
| { |
| ModContainer mc = FMLCommonHandler.instance().findContainerFor(mod); |
| EntityRegistration er = new EntityRegistration(mc, entityClass, entityName, id, trackingRange, updateFrequency, sendsVelocityUpdates); |
| try |
| { |
| entityClassRegistrations.put(entityClass, er); |
| entityNames.put(entityName, mc); |
| if (!EntityList.classToStringMapping.containsKey(entityClass)) |
| { |
| String entityModName = String.format("%s.%s", mc.getModId(), entityName); |
| EntityList.classToStringMapping.put(entityClass, entityModName); |
| EntityList.stringToClassMapping.put(entityModName, entityClass); |
| FMLLog.finer("Automatically registered mod %s entity %s as %s", mc.getModId(), entityName, entityModName); |
| } |
| else |
| { |
| FMLLog.fine("Skipping automatic mod %s entity registration for already registered class %s", mc.getModId(), entityClass.getName()); |
| } |
| } |
| catch (IllegalArgumentException e) |
| { |
| FMLLog.log(Level.WARN, e, "The mod %s tried to register the entity (name,class) (%s,%s) one or both of which are already registered", mc.getModId(), entityName, entityClass.getName()); |
| return; |
| } |
| entityRegistrations.put(mc, er); |
| } |
| |
| public static void registerGlobalEntityID(Class entityClass, String entityName, int id) |
| { |
| if (EntityList.classToStringMapping.containsKey(entityClass)) |
| { |
| ModContainer activeModContainer = Loader.instance().activeModContainer(); |
| String modId = "unknown"; |
| if (activeModContainer != null) |
| { |
| modId = activeModContainer.getModId(); |
| } |
| else |
| { |
| FMLLog.severe("There is a rogue mod failing to register entities from outside the context of mod loading. This is incredibly dangerous and should be stopped."); |
| } |
| FMLLog.warning("The mod %s tried to register the entity class %s which was already registered - if you wish to override default naming for FML mod entities, register it here first", modId, entityClass); |
| return; |
| } |
| id = instance().validateAndClaimId(id); |
| EntityList.addMapping(entityClass, entityName, id); |
| } |
| |
| private int validateAndClaimId(int id) |
| { |
| |
| int realId = id; |
| if (id < Byte.MIN_VALUE) |
| { |
| FMLLog.warning("Compensating for modloader out of range compensation by mod : entityId %d for mod %s is now %d", id, Loader.instance().activeModContainer().getModId(), realId); |
| realId += 3000; |
| } |
| |
| if (realId < 0) |
| { |
| realId += Byte.MAX_VALUE; |
| } |
| try |
| { |
| UnsignedBytes.checkedCast(realId); |
| } |
| catch (IllegalArgumentException e) |
| { |
| FMLLog.log(Level.ERROR, "The entity ID %d for mod %s is not an unsigned byte and may not work", id, Loader.instance().activeModContainer().getModId()); |
| } |
| |
| if (!availableIndicies.get(realId)) |
| { |
| FMLLog.severe("The mod %s has attempted to register an entity ID %d which is already reserved. This could cause severe problems", Loader.instance().activeModContainer().getModId(), id); |
| } |
| availableIndicies.clear(realId); |
| return realId; |
| } |
| |
| public static void registerGlobalEntityID(Class entityClass, String entityName, int id, int backgroundEggColour, int foregroundEggColour) |
| { |
| if (EntityList.classToStringMapping.containsKey(entityClass)) |
| { |
| ModContainer activeModContainer = Loader.instance().activeModContainer(); |
| String modId = "unknown"; |
| if (activeModContainer != null) |
| { |
| modId = activeModContainer.getModId(); |
| } |
| else |
| { |
| FMLLog.severe("There is a rogue mod failing to register entities from outside the context of mod loading. This is incredibly dangerous and should be stopped."); |
| } |
| FMLLog.warning("The mod %s tried to register the entity class %s which was already registered - if you wish to override default naming for FML mod entities, register it here first", modId, entityClass); |
| return; |
| } |
| instance().validateAndClaimId(id); |
| EntityList.addMapping(entityClass, entityName, id, backgroundEggColour, foregroundEggColour); |
| } |
| |
| public static void addSpawn(Class entityClass, int weightedProb, int min, int max, EnumCreatureType typeOfCreature, BiomeGenBase... biomes) |
| { |
| for (BiomeGenBase biome : biomes) |
| { |
| @SuppressWarnings("unchecked") |
| List <spawnlistentry>spawns = biome.getSpawnableList(typeOfCreature); |
| |
| for (SpawnListEntry entry : spawns) |
| { |
| |
| if (entry.entityClass == entityClass) |
| { |
| entry.itemWeight = weightedProb; |
| entry.minGroupCount = min; |
| entry.maxGroupCount = max; |
| break; |
| } |
| } |
| |
| spawns.add(new SpawnListEntry(entityClass, weightedProb, min, max)); |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| public static void addSpawn(String entityName, int weightedProb, int min, int max, EnumCreatureType spawnList, BiomeGenBase... biomes) |
| { |
| Class entityClazz = (Class) EntityList.stringToClassMapping.get(entityName); |
| |
| if (EntityLiving.class.isAssignableFrom(entityClazz)) |
| { |
| addSpawn((Class ) entityClazz, weightedProb, min, max, spawnList, biomes); |
| } |
| } |
| |
| public static void removeSpawn(Class entityClass, EnumCreatureType typeOfCreature, BiomeGenBase... biomes) |
| { |
| for (BiomeGenBase biome : biomes) |
| { |
| @SuppressWarnings("unchecked") |
| Iterator <spawnlistentry>spawns = biome.getSpawnableList(typeOfCreature).iterator(); |
| |
| while (spawns.hasNext()) |
| { |
| SpawnListEntry entry = spawns.next(); |
| if (entry.entityClass == entityClass) |
| { |
| spawns.remove(); |
| } |
| } |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| public static void removeSpawn(String entityName, EnumCreatureType spawnList, BiomeGenBase... biomes) |
| { |
| Class entityClazz = (Class) EntityList.stringToClassMapping.get(entityName); |
| |
| if (EntityLiving.class.isAssignableFrom(entityClazz)) |
| { |
| removeSpawn((Class ) entityClazz, spawnList, biomes); |
| } |
| } |
| |
| public static int findGlobalUniqueEntityId() |
| { |
| int res = instance().availableIndicies.nextSetBit(0); |
| if (res < 0) |
| { |
| throw new RuntimeException("No more entity indicies left"); |
| } |
| return res; |
| } |
| |
| public EntityRegistration lookupModSpawn(Class clazz, boolean keepLooking) |
| { |
| Class localClazz = clazz; |
| |
| do |
| { |
| EntityRegistration er = entityClassRegistrations.get(localClazz); |
| if (er != null) |
| { |
| return er; |
| } |
| localClazz = localClazz.getSuperclass(); |
| keepLooking = (!Object.class.equals(localClazz)); |
| } |
| while (keepLooking); |
| |
| return null; |
| } |
| |
| public EntityRegistration lookupModSpawn(ModContainer mc, int modEntityId) |
| { |
| for (EntityRegistration er : entityRegistrations.get(mc)) |
| { |
| if (er.getModEntityId() == modEntityId) |
| { |
| return er; |
| } |
| } |
| return null; |
| } |
| |
| public boolean tryTrackingEntity(EntityTracker entityTracker, Entity entity) |
| { |
| |
| EntityRegistration er = lookupModSpawn(entity.getClass(), true); |
| if (er != null) |
| { |
| entityTracker.addEntityToTracker(entity, er.getTrackingRange(), er.getUpdateFrequency(), er.sendsVelocityUpdates()); |
| return true; |
| } |
| return false; |
| } |
| } |