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 a block with the world
157         *
158         */
159        public static void registerBlock(net.minecraft.block.Block block)
160        {
161            registerBlock(block, ItemBlock.class);
162        }
163    
164        /**
165         * Register a block with the world, with the specified item class
166         *
167         * @param block
168         * @param itemclass
169         */
170        public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass)
171        {
172            if (Loader.instance().isInState(LoaderState.CONSTRUCTING))
173            {
174                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());
175            }
176            try
177            {
178                assert block != null : "registerBlock: block cannot be null";
179                assert itemclass != null : "registerBlock: itemclass cannot be null";
180                int blockItemId = block.blockID - 256;
181                itemclass.getConstructor(int.class).newInstance(blockItemId);
182            }
183            catch (Exception e)
184            {
185                FMLLog.log(Level.SEVERE, e, "Caught an exception during block registration");
186                throw new LoaderException(e);
187            }
188            blockRegistry.put(Loader.instance().activeModContainer(), (BlockProxy) block);
189        }
190    
191        public static void addRecipe(ItemStack output, Object... params)
192        {
193            CraftingManager.getInstance().addRecipe(output, params);
194        }
195    
196        public static void addShapelessRecipe(ItemStack output, Object... params)
197        {
198            CraftingManager.getInstance().addShapelessRecipe(output, params);
199        }
200    
201        public static void addRecipe(IRecipe recipe)
202        {
203            CraftingManager.getInstance().getRecipeList().add(recipe);
204        }
205    
206        public static void addSmelting(int input, ItemStack output, float xp)
207        {
208            FurnaceRecipes.smelting().addSmelting(input, output, xp);
209        }
210    
211        public static void registerTileEntity(Class<? extends TileEntity> tileEntityClass, String id)
212        {
213            TileEntity.addMapping(tileEntityClass, id);
214        }
215    
216        public static void addBiome(BiomeGenBase biome)
217        {
218            WorldType.DEFAULT.addNewBiome(biome);
219        }
220    
221        public static void removeBiome(BiomeGenBase biome)
222        {
223            WorldType.DEFAULT.removeBiome(biome);
224        }
225    
226        public static void registerFuelHandler(IFuelHandler handler)
227        {
228            fuelHandlers.add(handler);
229        }
230        public static int getFuelValue(ItemStack itemStack)
231        {
232            int fuelValue = 0;
233            for (IFuelHandler handler : fuelHandlers)
234            {
235                fuelValue = Math.max(fuelValue, handler.getBurnTime(itemStack));
236            }
237            return fuelValue;
238        }
239    
240        public static void registerCraftingHandler(ICraftingHandler handler)
241        {
242            craftingHandlers.add(handler);
243        }
244    
245        public static void onItemCrafted(EntityPlayer player, ItemStack item, IInventory craftMatrix)
246        {
247            for (ICraftingHandler handler : craftingHandlers)
248            {
249                handler.onCrafting(player, item, craftMatrix);
250            }
251        }
252    
253        public static void onItemSmelted(EntityPlayer player, ItemStack item)
254        {
255            for (ICraftingHandler handler : craftingHandlers)
256            {
257                handler.onSmelting(player, item);
258            }
259        }
260    
261        public static void registerPickupHandler(IPickupNotifier handler)
262        {
263            pickupHandlers.add(handler);
264        }
265    
266        public static void onPickupNotification(EntityPlayer player, EntityItem item)
267        {
268            for (IPickupNotifier notify : pickupHandlers)
269            {
270                notify.notifyPickup(item, player);
271            }
272        }
273    
274        public static void registerPlayerTracker(IPlayerTracker tracker)
275        {
276            playerTrackers.add(tracker);
277        }
278    
279        public static void onPlayerLogin(EntityPlayer player)
280        {
281            for(IPlayerTracker tracker : playerTrackers)
282                tracker.onPlayerLogin(player);
283        }
284    
285        public static void onPlayerLogout(EntityPlayer player)
286        {
287            for(IPlayerTracker tracker : playerTrackers)
288                tracker.onPlayerLogout(player);
289        }
290    
291        public static void onPlayerChangedDimension(EntityPlayer player)
292        {
293            for(IPlayerTracker tracker : playerTrackers)
294                tracker.onPlayerChangedDimension(player);
295        }
296    
297        public static void onPlayerRespawn(EntityPlayer player)
298        {
299            for(IPlayerTracker tracker : playerTrackers)
300                tracker.onPlayerRespawn(player);
301        }
302    
303    }