From 8b9547a928bc379bccda68be52591c8a4464d389 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 10 Jul 2026 14:28:09 +0200 Subject: [PATCH] Add README Covers quick start, the two web UIs, non-Docker build instructions, repo layout, and the two Windows-porting gotchas (clock() semantics, DB string widths) most likely to bite future changes. --- .env.example | 2 +- README.md | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 README.md diff --git a/.env.example b/.env.example index 6ecc943..f129573 100644 --- a/.env.example +++ b/.env.example @@ -35,7 +35,7 @@ SHARED_LOGIN_PASS=789456 SHARED_CHAR_PASS=456123 SHARED_WORLD_PASS=321654 -# --- Web admin panel (http://:8081) ----------------------------------- +# --- Web admin panel (http:///admin/) ---------------------------------- # Logs in with an existing game account; only accounts with # accesslevel >= ADMIN_MIN_ACCESSLEVEL are allowed in. # Generate your own with: python3 -c "import secrets; print(secrets.token_hex(32))" diff --git a/README.md b/README.md new file mode 100644 index 0000000..085f202 --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# ROSS + +A [ROSE Online](https://en.wikipedia.org/wiki/Rose_Online) (KTRose, pre-evo era) private server emulator, ported from its +original Windows/MSVC codebase to build and run natively on Linux, packaged as a Docker Compose stack. + +Three C++ servers (login, character, world) talk to a MariaDB database and to each other over plain sockets, exactly like +the original 2007-era server did — just with the Windows-only bits (MSVC CRT calls, `clock()` semantics, path handling) +shimmed out so it builds and runs correctly under Linux/glibc/POSIX threads. + +## Quick start + +```sh +cp .env.example .env # edit PUBLIC_HOST at minimum if clients connect from another machine +docker compose up -d --build +``` + +That brings up: + +| Service | Container | Port | What it is | +|---|---|---|---| +| `db` | `ross-db-1` | — (internal) | MariaDB, schema auto-loaded from `database sql files/` on first start | +| `loginserver` | `ross-loginserver-1` | `29000` | Account login | +| `charserver` | `ross-charserver-1` | `29100` | Character select/create/delete | +| `worldserver` | `ross-worldserver-1` | `29200` | The actual game world | +| `webtools` | `ross-webtools-1` | `80` | Static GM toolbox (see below) + reverse-proxies `/admin/` | +| `webadmin` | `ross-webadmin-1` | — (behind webtools) | Account/character/server admin panel | + +Point a KTRose pre-evo client at `PUBLIC_HOST:29000` and log in — `LOGIN_CREATE_ACCOUNT=1` (the default) auto-creates an +account on first login with that username/password. + +## Web tools — `http:///` + +A static, no-build-step GM toolbox, generated from the same STB/DB data the server itself reads: + +- **GM Commands** — every `/command` `gmcmds.cpp` understands, with syntax, access-level, and a copy button. +- **Item Configurator** — browse all ~9,950 items, configure refine/count/etc., copy the exact `/item` or `/give2` command. +- **Maps** — every map with spawn/NPC activity, named from `LIST_ZONE.STB` (row index = map id, same as the server's own + `CWorldServer::LoadZoneData`). +- **NPCs** — every placed NPC (`list_npcs`) with coordinates; click to copy a `/tele `. +- **Monsters** — all 1,193 named monster types from `LIST_NPC.STB`; click to copy a `/mon `. + +## Web admin — `http:///admin/` + +Logs in with an existing **game account** — only accounts with `accesslevel >= ADMIN_MIN_ACCESSLEVEL` (default `900`) get +in. From there: + +- Browse/edit/delete accounts and characters, reset stats, grant GM/DEV, reset a stuck "online" flag. +- **Server** tab: start/stop/restart each of the three game servers, live-tail their logs (SSE), broadcast a message to + everyone online, or kick a character — all straight from the browser. + +The server-control features talk to the Docker API (`/var/run/docker.sock`, mounted read-only into `webadmin`), so this +panel effectively has host-level privileges. It's fine behind GM-only login on a machine you control; don't put it +directly on the public internet without a reverse proxy that adds another auth layer. + +## Building without Docker + +```sh +apt-get install cmake g++ make libmariadb-dev pkg-config +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build -j"$(nproc)" +``` + +Produces `build/loginserver`, `build/charserver`, `build/worldserver`. Each expects a `.conf` file as its only argument +(see `docker/conf/*.conf.tmpl` for the format, or `Binary/*.conf` for a filled-in example) and reads game data relative +to its working directory — run it from a directory containing `3DData/` (see below) and `clanmark/`. + +## Repo layout + +- `Src/` — the three servers' C++ source, plus `Src/Common/` (shared networking/DB/crypto code all three link against). +- `database sql files/` — MariaDB schema, loaded automatically into a fresh `db` container. +- `Binary/3DData/` — the subset of the original game's data files the **server** actually reads at runtime: item/skill/ + quest/zone definitions (`STB/`), quest scripts (`QUESTDATA/`), monster AI scripts (`AI/`). This is *not* the client's + 3D models/textures/sound — the server never touches those, so they aren't in this repo. +- `webtools/`, `webadmin/` — the two web UIs described above. +- `docker/` — Dockerfile support files: config templates, entrypoint script, the webtools nginx config. +- `tools/rose_login_test.cpp` — a standalone protocol-level login smoke test, linking against the server's own + `rosecrypt.cpp` so it exercises the real crypto/handshake instead of a reimplementation. + +## Notes for anyone touching the server code + +This codebase was written entirely against Windows/MSVC assumptions that don't hold on Linux. The two that will bite you +if you're not aware of them: + +- **`clock()`**: POSIX `clock()` returns *CPU time summed across every thread in the process*, not wall-clock time, and + ticks at `CLOCKS_PER_SEC == 1,000,000` instead of Windows' `1,000`. `Src/Common/sockets.h` `#define`s `clock()` to a + `CLOCK_MONOTONIC`-backed wall-clock millisecond counter for the whole codebase — don't remove that shim, and don't + call `clock()` expecting Windows semantics anywhere it might not apply. +- **DB string widths**: this server was built against MySQL 5.0, which silently truncated over-length strings instead + of rejecting them. MariaDB's default strict mode does not — if you add a new DB-backed field that stores a + server-generated string (timestamps, etc.), size the column generously.