Port the production hardening and performance fixes tested on Avalorium into Canary.
This change fixes Lua shared-userdata ownership issues in which std::shared_ptr<T> values stored inside Lua userdata could leak or use the wrong finalizer when the assigned metatable did not match the underlying C++ type. It also reduces avoidable shared_ptr copies and shared_from_this() churn in movement, spectator, and monster hot paths.
Lua userdata fixes:
- Add typed Lua shared-userdata helpers through LuaUserdataTraits<T>.
- Add Lua::registerSharedClass<T>.
- Add Lua::pushSharedUserdata<T>.
- Add Lua::pushBorrowedSharedUserdata<T>.
- Add typed Lua::luaSharedPtrGarbageCollection<T>.
- Migrate KV, Condition, and NetworkMessage to the typed shared-userdata path.
- Migrate high-priority non-SharedObject bindings away from the legacy generic finalizer path.
- Deprecate old untyped shared userdata helpers so new bindings are less likely to repeat the same ownership bug.
- Document the Lua shared-userdata ownership contract and add AGENTS.md review guidance for future binding changes.
Critical leak cases fixed:
- KV values returned by kv:scoped() and player:kv() now use typed cleanup.
- Condition values returned by creature:getCondition() now release the stored std::shared_ptr<Condition> correctly.
- Borrowed NetworkMessage callback userdata now uses a no-op deleter and typed userdata cleanup instead of an invalid ownership path.
Additional bindings migrated:
- revscripts/events
- Combat
- ModalWindow
- Town
- Guild
- Vocation
- Group
- Mount
- Shop
- Loot
- MonsterSpell
- MonsterType
- Spell
- Weapon
- Charm
- Zone
- BatchUpdate
Movement and spectator hot paths:
- Add raw creature type accessors for cheaper type checks without shared_from_this().
- Reduce movement/remove notification refcount churn by using local Player* vectors anchored by the existing strong Spectators snapshot.
- Preserve client index semantics with getClientIndexOfCreature to avoid stack-high ghost or desync regressions.
- Avoid unnecessary self shared_ptr construction in Monster hot paths.
Safety:
- Does not change general game ownership.
- Does not convert Spectators or cache storage to raw pointers.
- Keeps raw Player* values local only, lifetime-anchored by the Spectators' snapshot in the same scope.
- Uses a no-op deleter for borrowed NetworkMessage userdata.
- Leaves polymorphic core userdata such as Creature, Player, Monster, Npc, Item, Container, Tile, and Teleport for a separate audit.
- Keeps Position on the legacy helper because it is represented as a Lua table with a metatable, not as shared userdata.
Validation:
- Ran git diff --check.
- Built Windows release with cmake --preset windows-release.
- Built target canary with cmake --build --preset windows-release --target canary.
- Verified critical legacy patterns are gone with grep checks.
- Verified migrated non-SharedObject bindings no longer use the old shared_ptr pushUserdata plus setMetatable pattern.
- Reviewed before/after profiling from the live-server hotspot context.
This improves the correctness of Lua bindings, reduces shared_ptr lifetime risks, and lowers refcount churn in movement/spectator paths without changing gameplay ownership semantics.
Add Canary's official Lua API documentation generator and keep the generated Lua API reference synchronized with the C++ Lua binding surface.
Main changes:
- Add LuaApiDocGenerator and LuaBindingScanner to discover Lua classes, methods, globals, constants, parameters, returns, fields, overloads, aliases, source files, and class inheritance from the C++ binding layer.
- Generate docs/lua-api/lua_api.d.lua for Lua Language Server and VSCode IntelliSense.
- Generate docs/lua-api/lua_api.md for human-readable API documentation.
- Generate docs/lua-api/lua_api.json for structured tooling and CI metadata.
- Generate docs/lua-api/lua_api_quality_baseline.json for weak-signature regression tracking.
- Integrate documentation generation into the startup after loadConfigLua, controlled by generateLuaApiDocs and luaApiDocsOutputDirectory.
- Add --generate-lua-api-docs-only so CI can regenerate docs without starting the game server, loading maps, connecting to the database, or running shutdown/save paths.
Generator behavior:
- Force documentation generation in docgen-only mode so CI sync checks cannot silently become no-ops.
- Warn instead of crashing the startup when doc generation fails.
- Write generated files atomically.
- Skip unchanged writes.
- Use deterministic ordering and normalized file endings.
- Keep source paths relative and portable.
- Normalize inferred C++ types into Lua and LuaLS-friendly types.
- Avoid exposing raw C++ types in generated stubs.
LuaLS support:
- Emit LuaLS-compatible annotations, including meta, aliases, classes, fields, overloads, params, returns, inheritance, callable constructors, typed arrays, and operators for supported metamethods.
- Avoid exposing internal metamethods such as __eq, __add, and __gc as normal public Lua methods.
- Add explicit signature overlays with docblocks for APIs where automatic inference is not precise enough.
- Add overlays for high-impact APIs such as Player, Game, Result, db async calls, Actions, TalkActions, Spells, Weapons, MoveEvents, GlobalEvents, CreatureEvents, NpcType, Position, and NetworkMessage.
Editor and documentation:
- Add .luarc.json so LuaLS loads docs/lua-api by default.
- Raise LuaLS preload limits for lua_api.d.lua.
- Exclude generated build, cache, Visual Studio, and vcpkg directories from LuaLS workspace indexing.
- Add tools/setup_vscode_lua_api.ps1 to configure VSCode and LuaLS locally.
- Add docs/systems/lua-api-docgen.md explaining configuration, binding documentation, docblocks, quality baselines, and CI checks.
- Mention the generated Lua API docs from the README and systems index.
- Add Visual Studio project and CMake integration for the generator.
CI and regression protection:
- Add CI sync validation that runs --generate-lua-api-docs-only and checks docs/lua-api for diffs.
- Add tools/check_lua_api_quality.py to compare weak-signature metrics against the committed baseline.
- Add tools/check_lua_api_binding_docs.py to require explicit docblocks when new bindings would generate weak signatures.
- Exclude generated Lua API outputs from Sonar duplication/noise while keeping the generator and tooling checked.
Validation:
- Verified docs/lua-api/lua_api.json parses successfully.
- Verified luac -p passes for docs/lua-api/lua_api.d.lua.
- Verified Lua API binding docs and quality checks pass.
- Verified tools/setup_vscode_lua_api.ps1 -WhatIf succeeds.
- Verified VSCode and LuaLS resolve generated Canary classes and methods from lua_api.d.lua.
- Checked generated docs for stale root-level references, temporary paths, local machine paths, and obvious raw C++ types.
This gives Canary a repeatable source-of-truth pipeline for Lua API documentation, editor IntelliSense, and CI enforcement while keeping the generated docs synchronized with the C++ binding layer.