feat: ASM based packet abstraction
This commit is contained in:
parent
fcab7822fb
commit
a2f1d5f4c1
|
@ -76,6 +76,10 @@ processResources {
|
|||
task deobfJar(type: Jar) {
|
||||
from sourceSets.main.output
|
||||
classifier = 'deobf'
|
||||
|
||||
manifest {
|
||||
attributes "FMLAT": "anvillib_at.cfg"
|
||||
}
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
|
|
|
@ -10,9 +10,7 @@ import cpw.mods.fml.common.SidedProxy;
|
|||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLServerStoppedEvent;
|
||||
import cpw.mods.fml.common.network.NetworkRegistry;
|
||||
import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import net.anvilcraft.anvillib.network.AnvilChannel;
|
||||
import net.anvilcraft.anvillib.network.PacketUpdateUserCache;
|
||||
import net.anvilcraft.anvillib.proxy.CommonProxy;
|
||||
import net.anvilcraft.anvillib.usercache.UserCache;
|
||||
|
@ -30,7 +28,7 @@ public class AnvilLib {
|
|||
)
|
||||
public static CommonProxy proxy;
|
||||
|
||||
public static SimpleNetworkWrapper channel;
|
||||
public static AnvilChannel channel;
|
||||
|
||||
@EventHandler
|
||||
public static void preInit(FMLPreInitializationEvent ev) {
|
||||
|
@ -43,14 +41,8 @@ public class AnvilLib {
|
|||
new Thread(() -> proxy.saveUserCache(UserCache.INSTANCE))
|
||||
);
|
||||
|
||||
channel = NetworkRegistry.INSTANCE.newSimpleChannel("anvillib");
|
||||
int pktid = 0;
|
||||
channel.registerMessage(
|
||||
PacketUpdateUserCache.Handler.class,
|
||||
PacketUpdateUserCache.class,
|
||||
pktid++,
|
||||
Side.CLIENT
|
||||
);
|
||||
channel = new AnvilChannel("anvillib");
|
||||
channel.register(PacketUpdateUserCache.class);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package net.anvilcraft.anvillib.asm;
|
||||
|
||||
/**
|
||||
* A simple wrapper around the current ClassLoader to allow defining classes manually.
|
||||
*/
|
||||
public class ASMClassLoader extends ClassLoader {
|
||||
public static final ASMClassLoader INSTANCE = new ASMClassLoader();
|
||||
|
||||
private ASMClassLoader() {
|
||||
super(ASMClassLoader.class.getClassLoader());
|
||||
}
|
||||
|
||||
public Class<?> define(String name, byte[] code) {
|
||||
return super.defineClass(name, code, 0, code.length);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package net.anvilcraft.anvillib.network;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
|
||||
import net.anvilcraft.alec.jalec.factories.AlecCriticalRuntimeErrorExceptionFactory;
|
||||
import net.anvilcraft.anvillib.asm.ASMClassLoader;
|
||||
|
||||
public class AnvilChannel extends SimpleNetworkWrapper {
|
||||
private int nextID;
|
||||
|
||||
public AnvilChannel(String channelName) {
|
||||
super(channelName);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "ALEC" })
|
||||
public void register(Class<? extends IAnvilPacket> clazz) {
|
||||
AnvilPacket anno = clazz.getAnnotation(AnvilPacket.class);
|
||||
if (anno == null)
|
||||
throw AlecCriticalRuntimeErrorExceptionFactory.PLAIN.createAlecException(
|
||||
"Packet class", clazz, "is missing AnvilPacket annotation!"
|
||||
);
|
||||
|
||||
String name
|
||||
= "net.anvilcraft.asm." + clazz.getName().replace('.', '_') + "#EventHandler";
|
||||
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(
|
||||
V1_6,
|
||||
ACC_PUBLIC | ACC_SUPER,
|
||||
name.replace('.', '/'),
|
||||
null,
|
||||
"java/lang/Object",
|
||||
new String[] { Type.getInternalName(IMessageHandler.class) }
|
||||
);
|
||||
cw.visitSource("alechoefler.java", null);
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(
|
||||
ACC_PUBLIC,
|
||||
"onMessage",
|
||||
"(Lcpw/mods/fml/common/network/simpleimpl/IMessage;Lcpw/mods/fml/common/network/simpleimpl/MessageContext;)Lcpw/mods/fml/common/network/simpleimpl/IMessage;",
|
||||
null,
|
||||
null
|
||||
);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(
|
||||
INVOKEINTERFACE,
|
||||
"net/anvilcraft/anvillib/network/IAnvilPacket",
|
||||
"handle",
|
||||
"(Lcpw/mods/fml/common/network/simpleimpl/MessageContext;)V",
|
||||
true
|
||||
);
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(2, 3);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
Class<?> handlerClass = ASMClassLoader.INSTANCE.define(name, cw.toByteArray());
|
||||
|
||||
try {
|
||||
this.registerMessage(
|
||||
(IMessageHandler<IAnvilPacket, IMessage>) handlerClass.newInstance(),
|
||||
clazz,
|
||||
this.nextID++,
|
||||
anno.value()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
throw AlecCriticalRuntimeErrorExceptionFactory.PLAIN
|
||||
.createAlecExceptionWithCause(e, "Failed to instantiate ASM'd class");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package net.anvilcraft.anvillib.network;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
/**
|
||||
* This annotation must be present on every AnvilLib packet to declare metadata about it.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnvilPacket {
|
||||
/**
|
||||
* The side the packet is sent to.
|
||||
*/
|
||||
public Side value();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package net.anvilcraft.anvillib.network;
|
||||
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
public interface IAnvilPacket extends IMessage {
|
||||
public void handle(MessageContext ctx);
|
||||
}
|
|
@ -5,13 +5,14 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.anvilcraft.alec.jalec.AlecLogger;
|
||||
import net.anvilcraft.anvillib.usercache.UserCache;
|
||||
|
||||
public class PacketUpdateUserCache implements IMessage {
|
||||
@AnvilPacket(Side.CLIENT)
|
||||
public class PacketUpdateUserCache implements IAnvilPacket {
|
||||
public Map<UUID, String> entries;
|
||||
|
||||
public PacketUpdateUserCache(Map<UUID, String> entries) {
|
||||
|
@ -47,12 +48,9 @@ public class PacketUpdateUserCache implements IMessage {
|
|||
}
|
||||
}
|
||||
|
||||
public static class Handler
|
||||
implements IMessageHandler<PacketUpdateUserCache, IMessage> {
|
||||
@Override
|
||||
public IMessage onMessage(PacketUpdateUserCache pkt, MessageContext arg1) {
|
||||
UserCache.INSTANCE.users.putAll(pkt.entries);
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void handle(MessageContext ctx) {
|
||||
UserCache.INSTANCE.users.putAll(this.entries);
|
||||
AlecLogger.PLAIN.alec("AAAAALEEEEEC");
|
||||
}
|
||||
}
|
||||
|
|
10
src/main/java/net/anvilcraft/anvillib/util/AnvilUtil.java
Normal file
10
src/main/java/net/anvilcraft/anvillib/util/AnvilUtil.java
Normal file
|
@ -0,0 +1,10 @@
|
|||
package net.anvilcraft.anvillib.util;
|
||||
|
||||
public class AnvilUtil {
|
||||
public static <T extends Enum<T>> T enumFromInt(Class<T> clazz, int n) {
|
||||
T[] values = clazz.getEnumConstants();
|
||||
if (n < 0 || n >= values.length)
|
||||
return null;
|
||||
return values[n];
|
||||
}
|
||||
}
|
155
src/main/java/net/anvilcraft/anvillib/vector/Vec3.java
Normal file
155
src/main/java/net/anvilcraft/anvillib/vector/Vec3.java
Normal file
|
@ -0,0 +1,155 @@
|
|||
package net.anvilcraft.anvillib.vector;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
/**
|
||||
* A 3-Dimensional vector represented as 3 doubles.
|
||||
*/
|
||||
public class Vec3 {
|
||||
public double x;
|
||||
public double y;
|
||||
public double z;
|
||||
|
||||
public Vec3(Vec3 vec) {
|
||||
this.x = vec.x;
|
||||
this.y = vec.y;
|
||||
this.z = vec.z;
|
||||
}
|
||||
|
||||
public Vec3(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vec3(Entity ent) {
|
||||
this(ent.posX, ent.posY, ent.posZ);
|
||||
}
|
||||
|
||||
public Vec3(TileEntity te) {
|
||||
this(te.xCoord, te.yCoord, te.zCoord);
|
||||
}
|
||||
|
||||
public Vec3(MovingObjectPosition mop) {
|
||||
this(mop.blockX, mop.blockY, mop.blockZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads this Vec3 from a byte buf.
|
||||
*
|
||||
* @see writeToByteBuf
|
||||
*/
|
||||
public static Vec3 readFromByteBuf(ByteBuf buf) {
|
||||
return new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble());
|
||||
}
|
||||
|
||||
public int intX() {
|
||||
return (int) Math.floor(this.x);
|
||||
}
|
||||
|
||||
public int intY() {
|
||||
return (int) Math.floor(this.y);
|
||||
}
|
||||
|
||||
public int intZ() {
|
||||
return (int) Math.floor(this.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this Vec3 to a WorldVec, adding a given world.
|
||||
*/
|
||||
public WorldVec withWorld(World world) {
|
||||
return new WorldVec(world, this.x, this.y, this.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes this Vec3 to a byte buffer.
|
||||
*
|
||||
* @see readFromByteBuf
|
||||
*/
|
||||
public void writeToByteBuf(ByteBuf buf) {
|
||||
buf.writeDouble(this.x);
|
||||
buf.writeDouble(this.y);
|
||||
buf.writeDouble(this.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offsets this BlockVec in the given direction by the given amount.
|
||||
*
|
||||
* @param dir The direction to move in.
|
||||
* @param amt The amount to move by.
|
||||
*
|
||||
* @return this. This BlockVec is also modified.
|
||||
*/
|
||||
public Vec3 offset(ForgeDirection dir, double amt) {
|
||||
this.x += dir.offsetX * amt;
|
||||
this.y += dir.offsetY * amt;
|
||||
this.z += dir.offsetZ * amt;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offsets this BlockVec by one block in the given direction.
|
||||
*
|
||||
* @param dir The direction to move in.
|
||||
*
|
||||
* @return this. This BlockVec is also modified.
|
||||
*/
|
||||
public Vec3 offset(ForgeDirection dir) {
|
||||
return this.offset(dir, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the Vec3 by the given offset. Modifies this.
|
||||
*/
|
||||
public Vec3 offset(double x, double y, double z) {
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
this.z += z;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the Vec3 by the given vector. Modifies this.
|
||||
*/
|
||||
public Vec3 offset(Vec3 other) {
|
||||
return this.offset(other.x, other.y, other.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(x);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(y);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(z);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Vec3 other = (Vec3) obj;
|
||||
if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
|
||||
return false;
|
||||
if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
|
||||
return false;
|
||||
if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
98
src/main/java/net/anvilcraft/anvillib/vector/WorldVec.java
Normal file
98
src/main/java/net/anvilcraft/anvillib/vector/WorldVec.java
Normal file
|
@ -0,0 +1,98 @@
|
|||
package net.anvilcraft.anvillib.vector;
|
||||
|
||||
import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* An extension of a Vec3 that also includes a World.
|
||||
*/
|
||||
public class WorldVec extends Vec3 {
|
||||
public World world;
|
||||
|
||||
public WorldVec(WorldVec wv) {
|
||||
super(wv);
|
||||
this.world = wv.world;
|
||||
}
|
||||
|
||||
public WorldVec(World world, double x, double y, double z) {
|
||||
super(x, y, z);
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public WorldVec(World world, Vec3 vec) {
|
||||
super(vec);
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public WorldVec(Entity ent) {
|
||||
super(ent);
|
||||
this.world = ent.worldObj;
|
||||
}
|
||||
|
||||
public WorldVec(TileEntity te) {
|
||||
super(te);
|
||||
this.world = te.getWorldObj();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block at the position pointed to by this vector.
|
||||
*/
|
||||
public Block getBlock() {
|
||||
return this.world.getBlock(this.intX(), this.intY(), this.intZ());
|
||||
}
|
||||
|
||||
public int getBlockMeta() {
|
||||
return this.world.getBlockMetadata(this.intX(), this.intY(), this.intZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tile entity at the position pointed to by this vector.
|
||||
*/
|
||||
public TileEntity getTileEntity() {
|
||||
return this.world.getTileEntity(this.intX(), this.intY(), this.intZ());
|
||||
}
|
||||
|
||||
public void markForUpdate() {
|
||||
this.world.markBlockForUpdate(this.intX(), this.intY(), this.intZ());
|
||||
}
|
||||
|
||||
public void markForRenderUpdate() {
|
||||
this.world.markBlockRangeForRenderUpdate(
|
||||
this.intX(), this.intY(), this.intZ(), this.intX(), this.intY(), this.intZ()
|
||||
);
|
||||
}
|
||||
|
||||
public TargetPoint targetPoint(double range) {
|
||||
return new TargetPoint(
|
||||
this.world.provider.dimensionId, this.x, this.y, this.z, range
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((world == null) ? 0 : world.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
WorldVec other = (WorldVec) obj;
|
||||
if (world == null) {
|
||||
if (other.world != null)
|
||||
return false;
|
||||
} else if (world != other.world)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue