001    package cpw.mods.fml.common.registry;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    import java.util.Map;
006    import java.util.Random;
007    
008    import net.minecraft.entity.passive.EntityVillager;
009    import net.minecraft.item.Item;
010    import net.minecraft.util.Tuple;
011    import net.minecraft.village.MerchantRecipeList;
012    import net.minecraft.world.gen.structure.ComponentVillageStartPiece;
013    import net.minecraft.world.gen.structure.StructureVillagePieceWeight;
014    
015    import com.google.common.collect.ArrayListMultimap;
016    import com.google.common.collect.Lists;
017    import com.google.common.collect.Maps;
018    import com.google.common.collect.Multimap;
019    
020    import cpw.mods.fml.common.FMLLog;
021    
022    /**
023     * Registry for villager trading control
024     *
025     * @author cpw
026     *
027     */
028    public class VillagerRegistry
029    {
030        private static final VillagerRegistry INSTANCE = new VillagerRegistry();
031    
032        private Multimap<Integer, IVillageTradeHandler> tradeHandlers = ArrayListMultimap.create();
033        private Map<Class<?>, IVillageCreationHandler> villageCreationHandlers = Maps.newHashMap();
034        private Map<Integer, String> newVillagers = Maps.newHashMap();
035        private List<Integer> newVillagerIds = Lists.newArrayList();
036    
037        /**
038         * Allow access to the {@link StructureVillagePieces} array controlling new village
039         * creation so you can insert your own new village pieces
040         *
041         * @author cpw
042         *
043         */
044        public interface IVillageCreationHandler
045        {
046            /**
047             * Called when {@link MapGenVillage} is creating a new village
048             *
049             * @param random
050             * @param i
051             */
052            StructureVillagePieceWeight getVillagePieceWeight(Random random, int i);
053    
054            /**
055             * The class of the root structure component to add to the village
056             */
057            Class<?> getComponentClass();
058    
059    
060            /**
061             * Build an instance of the village component {@link StructureVillagePieces}
062             * @param villagePiece
063             * @param startPiece
064             * @param pieces
065             * @param random
066             * @param p1
067             * @param p2
068             * @param p3
069             * @param p4
070             * @param p5
071             */
072            Object buildComponent(StructureVillagePieceWeight villagePiece, ComponentVillageStartPiece startPiece, List pieces, Random random, int p1,
073                    int p2, int p3, int p4, int p5);
074        }
075    
076        /**
077         * Allow access to the {@link MerchantRecipeList} for a villager type for manipulation
078         *
079         * @author cpw
080         *
081         */
082        public interface IVillageTradeHandler
083        {
084            /**
085             * Called to allow changing the content of the {@link MerchantRecipeList} for the villager
086             * supplied during creation
087             *
088             * @param villager
089             * @param recipeList
090             */
091            void manipulateTradesForVillager(EntityVillager villager, MerchantRecipeList recipeList, Random random);
092        }
093    
094        public static VillagerRegistry instance()
095        {
096            return INSTANCE;
097        }
098    
099        /**
100         * Register a new skin for a villager type
101         *
102         * @param villagerId
103         * @param villagerSkin
104         */
105        public void registerVillagerType(int villagerId, String villagerSkin)
106        {
107            if (newVillagers.containsKey(villagerId))
108            {
109                FMLLog.severe("Attempt to register duplicate villager id %d", villagerId);
110                throw new RuntimeException();
111            }
112            newVillagers.put(villagerId, villagerSkin);
113            newVillagerIds.add(villagerId);
114        }
115    
116        /**
117         * Register a new village creation handler
118         *
119         * @param handler
120         */
121        public void registerVillageCreationHandler(IVillageCreationHandler handler)
122        {
123            villageCreationHandlers.put(handler.getComponentClass(), handler);
124        }
125    
126        /**
127         * Register a new villager trading handler for the specified villager type
128         *
129         * @param villagerId
130         * @param handler
131         */
132        public void registerVillageTradeHandler(int villagerId, IVillageTradeHandler handler)
133        {
134            tradeHandlers.put(villagerId, handler);
135        }
136    
137        /**
138         * Callback to setup new villager types
139         *
140         * @param villagerType
141         * @param defaultSkin
142         */
143        public static String getVillagerSkin(int villagerType, String defaultSkin)
144        {
145            if (instance().newVillagers.containsKey(villagerType))
146            {
147                return instance().newVillagers.get(villagerType);
148            }
149            return defaultSkin;
150        }
151    
152        /**
153         * Callback to handle trade setup for villagers
154         *
155         * @param recipeList
156         * @param villager
157         * @param villagerType
158         * @param random
159         */
160        public static void manageVillagerTrades(MerchantRecipeList recipeList, EntityVillager villager, int villagerType, Random random)
161        {
162            for (IVillageTradeHandler handler : instance().tradeHandlers.get(villagerType))
163            {
164                handler.manipulateTradesForVillager(villager, recipeList, random);
165            }
166        }
167    
168        public static void addExtraVillageComponents(ArrayList components, Random random, int i)
169        {
170            List<StructureVillagePieceWeight> parts = components;
171            for (IVillageCreationHandler handler : instance().villageCreationHandlers.values())
172            {
173                parts.add(handler.getVillagePieceWeight(random, i));
174            }
175        }
176    
177        public static Object getVillageComponent(StructureVillagePieceWeight villagePiece, ComponentVillageStartPiece startPiece, List pieces, Random random,
178                int p1, int p2, int p3, int p4, int p5)
179        {
180            return instance().villageCreationHandlers.get(villagePiece.villagePieceClass).buildComponent(villagePiece, startPiece, pieces, random, p1, p2, p3, p4, p5);
181        }
182    
183    
184        public static void addEmeraldBuyRecipe(EntityVillager villager, MerchantRecipeList list, Random random, Item item, float chance, int min, int max)
185        {
186            if (min > 0 && max > 0)
187            {
188                EntityVillager.villagerStockList.put(item.itemID, new Tuple(min, max));
189            }
190            villager.addMerchantItem(list, item.getMaxDamage(), random, chance);
191        }
192    
193        public static void addEmeraldSellRecipe(EntityVillager villager, MerchantRecipeList list, Random random, Item item, float chance, int min, int max)
194        {
195            if (min > 0 && max > 0)
196            {
197                EntityVillager.blacksmithSellingList.put(item.itemID, new Tuple(min, max));
198            }
199            villager.addBlacksmithItem(list, item.getMaxDamage(), random, chance);
200        }
201    
202        public static void applyRandomTrade(EntityVillager villager, Random rand)
203        {
204            int extra = instance().newVillagerIds.size();
205            int trade = rand.nextInt(5 + extra);
206            villager.setProfession(trade < 5 ? trade : instance().newVillagerIds.get(trade - 5));
207        }
208    }