Skip to content

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

{  
   "version": "3.4.2",
   "ccp": {},
   "shadow": {  
      "enabled": true,
      "version": 1
   },
   "addons": []
}

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 );
    }
}