added documentation and decompiled client
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
Proposed Direction
|
||||
|
||||
- Single core language: Go for all server runtime (gateway + lobby + game logic).
|
||||
- Web/UI: TypeScript (Next.js or simple React/Vite) only.
|
||||
- Goal: Keep binary protocol compatibility via a Gateway while the Core Monolith evolves.
|
||||
|
||||
———
|
||||
|
||||
Architecture (Monolith First)
|
||||
|
||||
[Game Client] ⇄ [Go Gateway] ⇄ [Go Core Monolith]
|
||||
├─ Lobby module
|
||||
├─ Matchmaking module
|
||||
├─ Game loop module
|
||||
└─ Data access layer
|
||||
|
||||
- Gateway: speaks binary protocol; maps opcodes to internal RPC/handlers.
|
||||
- Core Monolith: simple Go service with clear module boundaries; no network protocol details here.
|
||||
- Data: Postgres + Redis (optional) behind a DAL.
|
||||
|
||||
———
|
||||
|
||||
Phase 0: Baseline Observability (immediate)
|
||||
|
||||
- Add request/session IDs at the lobby entrypoint.
|
||||
- Add JSON logs (opcode, account, session, latency).
|
||||
- Add packet capture/replay harness (proxy or gateway shim).
|
||||
|
||||
This sets up parity testing for any rewrite.
|
||||
|
||||
———
|
||||
|
||||
Phase 1: Go Gateway (binary protocol fidelity)
|
||||
|
||||
- Implement binary parsing and encoding in Go.
|
||||
- Map each opcode to a handler interface.
|
||||
- For now, proxy handlers to legacy C servers (so clients keep working).
|
||||
|
||||
This becomes the compatibility anchor.
|
||||
|
||||
———
|
||||
|
||||
Phase 2: Go Core Monolith (first rewrite)
|
||||
|
||||
- Implement core modules in Go and progressively cut traffic over.
|
||||
- Start with lobby/auth/deck APIs (lower risk).
|
||||
- Add game loop later with deterministic state checks.
|
||||
|
||||
———
|
||||
|
||||
Phase 3: Data Migration
|
||||
|
||||
- Introduce Postgres schemas.
|
||||
- Mirror writes (old → new), then flip reads.
|
||||
- Eventually remove Couchbase.
|
||||
|
||||
———
|
||||
|
||||
Why this fits your preferences
|
||||
|
||||
- Only Go + TS.
|
||||
- Monolith first with future separation if needed.
|
||||
- Fully off C while maintaining client compatibility.
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
# Protocol Notes
|
||||
|
||||
## Opcode Decoder Map (Client)
|
||||
|
||||
Source: `hs-client/Assembly-CSharp/ConnectAPI.cs`.
|
||||
|
||||
- `116` → `PongPacketDecoder`
|
||||
- `169` → `Deadend`
|
||||
- `167` → `DeadendUtil`
|
||||
- `123` → `DebugConsoleCommand`
|
||||
- `124` → `DebugConsoleResponse`
|
||||
- `14` → `AllOptions`
|
||||
- `5` → `DebugMessage`
|
||||
- `17` → `EntityChoices`
|
||||
- `13` → `EntitiesChosen`
|
||||
- `16` → `GameSetup`
|
||||
- `19` → `PowerHistory`
|
||||
- `15` → `UserUI`
|
||||
- `9` → `TurnTimer`
|
||||
- `10` → `NAckOption`
|
||||
- `12` → `GameCanceled`
|
||||
- `23` → `ServerResult`
|
||||
- `24` → `SpectatorNotify`
|
||||
- `289` → `Disconnected`
|
||||
- `202` → `DeckList`
|
||||
- `207` → `Collection`
|
||||
- `215` → `GetDeckContentsResponse`
|
||||
- `216` → `DBAction`
|
||||
- `217` → `DeckCreated`
|
||||
- `218` → `DeckDeleted`
|
||||
- `219` → `DeckRenamed`
|
||||
- `212` → `ProfileNotices`
|
||||
- `224` → `BoosterList`
|
||||
- `226` → `BoosterContent`
|
||||
- `208` → `GamesInfo`
|
||||
- `231` → `ProfileDeckLimit`
|
||||
- `262` → `ArcaneDustBalance`
|
||||
- `278` → `GoldBalance`
|
||||
- `233` → `ProfileProgress`
|
||||
- `270` → `PlayerRecords`
|
||||
- `271` → `RewardProgress`
|
||||
- `232` → `MedalInfo`
|
||||
- `241` → `ClientOptions`
|
||||
- `246` → `DraftBeginning`
|
||||
- `247` → `DraftRetired`
|
||||
- `248` → `DraftChoicesAndContents`
|
||||
- `249` → `DraftChosen`
|
||||
- `288` → `DraftRewardsAcked`
|
||||
- `251` → `DraftError`
|
||||
- `252` → `Achieves`
|
||||
- `285` → `ValidateAchieveResponse`
|
||||
- `282` → `CancelQuestResponse`
|
||||
- `264` → `GuardianVars`
|
||||
- `260` → `CardValues`
|
||||
- `258` → `BoughtSoldCard`
|
||||
- `269` → `MassDisenchantResponse`
|
||||
- `265` → `BattlePayStatusResponse`
|
||||
- `295` → `ThirdPartyPurchaseStatusResponse`
|
||||
- `272` → `PurchaseMethod`
|
||||
- `275` → `CancelPurchaseResponse`
|
||||
- `256` → `PurchaseResponse`
|
||||
- `238` → `BattlePayConfigResponse`
|
||||
- `280` → `PurchaseWithGoldResponse`
|
||||
- `283` → `HeroXP`
|
||||
- `254` → `NoOpPacketDecoder`
|
||||
- `286` → `PlayQueue`
|
||||
- `330` → `CheckAccountLicensesResponse`
|
||||
- `331` → `CheckGameLicensesResponse`
|
||||
- `236` → `CardBacks`
|
||||
- `292` → `SetCardBackResponse`
|
||||
- `296` → `SetProgressResponse`
|
||||
- `299` → `TriggerEventResponse`
|
||||
- `300` → `NotSoMassiveLoginReply`
|
||||
- `304` → `AssetsVersionResponse`
|
||||
- `306` → `AdventureProgressResponse`
|
||||
- `307` → `UpdateLoginComplete`
|
||||
- `311` → `AccountLicenseAchieveResponse`
|
||||
- `315` → `SubscribeResponse`
|
||||
- `316` → `TavernBrawlInfo`
|
||||
- `317` → `TavernBrawlPlayerRecordResponse`
|
||||
- `318` → `FavoriteHeroesResponse`
|
||||
- `320` → `SetFavoriteHeroResponse`
|
||||
- `324` → `DebugCommandResponse`
|
||||
- `325` → `AccountLicensesInfoResponse`
|
||||
- `326` → `GenericResponse`
|
||||
- `328` → `ClientRequestResponse`
|
||||
- `322` → `GetAssetResponse`
|
||||
|
||||
## Opcode Encoder Map (Client → Server)
|
||||
|
||||
Game server outbound (QueueGamePacket):
|
||||
|
||||
- `22` → `SpectatorHandshake`
|
||||
- `168` → `Handshake`
|
||||
- `1` → `GetGameState`
|
||||
- `115` → `Ping`
|
||||
- `11` → `Concede`
|
||||
- `3` → `ChooseEntities`
|
||||
- `2` → `ChooseOption`
|
||||
- `15` → `UserUI` (emote + mouse)
|
||||
- `25` → `InviteToSpectate`
|
||||
- `26` → `RemoveSpectators`
|
||||
- `123` → `DebugConsoleCommand`
|
||||
|
||||
Debug console outbound (QueueDebugPacket):
|
||||
|
||||
- `124` → `DebugConsoleResponse`
|
||||
|
||||
Util server outbound (ClientRequestManager/UtilOutbound):
|
||||
|
||||
- `319` → `SetFavoriteHero`
|
||||
- `279` → `PurchaseWithGold`
|
||||
- `312` → `StartThirdPartyPurchase`
|
||||
- `293` → `SubmitThirdPartyReceipt`
|
||||
- `294` → `GetThirdPartyPurchaseStatus`
|
||||
- `250` → `GetPurchaseMethod`
|
||||
- `273` → `DoPurchase`
|
||||
- `274` → `CancelPurchase`
|
||||
- `237` → `GetBattlePayConfig`
|
||||
- `255` → `GetBattlePayStatus`
|
||||
- `268` → `MassDisenchantRequest`
|
||||
- `235` → `DraftBegin`
|
||||
- `242` → `DraftRetire`
|
||||
- `287` → `DraftAckRewards`
|
||||
- `244` → `DraftGetPicksAndContents`
|
||||
- `245` → `DraftMakePick`
|
||||
- `201` → `GetAccountInfo`
|
||||
- `327` → `GenericRequestList`
|
||||
- `205` → `UpdateLogin`
|
||||
- `214` → `GetDeckContents`
|
||||
- `209` → `CreateDeck`
|
||||
- `210` → `DeleteDeck`
|
||||
- `211` → `RenameDeck`
|
||||
- `332` → `DeckSetTemplateSource`
|
||||
- `222` → `DeckSetData`
|
||||
- `213` → `AckNotice`
|
||||
- `225` → `OpenBooster`
|
||||
- `230` → `SetProgress`
|
||||
- `298` → `TriggerLaunchDayEvent`
|
||||
- `303` → `GetAssetsVersion`
|
||||
- `308` → `AckWingProgress`
|
||||
- `309` → `AcknowledgeBanner`
|
||||
- `310` → `SetAdventureOptions`
|
||||
- `223` → `AckCardSeen`
|
||||
- `240` → `GetOptions`
|
||||
- `239` → `SetOptions`
|
||||
- `253` → `GetAchieves`
|
||||
- `284` → `ValidateAchieve`
|
||||
- `281` → `CancelQuest`
|
||||
- `243` → `AckAchieveProgress`
|
||||
- `297` → `CheckAccountLicenseAchieve`
|
||||
- `305` → `GetAdventureProgress`
|
||||
- `257` → `BuySellCard`
|
||||
- `267` → `CheckAccountLicenses`
|
||||
- `276` → `CheckGameLicenses`
|
||||
- `291` → `SetCardBack`
|
||||
- `321` → `GetAssetRequest`
|
||||
- `329` → `Unsubscribe`
|
||||
- `322` → `DebugCommandRequest`
|
||||
|
||||
## Learnings
|
||||
|
||||
- Client maintains deferred response maps for async requests in `Network.cs`.
|
||||
- Opcode map is a key compatibility anchor for the Go gateway.
|
||||
|
||||
## Protobuf Definitions (Source)
|
||||
|
||||
The repo does not contain the protobuf class definitions for most message
|
||||
types. They live in the client assemblies that were not decompiled here.
|
||||
To generate Go structs, extract `.proto` from the client install:
|
||||
|
||||
- `PegasusGame.dll` (game server packets)
|
||||
- `PegasusUtil.dll` (utility/account/collection packets)
|
||||
- `SpectatorProto.dll` (spectator packets)
|
||||
- `BobNetProto.dll` (misc/legacy)
|
||||
- `PegasusShared.dll` (shared types: `CardDef`, `BnetId`, enums)
|
||||
|
||||
Suggested mapping (verify by decompiling those DLLs):
|
||||
|
||||
- `PegasusGame`: `GameSetup`, `PowerHistory`, `EntityChoices`, `EntitiesChosen`,
|
||||
`UserUI`, `TurnTimer`, `NAckOption`, `GameCanceled`, `ServerResult`,
|
||||
`Disconnected`, `Handshake`, `GetGameState`, `Ping`, `Concede`,
|
||||
`ChooseEntities`, `ChooseOption`.
|
||||
- `SpectatorProto`: `SpectatorHandshake`, `SpectatorNotify`, `InviteToSpectate`,
|
||||
`RemoveSpectators`.
|
||||
- `PegasusUtil`: everything in the decoder/encoder maps that relates to
|
||||
collection, login, decks, purchases, achievements, and assets (most of the
|
||||
`UtilOutbound` messages).
|
||||
- `BobNetProto`: `Deadend`, `DeadendUtil` (verify).
|
||||
@@ -1,61 +0,0 @@
|
||||
## Development Environment Recommendations
|
||||
|
||||
This stack is most maintainable when the dev environment is repeatable and
|
||||
configuration is centralized. The current scripts assume Ubuntu 16.04 and
|
||||
hard-coded dependencies. The goal here is to make the environment predictable
|
||||
without touching the protocol or rewriting core services.
|
||||
|
||||
Key recommendations:
|
||||
|
||||
- Standardize the dev workflow with containers (prefer `docker-compose`).
|
||||
- Centralize ports, credentials, and paths into a single `.env` file.
|
||||
- Provide a single entrypoint script to build/start/stop/log services.
|
||||
- Keep database and service initialization scripted and idempotent.
|
||||
|
||||
## Focused Plan (Maintainability Only)
|
||||
|
||||
Phase 1: Audit and Baseline (1–3 days)
|
||||
|
||||
- Inventory the current scripts and dependencies in `hearthmod/`.
|
||||
- Confirm service ports and startup order (gameserver → lobbyserver → web).
|
||||
- Capture required Couchbase buckets and data seed steps.
|
||||
|
||||
Phase 2: Repeatable Local Environment (1–2 weeks)
|
||||
|
||||
- Add `docker-compose.yml` to orchestrate Couchbase, gameserver, lobbyserver,
|
||||
and web services.
|
||||
- Add `.env.example` for all required configuration values.
|
||||
- Create a single `./dev` or `./scripts/dev.sh` entrypoint:
|
||||
- `dev build` (build C services and web assets)
|
||||
- `dev up` (start all services)
|
||||
- `dev down` (stop services)
|
||||
- `dev logs` (tail logs)
|
||||
|
||||
Phase 3: Configuration Cleanup (1–2 weeks)
|
||||
|
||||
- Replace hard-coded ports and credentials with env-configured values.
|
||||
- Add a minimal config loader in `hm_web` and in C servers (config file or env).
|
||||
- Update nginx config to use env-substituted paths.
|
||||
|
||||
Phase 4: Minimal Tests + Docs (1 week)
|
||||
|
||||
- Add a simple smoke test script that validates service ports and Couchbase
|
||||
connectivity.
|
||||
- Document the workflow in `README-dev.md` and update top-level README with a
|
||||
pointer.
|
||||
|
||||
## Deliverables Checklist
|
||||
|
||||
- `docker-compose.yml` with defined services and volumes
|
||||
- `.env.example` with required config variables
|
||||
- A single dev entrypoint script
|
||||
- Updated docs (this file) and a quick-start section
|
||||
|
||||
## Non-Goals (Intentionally Deferred)
|
||||
|
||||
- Updating Hearthstone protocol compatibility
|
||||
- Rewriting the database or switching away from Couchbase
|
||||
- Migrating C services to a different language
|
||||
|
||||
If you want, I can start by drafting the `docker-compose.yml` and a `dev` script
|
||||
tailored to the current repo layout.
|
||||
@@ -28,3 +28,8 @@ behavior while enabling modernization behind compatibility boundaries.
|
||||
- Keep configuration centralized (env or config files).
|
||||
- Prefer a single entrypoint script or container orchestration for local dev.
|
||||
- Add small smoke tests to validate service health and database connectivity.
|
||||
|
||||
## Protocol Notes
|
||||
|
||||
See `PROTOCOL-NOTES.md` for the current opcode decoder map and client-derived
|
||||
learnings used for compatibility work.
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
couchbase:
|
||||
image: ${COUCHBASE_IMAGE:-couchbase:community-6.6.0}
|
||||
env_file: .env
|
||||
ports:
|
||||
- "8091-8096:8091-8096"
|
||||
- "11210:11210"
|
||||
volumes:
|
||||
- couchbase_data:/opt/couchbase/var
|
||||
|
||||
gameserver:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.gameserver
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- couchbase
|
||||
ports:
|
||||
- "3724:3724"
|
||||
volumes:
|
||||
- ./hm_gameserver:/workspace/hm_gameserver
|
||||
- ./hm_base:/workspace/hm_base
|
||||
- ./hm_database:/workspace/hm_database
|
||||
- ./hm_log:/workspace/hm_log
|
||||
working_dir: /workspace
|
||||
command: ["./hm_gameserver/hm_gameserver", "--log=/workspace/hm_log/hm_gameserver.log"]
|
||||
|
||||
lobbyserver:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.lobbyserver
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- couchbase
|
||||
- gameserver
|
||||
ports:
|
||||
- "45678:45678"
|
||||
volumes:
|
||||
- ./hm_lobbyserver:/workspace/hm_lobbyserver
|
||||
- ./hm_base:/workspace/hm_base
|
||||
- ./hm_database:/workspace/hm_database
|
||||
- ./hm_log:/workspace/hm_log
|
||||
working_dir: /workspace
|
||||
command:
|
||||
- "./hm_lobbyserver/hm_lobbyserver"
|
||||
- "--gameserver=gameserver"
|
||||
- "--log=/workspace/hm_log/hm_lobbyserver.log"
|
||||
|
||||
sunwell:
|
||||
build:
|
||||
context: ./hm_sunwell
|
||||
dockerfile: docker/Dockerfile.sunwell
|
||||
env_file: .env
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
web:
|
||||
build:
|
||||
context: ./hm_web
|
||||
dockerfile: docker/Dockerfile.web
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- couchbase
|
||||
- sunwell
|
||||
ports:
|
||||
- "9002:9002"
|
||||
volumes:
|
||||
- ./hm_web:/workspace/hm_web
|
||||
- ./hm_sunwell:/workspace/hm_sunwell
|
||||
working_dir: /workspace/hm_web
|
||||
command: ["python", "app.py"]
|
||||
|
||||
nginx:
|
||||
build:
|
||||
context: ./hm_nginx
|
||||
dockerfile: docker/Dockerfile.nginx
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- web
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- ./hm_web/static:/usr/local/web/static:ro
|
||||
|
||||
volumes:
|
||||
couchbase_data:
|
||||
Submodule
+1
Submodule hs-client added at 67b3ddf12c
Reference in New Issue
Block a user