001package cpw.mods.fml.common.registry;
002
003import java.util.List;
004import java.util.Map;
005import java.util.Random;
006import java.util.Set;
007import java.util.concurrent.CountDownLatch;
008import java.util.logging.Level;
009
010import net.minecraft.entity.item.EntityItem;
011import net.minecraft.entity.player.EntityPlayer;
012import net.minecraft.inventory.IInventory;
013import net.minecraft.item.Item;
014import net.minecraft.item.ItemBlock;
015import net.minecraft.item.ItemStack;
016import net.minecraft.item.crafting.CraftingManager;
017import net.minecraft.item.crafting.FurnaceRecipes;
018import net.minecraft.item.crafting.IRecipe;
019import net.minecraft.nbt.NBTTagCompound;
020import net.minecraft.nbt.NBTTagList;
021import net.minecraft.tileentity.TileEntity;
022import net.minecraft.world.World;
023import net.minecraft.world.WorldType;
024import net.minecraft.world.biome.BiomeGenBase;
025import net.minecraft.world.chunk.IChunkProvider;
026
027import com.google.common.base.Function;
028import com.google.common.collect.ArrayListMultimap;
029import com.google.common.collect.Lists;
030import com.google.common.collect.MapDifference;
031import com.google.common.collect.Maps;
032import com.google.common.collect.Multimap;
033import com.google.common.collect.Multimaps;
034import com.google.common.collect.Sets;
035import com.google.common.collect.Sets.SetView;
036
037import cpw.mods.fml.common.FMLLog;
038import cpw.mods.fml.common.ICraftingHandler;
039import cpw.mods.fml.common.IDispenseHandler;
040import cpw.mods.fml.common.IDispenserHandler;
041import cpw.mods.fml.common.IFuelHandler;
042import cpw.mods.fml.common.IPickupNotifier;
043import cpw.mods.fml.common.IPlayerTracker;
044import cpw.mods.fml.common.IWorldGenerator;
045import cpw.mods.fml.common.Loader;
046import cpw.mods.fml.common.LoaderException;
047import cpw.mods.fml.common.LoaderState;
048import cpw.mods.fml.common.Mod.Block;
049import cpw.mods.fml.common.ModContainer;
050
051public 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 IRecipe addRecipe(ItemStack output, Object... params)
252    {
253        return CraftingManager.getInstance().addRecipe(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}