package com.sijobe.spc.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import net.minecraft.src.ChunkCoordIntPair;
import net.minecraft.src.ChunkCoordinates;
import net.minecraft.src.DamageSource;
import net.minecraft.src.Entity;
import net.minecraft.src.EntityItem;
import net.minecraft.src.EntityLiving;
import net.minecraft.src.EntityPlayer;
import net.minecraft.src.EntityPlayerMP;
import net.minecraft.src.ItemInWorldManager;
import net.minecraft.src.WorldProvider;
/**
* Helper for compatiblity with Minecraft Forge
*
* @author q3hardcore
* @version 1.0
*/
public final class ForgeHelper {
public static final boolean HAS_FORGE = getHasForge();
private final static Class<?> forgeClass;
private final static Field eventBusField;
private final static Class<?> eventClass;
private final static Class<?> eventBusClass;
private final static Method post;
private final static Field capturedDropsField;
private final static Field captureDropsField;
private final static Class<?> playerDropsEventClass;
private final static Constructor<?> playerDropsEventConstructor;
private final static Class<?> watchClass;
private final static Constructor<?> watchConstructor;
private final static Method getBlockReachDistance;
private final static Method setBlockReachDistance;
private final static Class<?> forgeHooksClass;
private final static Method onLivingDeath;
private static boolean getHasForge() {
try {
Class.forName("net.minecraftforge.common.MinecraftForge");
return true;
} catch (Throwable t) {
return false;
}
}
public static ChunkCoordinates getRandomizedSpawnPoint(WorldProvider provider) {
ChunkCoordinates spawnPoint = new ChunkCoordinates(0, 64, 0);
try {
spawnPoint = (ChunkCoordinates)provider.getClass().getMethod("getRandomizedSpawnPoint").invoke(provider);
} catch (Throwable t) {
t.printStackTrace();
}
return spawnPoint;
}
public static void clearDrops(EntityPlayerMP entityPlayerMP) {
setCaptureDrops(entityPlayerMP, true);
getCapturedDrops(entityPlayerMP).clear();
}
@SuppressWarnings("unchecked")
public static void captureDrops(EntityPlayerMP entityPlayerMP, DamageSource damageSource, int recentlyHit) {
setCaptureDrops(entityPlayerMP, false);
Object event = createPlayerDropsEvent(entityPlayerMP, damageSource, getCapturedDrops(entityPlayerMP), recentlyHit > 0);
if(!postEvent(event)) {
for(EntityItem entityItem : getCapturedDrops(entityPlayerMP)) {
entityPlayerMP.worldObj.spawnEntityInWorld(entityItem);
}
}
}
private static boolean postEvent(Object event) {
if(event == null) {
System.err.println("SPC/Forge: No event to post.");
return false;
}
try {
Object returnVal = post.invoke(eventBusField.get(null), new Object[]{event});
return Boolean.parseBoolean(returnVal.toString());
} catch (Throwable t) {
t.printStackTrace();
return false;
}
}
public static void watchChunk(ChunkCoordIntPair chunkCoord, EntityPlayerMP player) {
try {
Object event = watchConstructor.newInstance(new Object[]{chunkCoord, player});
postEvent(event);
} catch (Throwable t) {
t.printStackTrace();
}
}
private static Object createPlayerDropsEvent(EntityPlayer player, DamageSource damageSource,
ArrayList<EntityItem> drops, boolean wasRecentlyHit) {
Object playerDropsEvent = null;
try {
playerDropsEvent = playerDropsEventConstructor.newInstance(new Object[]{player, damageSource, drops, wasRecentlyHit});
} catch (Throwable t) {
t.printStackTrace();
}
return playerDropsEvent;
}
private static void setCaptureDrops(Entity entity, boolean val) {
try {
captureDropsField.set(entity, val);
} catch (Throwable t) {
t.printStackTrace();
}
}
@SuppressWarnings("unchecked")
private static ArrayList<EntityItem> getCapturedDrops(Entity entity) {
ArrayList<EntityItem> capturedDrops = new ArrayList<EntityItem>();
try {
Object returnVal = capturedDropsField.get(entity);
if(returnVal instanceof ArrayList) {
capturedDrops = (ArrayList<EntityItem>)returnVal;
} else {
System.err.println("SPC/Forge: Couldn't determine captured drops.");
}
} catch (Throwable t) {
t.printStackTrace();
}
return capturedDrops;
}
public static boolean onLivingDeath(EntityPlayerMP entityPlayerMP, DamageSource damageSource) {
try {
Object returnVal = onLivingDeath.invoke(null, entityPlayerMP, damageSource);
return Boolean.parseBoolean(returnVal.toString());
} catch (Throwable t) {
t.printStackTrace();
return false;
}
}
public static double getBlockReachDistance(ItemInWorldManager manager) {
try {
Object returnVal = getBlockReachDistance.invoke(manager);
return Double.parseDouble(returnVal.toString());
} catch (Throwable t) {
t.printStackTrace();
return 5.0D;
}
}
public static void setBlockReachDistance(ItemInWorldManager manager, double distance) {
try {
setBlockReachDistance.invoke(manager, distance);
} catch (Throwable t) {
t.printStackTrace();
}
}
static {
if(HAS_FORGE) {
System.out.println("SPC: Detected Forge.");
forgeClass = ReflectionHelper.getClass("net.minecraftforge.common.MinecraftForge");
eventBusField = ReflectionHelper.getField(forgeClass, "EVENT_BUS");
eventClass = ReflectionHelper.getClass("net.minecraftforge.event.Event");
eventBusClass = ReflectionHelper.getClass("net.minecraftforge.event.EventBus");
post = ReflectionHelper.getMethod(eventBusClass, "post", eventClass);
capturedDropsField = ReflectionHelper.getField(Entity.class, "capturedDrops");
captureDropsField = ReflectionHelper.getField(Entity.class, "captureDrops");
playerDropsEventClass = ReflectionHelper.getClass("net.minecraftforge.event.entity.player.PlayerDropsEvent");
final Class[] params = new Class[]{ EntityPlayer.class, DamageSource.class, ArrayList.class, Boolean.TYPE };
playerDropsEventConstructor = ReflectionHelper.getConstructor(playerDropsEventClass, params);
watchClass = ReflectionHelper.getClass("net.minecraftforge.event.world.ChunkWatchEvent$Watch");
watchConstructor = ReflectionHelper.getConstructor(watchClass, new Class[]{ChunkCoordIntPair.class, EntityPlayerMP.class});
getBlockReachDistance = ReflectionHelper.getMethod(ItemInWorldManager.class, "getBlockReachDistance");
setBlockReachDistance = ReflectionHelper.getMethod(ItemInWorldManager.class, "setBlockReachDistance", Double.TYPE);
forgeHooksClass = ReflectionHelper.getClass("net.minecraftforge.common.ForgeHooks");
onLivingDeath = ReflectionHelper.getMethod(forgeHooksClass, "onLivingDeath", EntityLiving.class, DamageSource.class);
} else {
System.out.println("SPC: Forge not detected.");
forgeClass = null; eventBusField = null;
eventClass = null; eventBusClass = null;
post = null;
capturedDropsField = null; captureDropsField = null;
playerDropsEventClass = null; playerDropsEventConstructor = null;
watchClass = null; watchConstructor = null;
getBlockReachDistance = null; setBlockReachDistance = null;
forgeHooksClass = null; onLivingDeath = null;
}
}
}