    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.ObfuscationReflectionHelper;
    049import cpw.mods.fml.common.Mod.Block;
    050import cpw.mods.fml.common.ModContainer;
    051
    052public 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.block.Block) o);
    143        return o;
    144    }
    145
    146    /**
    147     * Private and not yet working properly
    148     *
    149     * @return a block id
    150     */
    151    private static int findSpareBlockId()
    152    {
    153        return BlockTracker.nextBlockId();
    154    }
    155
    156    /**
    157     * Register an item with the item registry with a custom name : this allows for easier server->client resolution
    158     *
    159     * @param item The item to register
    160     * @param name The mod-unique name of the item
    161     */
    162    public static void registerItem(net.minecraft.item.Item item, String name)
    163    {
    164        registerItem(item, name, null);
    165    }
    166
    167    /**
    168     * Register the specified Item with a mod specific name : overrides the standard type based name
    169     * @param item The item to register
    170     * @param name The mod-unique name to register it as - null will remove a custom name
    171     * @param modId An optional modId that will "own" this block - generally used by multi-mod systems
    172     * where one mod should "own" all the blocks of all the mods, null defaults to the active mod
    173     */
    174    public static void registerItem(net.minecraft.item.Item item, String name, String modId)
    175    {
    176        GameData.setName(item, name, modId);
    177    }
    178
    179    /**
    180     * Register a block with the world
    181     *
    182     */
    183    @Deprecated
    184    public static void registerBlock(net.minecraft.block.Block block)
    185    {
    186        registerBlock(block, ItemBlock.class);
    187    }
    188
    189
    190    /**
    191     * Register a block with the specified mod specific name : overrides the standard type based name
    192     * @param block The block to register
    193     * @param name The mod-unique name to register it as
    194     */
    195    public static void registerBlock(net.minecraft.block.Block block, String name)
    196    {
    197        registerBlock(block, ItemBlock.class, name);
    198    }
    199
    200    /**
    201     * Register a block with the world, with the specified item class
    202     *
    203     * Deprecated in favour of named versions
    204     *
    205     * @param block The block to register
    206     * @param itemclass The item type to register with it
    207     */
    208    @Deprecated
    209    public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass)
    210    {
    211        registerBlock(block, itemclass, null);
    212    }
    213    /**
    214     * Register a block with the world, with the specified item class and block name
    215     * @param block The block to register
    216     * @param itemclass The item type to register with it
    217     * @param name The mod-unique name to register it with
    218     */
    219    public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass, String name)
    220    {
    221        registerBlock(block, itemclass, name, null);
    222    }
    223    /**
    224     * Register a block with the world, with the specified item class, block name and owning modId
    225     * @param block The block to register
    226     * @param itemclass The iterm type to register with it
    227     * @param name The mod-unique name to register it with
    228     * @param modId The modId that will own the block name. null defaults to the active modId
    229     */
    230    public static void registerBlock(net.minecraft.block.Block block, Class<? extends ItemBlock> itemclass, String name, String modId)
    231    {
    232        if (Loader.instance().isInState(LoaderState.CONSTRUCTING))
    233        {
    234            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());
    235        }
    236        try
    237        {
    238            assert block != null : "registerBlock: block cannot be null";
    239            assert itemclass != null : "registerBlock: itemclass cannot be null";
    240            int blockItemId = block.blockID - 256;
    241            Item i = itemclass.getConstructor(int.class).newInstance(blockItemId);
    242            GameRegistry.registerItem(i,name, modId);
    243        }
    244        catch (Exception e)
    245        {
    246            FMLLog.log(Level.SEVERE, e, "Caught an exception during block registration");
    247            throw new LoaderException(e);
    248        }
    249        blockRegistry.put(Loader.instance().activeModContainer(), (BlockProxy) block);
    250    }
    251
    252    public static void addRecipe(ItemStack output, Object... params)
    253    {
    254        addShapedRecipe(output, params);
    255    }
    256
    257    public static IRecipe addShapedRecipe(ItemStack output, Object... params)
    258    {
    259        return CraftingManager.getInstance().addRecipe(output, params);
    260    }
    261
    262    public static void addShapelessRecipe(ItemStack output, Object... params)
    263    {
    264        CraftingManager.getInstance().addShapelessRecipe(output, params);
    265    }
    266
    267    public static void addRecipe(IRecipe recipe)
    268    {
    269        CraftingManager.getInstance().getRecipeList().add(recipe);
    270    }
    271
    272    public static void addSmelting(int input, ItemStack output, float xp)
    273    {
    274        FurnaceRecipes.smelting().addSmelting(input, output, xp);
    275    }
    276
    277    public static void registerTileEntity(Class<? extends TileEntity> tileEntityClass, String id)
    278    {
    279        TileEntity.addMapping(tileEntityClass, id);
    280    }
    281
    282    /**
    283     * Register a tile entity, with alternative TileEntity identifiers. Use with caution!
    284     * This method allows for you to "rename" the 'id' of the tile entity.
    285     *
    286     * @param tileEntityClass The tileEntity class to register
    287     * @param id The primary ID, this will be the ID that the tileentity saves as
    288     * @param alternatives A list of alternative IDs that will also map to this class. These will never save, but they will load
    289     */
    290    public static void registerTileEntityWithAlternatives(Class<? extends TileEntity> tileEntityClass, String id, String... alternatives)
    291    {
    292        TileEntity.addMapping(tileEntityClass, id);
    293        Map<String,Class> teMappings = ObfuscationReflectionHelper.getPrivateValue(TileEntity.class, null, "nameToClassMap", "a");
    294        for (String s: alternatives)
    295        {
    296            if (!teMappings.containsKey(s))
    297            {
    298                teMappings.put(s, tileEntityClass);
    299            }
    300        }
    301    }
    302
    303    public static void addBiome(BiomeGenBase biome)
    304    {
    305        WorldType.DEFAULT.addNewBiome(biome);
    306    }
    307
    308    public static void removeBiome(BiomeGenBase biome)
    309    {
    310        WorldType.DEFAULT.removeBiome(biome);
    311    }
    312
    313    public static void registerFuelHandler(IFuelHandler handler)
    314    {
    315        fuelHandlers.add(handler);
    316    }
    317    public static int getFuelValue(ItemStack itemStack)
    318    {
    319        int fuelValue = 0;
    320        for (IFuelHandler handler : fuelHandlers)
    321        {
    322            fuelValue = Math.max(fuelValue, handler.getBurnTime(itemStack));
    323        }
    324        return fuelValue;
    325    }
    326
    327    public static void registerCraftingHandler(ICraftingHandler handler)
    328    {
    329        craftingHandlers.add(handler);
    330    }
    331
    332    public static void onItemCrafted(EntityPlayer player, ItemStack item, IInventory craftMatrix)
    333    {
    334        for (ICraftingHandler handler : craftingHandlers)
    335        {
    336            handler.onCrafting(player, item, craftMatrix);
    337        }
    338    }
    339
    340    public static void onItemSmelted(EntityPlayer player, ItemStack item)
    341    {
    342        for (ICraftingHandler handler : craftingHandlers)
    343        {
    344            handler.onSmelting(player, item);
    345        }
    346    }
    347
    348    public static void registerPickupHandler(IPickupNotifier handler)
    349    {
    350        pickupHandlers.add(handler);
    351    }
    352
    353    public static void onPickupNotification(EntityPlayer player, EntityItem item)
    354    {
    355        for (IPickupNotifier notify : pickupHandlers)
    356        {
    357            notify.notifyPickup(item, player);
    358        }
    359    }
    360
    361    public static void registerPlayerTracker(IPlayerTracker tracker)
    362    {
    363        playerTrackers.add(tracker);
    364    }
    365
    366    public static void onPlayerLogin(EntityPlayer player)
    367    {
    368        for(IPlayerTracker tracker : playerTrackers)
    369            tracker.onPlayerLogin(player);
    370    }
    371
    372    public static void onPlayerLogout(EntityPlayer player)
    373    {
    374        for(IPlayerTracker tracker : playerTrackers)
    375            tracker.onPlayerLogout(player);
    376    }
    377
    378    public static void onPlayerChangedDimension(EntityPlayer player)
    379    {
    380        for(IPlayerTracker tracker : playerTrackers)
    381            tracker.onPlayerChangedDimension(player);
    382    }
    383
    384    public static void onPlayerRespawn(EntityPlayer player)
    385    {
    386        for(IPlayerTracker tracker : playerTrackers)
    387            tracker.onPlayerRespawn(player);
    388    }
    389
    390}