sean0x42 / mineshark

A (work in progress) packet sniffing proxy that sits between a Minecraft client and server. Essentially a MITM attack with custom middleware

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Change to a payload spec model in the packet registry

sean0x42 opened this issue · comments

Currently writing a packet's registry entry is a pretty exhausting task. Writing a reader and writer involves a LOT of duplication. See example:

Click to see a large example registry entry
Registry.register({
  id: 0x26,
  kind: PacketKind.JoinGame,
  source: PacketSource.Server,
  state: State.Play,

  read: (reader) => ({
    kind: PacketKind.JoinGame,
    payload: {
      entityId: reader.readInt(),
      isHardcore: reader.readBoolean(),
      gamemode: reader.readUnsignedByte(),
      previousGamemode: reader.readByte(),
      worlds: reader.readIdentifierArray(),
      dimensionCodec: reader.readNbt(),
      dimension: reader.readNbt(),
      worldName: reader.readString(),
      hashedSeed: reader.readLong(),
      maxPlayers: reader.readVarInt(),
      viewDistance: reader.readVarInt(),
      reducedDebugInfo: reader.readBoolean(),
      enableRespawnScreen: reader.readBoolean(),
      isDebug: reader.readBoolean(),
      isFlat: reader.readBoolean(),
    },
  }),

  write: (writer, packet) => {
    const payload = (packet as JoinGamePacket).payload;
    writer
      .writeInt(payload.entityId)
      .writeBoolean(payload.isHardcore)
      .writeUnsignedByte(payload.gamemode)
      .writeByte(payload.previousGamemode)
      .writeIdentifierArray(payload.worlds)
      .writeNbt(payload.dimensionCodec)
      .writeNbt(payload.dimension)
      .writeString(payload.worldName)
      .writeLong(payload.hashedSeed)
      .writeVarInt(payload.maxPlayers)
      .writeVarInt(payload.viewDistance)
      .writeBoolean(payload.reducedDebugInfo)
      .writeBoolean(payload.enableRespawnScreen)
      .writeBoolean(payload.isDebug)
      .writeBoolean(payload.isFlat);
  },
});

It would be fantastic if we moved towards a different model, where you define a specification for the packet's payload instead. Something like:

Registry.register({
  id: 0x26,
  kind: PacketKind.JoinGame,
  source: PacketSource.Server,
  state: State.Play,

  payload: {
    entityId: DataType.Int,
    isHardcore: DataType.Boolean,
    gamemode: DataType.UnsignedByte,
    // ...

    // Custom data types could provide a callback reader and writer like the old way
    worlds: {
      read(reader) { /* ... */ },
      write(writer, packet) { /* ... */ }
    },
    // ...

    // Optional trailing data could be denoted with an extra flag
    isFlat: {
      type: DataType.Boolean,
      optional: true
    }
  }
});