# Shared server framework ("Magi") — configuration and database access The server EXEs share one in-house framework. Its classes are named `Magi*`, and the network sessions are `MG*Session`. This document defines the parts every binary shares: - server identity; - startup modes; - configuration files; - the path to the database. Analyse each new binary against this document, and record in its own `evidence.md` where it differs, rather than re-deriving the framework. Status: first pass. **Primary evidence:** `MessageServer_Release_x64.exe` (`decomp/MessageServer_Release_x64/`). **Cross-binary checks:** strings and RTTI only, unless a row says otherwise. Field offsets are from MessageServer. Other binaries share the same code, so they are *expected* to match, but this hasn't been verified. Every claim is static; nothing here was observed at runtime. Notation: **O** = observed in decompiled code, **S** = observed in strings/RTTI only, **I** = inference, **?** = unknown. `MS:0x…` means a function in `decomp/MessageServer_Release_x64/full/functions/0x….c`. --- ## 1. Framework presence across binaries (S) | Marker | Present in | |---|---| | RTTI `MagiServerOption`, `MagiCustomOption`, `MagiServerFile`, `MagiServerManager` | all 14 server EXEs. The two SMMonitoring EXEs only have `MagiServerManager`. | | Option-loader keys (`write_thread_count`, `each_option`), the `-AGNET MODE-` banner [sic], and the `DBC_CHAT`/`DBC_EMERGENCY` names | all 14 server EXEs; none in SMMonitoring | | `Servers2DbcProxy` RTTI (client of the DBC servers) | Auction, Dungeon, GameGateway, Game, GM, Guild, Manager, Message, PVP | | ADO / `_Connection` strings (direct SQL access) | DBCServer and DBCServer_LOG (4 hits each); 1–2 hits in Auction, Dungeon, Game, Guild, Manager and PVP (**?** — may be incidental) | **Inference:** only the DBC servers talk to SQL Server. Every other server reaches the database through ProudNet RMI to a DBC server (§5). This needs confirming by decompiling the ADO usage in the six non-DBC servers that have hits. ## 2. Server-kind enum (O, `MS:0x140002930`) The one-byte server type is stored in the option object (`+0x1e8`) and in peer/session records. Names below are the wide strings the binary prints. | Value | Name | Value | Name | |---|---|---|---| | 1 | Lobby (= GameServer EXE, D: `ServerFile`) | 0x0c | DBC_GAME | | 2 | Dungeon | 0x0d | Agent | | 3 | PVP | 0x11 | DBC_LOG | | 4 | WAR | 0x12 | DBC_CHAT | | 5 | Guild | 0x13 | DBC_EMERGENCY | | 6 | Message | 0x15 | Agentmanager | | 7 | GM | 0x16 | MiniGame | | 8 | Gate | 0x17 | `api` peer (no display name; `MS:0x14005dc20`) | | 9 | Manager | 0x0e–0x10, 0x14 | ? | | 0x0a | Auction | | | | 0x0b | Match | 0x18 (24) | PatchServer (D: `ServerFile` only; not shipped) | The same numbers are stored in `RustyHearts_Auth.ServerOption.Type`, and `ServerFile` maps each one to an EXE (D; see `CONFIG.md` §5). Separately, servers also have a numeric **code** (the instance ID). It appears in XML as `code="61"` and in file names such as `MSG_61.xml`. In the shipped deployment config every kind has one code: DBC_GAME=1, DBC_LOG=2, DBC_CHAT=3, DBC_EMERGENCY=4, Msg=61, GM=71, Gate=81, Manager=91, Auction=101, Match=111, Agent=800, AgentManager=900, Dungeon=2001, PvP=3003, Guild=5001, Lobby=21001 (S, `binaries/Option/*.xml`). ## 3. Startup modes (O, `MS:0x14005c7b0`) `MagiServerOption::Init(argv1)` records the PID and the start time (`+0x1ec`, `+0x1f0`), then branches on the first character of the argument: | `argv[1]` | Mode | What is loaded | |---|---|---| | does not start with a digit | **standalone** | `argv[1]` is a path to a per-server XML file, which `MS:0x14005dc20` parses (§4.1) | | starts with a digit | **agent mode** (prints `-AGNET MODE-`) | `atoi(argv1)` is this server's **code**. `MS:0x14005ceb0` reads `option\total_option.xml` (§4.3). The full server list then arrives from the Agent over RMI: the `MGSAgentSession` vftable slot 7 is `MS:0x140065ab0`. The entry whose code equals our code configures this server (`MS:0x14005c9f0`); every other entry is added as a peer (`MS:0x14005ff50`). | This matches the Agent side: the Agent launches a server with the numeric server code as its argument (`decomp/Agent_Release_x64/evidence.md` finding 3). **ServerInfo record** pushed by the Agent (O, copy constructor `MS:0x140065900`; offsets in bytes): | Off | Type | Field (I) | |---|---|---| | +0x00 | int | world | | +0x04 | int | code | | +0x08 | int | ? | | +0x0c | u8 | server kind (§2) | | +0x10 | int | private_port | | +0x14 | int | public_port | | +0x18 | int | public_udpport | | +0x1c | int | udp_count | | +0x20 | u8 | ? | | +0x28 | `std::wstring` | private_ip | | +0x50 | `std::wstring` | public_ip | | +0x78 | `std::wstring` | name | ## 4. Configuration files Moved to [`CONFIG.md`](CONFIG.md). It covers: - the per-server XML schema with field offsets; - `total_option.xml` and `customoption.xml`; - the database-backed server topology (`RustyHearts_Auth.ServerOption` / `ServerFile`). The `MagiServerOption` field layout matches between MessageServer and DBCServer (O). ## 5. Database access path Moved to [`DATABASE.md`](DATABASE.md). It covers the RMI → command queue → `DBReq*` → stored procedure chain, the four connection types, the RMI → procedure map and the schema of the five databases. Summary: - **Clients and connections:** client servers keep 4 `MGDBCMsgSession` pools (GAME/LOG/CHAT/EMERGENCY), sized by `db_cache session_count`. They send `SERVERS2DBC` RMIs (262, IDs 0x2ee1–0x2fe6); this table is **identical in MessageServer and DBCServer**, O. DBCServer runs stored procedures over ADO and answers with `DBC2SERVERS` (76 RMIs, 0x2af9–0x2b46). ## 6. Other shared protocols seen in MessageServer (O) | Protocol | IDs | Direction | |---|---|---| | `SERVERS2MSG` (stub) / `MSG2SERVERS` (proxy) | 0x3a99–0x3aa0 | servers ↔ MessageServer (`decomp/MessageServer_Release_x64/evidence.md`) | | `SERVER2AGENT` | 12 proxy RMIs | see the TSV | | `AGENT2SERVER` (stub) | ? | Agent pushes ServerInfo (§3) | ## 7. Open questions (priority order) 1. AgentManager: confirm that it reads `ServerOption`/`ServerFile` and pushes the topology (`CONFIG.md` §5). 2. DBCServer_LOG: the LOG RMIs and RustyHearts_Log (`DATABASE.md` §5). 3. Diff the `SERVERS2DBC` table in the remaining client binaries. 4. Semantics of `send`, `auto`, `lock`, `each_option`, `guildlobby`, `channel`, and of the `api` peer. 5. Server kinds 0x0e–0x10 and 0x14.