001    package cpw.mods.fml.common.registry;
002    
003    import java.util.List;
004    import java.util.Random;
005    import java.util.Set;
006    import java.util.logging.Level;
007    
008    import net.minecraft.src.BiomeGenBase;
009    import net.minecraft.src.CraftingManager;
010    import net.minecraft.src.EntityItem;
011    import net.minecraft.src.EntityPlayer;
012    import net.minecraft.src.FurnaceRecipes;
013    import net.minecraft.src.IChunkProvider;
014    import net.minecraft.src.IInventory;
015    import net.minecraft.src.IRecipe;
016    import net.minecraft.src.ItemBlock;
017    import net.minecraft.src.ItemStack;
018    import net.minecraft.src.TileEntity;
019    import net.minecraft.src.World;
020    import net.minecraft.src.WorldType;
021    
022    import com.google.common.collect.ArrayListMultimap;
023    import com.google.common.collect.Lists;
024    import com.google.common.collect.Multimap;
025    import com.google.common.collect.Sets;
026    
027    import cpw.mods.fml.common.FMLLog;
028    import cpw.mods.fml.common.ICraftingHandler;
029    import cpw.mods.fml.common.IDispenseHandler;
030    import cpw.mods.fml.common.IDispenserHandler;
031    import cpw.mods.fml.common.IFuelHandler;
032    import cpw.mods.fml.common.IPickupNotifier;
033    import cpw.mods.fml.common.IPlayerTracker;
034    import cpw.mods.fml.common.IWorldGenerator;
035    import cpw.mods.fml.common.Loader;
036    import cpw.mods.fml.common.LoaderException;
037    import cpw.mods.fml.common.LoaderState;
038    import cpw.mods.fml.common.Mod.Block;
039    import cpw.mods.fml.common.ModContainer;
040    
041    public class GameRegistry
042    {
043        private static Multimap<ModContainer, BlockProxy> blockRegistry = ArrayListMultimap.create();
044        private static Multimap<ModContainer, ItemProxy> itemRegistry = ArrayListMultimap.create();
045        private static Set<IWorldGenerator> worldGenerators = Sets.newHashSet();
046        private static List<IFuelHandler> fuelHandlers = Lists.newArrayList();
047        private static List<ICraftingHandler> craftingHandlers = Lists.newArrayList();
048        private static List<IDispenserHandler> dispenserHandlers = Lists.newArrayList();
049        private static List<IPickupNotifier> pickupHandlers = Lists.newArrayList();
050        private static List<IPlayerTracker> playerTrackers = Lists.newArrayList();
051    
052        /**
053         * Register a world generator - something that inserts new block types into the world
054         *
055         * @param generator
056         */
057        public static void registerWorldGenerator(IWorldGenerator generator)
058        {
059            worldGenerators.add(generator);
060        }
061    
062        /**
063         * Callback hook for world gen - if your mod wishes to add extra mod related generation to the world
064         * call this
065         *
066         * @param chunkX
067         * @param chunkZ
068         * @param world
069         * @param chunkGenerator
070         * @param chunkProvider
071         */
072        public static void generateWorld(int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider)
073        {
074            long worldSeed = world.getSeed();
075            Random fmlRandom = new Random(worldSeed);
076            long xSeed = fmlRandom.nextLong() >> 2 + 1L;
077            long zSeed = fmlRandom.nextLong() >> 2 + 1L;
078            fmlRandom.setSeed((xSeed * chunkX + zSeed * chunkZ) ^ worldSeed);
079    
080            for (IWorldGenerator generator : worldGenerators)
081            {
082                generator.generate(fmlRandom, chunkX, chunkZ, world, chunkGenerator, chunkProvider);
083            }
084        }
085    
086        public static void registerDispenserHandler(IDispenserHandler handler)
087        {
088            dispenserHandlers.add(handler);
089        }
090        /**
091         * Register a handler for dispensers
092         *
093         * @param handler
094         */
095        @Deprecated
096        public static void registerDispenserHandler(final IDispenseHandler handler)
097        {
098            registerDispenserHandler(new IDispenserHandler()
099            {
100    
101                @Override
102                public int dispense(int x, int y, int z, int xVelocity, int zVelocity, World world, ItemStack item, Random random, double entX, double entY, double entZ)
103                {
104                    return handler.dispense(x, y, z, xVelocity, zVelocity, world, item, random, entX, entY, entZ);
105                }
106            });
107        }
108    
109    
110        /**
111         * Callback hook for dispenser activities - if you add a block and want mods to be able
112         * to extend their dispenser related activities to it call this
113         *
114         * @param world
115         * @param x
116         * @param y
117         * @param z
118         * @param xVelocity
119         * @param zVelocity
120         * @param item
121         * @return
122         */
123        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)
124        {
125            for (IDispenserHandler handler : dispenserHandlers)
126            {
127                int dispensed = handler.dispense(x, y, z, xVelocity, zVelocity, world, item, random, entX, entY, entZ);
128                if (dispensed>-1)
129                {
130                    return dispensed;
131                }
132            }
133            return -1;
134        }
135        /**
136         * Internal method for creating an @Block instance
137         * @param container
138         * @param type
139         * @param annotation
140         * @return
141         * @throws Exception
142         */
143        public static Object buildBlock(ModContainer container, Class<?> type, Block annotation) throws Exception
144        {
145            Object o = type.getConstructor(int.class).newInstance(findSpareBlockId());
146            registerBlock((net.minecraft.src.Block) o);
147            return o;
148        }
149    
150        /**
151         * Private and not yet working properly
152         *
153         * @return
154         */
155        private static int findSpareBlockId()
156        {
157            return BlockTracker.nextBlockId();
158        }
159    
160        /**
161         * Register a block with the world
162         *
163         */
164        public static void registerBlock(net.minecraft.src.Block block)
165        {
166            registerBlock(block, ItemBlock.class);
167        }
168    
169        /**
170         * Register a block with the world, with the specified item class
171         *
172         * @param block
173         * @param itemclass
174         */
175        public static void registerBlock(net.minecraft.src.Block block, Class<? extends ItemBlock> itemclass)
176        {
177            if (Loader.instance().isInState(LoaderState.CONSTRUCTING))
178            {
179                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());
180            }
181            try
182            {
183                assert block != null : "registerBlock: block cannot be null";
184                assert itemclass != null : "registerBlock: itemclass cannot be null";
185                int blockItemId = block.blockID - 256;
186                itemclass.getConstructor(int.class).newInstance(blockItemId);
187            }
188            catch (Exception e)
189            {
190                FMLLog.log(Level.SEVERE, e, "Caught an exception during block registration");
191                throw new LoaderException(e);
192            }
193            blockRegistry.put(Loader.instance().activeModContainer(), (BlockProxy) block);
194        }
195    
196        public static void addRecipe(ItemStack output, Object... params)
197        {
198            CraftingManager.getInstance().addRecipe(output, params);
199        }
200    
201        public static void addShapelessRecipe(ItemStack output, Object... params)
202        {
203            CraftingManager.getInstance().addShapelessRecipe(output, params);
204        }
205    
206        public static void addRecipe(IRecipe recipe)
207        {
208            CraftingManager.getInstance().getRecipeList().add(recipe);
209        }
210    
211        public static void addSmelting(int input, ItemStack output, float xp)
212        {
213            FurnaceRecipes.smelting().addSmelting(input, output, xp);
214        }
215    
216        public static void registerTileEntity(Class<? extends TileEntity> tileEntityClass, String id)
217        {
218            TileEntity.addMapping(tileEntityClass, id);
219        }
220    
221        public static void addBiome(BiomeGenBase biome)
222        {
223            WorldType.DEFAULT.addNewBiome(biome);
224        }
225    
226        public static void removeBiome(BiomeGenBase biome)
227        {
228            WorldType.DEFAULT.removeBiome(biome);
229        }
230    
231        public static void registerFuelHandler(IFuelHandler handler)
232        {
233            fuelHandlers.add(handler);
234        }
235        public static int getFuelValue(ItemStack itemStack)
236        {
237            int fuelValue = 0;
238            for (IFuelHandler handler : fuelHandlers)
239            {
240                fuelValue = Math.max(fuelValue, handler.getBurnTime(itemStack));
241            }
242            return fuelValue;
243        }
244    
245        public static void registerCraftingHandler(ICraftingHandler handler)
246        {
247            craftingHandlers.add(handler);
248        }
249    
250        public static void onItemCrafted(EntityPlayer player, ItemStack item, IInventory craftMatrix)
251        {
252            for (ICraftingHandler handler : craftingHandlers)
253            {
254                handler.onCrafting(player, item, craftMatrix);
255            }
256        }
257    
258        public static void onItemSmelted(EntityPlayer player, ItemStack item)
259        {
260            for (ICraftingHandler handler : craftingHandlers)
261            {
262                handler.onSmelting(player, item);
263            }
264        }
265    
266        public static void registerPickupHandler(IPickupNotifier handler)
267        {
268            pickupHandlers.add(handler);
269        }
270    
271        public static void onPickupNotification(EntityPlayer player, EntityItem item)
272        {
273            for (IPickupNotifier notify : pickupHandlers)
274            {
275                notify.notifyPickup(item, player);
276            }
277        }
278    
279        public static void registerPlayerTracker(IPlayerTracker tracker)
280        {
281            playerTrackers.add(tracker);
282        }
283    
284        public static void onPlayerLogin(EntityPlayer player)
285        {
286            for(IPlayerTracker tracker : playerTrackers)
287                tracker.onPlayerLogin(player);
288        }
289    
290        public static void onPlayerLogout(EntityPlayer player)
291        {
292            for(IPlayerTracker tracker : playerTrackers)
293                tracker.onPlayerLogout(player);
294        }
295    
296        public static void onPlayerChangedDimension(EntityPlayer player)
297        {
298            for(IPlayerTracker tracker : playerTrackers)
299                tracker.onPlayerChangedDimension(player);
300        }
301    
302        public static void onPlayerRespawn(EntityPlayer player)
303        {
304            for(IPlayerTracker tracker : playerTrackers)
305                tracker.onPlayerRespawn(player);
306        }
307    }