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    }