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.
This commit is contained in:
1 parent
e0d1f629db
commit
8b9547a928
2 files changed
+91
-1
No files matched your search
+1
-1
@@ -35,7 +35,7 @@ SHARED_LOGIN_PASS=789456
|
||||
SHARED_CHAR_PASS=456123
|
||||
SHARED_WORLD_PASS=321654
|
||||
|
||||
# --- Web admin panel (http://<host>:8081) -----------------------------------
|
||||
# --- Web admin panel (http://<host>/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))"
|
||||
|
||||
@@ -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://<host>/`
|
||||
|
||||
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 <map> <x> <y>`.
|
||||
- **Monsters** — all 1,193 named monster types from `LIST_NPC.STB`; click to copy a `/mon <montype> <count> <ai>`.
|
||||
|
||||
## Web admin — `http://<host>/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.
|
||||
Reference in new issue
Block a user