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 an item with the item registry with a custom name : this allows for easier server->client resolution 157 * 158 * @param item The item to register 159 * @param name The mod-unique name of the item 160 */ 161 public static void registerItem(net.minecraft.item.Item item, String name) 162 { 163 registerItem(item, name, null); 164 } 165 166 /** 167 * Register the specified Item with a mod specific name : overrides the standard type based name 168 * @param item The item to register 169 * @param name The mod-unique name to register it as - null will remove a custom name 170 * @param modId An optional modId that will "own" this block - generally used by multi-mod systems 171 * where one mod should "own" all the blocks of all the mods, null defaults to the active mod 172 */ 173 public static void registerItem(net.minecraft.item.Item item, String name, String modId) 174 { 175 GameData.setName(item, name, modId); 176 } 177 178 /** 179 * Register a block with the world 180 * 181 */ 182 @Deprecated 183 public static void registerBlock(net.minecraft.block.Block block) 184 { 185 registerBlock(block, ItemBlock.class); 186 } 187 188 189 /** 190 * Register a block with the specified mod specific name : overrides the standard type based name 191 * @param block The block to register 192 * @param name The mod-unique name to register it as 193 */ 194 public static void registerBlock(net.minecraft.block.Block block, String name) 195 { 196 registerBlock(block, ItemBlock.class, name); 197 } 198 199 /** 200 * Register a block with the world, with the specified item class 201 * 202 * Deprecated in favour of named versions 203 * 204 * @param block The block to register 205 * @param itemclass The item type to register with it 206 */ 207 @Deprecated 208 public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass) 209 { 210 registerBlock(block, itemclass, null); 211 } 212 /** 213 * Register a block with the world, with the specified item class and block name 214 * @param block The block to register 215 * @param itemclass The item type to register with it 216 * @param name The mod-unique name to register it with 217 */ 218 public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass, String name) 219 { 220 registerBlock(block, itemclass, name, null); 221 } 222 /** 223 * Register a block with the world, with the specified item class, block name and owning modId 224 * @param block The block to register 225 * @param itemclass The iterm type to register with it 226 * @param name The mod-unique name to register it with 227 * @param modId The modId that will own the block name. null defaults to the active modId 228 */ 229 public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass, String name, String modId) 230 { 231 if (Loader.instance().isInState(LoaderState.CONSTRUCTING)) 232 { 233 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()); 234 } 235 try 236 { 237 assert block != null : "registerBlock: block cannot be null"; 238 assert itemclass != null : "registerBlock: itemclass cannot be null"; 239 int blockItemId = block.blockID - 256; 240 Item i = itemclass.getConstructor(int.class).newInstance(blockItemId); 241 GameRegistry.registerItem(i,name, modId); 242 } 243 catch (Exception e) 244 { 245 FMLLog.log(Level.SEVERE, e, "Caught an exception during block registration"); 246 throw new LoaderException(e); 247 } 248 blockRegistry.put(Loader.instance().activeModContainer(), (BlockProxy) block); 249 } 250 251 public static void addRecipe(ItemStack output, Object... params) 252 { 253 CraftingManager.getInstance().func_92051_a(output, params); 254 } 255 256 public static void addShapelessRecipe(ItemStack output, Object... params) 257 { 258 CraftingManager.getInstance().addShapelessRecipe(output, params); 259 } 260 261 public static void addRecipe(IRecipe recipe) 262 { 263 CraftingManager.getInstance().getRecipeList().add(recipe); 264 } 265 266 public static void addSmelting(int input, ItemStack output, float xp) 267 { 268 FurnaceRecipes.smelting().addSmelting(input, output, xp); 269 } 270 271 public static void registerTileEntity(Class<? extends TileEntity> tileEntityClass, String id) 272 { 273 TileEntity.addMapping(tileEntityClass, id); 274 } 275 276 public static void addBiome(BiomeGenBase biome) 277 { 278 WorldType.DEFAULT.addNewBiome(biome); 279 } 280 281 public static void removeBiome(BiomeGenBase biome) 282 { 283 WorldType.DEFAULT.removeBiome(biome); 284 } 285 286 public static void registerFuelHandler(IFuelHandler handler) 287 { 288 fuelHandlers.add(handler); 289 } 290 public static int getFuelValue(ItemStack itemStack) 291 { 292 int fuelValue = 0; 293 for (IFuelHandler handler : fuelHandlers) 294 { 295 fuelValue = Math.max(fuelValue, handler.getBurnTime(itemStack)); 296 } 297 return fuelValue; 298 } 299 300 public static void registerCraftingHandler(ICraftingHandler handler) 301 { 302 craftingHandlers.add(handler); 303 } 304 305 public static void onItemCrafted(EntityPlayer player, ItemStack item, IInventory craftMatrix) 306 { 307 for (ICraftingHandler handler : craftingHandlers) 308 { 309 handler.onCrafting(player, item, craftMatrix); 310 } 311 } 312 313 public static void onItemSmelted(EntityPlayer player, ItemStack item) 314 { 315 for (ICraftingHandler handler : craftingHandlers) 316 { 317 handler.onSmelting(player, item); 318 } 319 } 320 321 public static void registerPickupHandler(IPickupNotifier handler) 322 { 323 pickupHandlers.add(handler); 324 } 325 326 public static void onPickupNotification(EntityPlayer player, EntityItem item) 327 { 328 for (IPickupNotifier notify : pickupHandlers) 329 { 330 notify.notifyPickup(item, player); 331 } 332 } 333 334 public static void registerPlayerTracker(IPlayerTracker tracker) 335 { 336 playerTrackers.add(tracker); 337 } 338 339 public static void onPlayerLogin(EntityPlayer player) 340 { 341 for(IPlayerTracker tracker : playerTrackers) 342 tracker.onPlayerLogin(player); 343 } 344 345 public static void onPlayerLogout(EntityPlayer player) 346 { 347 for(IPlayerTracker tracker : playerTrackers) 348 tracker.onPlayerLogout(player); 349 } 350 351 public static void onPlayerChangedDimension(EntityPlayer player) 352 { 353 for(IPlayerTracker tracker : playerTrackers) 354 tracker.onPlayerChangedDimension(player); 355 } 356 357 public static void onPlayerRespawn(EntityPlayer player) 358 { 359 for(IPlayerTracker tracker : playerTrackers) 360 tracker.onPlayerRespawn(player); 361 } 362 363 }