server-re/docs/SHARED_FRAMEWORK.md

6.4 KiB
Raw Blame History

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. 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. 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.