update docs and add details on proudnet version

This commit is contained in:
Benjamin Palko 2026-10-15 09:02:53 -04:00
parent 7834b98bf0
commit af36074fed
5 changed files with 115 additions and 3 deletions

View file

@ -31,7 +31,7 @@ holds the binary-specific evidence.
| 3 | The worker dispatches commands 1001–1317 through a jump table to `DBReq*` methods | O (disassembly) | `0x1400a8190`, `cmd_dispatch.tsv` | | 3 | The worker dispatches commands 1001–1317 through a jump table to `DBReq*` methods | O (disassembly) | `0x1400a8190`, `cmd_dispatch.tsv` |
| 4 | Each `DBReq*` runs one stored procedure through `ADODB.Command` with named parameters, and maps recordset fields by name | O | `0x1400acbb0` (`up_create_character`) | | 4 | Each `DBReq*` runs one stored procedure through `ADODB.Command` with named parameters, and maps recordset fields by name | O | `0x1400acbb0` (`up_create_character`) |
| 5 | Four connection types: 1 WEB(`db_web`), 2 AUTH(`db_account`), 3 GAME(`db_game`), 4 GAME LOG(`db_game_log`). AUTH uses the WEB timeout (bug). Timeout 0 → 500. String length ≤255 | O | `0x1400a7aa0` (REA `ev_00545a3e…`) | | 5 | Four connection types: 1 WEB(`db_web`), 2 AUTH(`db_account`), 3 GAME(`db_game`), 4 GAME LOG(`db_game_log`). AUTH uses the WEB timeout (bug). Timeout 0 → 500. String length ≤255 | O | `0x1400a7aa0` (REA `ev_00545a3e…`) |
| 6 | Startup opens AUTH and GAME connections, allocates 125-slot write-queue arrays, and logs connect failures to `Error_ADO DB Connect.Log` | O | `0x140042cf0`, `0x1400a80c0` | | 6 | Startup opens AUTH and GAME connections, allocates 1000-slot write-queue arrays (125 iterations × 8 pointers), and logs connect failures to `Error_ADO DB Connect.Log` | O | `0x140042cf0`, `0x1400a80c0` |
| 7 | 210 of 262 RMIs map to a procedure. 7 of those procedures are missing from the shipped schema | O + D | `rmi_to_proc.tsv` | | 7 | 210 of 262 RMIs map to a procedure. 7 of those procedures are missing from the shipped schema | O + D | `rmi_to_proc.tsv` |
| 8 | Original source layout: `DBLobbyWriteQuery<Area>.cpp` ×28 plus `DBWriteQueryServerOption.cpp` | O (`__FILE__` strings) | `dbreq_methods.tsv` | | 8 | Original source layout: `DBLobbyWriteQuery<Area>.cpp` ×28 plus `DBWriteQueryServerOption.cpp` | O (`__FILE__` strings) | `dbreq_methods.tsv` |
| 9 | The option-loader layout equals MessageServer's (same offsets for every element) | O | `0x140156650`, `0x140155420` | | 9 | The option-loader layout equals MessageServer's (same offsets for every element) | O | `0x140156650`, `0x140155420` |

View file

