Extend the game
without touching
the engine.
UniversalCore turns hardcoded, recompile-required C++ systems into declarative, scriptable, observable platforms — so you ship features in Lua, Python and YAML, not engine patches.
-- register a feature, no C++ required local d = core.feature { id = "rejoin_dungeon", rejoin = true, on_enter = function(player, ctx) if ctx:has_flag("cleared") then return player:teleport(ctx.checkpoint) end ctx:spawn_wave("stage_1") end, }
Everything the engine never gave you.
Scripting foundation
A first-class bridge that exposes engine primitives, event hooks and messaging to Lua and Python — write features, not patches.
Declarative content
Drops, affects, skills and UI move from hardcoded C++ to YAML + Lua declarations you can read, diff and hot-reload.
Composable subsystems
Avatars, dungeons, skill graphs and more — each built on the same foundation, each extendable without forking the engine.
Real developer UX
Source maps, a quest/forge compiler and a remote debugger for Lua and Python — set a breakpoint in the running client.
Built-in observability
Structured logs, faucet/sink profiling and a server-wide backoffice — see what your economy and players are actually doing.
Clean dev APIs
Precise, documented, versioned interfaces with fixed extension points — so integrating a custom feature is a pleasure, not a hunt.
Describe it. Don't hardcode it.
Systems that used to mean editing the engine and recompiling become plain declarations. Tune a drop table or an affect in YAML, wire the behaviour in Lua, and reload — the running client picks it up.
Every declaration is validated on load, so a typo fails fast with a source-mapped error — not a silent crash mid-raid.
boss_wing: from: "metin_of_rage" rolls: - item: "wing_of_dawn" chance: 0.5 - item: "soul_shard" chance: 12.0
core.affect("warmup", { duration = 30, apply = function(p) p:mod("atk_spd", 0.15) end, })
Read the story behind the platform.
Start with the docs, or follow the build journal on the blog.