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