Claude Code Plugins

Community-maintained marketplace

Feedback

Create a new packet analyzer for Minecraft Bedrock logs. Generates template code, provides documentation links, and guides testing workflow.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name create-analyzer
description Create a new packet analyzer for Minecraft Bedrock logs. Generates template code, provides documentation links, and guides testing workflow.
allowed-tools Read, Write, Glob, Grep, Bash

Create Minecraft Bedrock Packet Analyzer

Generate a new domain-specific packet analyzer for analyzing captured Bedrock packets.

Quick Start

  1. Identify the domain: inventory, movement, entities, chat, blocks, etc.
  2. Find relevant packets: Search protocol.d.ts for packet types
  3. Generate analyzer file using template below
  4. Export from index.ts
  5. Test with captured logs

Analyzer Template

Create file at: packages/minecraft-logs-analyzers/src/analyzers/{domain}.ts

import { BaseAnalyzer } from "../base-analyzer.ts";
import type { Direction, LogEntry, AnalyzerConfig } from "../types.ts";

const PACKETS_TO_LOG = [
  // Add packet names from protocol.d.ts
];

/**
 * Analyzer for {domain}-related packets.
 */
export class {Domain}Analyzer extends BaseAnalyzer {
  readonly config: AnalyzerConfig = {
    name: "{domain}",
    packets: PACKETS_TO_LOG,
  };

  constructor(basePath: string, registry?: any) {
    super(basePath);
    if (registry) this.registry = registry;
    this.init();
  }

  protected extractFields(
    direction: Direction,
    name: string,
    packet: any
  ): LogEntry | null {
    const base = this.createBaseEntry(direction, name);

    switch (name) {
      // Add case for each packet type
      // case "packet_name":
      //   return { ...base, field: packet.field };

      default:
        return null;
    }
  }
}

Registration

Add export to packages/minecraft-logs-analyzers/src/index.ts:

export { {Domain}Analyzer } from "./analyzers/{domain}.ts";

Documentation Locations

Resource Location
Protocol types packages/mineflayer-bedrock/src/protocol.d.ts
Existing analyzers packages/minecraft-logs-analyzers/src/analyzers/
Base class packages/minecraft-logs-analyzers/src/base-analyzer.ts
Types packages/minecraft-logs-analyzers/src/types.ts
Bedrock plugins packages/mineflayer/lib/bedrockPlugins/

Finding Relevant Packets

# Search protocol.d.ts for packet types
grep -n "packet_" packages/mineflayer-bedrock/src/protocol.d.ts | head -50

# Find packets used by a specific plugin
grep -n "client.on" packages/mineflayer/lib/bedrockPlugins/*.mts

# Search for specific packet handling
grep -rn "move_player" packages/mineflayer/lib/bedrockPlugins/

Common Packet Domains

Domain Key Packets
Inventory inventory_slot, inventory_content, inventory_transaction, item_stack_request, item_stack_response, mob_equipment
Movement player_auth_input, move_player, set_actor_motion, move_actor_absolute, move_actor_delta
Entities add_entity, remove_entity, set_entity_data, set_entity_motion, add_player
Chat text, command_request, command_output
Blocks update_block, block_event, level_event, update_sub_chunk_blocks
Combat actor_event, hurt_armor, entity_fall, animate
World level_chunk, sub_chunk, network_chunk_publisher_update

Testing Workflow

1. Capture Packets from Real Client

Critical: Always capture from the real Minecraft client first to understand the exact packet format.

# Start capture proxy
npm run start --workspace=minecraft-logs-recorder -- -o ./test-logs

# Connect Minecraft Bedrock to localhost:19150
# Perform the exact action you want to implement (crafting, chest interaction, etc.)
# Disconnect to save logs

The .jsonl file contains processed packets, .bin contains raw data for replay.

2. Analyze Captured Logs

# View first 20 packets
head -20 test-logs/*.jsonl

# Count packets by type
grep -o '"p":"[^"]*"' test-logs/*.jsonl | sort | uniq -c | sort -rn

# Find specific packets
grep '"p":"move_player"' test-logs/*.jsonl | head -5

3. Test Your Analyzer

import { {Domain}Analyzer } from 'minecraft-logs-analyzers';
import { createReplayClient } from 'minecraft-logs-recorder/replay';

// Attach analyzer to replay client
const analyzer = new {Domain}Analyzer('test-output/replay');
const client = createReplayClient('test-logs/1.21.130-*.bin');

// Analyzer will log packets to test-output/replay-{domain}.jsonl
analyzer.attachToBot(client);

// Check output
// cat test-output/replay-{domain}.jsonl

4. Verify Output Format

# View analyzer output
cat test-output/replay-{domain}.jsonl | head -10

# Validate JSON
cat test-output/replay-{domain}.jsonl | jq -c '.' | head -10

BaseAnalyzer Methods

Method Description
createBaseEntry(direction, name) Create log entry with t, tick, d, p fields
updateTick(packet) Extract tick from packet.tick
itemName(item) Resolve item name from network_id
writeEntry(entry) Write entry to JSONL file
message(msg, data?) Log custom debug message

Override Points

Method When to Override
shouldLog(name, packet) Custom filtering (e.g., only log non-empty actions)
extractFields(direction, name, packet) Required - extract relevant fields

IMPORTANT: Start with Full Packets

Always log full packet data initially, not filtered/summarized data. This was critical for solving crafting implementation:

// BAD: Filtering too early loses critical details
protected shouldLog(name: string, packet: unknown): boolean {
  // Only log if it has crafting containers...  ❌
  return hasCraftingContainer;
}

// GOOD: Log everything first, filter later
protected shouldLog(name: string, packet: unknown): boolean {
  return true;  // ✅ See all packets first
}

// GOOD: Return full packet data in extractFields
return {
  ...base,
  responses: p.responses,  // ✅ Full data, not summarized
};

Real client packet captures revealed crucial details that were being filtered out:

  • craft_recipe_auto uses hotbar_and_inventory container, not crafting_input
  • results_deprecated action requires result_items array with full item data
  • Stack IDs use negative request_id for chained actions
  • place goes directly to inventory, not through cursor

Only add filtering after you fully understand the protocol.

Example: Movement Analyzer

import { BaseAnalyzer } from "../base-analyzer.ts";
import type { Direction, LogEntry, AnalyzerConfig } from "../types.ts";

const PACKETS_TO_LOG = [
  "player_auth_input",
  "move_player",
  "set_actor_motion",
];

export class MovementAnalyzer extends BaseAnalyzer {
  readonly config: AnalyzerConfig = {
    name: "movement",
    packets: PACKETS_TO_LOG,
  };

  constructor(basePath: string) {
    super(basePath);
    this.init();
  }

  protected extractFields(
    direction: Direction,
    name: string,
    packet: any
  ): LogEntry | null {
    const base = this.createBaseEntry(direction, name);

    switch (name) {
      case "player_auth_input":
        this.updateTick(packet);
        return {
          ...base,
          tick: packet.tick,
          pos: [packet.position?.x, packet.position?.y, packet.position?.z],
          yaw: packet.yaw,
          pitch: packet.pitch,
        };

      case "move_player":
        return {
          ...base,
          pos: [packet.position?.x, packet.position?.y, packet.position?.z],
          mode: packet.mode,
          onGround: packet.on_ground,
        };

      case "set_actor_motion":
        return {
          ...base,
          entityId: packet.runtime_entity_id,
          velocity: [packet.velocity?.x, packet.velocity?.y, packet.velocity?.z],
        };

      default:
        return null;
    }
  }
}