001    package net.minecraftforge.common;
002    
003    import java.util.*;
004    
005    import net.minecraft.item.ItemStack;
006    import net.minecraft.util.WeightedRandomChestContent;
007    import net.minecraft.world.WorldServer;
008    import net.minecraft.world.gen.structure.*;
009    
010    public class ChestGenHooks
011    {
012        //Currently implemented categories for chests/dispensers, Dungeon loot is still in DungeonHooks
013        public static final String MINESHAFT_CORRIDOR       = "mineshaftCorridor";
014        public static final String PYRAMID_DESERT_CHEST     = "pyramidDesertyChest";
015        public static final String PYRAMID_JUNGLE_CHEST     = "pyramidJungleChest";
016        public static final String PYRAMID_JUNGLE_DISPENSER = "pyramidJungleDispenser";
017        public static final String STRONGHOLD_CORRIDOR      = "strongholdCorridor";
018        public static final String STRONGHOLD_LIBRARY       = "strongholdLibrary";
019        public static final String STRONGHOLD_CROSSING      = "strongholdCrossing";
020        public static final String VILLAGE_BLACKSMITH       = "villageBlacksmith";
021        public static final String BONUS_CHEST              = "bonusChest";
022    
023        private static final HashMap<String, ChestGenHooks> chestInfo = new HashMap<String, ChestGenHooks>();
024        private static boolean hasInit = false;
025        static 
026        {
027            init();
028        }
029    
030        private static void init()
031        {
032            if (hasInit)
033            {
034                return;
035            }
036            addInfo(MINESHAFT_CORRIDOR,       StructureMineshaftPieces.mineshaftChestContents,                         3,  7);
037            addInfo(PYRAMID_DESERT_CHEST,     ComponentScatteredFeatureDesertPyramid.itemsToGenerateInTemple,          2,  7);
038            addInfo(PYRAMID_JUNGLE_CHEST,     ComponentScatteredFeatureJunglePyramid.junglePyramidsChestContents,      2,  7);
039            addInfo(PYRAMID_JUNGLE_DISPENSER, ComponentScatteredFeatureJunglePyramid.junglePyramidsDispenserContents,  2,  2);
040            addInfo(STRONGHOLD_CORRIDOR,      ComponentStrongholdChestCorridor.strongholdChestContents,                2,  4);
041            addInfo(STRONGHOLD_LIBRARY,       ComponentStrongholdLibrary.strongholdLibraryChestContents,               1,  5);
042            addInfo(STRONGHOLD_CROSSING,      ComponentStrongholdRoomCrossing.strongholdRoomCrossingChestContents,     1,  5);
043            addInfo(VILLAGE_BLACKSMITH,       ComponentVillageHouse2.villageBlacksmithChestContents,                   3,  9);
044            addInfo(BONUS_CHEST,              WorldServer.bonusChestContent,                                          10, 10);
045        }
046    
047        private static void addInfo(String category, WeightedRandomChestContent[] items, int min, int max)
048        {
049            chestInfo.put(category, new ChestGenHooks(category, items, min, max));
050        }
051    
052        /**
053         * Retrieves, or creates the info class for the specified category.
054         * 
055         * @param category The category name
056         * @return A instance of ChestGenHooks for the specified category.
057         */
058        public static ChestGenHooks getInfo(String category)
059        {
060            if (!chestInfo.containsKey(category))
061            {
062                chestInfo.put(category, new ChestGenHooks(category));
063            }
064            return chestInfo.get(category);
065        }
066    
067        /**
068         * Generates an array of items based on the input min/max count.
069         * If the stack can not hold the total amount, it will be split into 
070         * stacks of size 1.
071         * 
072         * @param rand A random number generator
073         * @param source Source item stack
074         * @param min Minimum number of items
075         * @param max Maximum number of items
076         * @return An array containing the generated item stacks 
077         */
078        public static ItemStack[] generateStacks(Random rand, ItemStack source, int min, int max)
079        {
080            int count = min + (rand.nextInt(max - min + 1));
081    
082            ItemStack[] ret;
083            if (source.getItem() == null)
084            {
085                ret = new ItemStack[0];
086            }
087            else if (count > source.getItem().getItemStackLimit())
088            {
089                ret = new ItemStack[count];
090                for (int x = 0; x < count; x++)
091                {
092                    ret[x] = source.copy();
093                    ret[x].stackSize = 1;
094                }
095            }
096            else
097            {
098                ret = new ItemStack[1];
099                ret[0] = source.copy();
100                ret[0].stackSize = count;
101            }
102            return ret;
103        }
104    
105        //shortcut functions, See the non-static versions below
106        public static WeightedRandomChestContent[] getItems(String category){ return getInfo(category).getItems(); }
107        public static int getCount(String category, Random rand){ return getInfo(category).getCount(rand); }
108        public static void addItem(String category, WeightedRandomChestContent item){ getInfo(category).addItem(item); }
109        public static void removeItem(String category, ItemStack item){ getInfo(category).removeItem(item); }
110    
111        private String category;
112        private int countMin = 0;
113        private int countMax = 0;
114        private ArrayList<WeightedRandomChestContent> contents = new ArrayList<WeightedRandomChestContent>();
115    
116        public ChestGenHooks(String category)
117        {
118            this.category = category;
119        }
120        
121        public ChestGenHooks(String category, WeightedRandomChestContent[] items, int min, int max)
122        {
123            this(category);
124            for (WeightedRandomChestContent item : items)
125            {
126                contents.add(item);
127            }
128            countMin = min;
129            countMax = max;
130        }
131        
132        /**
133         * Adds a new entry into the possible items to generate.
134         * 
135         * @param item The item to add.
136         */
137        public void addItem(WeightedRandomChestContent item)
138        {
139            contents.add(item);
140        }
141        
142        /**
143         * Removes all items that match the input item stack, Only metadata and item ID are checked.
144         * If the input item has a metadata of -1, all metadatas will match.
145         * 
146         * @param item The item to check
147         */
148        public void removeItem(ItemStack item)
149        {
150            Iterator<WeightedRandomChestContent> itr = contents.iterator();
151            while(itr.hasNext())
152            {
153                WeightedRandomChestContent cont = itr.next();
154                if (item.isItemEqual(cont.itemStack) || (item.getItemDamage() == -1 && item.itemID == cont.itemStack.itemID))
155                {
156                    itr.remove();
157                }
158            }
159        }
160    
161        /**
162         * Gets an array of all random objects that are associated with this category.
163         * 
164         * @return The random objects
165         */
166        public WeightedRandomChestContent[] getItems()
167        {
168            return contents.toArray(new WeightedRandomChestContent[contents.size()]);
169        }
170    
171        /**
172         * Gets a random number between countMin and countMax.
173         * 
174         * @param rand A RNG
175         * @return A random number where countMin <= num <= countMax
176         */
177        public int getCount(Random rand)
178        {
179            return countMin < countMax ? countMin + rand.nextInt(countMax - countMin) : countMin;
180        }
181    
182        //Accessors
183        public int getMin(){ return countMin; }
184        public int getMax(){ return countMax; }
185        public void setMin(int value){ countMin = value; }
186        public void setMax(int value){ countMax = value; }
187    }