@ -26,7 +26,7 @@ hypotheses to confirm or revise during analysis.
| `ManagerServer_Release_USA_x64.exe` | 6666752 | 6510.5 | c239477294c199f8df4ef70138cc1583c87838dd5e8cebed2ff0fae2bc6c5be2 | management/admin | pending | | `ManagerServer_Release_USA_x64.exe` | 6666752 | 6510.5 | c239477294c199f8df4ef70138cc1583c87838dd5e8cebed2ff0fae2bc6c5be2 | management/admin | pending |
| `AuctionServer_Release_USA_x64.exe` | 6477824 | 6326.0 | ebca9cc047aeca125ac0621e3652339096c74862746157adc6c72057422f6dcf | auction house | pending | | `AuctionServer_Release_USA_x64.exe` | 6477824 | 6326.0 | ebca9cc047aeca125ac0621e3652339096c74862746157adc6c72057422f6dcf | auction house | pending |
| `MatchServer_Release_USA_x64.exe` | 6134784 | 5991.0 | 341dd4a38c9e1abb590f60325ef52bf24b60a48a70e36e2f1651bbf00591fcf2 | matchmaking | pending | | `MatchServer_Release_USA_x64.exe` | 6134784 | 5991.0 | 341dd4a38c9e1abb590f60325ef52bf24b60a48a70e36e2f1651bbf00591fcf2 | matchmaking | pending |
| `DBCServer_Release_x64.exe` | 3542016 | 3459.0 | d9e4fccdf3482e50247686d4452c0b13c75a53efc4bd7320668eece8d1ce828c | DB access server (observed: SERVERS2DBC RMI → write queues → ADO stored procs; 4 connection types) | open | | `DBCServer_Release_x64.exe` | 3542016 | 3459.0 | d9e4fccdf3482e50247686d4452c0b13c75a53efc4bd7320668eece8d1ce828c | DB access server (observed: SERVERS2DBC RMI → write queues → ADO stored procs; 4 connection types; Linux port `src/dbc_server/`) | open |
| `DBCServer_LOG_Release_x64.exe` | 3394560 | 3315.0 | 2636d51679abb7703a6386a398f2afb985704aa0ce00d53e75d0ff3b093f5836 | logging DB variant | pending | | `DBCServer_LOG_Release_x64.exe` | 3394560 | 3315.0 | 2636d51679abb7703a6386a398f2afb985704aa0ce00d53e75d0ff3b093f5836 | logging DB variant | pending |
| `GameGatewayServer_Release_x64.exe` | 3330560 | 3252.5 | 4cbec55dc3dfe5a0eeba3170722e6f1d33e55d6a0d007774266fe9db96f25d1a | gateway/proxy | pending | | `GameGatewayServer_Release_x64.exe` | 3330560 | 3252.5 | 4cbec55dc3dfe5a0eeba3170722e6f1d33e55d6a0d007774266fe9db96f25d1a | gateway/proxy | pending |
| `GMServer_Release_x64.exe` | 2004480 | 1957.5 | 8fba9dbb8809419d6e2edaee31d9ad60501341d97dca0fc82a1c1e7cc32199d1 | game-master tools | pending | | `GMServer_Release_x64.exe` | 2004480 | 1957.5 | 8fba9dbb8809419d6e2edaee31d9ad60501341d97dca0fc82a1c1e7cc32199d1 | game-master tools | pending |

View file

