Skip to content

Architecture

el211 edited this page Sep 9, 2026 · 1 revision

Architecture

GoCraft is built around a protocol-independent game core with edition-specific network adapters at the boundary.

Overview

Java Edition client ───▶  java/ adapter
                                │
                         ┌──────▼──────┐
                         │   core/     │  ← no Java or Bedrock imports
                         │  World      │
                         │  Entity     │
                         │  Player     │
                         └──────┬──────┘
                                │
Bedrock client ────────▶  bedrock/ adapter
  • core/ owns the edition-neutral game state: blocks, chunks, world, entities, players, inventories, and spatial types. It never imports java/ or bedrock/. This is enforced by a compile-time architecture test in core/world/arch_test.go.
  • java/ reads from core/ and produces native Java Edition packets: TCP framing, login auth, encryption, chunk encoding, and play-state management. It does not know Bedrock exists.
  • bedrock/ uses RakNet/UDP and optional Xbox authentication, translates canonical chunks to Bedrock block hashes, posts gameplay intents to the core, and synchronizes shared state back to every Bedrock session.
  • server/ wires configuration, the core, and the active adapters into the executable.

Block identity

The canonical block type carries no edition-specific IDs:

// core/world — shared by all adapters
type Block struct {
    Namespace  string            // "minecraft"
    Name       string            // "stone", "grass_block", …
    Properties map[string]string // {"snowy": "false"}, nil = default state
}

Edition-specific IDs are resolved entirely at the adapter boundary:

Canonical Block
       │
┌──────┴──────┐
▼             ▼
Java global   Bedrock runtime
state ID      ID

Only the encoder packages change when updating Java versions or adding new Bedrock support; core/ is untouched.

Registry abstraction

Known-packs negotiation and registry delivery sit behind a registry.Provider interface:

type Provider interface {
    Packs() []Pack
    SendRegistries(conn *network.ClientConn) error
}

VanillaProvider uses the Known-Packs shortcut (zero registry packets for vanilla 1.21.4). A future ExplicitProvider will send full registry data for custom dimensions and additional Java versions.

Not a translator

GoCraft is not a protocol translator like Geyser. The Bedrock adapter does not consume Java packets and re-encode them. Both adapters independently read from the same canonical game state and produce their own native wire format:

                    ┌─────────────────────────────┐
                    │         core/               │
                    │  World · Entity · Inventory │  ← no Java, no Bedrock
                    └────────────┬────────────────┘
                                 │ canonical state
               ┌─────────────────┴──────────────────┐
               ▼                                    ▼
   ┌───────────────────────┐          ┌───────────────────────┐
   │     java/ adapter     │          │   bedrock/ adapter    │
   │  native Java packets  │          │  native Bedrock packets│
   │  Java state IDs       │          │  Bedrock runtime IDs  │
   └───────────────────────┘          └───────────────────────┘
         Java client                       Bedrock client

This lets GoCraft evolve both protocol implementations independently, without the coupling issues proxy-based translators face.

Data-driven registries

Block states, item IDs, entity types, biomes, and packet IDs are loaded from versioned JSON at startup via go:embed (internal/gamedata/ and internal/protocoldata/). There are no hardcoded ID maps, which keeps version bumps localized to data files and encoders.

Intents and events

Adapters translate client input into edition-neutral intents posted to the core, and the core emits events (e.g. PlayerJoinEvent, BlockBreakEvent) consumed by plugins. Neither packets nor numeric protocol IDs are exposed to plugins. See Native Go Plugins.

See Project Structure for the full directory tour.

Clone this wiki locally