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