• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!
  • 2026 staff recruitment is open! Check it out and consider applying!

Tibia Clone with Nakama (Go) + Godot 4 — Custom Binary Protocol, OTBM Parser, Full Sprite Pipeline

lyloloq

Intermediate OT User
Joined
Jun 24, 2020
Messages
51
Reaction score
132
Location
Canada
Hey everyone,

I've been working on a Tibia clone built from scratch using a completely different tech stack from the traditional OT approach. Instead of the C++ server + custom client, I'm using:
  • Server: Nakama game server with a Go runtime plugin
  • Client: Godot 4 (GDScript)
  • Data Pipeline: Python scripts converting original Tibia v1100 assets (.spr, .dat, OTBM maps)

What's Implemented

Server-side (Go/Nakama):

  • Combat system (melee, distance, magic) with armor/defense calculations
  • 10+ condition types (poison, fire, energy, bleed, haste, paralyze, etc.)
  • Spell system with per-spell and group cooldowns, vocation/level requirements
  • Monster AI with FSM states (idle → chase → attack → flee → return)
  • Spawn system with respawn tracking
  • Party system with shared XP (distance + level gating)
  • PvP with skull system (white/red/black), PZ locks, unjust kill tracking
  • Item system: pickup, drop, equipment slots, backpack, item decay, loot generation
  • Experience & leveling with vocation-based stat gains
  • NPC interactions and shops
  • 8-way movement with speed-based walk timing
  • Player persistence via Nakama storage (save on disconnect)
  • 50+ binary message types

Client-side (Godot 4):

  • Full sprite pipeline: extracts 463k sprites from Tibia.spr (RLE), packs into 114 atlas sheets (2048x2048), lazy-loaded on demand
  • Thing metadata parsed from Tibia.dat (43k items, 1.6k creatures, 247 effects)
  • Outfit color shader (RGBA mask tinting for head/body/legs/feet)
  • Y-sorted 2D tile renderer with ground + item passes
  • v1-style login flow (login screen, character list, create account)
  • Inventory, hotbar, battle list, party panel, chat, minimap, NPC dialog, loot container
  • Creature sprites with walk animations from original lookTypes

Binary Protocol:

  • Custom binary codec replacing JSON for all game messages
  • Typed fields: U8, U16, U32, I64, F64, String (U16 length-prefixed), UUID (16 bytes), Position (5 bytes)
  • Composite blocks for creatures, items, tiles, spells

OTBM Map Parser (Go):

  • Parses real OTBM files (tested with Canary maps)
  • Supports tile areas, items, towns, waypoints, house tiles, zone definitions
  • Handles node escape sequences and attribute parsing
  • Falls back to JSON map if OTBM loading fails

Data Pipeline (Python):

  • convert_sprites.py — RLE sprite extraction from v1100 format
  • convert_dat.py — Thing metadata with v1000+ attribute remapping
  • pack_atlas.py — Atlas generation with JSON index
  • Converters for vocations, monsters, items, spells from Canary XML → JSON

Screenshots


1771477307054.webp
1771477427545-webp.98411


screen-recording.gif

Technical Highlights

  • 10 Hz server tick rate with all systems (combat, AI, spawning, conditions, decay) running per tick
  • Lazy atlas loading — 114 sheets loaded on-demand, not at startup
  • OTBM with graceful fallback — loads real maps, degrades to JSON, generates default 256x256 if both fail
  • Tile visibility culling — only 9x7 tiles around the player are transmitted

What's Next

  • Pathfinding (A*)
  • More OTBM integration (spawns from XML, full house support)
  • Sound system
  • Container system (bags, depot)

Would love to hear feedback from the community. Happy to answer any questions about the tech stack choices or the AI-assisted development approach.
 

Attachments

  • 1771477427545.webp
    1771477427545.webp
    97.4 KB · Views: 495 · VirusTotal
Last edited:
The way the dirt border next to the water moves genuinelly creeps me out. D:

Haha it does look a bit alive doesn't it! Something to iron out eventually 😄

Are you thinking about putting this on GitHub?

Maybe eventually when it's in a more stable state! For now it's more of a personal/hobby project and I don't have the bandwidth to maintain a public repo on top of my day job. I'll definitely share more here as it progresses though.
 
The way the dirt border next to the water moves genuinelly creeps me out. D:
LUA:
local water = true
local dirtBorder = false

if (water == true)
{
    dirtBorder = true;
    return water;
}
else
{
    return dirtBorder;
}
 
Back
Top