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 }