Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save RareScrap/d032aab61d010117743994df1976453c to your computer and use it in GitHub Desktop.
Save RareScrap/d032aab61d010117743994df1976453c to your computer and use it in GitHub Desktop.
Коллекция идиотских (но местами интересных) способ отслеживания изменения инвентарей в Minecraft 1.7.10
package ru.rarescrap.simpleweightsystem;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.*;
import net.minecraft.item.Item;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.player.EntityInteractEvent;
import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent;
import ru.rarescrap.gloomyfolken.hooklib.asm.Hook;
import ru.rarescrap.gloomyfolken.hooklib.asm.ReturnCondition;
import ru.rarescrap.gloomyfolken.hooklib.minecraft.HookLoader;
import ru.rarescrap.gloomyfolken.hooklib.minecraft.PrimaryClassTransformer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import ru.rarescrap.weightapi.IWeightProvider;
import ru.rarescrap.weightapi.WeightRegistry;
import ru.rarescrap.weightapi.event.CalculateInventoryWeightEvent;
import ru.rarescrap.weightapi.event.WeightChangedEvent;
import java.util.List;
public class ASMHookLoader extends HookLoader {
// включает саму HookLib'у. Делать это можно только в одном из ASMHookLoader'ов.
// При желании, можно включить ru.rarescrap.gloomyfolken.hooklib.minecraft.HookLibPlugin и не указывать здесь это вовсе.
// TODO: Как включить плагин?
@Override
public String[] getASMTransformerClass() {
return new String[]{PrimaryClassTransformer.class.getName()};
}
@Override
public void registerHooks() {
//регистрируем класс, где есть методы с аннотацией @Hook
//registerHookContainer(PlayerWeightTrackerHooks.class.getName());
//registerHookContainer(PlayerInventoryHooks.class.getName());
//registerHookContainer(ICraftingHooks.class.getName());
}
public static class PlayerWeightTrackerHooks {
private static double prevWeight;
private static void updatePrevWeight(InventoryPlayer inventoryPlayer, Entity owner) {
prevWeight = WeightRegistry.getWeightProvider().getWeight(inventoryPlayer, owner);
}
// UI: Вычисляем вес до изменения инвентаря
@Hook
public static void putStack(Slot slot, ItemStack p_75215_1_) {
IWeightProvider weightProvider = WeightRegistry.getWeightProvider();
// На случай, если WeightProvider должен приходить с сервера. Т.к. контент
// игрока может высылаться на клиент раньше, чем придет WeightProvider
if (slot.inventory instanceof InventoryPlayer && weightProvider != null) {
InventoryPlayer inventoryPlayer = (InventoryPlayer) slot.inventory;
updatePrevWeight(inventoryPlayer, inventoryPlayer.player);
}
}
// UI: Шлем евент изменения веса
@Hook
public static void onSlotChanged(Slot slot) {
IWeightProvider weightProvider = WeightRegistry.getWeightProvider();
if (slot.inventory instanceof InventoryPlayer && weightProvider != null) {
InventoryPlayer inventoryPlayer = (InventoryPlayer) slot.inventory;
MinecraftForge.EVENT_BUS.post(new WeightChangedEvent(inventoryPlayer,
prevWeight,
weightProvider.getWeight(inventoryPlayer, inventoryPlayer.player),
weightProvider.isOverloaded(inventoryPlayer, inventoryPlayer.player),
inventoryPlayer.player));
}
}
// Drop Item: Вычисляем вес до изменения инвентаря
@Hook(injectOnExit = true, returnCondition = ReturnCondition.ON_TRUE)
public static boolean onDroppedByPlayer(Item item, ItemStack itemStack, EntityPlayer player) {
updatePrevWeight(player.inventory, player);
return true;
}
// Drop Item: Шлем евент изменения веса
// Выбрасывание итемов изменяет инвентарь не через слоты, а напрямую. Отлавливаем это.
// TODO: Вот такой вот самопальный "static @SubscribeEvent". Как его заменить кошерными средствами на 1.7.10?
@Hook(injectOnExit = true, returnCondition = ReturnCondition.ON_NOT_NULL)
public static EntityItem onPlayerTossEvent(ForgeHooks hooks, EntityPlayer player, ItemStack item, boolean includeName, @Hook.ReturnValue EntityItem returnValue) {
Slot slot = player.inventoryContainer.getSlotFromInventory(player.inventory, player.inventory.currentItem);
onSlotChanged(slot); // Думаю, это лучше чем вызывать ванильный slot.onSlotChanged();
return returnValue;
}
// Item Use: Шлем евент изменения веса
// TODO: А вот тут я не могу заюзать подход выше, т.к. PlayerDestroyItemEvent может выброситься миновав вызов ForgeEventFactory#onPlayerDestroyItem()
@SubscribeEvent
public void onPlayerDestroyItem(PlayerDestroyItemEvent event) {
Slot slot = event.entityPlayer.inventoryContainer.getSlotFromInventory(event.entityPlayer.inventory, event.entityPlayer.inventory.currentItem); // TODO: Предмет в руке?
onSlotChanged(slot); // Думаю, это лучше чем вызывать ванильный slot.onSlotChanged();
}
@Hook
public static void tryPlaceItemIntoWorld(ItemStack itemStack, EntityPlayer p_77943_1_, World p_77943_2_, int p_77943_3_, int p_77943_4_, int p_77943_5_, int p_77943_6_, float p_77943_7_, float p_77943_8_, float p_77943_9_) {
updatePrevWeight(p_77943_1_.inventory, p_77943_1_);
}
@SubscribeEvent
public void onInteract(EntityInteractEvent event) {
updatePrevWeight(event.entityPlayer.inventory, event.entityPlayer);
}
@Hook(injectOnExit = true)
public static void interactWith(EntityPlayer player, Entity p_70998_1_) {
Slot slot = player.inventoryContainer.getSlotFromInventory(player.inventory, player.inventory.currentItem); // TODO: Предмет в руке?
onSlotChanged(slot); // Думаю, это лучше чем вызывать ванильный slot.onSlotChanged();
}
}
public static class PlayerInventoryHooks {
private static double prevWeight;
@Hook(targetMethod = "setInventorySlotContents")
public static void setInventorySlotContents_before(InventoryPlayer inventoryPlayer, int p_70299_1_, ItemStack p_70299_2_) {
prevWeight = WeightRegistry.getWeightProvider().getWeight(inventoryPlayer, inventoryPlayer.player);
}
@Hook(targetMethod = "setInventorySlotContents", injectOnExit = true)
public static void setInventorySlotContents_after(InventoryPlayer inventoryPlayer, int p_70299_1_, ItemStack p_70299_2_) {
IWeightProvider weightProvider = WeightRegistry.getWeightProvider();
if (weightProvider != null) {
MinecraftForge.EVENT_BUS.post(new WeightChangedEvent(inventoryPlayer,
prevWeight,
weightProvider.getWeight(inventoryPlayer, inventoryPlayer.player),
weightProvider.isOverloaded(inventoryPlayer, inventoryPlayer.player),
inventoryPlayer.player));
}
}
@Hook(targetMethod = "decrStackSize")
public static void decrStackSize_before(InventoryPlayer inventoryPlayer, int p_70298_1_, int p_70298_2_) {
prevWeight = WeightRegistry.getWeightProvider().getWeight(inventoryPlayer, inventoryPlayer.player);
}
@Hook(targetMethod = "decrStackSize", injectOnExit = true)
public static void decrStackSize_after(InventoryPlayer inventoryPlayer, int p_70298_1_, int p_70298_2_) {
IWeightProvider weightProvider = WeightRegistry.getWeightProvider();
if (weightProvider != null) {
MinecraftForge.EVENT_BUS.post(new WeightChangedEvent(inventoryPlayer,
prevWeight,
weightProvider.getWeight(inventoryPlayer, inventoryPlayer.player),
weightProvider.isOverloaded(inventoryPlayer, inventoryPlayer.player),
inventoryPlayer.player));
}
}
}
public static class ICraftingHooks {
// private static boolean isInDetectAndSendChanges;
// private static Container container;
// private static Entity owner;
//
// private static double prevWeight;
//
// @Hook(targetMethod = "detectAndSendChanges")
// public static void enableFlag(Container container) {
// isInDetectAndSendChanges = true;
// ICraftingHooks.container = container;
// }
//
// @Hook(targetMethod = "detectAndSendChanges", injectOnExit = true)
// public static void disableFlag(Container container) {
// isInDetectAndSendChanges = false;
// }
//
// @Hook(targetMethod = "areItemStacksEqual", injectOnExit = true)
// public static void injectWeightPrecalculating(ItemStack itemStack, ItemStack p_77989_0_, ItemStack p_77989_1_, @Hook.ReturnValue boolean returnValue) {
// if (container instanceof ContainerPlayer)
// prevWeight = WeightRegistry.getWeightProvider().getWeight(
// ((ContainerPlayer) container).thePlayer.inventory,
// ((ContainerPlayer) container).thePlayer
// );
// }
// @Hook(returnCondition = ReturnCondition.ALWAYS)
// public static void detectAndSendChanges(Container container)
// {
// for (int i = 0; i < container.inventorySlots.size(); ++i)
// {
// ItemStack itemstack = ((Slot)container.inventorySlots.get(i)).getStack();
// ItemStack itemstack1 = (ItemStack)container.inventoryItemStacks.get(i);
//
// if (!ItemStack.areItemStacksEqual(itemstack1, itemstack))
// {
// prevWeight = WeightRegistry.getWeightProvider().getWeight(((Slot) container.inventorySlots.get(i)).inventory, )
// itemstack1 = itemstack == null ? null : itemstack.copy();
// container.inventoryItemStacks.set(i, itemstack1);
//
// for (int j = 0; j < container.crafters.size(); ++j)
// {
// ((ICrafting)container.crafters.get(j)).sendSlotContents(container, i, itemstack1);
// }
// }
// }
// }
// // Для начала попробуем прсто вставлять в начало метода
// @Hook
// public static void sendSlotContents(EntityPlayerMP entityPlayerMP, Container p_71111_1_, int p_71111_2_, ItemStack p_71111_3_) {
// //WeightChangedEvent event = new WeightChangedEvent(entityPlayerMP.inventory, )
// }
}
}