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).
|
- Keep configuration centralized (env or config files).
|
||||||
- Prefer a single entrypoint script or container orchestration for local dev.
|
- Prefer a single entrypoint script or container orchestration for local dev.
|
||||||
- Add small smoke tests to validate service health and database connectivity.
|
- 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