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.server.MinecraftServer; 011 import net.minecraft.src.BiomeGenBase; 012 import net.minecraft.src.CraftingManager; 013 import net.minecraft.src.EntityItem; 014 import net.minecraft.src.EntityPlayer; 015 import net.minecraft.src.FurnaceRecipes; 016 import net.minecraft.src.IChunkProvider; 017 import net.minecraft.src.IInventory; 018 import net.minecraft.src.IRecipe; 019 import net.minecraft.src.Item; 020 import net.minecraft.src.ItemBlock; 021 import net.minecraft.src.ItemStack; 022 import net.minecraft.src.NBTTagCompound; 023 import net.minecraft.src.NBTTagList; 024 import net.minecraft.src.TileEntity; 025 import net.minecraft.src.World; 026 import net.minecraft.src.WorldType; 027 028 import com.google.common.base.Function; 029 import com.google.common.collect.ArrayListMultimap; 030 import com.google.common.collect.Lists; 031 import com.google.common.collect.MapDifference; 032 import com.google.common.collect.Maps; 033 import com.google.common.collect.Multimap; 034 import com.google.common.collect.Multimaps; 035 import com.google.common.collect.Sets; 036 import com.google.common.collect.Sets.SetView; 037 038 import cpw.mods.fml.common.FMLLog; 039 import cpw.mods.fml.common.ICraftingHandler; 040 import cpw.mods.fml.common.IDispenseHandler; 041 import cpw.mods.fml.common.IDispenserHandler; 042 import cpw.mods.fml.common.IFuelHandler; 043 import cpw.mods.fml.common.IPickupNotifier; 044 import cpw.mods.fml.common.IPlayerTracker; 045 import cpw.mods.fml.common.IWorldGenerator; 046 import cpw.mods.fml.common.Loader; 047 import cpw.mods.fml.common.LoaderException; 048 import cpw.mods.fml.common.LoaderState; 049 import cpw.mods.fml.common.Mod.Block; 050 import cpw.mods.fml.common.ModContainer; 051 052 public 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.src.Block) o); 143 return o; 144 } 145 146 /** 147 * Private and not yet working properly 148 * 149 * @return 150 */ 151 private static int findSpareBlockId() 152 { 153 return BlockTracker.nextBlockId(); 154 } 155 156 /** 157 * Register a block with the world 158 * 159 */ 160 public static void registerBlock(net.minecraft.src.Block block) 161 { 162 registerBlock(block, ItemBlock.class); 163 } 164 165 /** 166 * Register a block with the world, with the specified item class 167 * 168 * @param block 169 * @param itemclass 170 */ 171 public static void registerBlock(net.minecraft.src.Block block, Class<? extends ItemBlock> itemclass) 172 { 173 if (Loader.instance().isInState(LoaderState.CONSTRUCTING)) 174 { 175 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()); 176 } 177 try 178 { 179 assert block != null : "registerBlock: block cannot be null"; 180 assert itemclass != null : "registerBlock: itemclass cannot be null"; 181 int blockItemId = block.blockID - 256; 182 itemclass.getConstructor(int.class).newInstance(blockItemId); 183 } 184 catch (Exception e) 185 { 186 FMLLog.log(Level.SEVERE, e, "Caught an exception during block registration"); 187 throw new LoaderException(e); 188 } 189 blockRegistry.put(Loader.instance().activeModContainer(), (BlockProxy) block); 190 } 191 192 public static void addRecipe(ItemStack output, Object... params) 193 { 194 CraftingManager.getInstance().addRecipe(output, params); 195 } 196 197 public static void addShapelessRecipe(ItemStack output, Object... params) 198 { 199 CraftingManager.getInstance().addShapelessRecipe(output, params); 200 } 201 202 public static void addRecipe(IRecipe recipe) 203 { 204 CraftingManager.getInstance().getRecipeList().add(recipe); 205 } 206 207 public static void addSmelting(int input, ItemStack output, float xp) 208 { 209 FurnaceRecipes.smelting().addSmelting(input, output, xp); 210 } 211 212 public static void registerTileEntity(Class<? extends TileEntity> tileEntityClass, String id) 213 { 214 TileEntity.addMapping(tileEntityClass, id); 215 } 216 217 public static void addBiome(BiomeGenBase biome) 218 { 219 WorldType.DEFAULT.addNewBiome(biome); 220 } 221 222 public static void removeBiome(BiomeGenBase biome) 223 { 224 WorldType.DEFAULT.removeBiome(biome); 225 } 226 227 public static void registerFuelHandler(IFuelHandler handler) 228 { 229 fuelHandlers.add(handler); 230 } 231 public static int getFuelValue(ItemStack itemStack) 232 { 233 int fuelValue = 0; 234 for (IFuelHandler handler : fuelHandlers) 235 { 236 fuelValue = Math.max(fuelValue, handler.getBurnTime(itemStack)); 237 } 238 return fuelValue; 239 } 240 241 public static void registerCraftingHandler(ICraftingHandler handler) 242 { 243 craftingHandlers.add(handler); 244 } 245 246 public static void onItemCrafted(EntityPlayer player, ItemStack item, IInventory craftMatrix) 247 { 248 for (ICraftingHandler handler : craftingHandlers) 249 { 250 handler.onCrafting(player, item, craftMatrix); 251 } 252 } 253 254 public static void onItemSmelted(EntityPlayer player, ItemStack item) 255 { 256 for (ICraftingHandler handler : craftingHandlers) 257 { 258 handler.onSmelting(player, item); 259 } 260 } 261 262 public static void registerPickupHandler(IPickupNotifier handler) 263 { 264 pickupHandlers.add(handler); 265 } 266 267 public static void onPickupNotification(EntityPlayer player, EntityItem item) 268 { 269 for (IPickupNotifier notify : pickupHandlers) 270 { 271 notify.notifyPickup(item, player); 272 } 273 } 274 275 public static void registerPlayerTracker(IPlayerTracker tracker) 276 { 277 playerTrackers.add(tracker); 278 } 279 280 public static void onPlayerLogin(EntityPlayer player) 281 { 282 for(IPlayerTracker tracker : playerTrackers) 283 tracker.onPlayerLogin(player); 284 } 285 286 public static void onPlayerLogout(EntityPlayer player) 287 { 288 for(IPlayerTracker tracker : playerTrackers) 289 tracker.onPlayerLogout(player); 290 } 291 292 public static void onPlayerChangedDimension(EntityPlayer player) 293 { 294 for(IPlayerTracker tracker : playerTrackers) 295 tracker.onPlayerChangedDimension(player); 296 } 297 298 public static void onPlayerRespawn(EntityPlayer player) 299 { 300 for(IPlayerTracker tracker : playerTrackers) 301 tracker.onPlayerRespawn(player); 302 } 303 304 }