Skip to content

Repository files navigation

go-metin2-server

Clean-room Metin2 server emulator in Go, targeting TMP4-era client compatibility.

This repository is a public rewrite built around owned protocol documentation, small verified slices, and a gradual path from a stable boot flow to a real shared-world game server. It intentionally avoids copying legacy source code: legacy trees and captures are treated only as external behavior oracles.

Status at a glance

go-metin2-server is pre-alpha. It is not a playable legacy-compatible server yet, but it is also no longer just a packet experiment. The repository currently has:

  • real authd and gamed daemon entrypoints,
  • a secure legacy handshake and login/select/game boot path,
  • a shared in-process world runtime,
  • protocol codecs and fixtures for the owned packet families,
  • real-client-oriented integration tests around movement, visibility, chat, items, shops, combat, death, restart, and respawn slices,
  • local operator/debug endpoints for runtime inspection, controlled bootstrap actions, static-actor respawn timer plus spawn-group snapshot/map-occupancy/transfer visibility inspection, and strict manifest-backed item-template/account-store backup/restore preflights.

Current repository shape from the latest scan:

  • Go version: 1.26
  • Go packages: 38
  • Go files: 122
  • Go test files: 67
  • Markdown docs: 115
  • protocol docs under spec/protocol: 68
  • CI: GitHub Actions runs gofmt, go test ./..., go vet ./..., daemon builds, and Docker runtime/debug builds

Legend used below:

  • [x] implemented enough for the current milestone
  • [~] partial / bootstrap / intentionally narrow
  • [ ] not started or not compatibility-grade yet

Milestone ladder

  • [x] M0 — Protocol-owned boot path

    • Frame parsing, session phases, secure legacy handshake, auth/login, character selection, loading, enter-game, initial character/point bootstrap, and basic control packets are owned by Go code, protocol docs, and tests.
  • [~] M1 — Shared-world pre-alpha

    • Multiple players can exist in the same in-process world, see each other, move, sync position, talk locally, receive notices, route whispers by exact name, transfer through bootstrap map seams, reconnect/cleanup, and rebuild visibility. It is still a single-process bootstrap runtime, not a production channel/shard architecture.
  • [~] M2 — World/entity runtime foundation

    • The repo has topology, map indexing, AOI/radius-style visibility, player/session directories, entity registries, non-player directories, static actors, spawn groups, runtime scopes, and operator snapshots. Directory and map-index repair paths prune or suppress stale player/static lookup and occupancy remnants after partial teardown instead of leaking ghost actors into visibility/scope readers; ambiguous map-only collisions fail closed, while directory-only player/static collisions are suppressed from snapshot/scope and secondary lookup paths without deleting explicit cleanup handles. Player names now share a runtime-owned fail-closed validator before directory or map-index insertion, matching the account/login-ticket persistence boundary for whitespace, NUL, and UTF-8 rejection. Static-actor names now share one runtime-owned fail-closed validator across worldruntime, persistence, and minimal runtime paths; static-actor entity IDs are validated against the same uint32 visibility-VID carrier used by client-visible actor packets before runtime registration or snapshot restore. The next work is depth: richer lifecycle, better spawn policy, stronger transfer/reconnect edges, and long-running production behavior.
  • [~] M3 — Character, inventory, and item systems

    • Inventory/equipment bootstrap, carried item movement, counted split/merge, quickslot edits, consumable use, ITEM_USE_TO_ITEM stack merging with count-only target refreshes, item dropping, ground visibility, pickup, merchant buy/sell, gold mutation, template-backed peer gold-marker anti_give rejection, and item/quickslot persistence slices exist. Full legacy item semantics are still not done: sockets, attributes, refine, anti-flag breadth, storage, trade, ownership timers, and compatibility-grade DB persistence remain future work.
  • [~] M4 — NPCs, shops, static actors, and authored content

    • Static actors can be authored, inspected, imported/exported, and connected to info, talk, warp, and shop_preview definitions. Shops have structured catalogs and first buy/sell behavior. Spawn groups can materialize stationary practice mobs with bootstrap combat profiles and reward descriptors, including canonical portable combat_profiles snapshots that validation can register before spawn validation, and import previews now report exact added/removed/changed portable combat-profile rows plus per-map static-actor/spawn-group rows before replacement. The loopback runtime also exposes filtered spawn-group snapshots as a flat list, per-map occupancy subsets, per-player visibility subsets, and structured relocation preview/transfer visibility deltas for local QA. This is a useful content seam, not a complete quest/NPC/content scripting system.
  • [~] M5 — Combat, mobs, death, restart, and rewards

    • Target selection, normal attack ingress, cadence gates, runtime HP, dead-state rejection, delayed respawn, aggro-lite engagement ownership, retaliation, player death floor, restart-here/restart-town bootstrap recovery, deterministic EXP/gold rewards, and fixed drop-vnum reward seams exist for practice mobs. Real combat formulas, skills, PvP, mob AI, chase/leash/return, loot tables, and full revive choreography are not compatibility-grade yet.
  • [~] M6 — Operations and developer workflow

    • The project has a Makefile, Dockerfile, CI, pprof/debug mux, health endpoint, local-only runtime-config/player/visibility/map/content endpoints, exact per-map occupancy lookup, static-actor respawn timer inspection, global and per-player spawn-group snapshot inspection, strict manifest-backed account-store and item-template backup validation, and development/testing/debugging docs. The runtime-config endpoint exposes the active bootstrap visibility/AOI policy (whole_map vs radius) so local QA can inspect daemon state without reading environment variables. It still needs release/versioning policy, production deployment docs, migrations, broader admin tooling, and multi-channel ops maturity.
  • [ ] M7 — Legacy parity / production server

    • Not started as a claim. The current goal is to keep landing small verified compatibility slices until the server can support a narrow playable vertical, then broaden toward legacy-grade systems.

