001 package cpw.mods.fml.common.registry; 002 003 import java.util.List; 004 import java.util.Map; 005 import java.util.Random; 006 import java.util.Set; 007 import java.util.concurrent.CountDownLatch; 008 import java.util.logging.Level; 009 010 import net.minecraft.entity.item.EntityItem; 011 import net.minecraft.entity.player.EntityPlayer; 012 import net.minecraft.inventory.IInventory; 013 import net.minecraft.item.Item; 014 import net.minecraft.item.ItemBlock; 015 import net.minecraft.item.ItemStack; 016 import net.minecraft.item.crafting.CraftingManager; 017 import net.minecraft.item.crafting.FurnaceRecipes; 018 import net.minecraft.item.crafting.IRecipe; 019 import net.minecraft.nbt.NBTTagCompound; 020 import net.minecraft.nbt.NBTTagList; 021 import net.minecraft.tileentity.TileEntity; 022 import net.minecraft.world.World; 023 import net.minecraft.world.WorldType; 024 import net.minecraft.world.biome.BiomeGenBase; 025 import net.minecraft.world.chunk.IChunkProvider; 026 027 import com.google.common.base.Function; 028 import com.google.common.collect.ArrayListMultimap; 029 import com.google.common.collect.Lists; 030 import com.google.common.collect.MapDifference; 031 import com.google.common.collect.Maps; 032 import com.google.common.collect.Multimap; 033 import com.google.common.collect.Multimaps; 034 import com.google.common.collect.Sets; 035 import com.google.common.collect.Sets.SetView; 036 037 import cpw.mods.fml.common.FMLLog; 038 import cpw.mods.fml.common.ICraftingHandler; 039 import cpw.mods.fml.common.IDispenseHandler; 040 import cpw.mods.fml.common.IDispenserHandler; 041 import cpw.mods.fml.common.IFuelHandler; 042 import cpw.mods.fml.common.IPickupNotifier; 043 import cpw.mods.fml.common.IPlayerTracker; 044 import cpw.mods.fml.common.IWorldGenerator; 045 import cpw.mods.fml.common.Loader; 046 import cpw.mods.fml.common.LoaderException; 047 import cpw.mods.fml.common.LoaderState; 048 import cpw.mods.fml.common.Mod.Block; 049 import cpw.mods.fml.common.ModContainer; 050 051 public class GameRegistry 052 { 053 private static Multimap<ModContainer, BlockProxy> blockRegistry = ArrayListMultimap.create(); 054 private static Set<IWorldGenerator> worldGenerators = Sets.newHashSet(); 055 private static List<IFuelHandler> fuelHandlers = Lists.newArrayList(); 056 private static List<ICraftingHandler> craftingHandlers = Lists.newArrayList(); 057 private static List<IPickupNotifier> pickupHandlers = Lists.newArrayList(); 058 private static List<IPlayerTracker> playerTrackers = Lists.newArrayList(); 059 060 /** 061 * Register a world generator - something that inserts new block types into the world 062 * 063 * @param generator 064 */ 065 public static void registerWorldGenerator(IWorldGenerator generator) 066 { 067 worldGenerators.add(generator); 068 } 069 070 /** 071 * Callback hook for world gen - if your mod wishes to add extra mod related generation to the world 072 * call this 073 * 074 * @param chunkX 075 * @param chunkZ 076 * @param world 077 * @param chunkGenerator 078 * @param chunkProvider 079 */ 080 public static void generateWorld(int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) 081 { 082 long worldSeed = world.getSeed(); 083 Random fmlRandom = new Random(worldSeed); 084 long xSeed = fmlRandom.nextLong() >> 2 + 1L; 085 long zSeed = fmlRandom.nextLong() >> 2 + 1L; 086 fmlRandom.setSeed((xSeed * chunkX + zSeed * chunkZ) ^ worldSeed); 087 088 for (IWorldGenerator generator : worldGenerators) 089 { 090 generator.generate(fmlRandom, chunkX, chunkZ, world, chunkGenerator, chunkProvider); 091 } 092 } 093 094 /** 095 * Deprecated without replacement. Use vanilla DispenserRegistry code 096 * 097 * @param handler 098 */ 099 @Deprecated 100 public static void registerDispenserHandler(IDispenserHandler handler) 101 { 102 } 103 /** 104 * Deprecated without replacement. Use vanilla DispenserRegistry code 105 * 106 * @param handler 107 */ 108 @Deprecated 109 public static void registerDispenserHandler(final IDispenseHandler handler) 110 { 111 } 112 113 114 /** 115 * 116 * Deprecated without replacement, use vanilla DispenserRegistry code 117 * 118 * @param world 119 * @param x 120 * @param y 121 * @param z 122 * @param xVelocity 123 * @param zVelocity 124 * @param item 125 */ 126 @Deprecated 127 public static int tryDispense(World world, int x, int y, int z, int xVelocity, int zVelocity, ItemStack item, Random random, double entX, double entY, double entZ) 128 { 129 return -1; 130 } 131 /** 132 * Internal method for creating an @Block instance 133 * @param container 134 * @param type 135 * @param annotation 136 * @throws Exception 137 */ 138 public static Object buildBlock(ModContainer container, Class<?> type, Block annotation) throws Exception 139 { 140 Object o = type.getConstructor(int.class).newInstance(findSpareBlockId()); 141 registerBlock((net.minecraft.block.Block) o); 142 return o; 143 } 144 145 /** 146 * Private and not yet working properly 147 * 148 * @return 149 */ 150 private static int findSpareBlockId() 151 { 152 return BlockTracker.nextBlockId(); 153 } 154 155 /** 156 * Register a block with the world 157 * 158 */ 159 public static void registerBlock(net.minecraft.block.Block block) 160 { 161 registerBlock(block, ItemBlock.class); 162 } 163 164 /** 165 * Register a block with the world, with the specified item class 166 * 167 * @param block 168 * @param itemclass 169 */ 170 public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass) 171 { 172 if (Loader.instance().isInState(LoaderState.CONSTRUCTING)) 173 { 174 FMLLog.warning("The mod %s is attempting to register a block whilst it it being constructed. This is bad modding practice - please use a proper mod lifecycle event.", Loader.instance().activeModContainer()); 175 } 176 try 177 { 178 assert block != null : "registerBlock: block cannot be null"; 179 assert itemclass != null : "registerBlock: itemclass cannot be null"; 180 int blockItemId = block.blockID - 256; 181 itemclass.getConstructor(int.class).newInstance(blockItemId); 182 } 183 catch (Exception e) 184 { 185 FMLLog.log(Level.SEVERE, e, "Caught an exception during block registration"); 186 throw new LoaderException(e); 187 } 188 blockRegistry.put(Loader.instance().activeModContainer(), (BlockProxy) block); 189 } 190 191 public static void addRecipe(ItemStack output, Object... params) 192 { 193 CraftingManager.getInstance().addRecipe(output, params); 194 } 195 196 public static void addShapelessRecipe(ItemStack output, Object... params) 197 { 198 CraftingManager.getInstance().addShapelessRecipe(output, params); 199 } 200 201 public static void addRecipe(IRecipe recipe) 202 { 203 CraftingManager.getInstance().getRecipeList().add(recipe); 204 } 205 206 public static void addSmelting(int input, ItemStack output, float xp) 207 { 208 FurnaceRecipes.smelting().addSmelting(input, output, xp); 209 } 210 211 public static void registerTileEntity(Class<? extends TileEntity> tileEntityClass, String id) 212 { 213 TileEntity.addMapping(tileEntityClass, id); 214 } 215 216 public static void addBiome(BiomeGenBase biome) 217 { 218 WorldType.DEFAULT.addNewBiome(biome); 219 } 220 221 public static void removeBiome(BiomeGenBase biome) 222 { 223 WorldType.DEFAULT.removeBiome(biome); 224 } 225 226 public static void registerFuelHandler(IFuelHandler handler) 227 { 228 fuelHandlers.add(handler); 229 } 230 public static int getFuelValue(ItemStack itemStack) 231 { 232 int fuelValue = 0; 233 for (IFuelHandler handler : fuelHandlers) 234 { 235 fuelValue = Math.max(fuelValue, handler.getBurnTime(itemStack)); 236 } 237 return fuelValue; 238 } 239 240 public static void registerCraftingHandler(ICraftingHandler handler) 241 { 242 craftingHandlers.add(handler); 243 } 244 245 public static void onItemCrafted(EntityPlayer player, ItemStack item, IInventory craftMatrix) 246 { 247 for (ICraftingHandler handler : craftingHandlers) 248 { 249 handler.onCrafting(player, item, craftMatrix); 250 } 251 } 252 253 public static void onItemSmelted(EntityPlayer player, ItemStack item) 254 { 255 for (ICraftingHandler handler : craftingHandlers) 256 { 257 handler.onSmelting(player, item); 258 } 259 } 260 261 public static void registerPickupHandler(IPickupNotifier handler) 262 { 263 pickupHandlers.add(handler); 264 } 265 266 public static void onPickupNotification(EntityPlayer player, EntityItem item) 267 { 268 for (IPickupNotifier notify : pickupHandlers) 269 { 270 notify.notifyPickup(item, player); 271 } 272 } 273 274 public static void registerPlayerTracker(IPlayerTracker tracker) 275 { 276 playerTrackers.add(tracker); 277 } 278 279 public static void onPlayerLogin(EntityPlayer player) 280 { 281 for(IPlayerTracker tracker : playerTrackers) 282 tracker.onPlayerLogin(player); 283 } 284 285 public static void onPlayerLogout(EntityPlayer player) 286 { 287 for(IPlayerTracker tracker : playerTrackers) 288 tracker.onPlayerLogout(player); 289 } 290 291 public static void onPlayerChangedDimension(EntityPlayer player) 292 { 293 for(IPlayerTracker tracker : playerTrackers) 294 tracker.onPlayerChangedDimension(player); 295 } 296 297 public static void onPlayerRespawn(EntityPlayer player) 298 { 299 for(IPlayerTracker tracker : playerTrackers) 300 tracker.onPlayerRespawn(player); 301 } 302 303 }