Color applicator improvements (#360)

* Now properly updates the Applicator's set color when a dye runs out, instead of staying stuck on a color which has no dye left
* Holding Applicator in offhand will now paint cables on placement
* Middle-clicking a colored tile while holding an Applicator in main or off hand will now set the Applicator's color to that color, if the dye is available in the Applicator
This commit is contained in:
Serenibyss
2024-01-12 01:21:24 -06:00
committed by GitHub
parent 2ea08a3fc9
commit 0709d2dfc4
6 changed files with 246 additions and 43 deletions
@@ -86,7 +86,9 @@ public class AppEngPacketHandlerBase {
PACKET_TERMINAL_KEYBIND(PacketTerminalUse.class),
PACKET_CRAFTING_TOAST(PacketCraftingToast.class);
PACKET_CRAFTING_TOAST(PacketCraftingToast.class),
PACKET_COLOR_APPLICATOR_SELECT_COLOR(PacketColorApplicatorSelectColor.class);
private final Class<? extends AppEngPacket> packetClass;
@@ -0,0 +1,53 @@
package appeng.core.sync.packets;
import appeng.api.util.AEColor;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.items.tools.powered.ToolColorApplicator;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import javax.annotation.Nullable;
public class PacketColorApplicatorSelectColor extends AppEngPacket {
@Nullable
private AEColor color = null;
@SuppressWarnings("unused")
public PacketColorApplicatorSelectColor(final ByteBuf stream) {
if (stream.readBoolean()) {
byte colorIdx = stream.readByte();
AEColor[] values = AEColor.values();
if (colorIdx >= 0 && colorIdx < values.length) {
this.color = values[colorIdx];
}
}
}
public PacketColorApplicatorSelectColor(@Nullable final AEColor color) {
final ByteBuf data = Unpooled.buffer();
data.writeInt(this.getPacketID());
if (color != null) {
data.writeBoolean(true);
data.writeByte(color.ordinal());
} else {
data.writeBoolean(false);
}
this.configureWrite(data);
}
@Override
public void serverPacketData(INetworkInfo manager, AppEngPacket packet, EntityPlayer player) {
switchColor(player.getHeldItemMainhand(), color);
switchColor(player.getHeldItemOffhand(), color);
}
private static void switchColor(ItemStack stack, AEColor color) {
if (!stack.isEmpty() && stack.getItem() instanceof ToolColorApplicator colorApp) {
colorApp.setActiveColor(stack, color);
}
}
}
@@ -26,6 +26,7 @@ import com.google.common.io.ByteStreams;
import net.minecraft.launchwrapper.IClassTransformer;
import net.minecraftforge.fml.common.Loader;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.ClassRemapper;
@@ -43,23 +44,29 @@ public class AE2ELTransformer implements IClassTransformer {
@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {
if (Loader.instance().getIndexedModList().get("stackup") != null) {
return basicClass;
}
transformedName = transformedName.replace('/', '.');
Consumer<ClassNode> consumer = (n) -> {
};
if ("net.minecraftforge.common.ForgeHooks".equals(transformedName)) {
ClassReader cr = new ClassReader(basicClass);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
ClassVisitor cv = new PickBlockPatch(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
}
Consumer<ClassNode> consumer = (n) -> {};
Consumer<ClassNode> emptyConsumer = consumer;
if ("net.minecraft.item.ItemStack".equals(transformedName)) {
consumer = consumer.andThen(ItemStackPatch::patchCountGetSet);
} else if ("net.minecraft.network.PacketBuffer".equals(transformedName)) {
consumer = consumer.andThen((node) -> {
spliceClasses(node, "appeng.core.transformer.PacketBufferPatch",
"readItemStack", "func_150791_c",
"writeItemStack", "func_150788_a");
});
if (Loader.instance().getIndexedModList().get("stackup") == null) {
if ("net.minecraft.item.ItemStack".equals(transformedName)) {
consumer = consumer.andThen(ItemStackPatch::patchCountGetSet);
} else if ("net.minecraft.network.PacketBuffer".equals(transformedName)) {
consumer = consumer.andThen((node) -> {
spliceClasses(node, "appeng.core.transformer.PacketBufferPatch",
"readItemStack", "func_150791_c",
"writeItemStack", "func_150788_a");
});
}
}
if (consumer != emptyConsumer) {
@@ -0,0 +1,76 @@
package appeng.core.transformer;
import appeng.api.AEApi;
import appeng.api.definitions.IItemDefinition;
import appeng.api.implementations.tiles.IColorableTile;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketColorApplicatorSelectColor;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class PickBlockPatch extends ClassVisitor {
public PickBlockPatch(ClassVisitor cv) {
super(Opcodes.ASM5, cv);
}
@SuppressWarnings("unused")
public static boolean testColorApplicatorPickBlock(RayTraceResult result, EntityPlayer player, World world) {
if (player == null || player.world == null || result == null || result.typeOfHit != RayTraceResult.Type.BLOCK) {
return false;
}
IItemDefinition applicator = AEApi.instance().definitions().items().colorApplicator();
if (!applicator.isSameAs(player.getHeldItemMainhand()) && !applicator.isSameAs(player.getHeldItemOffhand())) {
return false;
}
TileEntity tile = player.world.getTileEntity(result.getBlockPos());
if (tile instanceof IColorableTile colorableTile) {
NetworkHandler.instance().sendToServer(new PacketColorApplicatorSelectColor(colorableTile.getColor()));
return true;
}
return false;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if ("onPickBlock".equals(name)) {
return new OnPickBlockVisitor(mv);
}
return mv;
}
private static class OnPickBlockVisitor extends MethodVisitor implements Opcodes {
public OnPickBlockVisitor(MethodVisitor mv) {
super(Opcodes.ASM5, mv);
}
@Override
public void visitCode() {
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(
INVOKESTATIC,
"appeng/core/transformer/PickBlockPatch",
"testColorApplicatorPickBlock",
"(Lnet/minecraft/util/math/RayTraceResult;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;)Z",
false);
mv.visitInsn(DUP);
Label exitLabel = new Label();
mv.visitJumpInsn(IFEQ, exitLabel);
mv.visitInsn(IRETURN);
mv.visitLabel(exitLabel);
}
}
}