@ -0,0 +1,81 @@
#!/usr/bin/env python3
"""Generate the DBCServer port's static tables from decomp evidence.
Inputs (all derived, regenerable):
decomp/DBCServer_Release_x64/rmi_to_proc.tsv RMI -> cmd -> procedures
decomp/schema/<db>/routines.tsv procedure parameters
Output:
src/dbc_server/generated/tables.inc
Run from the repo root: python3 decomp/scripts/gen_dbc_tables.py
"""
import csv, os
ROOT = os.getcwd()
OUT = os.path.join(ROOT, 'src/dbc_server/generated/tables.inc')
# Database -> DBC connection type (DBC:0x1400a7aa0). The DB for a procedure is
# where it lives in the schema dump (inference, see docs/DATABASE.md).
DBTYPE = {'RustyHearts_Account': 'Web', 'RustyHearts_Auth': 'Auth',
'RustyHearts': 'Game', 'RustyHearts_Log': 'GameLog'}
SQLTYPE = {'int': 'Int', 'smallint': 'SmallInt', 'tinyint': 'TinyInt', 'bigint': 'BigInt',
'bit': 'Bit', 'float': 'Float', 'uniqueidentifier': 'Guid', 'nvarchar': 'NVarChar',
'nchar': 'NVarChar', 'varchar': 'VarChar', 'char': 'VarChar', 'datetime': 'DateTime'}
def rows(path):
with open(path, newline='') as f:
return list(csv.reader(f, delimiter='\t'))
procs = {} # lower name -> (name, db, [(param, type, maxlen, out)])
for db in DBTYPE:
for r in rows(f'{ROOT}/decomp/schema/{db}/routines.tsv')[1:]:
if len(r) < 7 or r[0] != 'SQL_STORED_PROCEDURE':
continue
p = procs.setdefault(r[1].lower(), (r[1], db, []))
if r[2] != 'NULL':
p[2].append((r[3], SQLTYPE.get(r[4], 'VarChar'), int(r[5]), r[6] == '1'))
rmi = rows(f'{ROOT}/decomp/DBCServer_Release_x64/rmi_to_proc.tsv')
hdr = rmi[0]; rmi = [dict(zip(hdr, r)) for r in rmi[1:]]
used = []
for r in rmi:
for p in filter(None, r['procs'].split(',')):
if p.lower() not in procs:
# Called by DBCServer but absent from the shipped schema: keep it so
# the port fails like the original would (ADO error). DB guessed from name.
procs[p.lower()] = (p, 'RustyHearts_Log' if '_log_' in p else 'RustyHearts', None)
if p.lower() not in used:
used.append(p.lower())
def cstr(s):
return '"' + s.replace('\\', '\\\\').replace('"', '\\"') + '"'
out = ['// GENERATED by decomp/scripts/gen_dbc_tables.py - do not edit.',
'// Sources: decomp/DBCServer_Release_x64/rmi_to_proc.tsv, decomp/schema/*/routines.tsv', '']
for i, key in enumerate(used):
name, db, ps = procs[key]
ps = ps or []
out.append(f'static const ProcParam kParams{i}[] = {{' +
''.join(f'{{{cstr(n)}, SqlType::{t}, {m}, {str(o).lower()}}},' for n, t, m, o in ps) +
('{nullptr, SqlType::Int, 0, false}' if not ps else '') + '};')
out.append('')
out.append('static const ProcDef kProcs[] = {')
for i, key in enumerate(used):
name, db, ps = procs[key]
known = ps is not None
out.append(f' {{{cstr(name)}, DbType::{DBTYPE[db]}, kParams{i}, {len(ps or [])}, {str(known).lower()}}},')
out.append('};')
out.append('')
out.append('// rmi_id, name, cmd_id (0 = not queued / unknown), proc indexes (-1 = none)')
out.append('static const RmiDef kRmis[] = {')
for r in rmi:
idx = [used.index(p.lower()) for p in filter(None, r['procs'].split(',')) if p.lower() in used]
idx = (idx + [-1, -1, -1])[:3]
missing = [p for p in filter(None, r['procs'].split(',')) if procs[p.lower()][2] is None]
note = f' // missing in schema: {",".join(missing)}' if missing else ''
out.append(f' {{{r["rmi_id"]}, {cstr(r["rmi_name"])}, {r["cmd_id"] or 0}, '
f'{{{idx[0]}, {idx[1]}, {idx[2]}}}}},{note}')
out.append('};')
os.makedirs(os.path.dirname(OUT), exist_ok=True)
open(OUT, 'w').write('\n'.join(out) + '\n')
print(f'{len(used)} procedures, {len(rmi)} RMIs -> {OUT}')

View file

@ -114,7 +114,7 @@ Further details:
`Error_ADO DB Connect.Log` (`DBC:0x1400a80c0`). `Error_ADO DB Connect.Log` (`DBC:0x1400a80c0`).
- Startup (`DBC:0x140042cf0`) opens a type-2 (AUTH) and a type-3 (GAME) - Startup (`DBC:0x140042cf0`) opens a type-2 (AUTH) and a type-3 (GAME)
connection for the server itself. It also allocates write-queue arrays of connection for the server itself. It also allocates write-queue arrays of
125 slots. 1000 slots (a 0x1f48-byte block: 125 loop iterations × 8 pointers).
**Which connection each procedure uses?** The connection object passed to each **Which connection each procedure uses?** The connection object passed to each
`DBReq` method hasn't been traced yet. The **I** answer is: the database that `DBReq` method hasn't been traced yet. The **I** answer is: the database that