Subsystem status

Foundation and workflow

Status: [x] strong for a pre-alpha repo.

Already present:

  • Go module with daemon entrypoints in cmd/authd and cmd/gamed.
  • Clean internal/* package boundaries for protocol, session flow, stores, world runtime, minimal integrated runtime, and ops.
  • Makefile targets for format, test, build, and Docker image builds.
  • GitHub Actions CI for formatting, tests, vet, daemon builds, and Docker builds.
  • Development, workflow, testing, QA, debugging/profiling, and clean-room policy docs.

Still missing:

  • release/versioning policy,
  • production deployment guide outside the current lab environment,
  • issue/contribution taxonomy,
  • migration/backup/recovery workflow beyond the current local account-store and item-template backup/validation primitives.

Protocol and boot path

Status: [x] owned for the current milestone, [~] incomplete for full legacy coverage.

Already present:

  • frame envelope and stream handling,
  • session phase model,
  • control handshake, phase, ping/pong, and key exchange,
  • auth/login/select/loading/game entry choreography,
  • character delete/select/bootstrap updates,
  • movement, sync, chat, whisper, notice, item, quickslot, interaction, shop, combat, and world packet families needed by current slices,
  • packet docs in spec/protocol/ with a maintained index.

Still missing:

  • many packet families outside the current verticals,
  • deeper evidence for uncertain client behaviors,
  • skill, quest, party/guild, messenger, trade/storage, player-shop, GM/admin, and broader world-event ownership.

Auth, login, and selection

Status: [x] bootstrap-compatible.

Already present:

  • authd and gamed sockets,
  • secure legacy handshake coverage,
  • login ticket flow,
  • account/character snapshot loading,
  • selection and enter-game transitions,
  • character delete in selection,
  • tolerated client-version path during loading.

Still missing:

  • real account database integration,
  • production authentication policy,
  • account/session security hardening beyond the current clean-room bootstrap,
  • multi-channel selection/dispatch semantics.

Shared world, visibility, maps, and transfer

Status: [~] real in-process runtime, not production world architecture.

Already present:

  • connected session registry,
  • player directory and map index, including tolerant player/static partial-teardown repair when one owned index is cleared before another and direct per-map or connected-player scope readers need to prune, rehome, or repair ghost buckets before returning occupancy/visibility; duplicate map-only repairs preserve remembered effective-map buckets before older stale source buckets when that effective-map memory survived primary-index loss,
  • topology model,
  • AOI/radius-style visibility boundaries,
  • visibility rebuild helpers,
  • local chat/move/sync peer fanout,
  • map relocation and transfer bootstrap paths,
  • reconnect/quit/logout cleanup,
  • player list, map, visibility, transfer, and relocate operator views/actions.

Still missing:

  • production channel/shard ownership,
  • long-running resource/concurrency policy,
  • richer sector behavior,
  • robust multi-map content lifecycle,
  • world-state persistence and crash recovery.

Character, inventory, equipment, and quickslots

Status: [~] broad bootstrap coverage with many legacy details still pending.

Already present:

  • carried inventory/equipment bootstrap replay,
  • item set/delete/update refreshes, including selected-character ITEM_SET projection of the currently owned authored item flag metadata (refineable, save, stackable, sell_count_per_gold, slow_query, rare, unique, make_count, irremovable, confirm_when_use, quest_use, quest_use_multiple, log, and applicable), anti-flag metadata (anti_get, transfer/job/sex/empire guards, stack guard, and storage/shop metadata bits anti_save, anti_pk_drop, anti_myshop, and anti_safebox), display socket/attribute metadata, and template-authored highlight hints while leaving unowned bits zero; partial-stack consumable, compatible merchant/drag-to-item/pickup merge, counted-drop, and compatible carried ITEM_MOVE merge ITEM_UPDATE refreshes preserve authored display sockets/attributes while updating only the count; incompatible occupied-destination carried ITEM_MOVE swaps now require both authored templates when an item-template snapshot is loaded, reject source/target live counts already above authored max_count, and project each resolved template's metadata into the swapped ITEM_SET refreshes,
  • item move, swap, split, and merge cases,
  • fail-closed item-template validation for malformed equipment metadata, missing or null template collections, embedded-NUL template names, oversized merchant sell prices, and unguarded authored pickup rejection text, including snapshots that combine stackable item semantics with an authored equip_slot,
  • stack compatibility checks and max-stack guards for current slices,
  • locked source/target and duplicate occupancy rejection paths,
  • template-backed equip/unequip point-effect application and removal guards, including signed equip-effect penalties, authored irremovable equipment unequip rejection with template-authored unequip_reject_message info-chat feedback, fail-closed rejection when live equipment-source counts exceed authored template max_count, and visible appearance projection for equipped body, weapon, head, and hair items,
  • consumable item use, including template-authored signed use_effect.point_delta values so authored negative consumables can emit self-only point decreases, optional use_effect.consume_count values so multi-count consumables decrement authored stack units instead of a runtime-hardcoded single item, optional use_effect.info_message text for the successful-use self-only info-chat placeholder, embedded-NUL rejection for use_effect.message / use_effect.info_message text at item-template load time, and optional use_reject_message text for guarded direct-use rejection feedback that is emitted before any hypothetical point delta from the rejected item would be applied; signed point overflow/underflow, overdrawn consume-count requests, and confirm_when_use, quest_use, quest_use_multiple, or applicable consumables fail closed,
  • ITEM_USE_TO_ITEM stack merge behavior,
  • quickslot add/delete/swap persistence, including rejection of item quickslot bindings to malformed or locked carried items, type-scoped retarget cleanup when an item/skill/command tuple is rebound to a new bar position, type-none clear hardening that rejects non-zero stale payload bytes, and fail-closed file-backed snapshot validation for duplicate non-item skill/command tuple bindings,
  • quickslot cleanup and retargeting when item mutations remove, move, or fully merge a source slot, including the bootstrap /inventory_move compatibility seam, while stale/reclaimed item-drop sockets remain self-local and cannot register bootstrap ground handles or overwrite the fresh authoritative item/quickslot snapshot,
  • basic persisted account/character snapshots, including fail-closed validation for malformed carried/equipped item instances, duplicate per-character item instance IDs, duplicate equipped-slot occupancy, and duplicate carried-slot occupancy on account save and login-ticket issue/load before new snapshots or login tickets become authoritative.

Still missing:

  • full item-type behavior,
  • sockets, attributes, refine, metin stones, bonus changers, books/scroll families,
  • complete anti-flag/class/sex/level/equipment restrictions,
  • storage/safebox/mall,
  • player trade/exchange and player shops,
  • compatibility-grade database persistence.

Ground items, pickup, gold, and merchant economy

Status: [~] useful first vertical, not a real economy yet.

Already present:

  • carried item drop and counted drop with template-authored transfer/selected-character guards, including anti_stack, template-authored drop-rejection info messages for transfer guards and authored selected-character restrictions, plus fail-closed deterministic ground-VID collision guards before item or persistence mutation,
  • temporary ground handles,
  • ground-item visibility to peers in scope,
  • ITEM_GROUND_ADD encoding now uses the TMP4-compatible client-facing payload order x/y/z/vid/vnum,
  • pickup into inventory with stack-merge behavior, valid authored equipment-template pickup as carried items rather than auto-equip, and guarded template-authored pickup-rejection info text for transfer/selected-character restriction failures,
  • first owner-delivery/notice shape for pickups,
  • merchant preview/catalog/open/close/buy/sell slices, including GC::SHOP START catalog entries backed by template-authored display sockets/attributes, refresh-only merchant-buy success bursts shared by packet SHOP BUY and the local /shop_buy debug harness, template-authored shop_sell_price sell-back credit before derived price/tax fallback, template-authored anti_get plus selected-character buy rejection info text, template-authored anti_sell fallback/info text plus authored anti_get / anti_drop / anti_give / anti_stack sell rejection text, selected-character sell rejection info text, malformed carried-item, over-template-max, sell-credit carrier overflow, and resulting-gold carrier overflow fail-closed sell-back rejection, and partial-stack sell ITEM_UPDATE refreshes that preserve authored display sockets/attributes,
  • gold mutation for current merchant and reward cases.

Still missing:

  • durable ground ownership timers,
  • party ownership rules based on real party state,
  • drop permission transitions,
  • complete merchant edge cases and shop variants,
  • NPC-driven service breadth,
  • real economy balancing and persistence.

Static actors, NPCs, shops, and content authoring

Status: [~] authored bootstrap content seam.

Already present:

  • static actor store,
  • interaction definition store,
  • info, talk, warp, and shop_preview interaction kinds, with static-actor runtime validation now rejecting unsupported interaction kinds before they can be registered or updated and dead visible interactables now failing closed with a self-only info-chat response instead of resolving authored content,
  • fail-closed static-actor visibility identity validation: entity_id must fit the current uint32 client-visible VID carrier and race_num must fit the current uint16 CHARACTER_ADD projection,
  • structured merchant catalogs,
  • content bundle import/export with commit-only live visibility replay for static-actor replacement, fail-closed rejection of unsupported future interaction kinds in static-actor metadata, and import-preview deltas that include top-level counts, per-map static actor/spawn-group rows, portable combat-profile rows, grouped reward-drop rows, NPC service route rows, and authored warp destination rows,
  • loopback-only local endpoints for static actors, interactions, visibility, and content bundles, including Unicode-safe compact summaries with interaction-definition previews, shop catalog details, warp destination details, and import-preview deltas for portable combat-profile snapshots plus grouped reward-drop and warp-destination changes,
  • example bootstrap NPC service bundle.

Still missing:

  • quest runtime,
  • scripted triggers/results,
  • richer NPC service kinds,
  • live content reload policy,
  • content validation tooling beyond current store/bundle checks,
  • compatibility-grade regen/drop table ingestion.

Non-player entities, mobs, combat, death, and rewards

Status: [~] first PvE loop exists around practice mobs.

Already present:

  • non-player entity directory,
  • static/non-player combat profiles,
  • target selection, client-originated silent target clear, normal attack packet ingress, and game-flow rejection of unsupported attack types before runtime mutation,
  • selected-target snapshot/version checks,
  • loopback combat-target introspection for selected-target ownership and HP debugging,
  • no-op content-bundle reimports and failed replacement rollbacks that preserve live practice-mob HP, selected-target ownership, combat snapshot/respawn state, and visibility state when authored content has not committed,
  • HP mutation and HP percent refreshes,
  • self and visible-peer DAMAGE_INFO hit-effect emission for standalone bootstrap combat-profile and spawn-backed practice-mob non-lethal hits, while broader hit-result policy remains narrow,
  • dead-state rejection and target clear,
  • delayed respawn rebuild path with combat-profile respawn delays validated before they are converted into runtime timers,
  • engagement ownership to prevent noisy multi-owner combat loops,
  • retaliation ticks against the engaged player for built-in and registered spawn-group combat profiles,
  • player death floor with denial gates for several live actions, including self DEAD replay when entering GAME from an already-0-HP selected-character snapshot,
  • restart-here and restart-town slash-command recovery seams,
  • deterministic EXP/gold/fixed-drop reward descriptors for accepted non-player deaths,
  • extensive TCP-level regression tests around watcher/owner respawn, retarget, cleanup, and reward cases.

Still missing:

  • real damage formulas,
  • attack animations/types beyond the first normal path,
  • skill combat,
  • PvP and duel policy,
  • mob AI: aggro radius, chase, leash, return, patrol, target switching,
  • broad loot/drop tables,
  • full death/revive/corpse/menu evidence.

Social systems and chat

Status: [~] chat works, social systems are bootstrap-only.

Already present:

  • local talking chat fanout,
  • exact-name whisper routing,
  • shout/party/guild bootstrap fanout,
  • server notices and info messages,
  • some dead-player denial behavior for selected paths.

Still missing:

  • party membership state,
  • party invite/leave/kick/roles,
  • party EXP/drop sharing,
  • guild roster/ranks/wars/notices,
  • friend/messenger/block systems,
  • moderation and permission model.

Persistence and data model

Status: [~] enough for bootstrap slices, not legacy-grade.

Already present:

  • file-backed account/login-ticket snapshots,
  • persisted selected character state used by current boot flow,
  • persisted position for selected slices,
  • persisted inventory/equipment/quickslots/gold for current item and merchant paths,
  • item/static/interaction stores and bundle import/export.

Still missing:

  • real database-backed schema,
  • migrations,
  • domain repositories for gameplay systems,
  • crash recovery policy,
  • backup/restore,
  • persistent party/guild/quest/world state.

Operations, debug, and local tooling

Status: [~] good lab/debug surface, not production ops.

Already present:

  • pprof/debug mux,
  • /healthz,
  • local runtime config endpoint,
  • local account/login-ticket/item-template validation endpoints, account/item-template backup/restore endpoints, and local crash-temp cleanup endpoints for account and item-template stores,
  • local inventory/equipment/currency snapshots,
  • local static actor and interaction authoring endpoints,
  • local content bundle import/export,
  • local notice, relocate, transfer, players, visibility, and maps endpoints,
  • Docker runtime and debug image targets.

Still missing:

  • authentication/authorization for production admin surfaces,
  • release packaging,
  • deployment guide,
  • metrics/logging policy,
  • backup/restore and migration runbooks,
  • admin/GM tooling beyond local debug endpoints.

What is in the repo

  • cmd/authd / cmd/gamed — daemon entrypoints.
  • internal/proto/* — owned packet codecs, fixtures, and wire contracts.
  • internal/auth, internal/authboot, internal/boot, internal/handshake, internal/login, internal/worldentry, internal/game — connection/session/auth/select/game flow.
  • internal/service — legacy TCP service runtime and secure session wiring.
  • internal/config — environment-driven daemon configuration.
  • internal/worldruntime — topology, maps, AOI/visibility, entities, sessions, combat-oriented static actor state, and runtime scopes.
  • internal/minimal — current integrated game runtime used by tests and daemons.
  • internal/player, internal/inventory, internal/itemstore — current character, inventory, item template, equipment, quickslot, and currency behavior.
  • internal/accountstore, internal/loginticket — bootstrap persistence stores.
  • internal/staticstore, internal/interactionstore, internal/contentbundle — authored content, static actors, interactions, merchant previews, and bundle import/export.
  • internal/ops — local debug/pprof/operator HTTP mux.
  • db/migrations — placeholder for future database migration work.
  • docs/ — engineering notes, QA, roadmaps, workflow, development, and clean-room docs.
  • spec/protocol/ — owned protocol contracts and packet inventory.

Development

Run the main checks:

make test
go vet ./...
git diff --check

Run the daemons locally:

go run ./cmd/authd
go run ./cmd/gamed

Default legacy listener addresses are documented in docs/development.md. The important defaults are:

  • authd: :11002
  • gamed: :13000
  • pprof/debug/local ops: 127.0.0.1:6061 for authd, 127.0.0.1:6060 for gamed; wildcard/non-loopback ops binds are rejected at startup because /local/* operator endpoints share this mux

Useful docs:

Roadmap focus

The next challenge is no longer proving that the target client can talk to a clean-room Go server. The next challenge is turning the owned slices into a coherent game loop.

Near-term priorities:

  1. PvE vertical depth — move practice mobs toward real spawned mobs with authored combat profiles, AI, chase/leash/return, broader rewards, and stable death/restart behavior.
  2. Item and economy parity — finish item-use families, anti-flags, ownership timers, pickup rules, shop variants, and persistence edges.
  3. World runtime hardening — make AOI, transfer, reconnect, respawn, static/non-player lifecycle, and visibility replay more robust under multiple clients.
  4. Content and quest seams — grow NPC services, content validation, spawn/regen/drop data, and the first quest-style state machine.
  5. Real social systems — replace bootstrap party/guild fanout with membership, permissions, persistence, and gameplay effects.
  6. Persistence and production ops — introduce DB migrations, backup/restore, release/deploy workflow, observability, and safe admin tooling.

Clean-room rule

This repository must only contain code, documentation, fixtures, and tests produced for this project.

Do not copy legacy Metin2 server/client source into this repository. Use legacy behavior only as an external oracle for independently written specs, tests, and Go implementations.

About

[WIP] Clean-room Metin2 server emulator in Go, targeting TMP4-era client compatibility.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages