001package cpw.mods.fml.common.registry; 002 003import java.util.List; 004import java.util.Map; 005import java.util.Random; 006import java.util.Set; 007import java.util.concurrent.CountDownLatch; 008import java.util.logging.Level; 009 010import net.minecraft.entity.item.EntityItem; 011import net.minecraft.entity.player.EntityPlayer; 012import net.minecraft.inventory.IInventory; 013import net.minecraft.item.Item; 014import net.minecraft.item.ItemBlock; 015import net.minecraft.item.ItemStack; 016import net.minecraft.item.crafting.CraftingManager; 017import net.minecraft.item.crafting.FurnaceRecipes; 018import net.minecraft.item.crafting.IRecipe; 019import net.minecraft.nbt.NBTTagCompound; 020import net.minecraft.nbt.NBTTagList; 021import net.minecraft.tileentity.TileEntity; 022import net.minecraft.world.World; 023import net.minecraft.world.WorldType; 024import net.minecraft.world.biome.BiomeGenBase; 025import net.minecraft.world.chunk.IChunkProvider; 026 027import com.google.common.base.Function; 028import com.google.common.collect.ArrayListMultimap; 029import com.google.common.collect.Lists; 030import com.google.common.collect.MapDifference; 031import com.google.common.collect.Maps; 032import com.google.common.collect.Multimap; 033import com.google.common.collect.Multimaps; 034import com.google.common.collect.Sets; 035import com.google.common.collect.Sets.SetView; 036 037import cpw.mods.fml.common.FMLLog; 038import cpw.mods.fml.common.ICraftingHandler; 039import cpw.mods.fml.common.IDispenseHandler; 040import cpw.mods.fml.common.IDispenserHandler; 041import cpw.mods.fml.common.IFuelHandler; 042import cpw.mods.fml.common.IPickupNotifier; 043import cpw.mods.fml.common.IPlayerTracker; 044import cpw.mods.fml.common.IWorldGenerator; 045import cpw.mods.fml.common.Loader; 046import cpw.mods.fml.common.LoaderException; 047import cpw.mods.fml.common.LoaderState; 048import cpw.mods.fml.common.ObfuscationReflectionHelper; 049import cpw.mods.fml.common.Mod.Block; 050import cpw.mods.fml.common.ModContainer; 051 052public class GameRegistry 053{ 054 private static Multimap<ModContainer, BlockProxy> blockRegistry = ArrayListMultimap.create(); 055 private static Set<IWorldGenerator> worldGenerators = Sets.newHashSet(); 056 private static List<IFuelHandler> fuelHandlers = Lists.newArrayList(); 057 private static List<ICraftingHandler> craftingHandlers = Lists.newArrayList(); 058 private static List<IPickupNotifier> pickupHandlers = Lists.newArrayList(); 059 private static List<IPlayerTracker> playerTrackers = Lists.newArrayList(); 060 061 /** 062 * Register a world generator - something that inserts new block types into the world 063 * 064 * @param generator 065 */ 066 public static void registerWorldGenerator(IWorldGenerator generator) 067 { 068 worldGenerators.add(generator); 069 } 070 071 /** 072 * Callback hook for world gen - if your mod wishes to add extra mod related generation to the world 073 * call this 074 * 075 * @param chunkX 076 * @param chunkZ 077 * @param world 078 * @param chunkGenerator 079 * @param chunkProvider 080 */ 081 public static void generateWorld(int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) 082 { 083 long worldSeed = world.getSeed(); 084 Random fmlRandom = new Random(worldSeed); 085 long xSeed = fmlRandom.nextLong() >> 2 + 1L; 086 long zSeed = fmlRandom.nextLong() >> 2 + 1L; 087 fmlRandom.setSeed((xSeed * chunkX + zSeed * chunkZ) ^ worldSeed); 088 089 for (IWorldGenerator generator : worldGenerators) 090 { 091 generator.generate(fmlRandom, chunkX, chunkZ, world, chunkGenerator, chunkProvider); 092 } 093 } 094 095 /** 096 * Deprecated without replacement. Use vanilla DispenserRegistry code 097 * 098 * @param handler 099 */ 100 @Deprecated 101 public static void registerDispenserHandler(IDispenserHandler handler) 102 { 103 } 104 /** 105 * Deprecated without replacement. Use vanilla DispenserRegistry code 106 * 107 * @param handler 108 */ 109 @Deprecated 110 public static void registerDispenserHandler(final IDispenseHandler handler) 111 { 112 } 113 114 115 /** 116 * 117 * Deprecated without replacement, use vanilla DispenserRegistry code 118 * 119 * @param world 120 * @param x 121 * @param y 122 * @param z 123 * @param xVelocity 124 * @param zVelocity 125 * @param item 126 */ 127 @Deprecated 128 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) 129 { 130 return -1; 131 } 132 /** 133 * Internal method for creating an @Block instance 134 * @param container 135 * @param type 136 * @param annotation 137 * @throws Exception 138 */ 139 public static Object buildBlock(ModContainer container, Class<?> type, Block annotation) throws Exception 140 { 141 Object o = type.getConstructor(int.class).newInstance(findSpareBlockId()); 142 registerBlock((net.minecraft.block.Block) o); 143 return o; 144 } 145 146 /** 147 * Private and not yet working properly 148 * 149 * @return a block id 150 */ 151 private static int findSpareBlockId() 152 { 153 return BlockTracker.nextBlockId(); 154 } 155 156 /** 157 * Register an item with the item registry with a custom name : this allows for easier server->client resolution 158 * 159 * @param item The item to register 160 * @param name The mod-unique name of the item 161 */ 162 public static void registerItem(net.minecraft.item.Item item, String name) 163 { 164 registerItem(item, name, null); 165 } 166 167 /** 168 * Register the specified Item with a mod specific name : overrides the standard type based name 169 * @param item The item to register 170 * @param name The mod-unique name to register it as - null will remove a custom name 171 * @param modId An optional modId that will "own" this block - generally used by multi-mod systems 172 * where one mod should "own" all the blocks of all the mods, null defaults to the active mod 173 */ 174 public static void registerItem(net.minecraft.item.Item item, String name, String modId) 175 { 176 GameData.setName(item, name, modId); 177 } 178 179 /** 180 * Register a block with the world 181 * 182 */ 183 @Deprecated 184 public static void registerBlock(net.minecraft.block.Block block) 185 { 186 registerBlock(block, ItemBlock.class); 187 } 188 189 190 /** 191 * Register a block with the specified mod specific name : overrides the standard type based name 192 * @param block The block to register 193 * @param name The mod-unique name to register it as 194 */ 195 public static void registerBlock(net.minecraft.block.Block block, String name) 196 { 197 registerBlock(block, ItemBlock.class, name); 198 } 199 200 /** 201 * Register a block with the world, with the specified item class 202 * 203 * Deprecated in favour of named versions 204 * 205 * @param block The block to register 206 * @param itemclass The item type to register with it 207 */ 208 @Deprecated 209 public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass) 210 { 211 registerBlock(block, itemclass, null); 212 } 213 /** 214 * Register a block with the world, with the specified item class and block name 215 * @param block The block to register 216 * @param itemclass The item type to register with it 217 * @param name The mod-unique name to register it with 218 */ 219 public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass, String name) 220 { 221 registerBlock(block, itemclass, name, null); 222 } 223 /** 224 * Register a block with the world, with the specified item class, block name and owning modId 225 * @param block The block to register 226 * @param itemclass The iterm type to register with it 227 * @param name The mod-unique name to register it with 228 * @param modId The modId that will own the block name. null defaults to the active modId 229 */ 230 public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass, String name, String modId) 231 { 232 if (Loader.instance().isInState(LoaderState.CONSTRUCTING)) 233 { 234 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()); 235 } 236 try 237 { 238 assert block != null : "registerBlock: block cannot be null"; 239 assert itemclass != null : "registerBlock: itemclass cannot be null"; 240 int blockItemId = block.blockID - 256; 241 Item i = itemclass.getConstructor(int.class).newInstance(blockItemId); 242 GameRegistry.registerItem(i,name, modId); 243 } 244 catch (Exception e) 245 { 246 FMLLog.log(Level.SEVERE, e, "Caught an exception during block registration"); 247 throw new LoaderException(e); 248 } 249 blockRegistry.put(Loader.instance().activeModContainer(), (BlockProxy) block); 250 } 251 252 public static void addRecipe(ItemStack output, Object... params) 253 { 254 addShapedRecipe(output, params); 255 } 256 257 public static IRecipe addShapedRecipe(ItemStack output, Object... params) 258 { 259 return CraftingManager.getInstance().addRecipe(output, params); 260 } 261 262 public static void addShapelessRecipe(ItemStack output, Object... params) 263 { 264 CraftingManager.getInstance().addShapelessRecipe(output, params); 265 } 266 267 public static void addRecipe(IRecipe recipe) 268 { 269 CraftingManager.getInstance().getRecipeList().add(recipe); 270 } 271 272 public static void addSmelting(int input, ItemStack output, float xp) 273 { 274 FurnaceRecipes.smelting().addSmelting(input, output, xp); 275 } 276 277 public static void registerTileEntity(Class<? extends TileEntity> tileEntityClass, String id) 278 { 279 TileEntity.addMapping(tileEntityClass, id); 280 } 281 282 /** 283 * Register a tile entity, with alternative TileEntity identifiers. Use with caution! 284 * This method allows for you to "rename" the 'id' of the tile entity. 285 * 286 * @param tileEntityClass The tileEntity class to register 287 * @param id The primary ID, this will be the ID that the tileentity saves as 288 * @param alternatives A list of alternative IDs that will also map to this class. These will never save, but they will load 289 */ 290 public static void registerTileEntityWithAlternatives(Class<? extends TileEntity> tileEntityClass, String id, String... alternatives) 291 { 292 TileEntity.addMapping(tileEntityClass, id); 293 Map<String,Class> teMappings = ObfuscationReflectionHelper.getPrivateValue(TileEntity.class, null, "nameToClassMap", "a"); 294 for (String s: alternatives) 295 { 296 if (!teMappings.containsKey(s)) 297 { 298 teMappings.put(s, tileEntityClass); 299 } 300 } 301 } 302 303 public static void addBiome(BiomeGenBase biome) 304 { 305 WorldType.DEFAULT.addNewBiome(biome); 306 } 307 308 public static void removeBiome(BiomeGenBase biome) 309 { 310 WorldType.DEFAULT.removeBiome(biome); 311 } 312 313 public static void registerFuelHandler(IFuelHandler handler) 314 { 315 fuelHandlers.add(handler); 316 } 317 public static int getFuelValue(ItemStack itemStack) 318 { 319 int fuelValue = 0; 320 for (IFuelHandler handler : fuelHandlers) 321 { 322 fuelValue = Math.max(fuelValue, handler.getBurnTime(itemStack)); 323 } 324 return fuelValue; 325 } 326 327 public static void registerCraftingHandler(ICraftingHandler handler) 328 { 329 craftingHandlers.add(handler); 330 } 331 332 public static void onItemCrafted(EntityPlayer player, ItemStack item, IInventory craftMatrix) 333 { 334 for (ICraftingHandler handler : craftingHandlers) 335 { 336 handler.onCrafting(player, item, craftMatrix); 337 } 338 } 339 340 public static void onItemSmelted(EntityPlayer player, ItemStack item) 341 { 342 for (ICraftingHandler handler : craftingHandlers) 343 { 344 handler.onSmelting(player, item); 345 } 346 } 347 348 public static void registerPickupHandler(IPickupNotifier handler) 349 { 350 pickupHandlers.add(handler); 351 } 352 353 public static void onPickupNotification(EntityPlayer player, EntityItem item) 354 { 355 for (IPickupNotifier notify : pickupHandlers) 356 { 357 notify.notifyPickup(item, player); 358 } 359 } 360 361 public static void registerPlayerTracker(IPlayerTracker tracker) 362 { 363 playerTrackers.add(tracker); 364 } 365 366 public static void onPlayerLogin(EntityPlayer player) 367 { 368 for(IPlayerTracker tracker : playerTrackers) 369 tracker.onPlayerLogin(player); 370 } 371 372 public static void onPlayerLogout(EntityPlayer player) 373 { 374 for(IPlayerTracker tracker : playerTrackers) 375 tracker.onPlayerLogout(player); 376 } 377 378 public static void onPlayerChangedDimension(EntityPlayer player) 379 { 380 for(IPlayerTracker tracker : playerTrackers) 381 tracker.onPlayerChangedDimension(player); 382 } 383 384 public static void onPlayerRespawn(EntityPlayer player) 385 { 386 for(IPlayerTracker tracker : playerTrackers) 387 tracker.onPlayerRespawn(player); 388 } 389 390}