Pin vcpkg registry and native developer toolchain This commit moves Canary patched protobuf port from the old overlay port model into a versioned local vcpkg registry and pins the native developer toolchain used by local builds and CI. The goal is to make dependency resolution more reproducible without changing the CMake target structure or the existing CI build flow. The project still builds through the same CMake presets and vcpkg manifest model, but protobuf is now resolved from a controlled repository local registry instead of an unversioned overlay port path. The vcpkg configuration now uses a pinned builtin registry baseline and a filesystem registry for the local protobuf package. The protobuf package is provided through the new vcpkg registry directory with its portfile metadata wrappers version database and Canary specific patches. This keeps the patched protobuf dependency versioned inside the repository and makes future dependency updates easier to review because the registry baseline package version port version and patch set are all explicit. The new local protobuf registry defines protobuf version 6.33.4 with port version 1 and keeps the required dependencies declared through the package metadata, including abseil host protobuf utf8 range vcpkg cmake and vcpkg cmake config. It also preserves optional zlib support through the protobuf zlib feature. The developer toolchain is now pinned through mise. The repository adds a mise configuration that pins CMake Ninja sccache and Python, sets the default CMake generator to Ninja, and defines standard tasks for bootstrapping configuring building testing installing and checking cache stats. Pinned tool versions • mise minimum version 2026.5.15 • CMake 4.3.4 • Ninja 1.13.2 • sccache 0.14.0 • Python 3.14.6 A new bootstrap script installs the pinned vcpkg checkout into the configured VCPKG ROOT path, defaulting to the repository local tools directory. The script clones microsoft vcpkg when needed, fetches and checks out the builtin baseline from the vcpkg manifest, bootstraps vcpkg with metrics disabled, and prints the selected vcpkg root. Main changes included in this commit • Moves the patched protobuf port from overlay ports to a local vcpkg registry • Adds a repository local vcpkg registry directory • Adds protobuf package metadata under the local registry • Adds protobuf version database entries for the local registry • Pins the default builtin vcpkg registry baseline • Configures protobuf to resolve from the filesystem registry • Keeps overlay triplets unchanged • Keeps CMake target structure unchanged • Keeps the existing CI build flow conceptually unchanged • Adds protobuf patches inside the versioned registry port • Adds wrappers and package configuration files needed by the patched protobuf port • Adds a mise based native developer toolchain definition • Pins CMake Ninja Python and sccache for local development • Sets VCPKG ROOT to the repository local tools vcpkg path by default • Sets Ninja as the default CMake generator for the pinned workflow • Adds mise tasks for bootstrap configure build test install and cache stats • Adds a Python bootstrap script for the pinned vcpkg checkout • Updates CI build workflows to install pinned build tools through mise • Updates Linux macOS and Windows reusable build workflows to use the repository local vcpkg directory for CMake builds • Updates CI path filters so changes to mise vcpkg configuration and the local registry trigger the correct jobs • Updates cmake format checks to use pinned Python setup and hashed Python requirements • Adds hashed requirements for cmakelang PyYAML and six • Updates README test instructions to use the pinned mise workflow • Updates development documentation to describe the unified local setup and build workflow Workflow behavior after this change Local developers can install the pinned tools and bootstrap vcpkg from the repository root before configuring or building Canary. The standard path is now based on mise install followed by the repository tasks for bootstrap configure build and test. CI now sets up pinned build tools through mise before running native build steps. Linux and macOS workflows no longer rely on system installed Ninja from apt or brew for the build tool version. They install only the remaining platform dependencies and use the pinned toolchain for CMake Ninja and Python. Windows CMake builds also use the pinned tool setup and place vcpkg under the repository local tools directory. Solution builds keep their existing repository vcpkg location behavior where needed. CMake formatting now installs its Python dependencies through a hashed requirements file before running cmakelang format. This makes the formatting tool dependencies more deterministic and avoids installing unpinned formatter dependencies directly in the workflow. Validation • macOS release preset configures successfully with the local registry • macOS release preset builds successfully with the local registry • Manual testing was otherwise not reported Overall this commit makes Canary native build dependency resolution more reproducible by versioning the patched protobuf port in a local vcpkg registry and pinning the developer toolchain through mise, while keeping the existing CMake presets target structure and CI build flow intact.
10 KiB
Development Guide
Introduction
This document describes the development workflow used by Canary and serves as a reference for contributors who want to:
- Build the server locally
- Develop new features
- Fix bugs
- Create Lua systems
- Write tests
- Submit pull requests
Canary is an MMORPG server emulator written primarily in:
- C++20 (server core)
- Lua (gameplay systems)
- SQL (database schema)
- CMake (build system)
Development Philosophy
Canary follows a few important principles:
- Keep the core engine stable.
- Prefer gameplay customization through Lua.
- Maintain compatibility with existing datapacks whenever possible.
- Favor readability over clever implementations.
- Keep systems modular and testable.
- Avoid introducing unnecessary dependencies.
Development Environment
Recommended Tools
IDEs
Supported:
- Visual Studio 2026
- CLion
- VSCode
Useful Extensions
VSCode:
- C/C++
- CMake Tools
Repository Structure
canary/
│
├── src/
├── data/
├── data-canary/
├── data-otservbr-global/
├── docs/
├── tests/
├── docker/
├── metrics/
│
├── schema.sql
├── config.lua.dist
├── CMakeLists.txt
├── CMakePresets.json
├── vcpkg.json
└── package.json
Development Setup
Option 1: Docker (Recommended for Beginners)
The fastest way to start local testing is using the Docker quickstart.
Services provided:
- Canary
- MariaDB
- MyAAC
- Login Server
Start the stack:
cd docker
cp .env.dist .env
docker compose up -d --build
This pulls the published Canary runtime image and builds the MyAAC quickstart image. It does not compile Canary locally.
Default endpoints:
Website: http://localhost:8080
Client login API: http://localhost:8088/login
Canary login protocol: 7171
Canary game protocol: 7172
Canary status protocol: 7173
Login-server gRPC: 9090
Docker is ideal when:
- Testing scripts
- Developing datapacks
- Learning the project structure
- Avoiding local dependency installation
- Running local or LAN demos with trusted defaults
Do not expose the quickstart directly to the public Internet with default
accounts, passwords or rolling image tags. See docker/DOCKER.md for the full
Docker quickstart contract.
Option 2: Native Development
Recommended for engine contributors.
Required Software
Install Git, a supported C++ compiler, and mise.
The repository's .mise.toml installs the pinned CMake, Ninja, Python, and
sccache versions used by the native development workflow and relevant CI jobs.
Linux requires GCC or Clang. Windows requires Visual Studio with Desktop Development with C++.
Cloning the Repository
git clone https://github.com/opentibiabr/canary.git
cd canary
Canary does not require Git submodules. Install the pinned tools and vcpkg checkout from the repository root:
mise install
mise run bootstrap
Configuration
Create your local configuration:
cp config.lua.dist config.lua
Important settings:
serverName = "Development Server"
ip = "127.0.0.1"
mysqlHost = "localhost"
mysqlUser = "root"
mysqlPass = "password"
Never commit personal configuration changes.
Build System
Use the tasks in .mise.toml so local builds use the same tool versions as CI:
mise run configure linux-debug
mise run build linux-debug
mise run test linux-debug
Replace linux-debug with another preset from CMakePresets.json as needed.
The underlying CMake commands remain available for IDE integration and
advanced use.
Building Canary
mise run configure linux-release
mise run build linux-release
Windows
Open the repository in Visual Studio.
Visual Studio can automatically:
- Detect CMake
- Resolve dependencies through vcpkg
- Generate the build cache
Make sure VCPKG_ROOT is configured before opening the folder or configuring
the CMake preset.
Then:
Build → Build All
Dependency Management
Canary uses:
vcpkg.json
to declare dependencies.
Examples:
- asio
- curl
- libmariadb
- LuaJIT
- mbedtls
- protobuf
- pugixml
- spdlog
If dependencies fail:
cd "$VCPKG_ROOT"
git pull
./bootstrap-vcpkg.sh
or on Windows:
Set-Location $env:VCPKG_ROOT
git pull
.\bootstrap-vcpkg.bat
Running the Server
After compilation:
./canary
Expected startup sequence:
Loading config
Loading map
Loading monsters
Loading NPCs
Loading scripts
Starting game server
Database Development
Database schema:
schema.sql
Import:
mysql -u root -p database_name < schema.sql
Main tables:
accounts
players
guilds
houses
market
player_storage
Schema modifications should:
- Be backward compatible when possible
- Include migration documentation
- Avoid destructive changes
Lua Development
Most gameplay features belong in Lua.
Examples:
- Quests
- NPCs
- Actions
- Talkactions
- Spells
- Events
Typical locations:
data/scripts/
data/actions/
data/spells/
data/npc/
Lua API
The server exposes C++ functionality through Lua bindings.
Examples:
player:addExperience(1000)
player:addItem(2160)
Game.getPlayers()
Generated API documentation is available in:
docs/lua-api/
Enable generation:
generateLuaApiDocs = true
Adding New Features
Prefer Lua First
Before modifying C++:
Ask:
Can this be implemented entirely in Lua?
If yes:
Use Lua.
If no:
Extend the C++ engine.
Adding a New Lua Event
Example:
local event = CreatureEvent("Example")
function event.onLogin(player)
player:sendTextMessage(MESSAGE_STATUS, "Welcome!")
return true
end
event:register()
C++ Development
Source Layout
src/
├── game/
├── creatures/
├── map/
├── items/
├── io/
├── lua/
├── server/
├── utils/
└── lib/
Before creating new modules:
- Check existing systems.
- Extend existing classes when appropriate.
- Avoid duplicate functionality.
Coding Standards
Naming
Classes:
Player
Monster
ProtocolGame
Methods:
addExperience()
getHealth()
sendTextMessage()
Variables:
playerLevel
damageAmount
targetPosition
Constants:
MAX_PLAYERS
MAX_CONTAINER_ITEMS
General Guidelines
Prefer:
const auto&
instead of unnecessary copies.
Prefer:
std::vector
std::unordered_map
std::shared_ptr
when they match the ownership model of the surrounding code.
Avoid:
new
delete
when smart pointers are possible.
For Lua bindings that expose shared C++ objects, read
docs/systems/lua-shared-userdata.md before changing ownership or userdata
registration code.
Logging
Use existing logging systems.
Good:
g_logger().info("Player {} logged in", playerName);
Bad:
std::cout << "debug" << std::endl;
Never commit debugging output.
Debugging
Linux
Run with GDB:
gdb ./canary
Helper script:
./start_gdb.sh
Common Debug Targets
Investigate:
- Crashes
- Memory corruption
- Infinite loops
- Scheduler deadlocks
Useful commands:
bt
frame
print
continue
Testing
Canary includes automated tests.
Build tests:
cmake --preset linux-debug
cmake --build --preset linux-debug
Run tests:
ctest --preset linux-debug
Tests should be added for:
- New systems
- Bug fixes
- Edge cases
- Regression prevention
Pull Request Workflow
Create a Branch
git checkout -b feature/new-system
Examples:
feature/
fix/
refactor/
docs/
Commit Messages
Good:
fix(player): prevent logout race condition
feat(wheel): add progression API
refactor(combat): simplify condition processing
Avoid:
fix stuff
update
changes
Before Opening a Pull Request
Checklist:
- Builds successfully
- Tests pass
- No debug code
- No merge conflicts
- Documentation updated
- Lua scripts validated
Reviewing Changes
When reviewing code:
Focus on:
- Correctness
- Performance
- Security
- Maintainability
- Backward compatibility
Do not approve changes solely because they work locally.
Performance Considerations
Critical systems:
- Pathfinding
- Combat
- Scheduler
- Dispatcher
- Networking
Before introducing changes:
Consider:
How does this behave with 1000 players?
Small inefficiencies become large server costs.
Common Development Tasks
Add a Spell
data/spells/
Add a Monster
data/monster/
Add an NPC
data/npc/
Add a Quest
data/scripts/
Add Engine Functionality
src/
and expose it through:
src/lua/
if Lua access is required.
Troubleshooting
Dependency Errors
Rebuild vcpkg:
cd "$VCPKG_ROOT"
git pull
./bootstrap-vcpkg.sh
CMake Cache Issues
Remove only the affected preset directory, then reconfigure the same preset:
rm -rf build/<preset-name>
cmake --preset <preset-name>
For example, if linux-release is the broken cache, remove
build/linux-release, not the entire build/ directory.
Lua Errors
Enable verbose logging.
Check:
data/logs/
and console output.
Development Workflow Summary
Create Branch
↓
Implement Feature
↓
Build
↓
Run Tests
↓
Manual Validation
↓
Update Documentation
↓
Open Pull Request
↓
Code Review
↓
Merge
Conclusion
Canary development is centered around:
- C++20 for engine performance
- Lua for gameplay flexibility
- CMake for reproducible builds
- vcpkg for dependency management
- Automated testing and code review
Contributors are encouraged to keep changes modular, documented, tested, and aligned with the project's goal of providing a modern and extensible MMORPG server platform.