package cyano.basemetals.util;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.registry.VillagerRegistry;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
/**
* Created by Chris on 3/30/2016.
*/
public class VillagerTradeHelper {
private static final ResourceLocation[] professionList = {
new ResourceLocation("minecraft:farmer"),
new ResourceLocation("minecraft:librarian"),
new ResourceLocation("minecraft:priest"),
new ResourceLocation("minecraft:smith"),
new ResourceLocation("minecraft:butcher")
};
/**
* Inserts one or more trades to the defaul villager trade table using dark magic (aka java reflection).
* @param professionID Villager profession ID (0-4)
* @param careerID Villager career ID (1-3)
* @param tradeLevel Level of trade (1+)
* @param trades Trades to add to the given level
* @throws NoSuchFieldException Thrown if java reflection has been disabled for security reasons
* @throws IllegalAccessException Thrown if java reflection has been disabled for security reasons
*/
public static void insertTrades(int professionID, int careerID, int tradeLevel, EntityVillager.ITradeList... trades) throws NoSuchFieldException, IllegalAccessException {
ResourceLocation profession = professionList[professionID];
insertTrades(profession,careerID,tradeLevel,trades);
/*
FMLLog.info("%s: injecting villager trades %s into default trade array table at position [%s][%s][%s][*]", BaseMetals.MODID, Arrays.toString(trades), professionID, careerID-1, tradeLevel-1);
Field vanillaTradeField = getTradeArrayFromClass(EntityVillager.class);
unlockPrivateFinalField(vanillaTradeField);
Object tradeTable = vanillaTradeField.get(null); // is static
appendToMultidimensionalArray(trades,tradeTable,professionID,Math.max(0,careerID-1),Math.max(0,tradeLevel-1));
*/
}
/**
* Inserts one or more trades to the defaul villager trade table using dark magic (aka java reflection).
* @param profession Villager profession
* @param careerID Villager career ID (1-3)
* @param tradeLevel Level of trade (1+)
* @param trades Trades to add to the given level
*/
public static void insertTrades(ResourceLocation profession, int careerID, int tradeLevel, EntityVillager.ITradeList... trades) {
for(EntityVillager.ITradeList trade : trades) {
VillagerRegistry.instance().getRegistry().getValue(profession).getCareer(careerID-1).addTrade(tradeLevel, trade);
}
}
public static void appendToMultidimensionalArray(Object append, Object array, int... indices){
appendToMultidimensionalArray(Arrays.asList(append).toArray(),array,indices);
}
public static void appendToMultidimensionalArray(Object[] append, Object array, int... indices){
// get the lowest level array
Object prevArray = null;
int i = 0;
while( i < indices.length){
int index = indices[i];
prevArray = array;
array = Array.get(array, index);
i++;
// make sure the next array is long enough
if(i < indices.length){
int nextIndex = indices[i];
if(Array.getLength(array) <= nextIndex){
Object pad;
if(array.getClass().getComponentType().isArray()){
pad = Array.newInstance(array.getClass().getComponentType().getComponentType(),0);
} else {
// this shouldn't happen
pad = null;
}
Object newArray = expandArray(array,nextIndex+1,pad);
Array.set(prevArray,index,newArray);
array = newArray;
}
}
}
// expand lowest level array to new size
Class aType = array.getClass().getComponentType();
if(!aType.isAssignableFrom(append.getClass().getComponentType())){
throw new IllegalArgumentException("Class type "+append.getClass().getComponentType().getCanonicalName()+" cannot be appended to "+aType.getCanonicalName()+" array");
}
Object newArray = expandArray(array,Array.getLength(array)+append.length,null);
System.arraycopy(append,0,newArray,Array.getLength(array),append.length);
Array.set(prevArray,indices[indices.length - 1],newArray);
}
public static Object expandArray(Object array, int newSize, Object fill){
Object newArray = Array.newInstance(array.getClass().getComponentType(),newSize);
if(Array.getLength(array) == 0) return newArray;
System.arraycopy(array,0,newArray,0,Array.getLength(array));
for (int i = Array.getLength(array); i < newSize; i++){
Array.set(newArray,i,fill);
}
return newArray;
}
public static void unlockPrivateFinalField(Field v) throws NoSuchFieldException, IllegalAccessException {
v.setAccessible(true);
Field modField = Field.class.getDeclaredField("modifiers");
modField.setAccessible(true);
modField.setInt(v, v.getModifiers() & ~Modifier.FINAL);
}
public static Field getTradeArrayFromClass(Class c){
// search for 4D array of ITradeList objects
for(Field f : c.getDeclaredFields()){
if(f.getType().isArray() // D1
&& f.getType().getComponentType().isArray() // D2
&& f.getType().getComponentType().getComponentType().isArray() // D3
&& f.getType().getComponentType().getComponentType().getComponentType().isArray() // D4
&& f.getType().getComponentType().getComponentType().getComponentType().getComponentType().isAssignableFrom(EntityVillager.ITradeList.class)) {
return f;
}
}
return null;
}
}