31
third-party/README.md vendored
View file

@ -95,6 +95,37 @@ ProudNet is not a separate DLL; it is linked into the server EXEs.
- To re-fetch: - To re-fetch:
`git archive ProudNetLibSetup-1.8.00001 ProudNet/include ProudNet-License-En.txt` `git archive ProudNetLibSetup-1.8.00001 ProudNet/include ProudNet-License-En.txt`
from that repo into `_local/proudnet-1.8.00001/`. from that repo into `_local/proudnet-1.8.00001/`.
- **`github.com/Nettention/ProudChatSDK` (checked 2026-10-15, `main` = tag
`1.1.0001`, commit `e0d9d6b8`).**
- **Contents:** bundles ProudNet **1.8.58849**: 185 headers, plus prebuilt
libraries for Windows (v110/v120/v140, dll), Android, iOS and
**x86_64 Linux** (`libProudNetServer.so/.a`, `libProudNetClient.so/.a`;
`__xstat` → old glibc).
- **Licence:** the repo's `LICENSE` (MIT) covers the chat SDK only;
`ProudNet/` keeps the same proprietary EULA (§1.2b). Nothing from it is
stored in this repo.
- **Headers:** identical to 1.8.00001 apart from the version banner and
translated doc comments in `ErrorType.h`. They add one error code and give
no new information beyond `_local/proudnet-1.8.00001`.
- **Compatibility with the 2013 ProudNet linked into DBCServer:**
| Aspect | Result | Type |
|---|---|---|
| PIDL proxy ABI | Matches: `IRmiProxy` keeps `m_signature` at +0x14, which the generated constructor checks against 1 (`MS:0x140008e20`). `RmiID` is still `uint16_t`. The `PIDL compiler is incompatible` and `CStartServerParameter::m_(fast)encryptedMessageKeyLength` strings appear in both | O |
| Internal implementation | 29 of DBCServer's 63 `Proud::` RTTI classes are absent from the 1.8.58849 Linux libraries' symbols, e.g. `CTcpLayer_C`, `CUdpSocket_S`, `CUpnp`, `ICompletionPortEventSink` | O |
| Internal net version | **2013 build: 196978 (0x30172)**, the global at `DBC:0x140344d40`. It is copied into the server object at +0x220 (`DBC:0x14018fa70`, instruction at `0x14019018d`) and into the client objects (`0x1401dd3e0`, `0x1401df000`). In the connect handshake (`DBC:0x1401a8110`, `NotifyServerConnectionRequestData`) the server reads a credential byte array, a 16-byte protocol GUID and a 4-byte int, and accepts only if the GUID **and** the int equal its own. The same value appears exactly once in `.data` of all 16 EXEs (O). **1.8.58849: 197144 (0x30218)** (`CNetConfig::InternalNetVersion`, rejected via `NotifyProtocolVersionMismatch`). The values differ by 166 | O |
| Licensing | 1.8 also contains license and activation checks (`CPNLic`, `NotifyLicenseMismatch`) | S |
- **Conclusion (I):**
- **Source-level:** usable as a header/ABI reference for PIDL-generated
stubs and proxies.
- **Wire-level:** **not** compatible with the original 2013 peers. The
internal net versions differ (196978 vs 197144), and the 2013 handshake
requires an exact match. This is O for the 2013 server side; I for the
1.8 side, which was not traced beyond the symbol name.
- **Linking:** linking `libProudNetServer.so` into `src/dbc_server`
would require accepting the EULA and a licence, and would give a
ProudNet 1.8 server that the original binaries likely cannot talk to.
Vendor attributions for XTrap (WiseLogic) and Apex are inferred from DLL Vendor attributions for XTrap (WiseLogic) and Apex are inferred from DLL
names, not corroborated by decompilation. names, not corroborated by decompilation.