Shadow (AntiCheat)
Warning
Not available in LabyMod 4 and unstable in LabyMod 3!
Overview
By using this protocol called SHADOW you can access the client's movement input keys. This protocol provides you the ability to improve the server side anticheat!
Enabling the protocol
The client will send you this information on join in the labymod3:main
channel
Message key: INFO
The server should answer on the labymod3:shadow
channel just an id that is an integer.
Warning
We changed the plugin channel name from SHADOW
to labymod3:shadow
since LabyMod 3.8.0 to support the latest Minecraft 1.16 version
There are following valid id's:
0: Reset the packet counter to zero.
1: Enable the protocol for this client
2: Disable the protocol for this client
Now you can setup the pipeline transformer for the new protocol:
EntityPlayer entityPlayer = ( ( CraftPlayer ) player ).getHandle();
Channel channel = entityPlayer.playerConnection.networkManager.channel;
ChannelPipeline pipeline = channel.pipeline();
pipeline.addAfter( "decoder", "shadowpacketin", new PacketPlayerIn( ) );
Example code of server
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import net.minecraft.server.v1_8_R3.PacketDataSerializer;
import net.minecraft.server.v1_8_R3.PacketPlayInCustomPayload;
import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
import net.minecraft.server.v1_8_R3.PacketPlayInFlying.PacketPlayInLook;
import net.minecraft.server.v1_8_R3.PacketPlayInFlying.PacketPlayInPosition;
import net.minecraft.server.v1_8_R3.PacketPlayInFlying.PacketPlayInPositionLook;
public class PacketPlayerIn extends ChannelInboundHandlerAdapter {
@Override
public void channelRead( ChannelHandlerContext ctx, Object msg ) throws Exception {
// Is incoming packet a custom payload?
if ( msg instanceof PacketPlayInCustomPayload ) {
PacketPlayInCustomPayload packet = ( PacketPlayInCustomPayload ) msg;
// Is channel name labymod3:shadow?
String channel = packet.a();
if ( channel.equals( "labymod3:shadow" ) ) {
PacketDataSerializer data = packet.b();
// First byte is the shadow packet id
byte id = data.readByte();
switch ( id ) {
case 0x00: // PacketPlayInPosition
double x = data.readDouble();
double y = data.readDouble();
double z = data.readDouble();
boolean onGround = data.readBoolean();
PacketPlayInPosition packetPlayInPosition = new PacketPlayInPosition();
setValue( PacketPlayInFlying.class, packetPlayInPosition, "x", x );
setValue( PacketPlayInFlying.class, packetPlayInPosition, "y", y );
setValue( PacketPlayInFlying.class, packetPlayInPosition, "z", z );
setValue( PacketPlayInFlying.class, packetPlayInPosition, "f", onGround );
super.channelRead( ctx, packetPlayInPosition );
break;
case 0x01: // PacketPlayInLook
float yaw = data.readFloat();
float pitch = data.readFloat();
onGround = data.readBoolean();
PacketPlayInLook packetPlayInLook = new PacketPlayInLook();
setValue( PacketPlayInFlying.class, packetPlayInLook, "yaw", yaw );
setValue( PacketPlayInFlying.class, packetPlayInLook, "pitch", pitch );
setValue( PacketPlayInFlying.class, packetPlayInLook, "f", onGround );
super.channelRead( ctx, packetPlayInLook );
break;
case 0x02: // PacketPlayInPositionLook
x = data.readDouble();
y = data.readDouble();
z = data.readDouble();
yaw = data.readFloat();
pitch = data.readFloat();
onGround = data.readBoolean();
PacketPlayInPositionLook packetPlayInPositionLook = new PacketPlayInPositionLook();
setValue( PacketPlayInFlying.class, packetPlayInPositionLook, "x", x );
setValue( PacketPlayInFlying.class, packetPlayInPositionLook, "y", y );
setValue( PacketPlayInFlying.class, packetPlayInPositionLook, "z", z );
setValue( PacketPlayInFlying.class, packetPlayInPositionLook, "yaw", yaw );
setValue( PacketPlayInFlying.class, packetPlayInPositionLook, "pitch", pitch );
setValue( PacketPlayInFlying.class, packetPlayInPositionLook, "f", onGround );
super.channelRead( ctx, packetPlayInPositionLook );
break;
case 0x03: // PacketPlayInFlying
onGround = data.readBoolean();
PacketPlayInFlying packetPlayInFlying = new PacketPlayInFlying();
setValue( PacketPlayInFlying.class, packetPlayInFlying, "f", onGround );
super.channelRead( ctx, packetPlayInFlying );
break;
}
// Timestamp of client at this packet
long time = data.readLong();
// Read all movement inputs
double moveForward = data.readDouble();
double moveStrafe = data.readDouble();
boolean jump = data.readBoolean();
boolean sneak = data.readBoolean();
double x = data.readDouble();
double y = data.readDouble();
double z = data.readDouble();
float yaw = data.readFloat();
float pitch = data.readFloat();
boolean sprinting = data.readBoolean();
// Packet counter since join
int packetCounter = data.readInt();
// Handle data
handleInput( time, moveForward, moveStrafe, jump, sneak, x, y, z, yaw, pitch, sprinting, packetCounter );
// Cancel this packet
return;
}
}
// This packet can pass
super.channelRead( ctx, msg );
}
private void setValue( Class clazz, Object instance, String field, Object value ) throws Exception {
Field f = clazz.getDeclaredField( field );
f.setAccessible( true );
f.set( instance, value );
}
}