update docs and add details on proudnet version
This commit is contained in:
parent
7834b98bf0
commit
af36074fed
5 changed files with 115 additions and 3 deletions
|
|
@ -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` |
|
||||||
|
|
|
||||||
|
|
@ -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 |
|
||||||
|
|
|
||||||
81
decomp/scripts/gen_dbc_tables.py
Normal file
81
decomp/scripts/gen_dbc_tables.py
Normal 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}')
|
||||||
|
|
@ -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
31
third-party/README.md
vendored
|
|
@ -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.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue