package de.take_weiland.mods.commons.internal; import com.google.common.collect.ImmutableSet; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import de.take_weiland.mods.commons.event.PlayerCloneEvent; import de.take_weiland.mods.commons.event.PlayerStartTrackingEvent; import de.take_weiland.mods.commons.event.client.GuiInitEvent; import de.take_weiland.mods.commons.internal.sync.SyncCompanions; import de.take_weiland.mods.commons.internal.sync.IEEPSyncCompanion; import de.take_weiland.mods.commons.internal.sync.SyncCompanion; import de.take_weiland.mods.commons.internal.tonbt.ToNbtFactories; import de.take_weiland.mods.commons.internal.tonbt.ToNbtHandler; import de.take_weiland.mods.commons.inv.Containers; import de.take_weiland.mods.commons.inv.NameableInventory; import de.take_weiland.mods.commons.nbt.NBT; import de.take_weiland.mods.commons.util.SCReflector; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.inventory.Container; import net.minecraft.inventory.ICrafting; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.packet.Packet250CustomPayload; import net.minecraftforge.common.IExtendedEntityProperties; import net.minecraftforge.common.MinecraftForge; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * A class containing methods called from ASM generated code. * * @author diesieben07 */ @SuppressWarnings("unused") public final class ASMHooks { public static final String CLASS_NAME = "de/take_weiland/mods/commons/internal/ASMHooks"; public static final String ON_START_TRACKING = "onStartTracking"; public static final String ON_PLAYER_CLONE = "onPlayerClone"; public static final String NEW_SYNC_STREAM = "newSyncStream"; public static final String SEND_SYNC_STREAM = "sendSyncStream"; public static final String FIND_CONTAINER_INVS = "findContainerInvs"; public static final String ON_LISTENER_ADDED = "onListenerAdded"; public static final String IS_USEABLE_CLIENT = "isUseableClient"; public static final String INVOKE_SYNC_COMP_CHECK = "invokeSyncCompanionCheck"; public static final String ON_GUI_INIT = "onGuiInit"; private ASMHooks() { } public static void invokeSyncCompanionCheck(Object obj, SyncCompanion companion) { if (companion != null) companion.check(obj, false); } public static final String TICK_IEEP_COMPANIONS = "tickIEEPCompanions"; public static void tickIEEPCompanions(List<IEEPSyncCompanion> props) { if (props != null) { // put actual logic into different method, to make this method smaller and more likely // to be inlined into the World class (called from there every tick for every entity!) tickIEEPCompanionsNonNull(props); } } private static void tickIEEPCompanionsNonNull(List<IEEPSyncCompanion> props) { //noinspection ForLoopReplaceableByForEach int i = props.size(); do { if (--i < 0) return; IEEPSyncCompanion companion = props.get(i); companion.check(companion._sc$ieep, false); } while (true); } public static final String ON_NEW_ENTITY_PROPS = "onNewEntityProps"; public static void onNewEntityProps(Entity entity, IExtendedEntityProperties props, String identifier) throws Throwable { IEEPSyncCompanion companion = (IEEPSyncCompanion) SyncCompanions.newCompanion(props.getClass()); if (companion == null) { return; } List<IEEPSyncCompanion> companions = ((EntityProxy) entity)._sc$getPropsCompanions(); if (companions == null) { companions = new ArrayList<>(); ((EntityProxy) entity)._sc$setPropsCompanions(companions); } companion._sc$ieep = props; companion._sc$entity = entity; companion._sc$ident = identifier; // maintain ordering in the list int len = companions.size(); int index = 0; for (int i = 0; i < len; i++) { if (companions.get(i)._sc$ident.compareTo(identifier) >= 0) { index = i; break; } } companions.add(index, companion); } public static final String WRITE_NBT_HOOK = "writeToNbtHook"; public static void writeToNbtHook(Object obj, NBTTagCompound nbt) { ToNbtHandler handler = ToNbtFactories.handlerFor(obj.getClass()); if (handler != null) { handler.write(obj, nbt); } } public static final String READ_NBT_HOOK = "readFromNbtHook"; public static void readFromNbtHook(Object obj, NBTTagCompound nbt) { ToNbtHandler handler = ToNbtFactories.handlerFor(obj.getClass()); if (handler != null) { handler.read(obj, nbt); } } public static final String IEEP_READ_NBT_HOOK = "readFromNBTIEEP"; public static void readFromNBTIEEP(Object obj, String ident, NBTTagCompound nbt) { ToNbtHandler handler = ToNbtFactories.handlerFor(obj.getClass()); if (handler != null) { handler.read(obj, nbt.getCompoundTag(ident)); } } public static final String IEEP_WRITE_NBT_HOOK = "writeToNBTIEEP"; public static void writeToNBTIEEP(Object obj, String ident, NBTTagCompound nbt) { ToNbtHandler handler = ToNbtFactories.handlerFor(obj.getClass()); if (handler != null) { handler.write(obj, NBT.getOrCreateCompound(nbt, ident)); } } @SideOnly(Side.CLIENT) public static boolean isUseableClient(Slot slot) { return slot != null && slot.canTakeStack(Minecraft.getMinecraft().thePlayer); } public static void onListenerAdded(Container container, ICrafting listener) { if (listener instanceof EntityPlayerMP) { List<IInventory> invs = Containers.getInventories(container).asList(); for (int i = 0, len = invs.size(); i < len; i++) { IInventory inv = invs.get(i); if (inv instanceof NameableInventory && ((NameableInventory) inv).hasCustomName()) { new PacketInventoryName(container.windowId, i, ((NameableInventory) inv).getCustomName()).sendTo((EntityPlayerMP) listener); } } } } public static ImmutableSet<IInventory> findContainerInvs(Container container) { IInventory last = null; ImmutableSet.Builder<IInventory> builder = ImmutableSet.builder(); @SuppressWarnings("unchecked") List<Slot> slots = container.inventorySlots; for (Slot slot : slots) { if (slot.inventory != last) { builder.add((last = slot.inventory)); } } return builder.build(); } public static void onPlayerClone(EntityPlayer oldPlayer, EntityPlayer newPlayer) { MinecraftForge.EVENT_BUS.post(new PlayerCloneEvent(oldPlayer, newPlayer)); } @SideOnly(Side.CLIENT) public static void onGuiInit(GuiScreen gui) { MinecraftForge.EVENT_BUS.post(new GuiInitEvent(gui, SCReflector.instance.getButtonList(gui))); } public static void onStartTracking(EntityPlayer player, Entity tracked) { MinecraftForge.EVENT_BUS.post(new PlayerStartTrackingEvent(player, tracked)); // PacketSyncPropsIDs.sendToIfNeeded(player, tracked); } private static final int SIGNED_SHORT_BITS = 0b0111_1111_1111_1111; private static final int SHORT_MS_BIT = 0b1000_0000_0000_0000; public static void writeExtPacketLen(DataOutput out, int len) throws IOException { int leftover = (len & ~SIGNED_SHORT_BITS) >>> 15; if (leftover != 0) { out.writeShort(len & SIGNED_SHORT_BITS | SHORT_MS_BIT); out.writeByte(leftover); } else { out.writeShort(len & SIGNED_SHORT_BITS); } } public static int readExtPacketLen(DataInput in) throws IOException { int low = in.readUnsignedShort(); if ((low & SHORT_MS_BIT) != 0) { int hi = in.readUnsignedByte(); return (low & SIGNED_SHORT_BITS) | (hi << 15); } else { return low; } } public static int additionalPacketSize(Packet250CustomPayload packet) { if ((packet.length & 0b0111_1111_1000_0000_0000_0000) != 0) { return 1; } else { return 0; } } public static int additionalPacketSize(int len) { if ((len & 0b0111_1111_1000_0000_0000_0000) != 0) { return 1; } else { return 0; } } }