og-edopro-server-ts/core/CMakeLists.txt
Diango Gavidia b1041a61fc
feat: integrate YGOPro OCGCore WASM engine with complete duel flow
* feat(srvpro2): register YGOProResourceLoader as singleton in DI container

- Add @Service() decorator to YGOProResourceLoader
- Register as singleton in shared dependency injection container
- Add required dependencies: better-lock, koishipro-core.js, ygopro-lflist-encode, yuzuthread
- Enables singleton card reader pattern (singleton at app level, not per-room)

* feat(srvpro2): pre-load card data at startup via YGOProResourceLoader

- Add YGOProResourceLoader instantiation in index.ts at startup
- Remove @Service() decorator (Logger not in DI container)
- Manual instantiation: new YGOProResourceLoader(logger)
- Logs progress: 'Loading card data...', 'Card data loaded successfully'
- Card data is now singleton, shared across all rooms (singleton pattern)

* feat(srvpro2): add OcgcoreWorker for WASM core integration

- Add OcgcoreWorker wrapper for WASM OCGCore (yuzuthread worker)
- Add OcgcoreWorkerOptions with @TransportType decorators
- Add calculateDuelOptions utility for duel options
- Add barrel exports in index.ts

Phase 1 of WASM OCGCore migration (see migration guide)

* fix(srvpro2): fix extraScriptPaths type for OcgcoreWorker

- Change extraScriptPaths from string to string[] array
- Update ygoproPaths to './ygopro' (more standard path)
- Matches OcgcoreWorkerOptions expectation

* fix(srvpro2): fix extraScriptPaths type for OcgcoreWorker

* feat(srvpro2): add YGOProResourceLoader singleton pattern

- Add initShared() and getShared() for singleton access
- Initialize card data loading at startup in index.ts
- CardStorage now shared across all rooms (no duplicate loading)

* feat(srvpro2): add OCGCore WASM integration to MercuryRoom

- Add OcgcoreWorker imports and initialization
- Add buildRegistry() for OCGCore configuration
- Add buildDecks() placeholder for deck data
- Add startCoreWasm() method for WASM-based duel core
- Add ocgcore getter and isOcgcoreWasm flag
- Add YGOProResourceLoader singleton reference
- Update HostInfo and RuleMappings to match srvpro2 format

* feat(srvpro2): refactor MercuryWaitingState for player management

- Extract handlePlayerJoin() and handleSpectatorJoin() methods
- Fix spectator position to 7 (NetPlayerType.OBSERVER)
- Add PlayerChangeState for sendTypeChangeMessage
- Add preparePlayerChangeMessage() for YGOProStocHsPlayerChange
- Add preparePlayerEnterMessage() for YGOProStocHsPlayerEnter
- Improve code organization and reduce duplication

* chore(srvpro2): add dependencies for WASM OCGCore integration

- Add better-lock for thread-safe locking
- Add koishipro-core.js for OCGCore WASM support
- Add ygopro-lflist-encode for banlist handling
- Add yuzuthread for worker thread management

* feat(srvpro2): add deck storage to MercuryClient

- Add YGOProDeck import for deck data structure
- Add _deck property to store player's deck
- Add saveDeck() method to set deck
- Add deck getter to retrieve deck
- Initialize _isReady = false in constructor

* feat(srvpro2): add deck storage and card reader to MercuryRoom

- Add YGOProResourceLoader singleton reference for deck/card operations
- Add YGOProDeck import for deck type

* feat(srvpro2): add deck validation and PlayerChange integration

- Add PlayerChangeState import for deck status
- Add sendPlayerChangeMessage() to broadcast ready/not ready state
- Add preparePlayerChangeMessage() for PlayerChange construction
- Add preparePlayerEnterMessage() for player join notifications
- Add isReady flag check in sendTypeChangeMessage

* chore(srvpro2): remove Mode.enum.ts (integrated into HostInfo)

- Delete Mode.enum.ts as GameMode is now part of HostInfo type
- Add dependency on ygopro-msg-encode for GameMode enum

* feat(srvpro2): add NOT_READY handler for deck management

- Add handleNotReady() method to process NOT_READY command
- Add event listener for Commands.NOT_READY in constructor
- Add notReady() method to YgoClient to set _isReady = false
- Add clearDeck() method to MercuryClient to clear deck state
- Update deck property to allow null (when cleared)
- Broadcast PlayerChange NOTREADY to all clients

* feat(srvpro2): enhance RPS state and add deck validation

- MercuryRockPaperScissorsState:
  - Add HandResult imports from ygopro-msg-encode
  - Add handResult array to track team choices
  - Add handleRPSChoice with proper message parsing
  - Add YGOProStocHandResult for result messages
  - Add YGOProStocSelectHand and YGOProStocSelectTp for RPS messages

- MercuryWaitingState:
  - Add UPDATE_DECK command handler for deck submission
  - Add saveDeck() integration with MercuryClient
  - Add PlayerChange message broadcasting on deck update

* feat(srvpro2): add team system for multi-player modes

- Add getTeam() method to MercuryRoom (like srvpro2 getDuelPos)
- Add getTeamPlayers() to get players by team
- Add teamOffsetBit getter (0 for single/match, 1 for tag)
- Add allPlayersReady getter to YgoRoom
- Add isReady property support to Client.ts and RoomState.ts
- Update MercuryChoosingOrderState and MercuryDuelingState with team support

* feat(srvpro2): add OCGCore deck utilities and enhance DuelingState

- Add calculate-ocgcore-deck.ts utility for deck conversion
- Add generate-seed.ts for seed generation
- Add read-card-with-reader.ts for card reading
- Enhance MercuryDuelingState with OCGCore integration
- Fix script path in YGOProResourceLoader (scripts -> script)
- Fix test import (Mode -> GameMode from ygopro-msg-encode)

* feat(srvpro2): add routeGameMsg to OCGCore class

- Add OCGCore class in ocgcore-worker/ocgcore.ts
- Implement routeGameMsg with modular helper methods:
  - refreshForMessage(), sendToTargets(), handleResponseOrRetry()
  - getIngameDuelPosPlayers(), getIngameOperatingPlayer()
- Add isUpdateMessage utility (from srvpro2)
- Remove OcgcoreWorker from MercuryRoom (now in OCGCore class)
- Refactor MercuryDuelingState to use OCGCore class
- Add nfkit for MayBeArray type

* feat(srvpro2): implement OCGCore advance loop with clean code

- Implement advance() method with modular helper methods
- Add handleAdvanceResult() for processing worker messages
- Add handleAdvanceError() for error handling with draw game
- Implement refreshForMessage() for field state updates
- Implement refreshSingleCard() with worker queryCard
- Implement refreshZone() placeholder
- Add splitRefreshLocations() helper
- Implement sendWaitingToNonOperator() with YGOProMsgWaiting
- Add setResponseTimer() placeholder
- Rename position helpers for clarity:
  - toIngamePosition(), getPlayersAtIngamePosition()
  - getActivePlayer(), getIngamePosition()
- Fix Logger method calls (warn -> info)
- Add YGOProMsgWaiting import

* feat(srvpro2): implement handleResponse and OCGCore response handling

OCGCore - Add public methods for response management:
- currentResponsePosition getter
- timeLimitEnabled getter
- hasOcgcore()
- clearResponseTimerState()
- clearResponseState()
- setResponse(buffer)

MercuryDuelingState:
- Implement handleResponse() for player responses
- Add response validation and processing
- Send response to OCGCore and advance duel

MercuryRoom:
- Add addResponse() placeholder for duel recording
- Add setDuelFinished() to transition to WAITING state

* feat(srvpro2): add DuelRecord and refactor Mercury room states

- Add DuelRecord class for duel recording/replay (from srvpro2)
- Add shuffle-decks-by-seed utility
- Refactor MercuryRoom with duel state management
- Refactor MercuryWaitingState with new state handling
- Refactor MercuryChoosingOrderState for order selection
- Add MercuryClient sendMessageToClient method
- Update YgoRoom with duel state properties
- Clean up unused JoinHandler code

* feat(srvpro2): add GameMessageMiddleware system with inheritance support

- Add GameMessageMiddleware class for processing game messages
- Support for inheritance chain - handlers for base classes apply to derived
- Register middlewares in OCGCore:
  - YGOProMsgBase: logging and replay recording
  - YGOProMsgNewTurn, NewPhase, ResetTime, Retry, Win (placeholders)
- Process messages through middleware in handleAdvanceResult()
- Add getTypeChain() to traverse class inheritance

* feat(srvpro2): expose messageMiddleware for external handlers

- Make messageMiddleware public via getter in OCGCore
- Rename internal gameMiddleware to _gameMiddleware
- Add duelRecord management in MercuryRoom
- Update MercuryDuelingState to use messageMiddleware

* feat(srvpro2): add turn/phase tracking and reconnect support

OCGCore:
- Add _phase property to track current duel phase
- Update middleware handlers for NewTurn and NewPhase
- Add increaseTurn() call on new turn

MercuryRoom:
- Add currentDuelRecord getter
- Add reconnect() method for player reconnection
  - Removes old socket listeners
  - Sets new socket
  - Sends join game and player enter messages

MercuryDuelingState:
- Add messageMiddleware handlers for win/turn/phase

Utilities:
- Add deck-equals.ts for deck comparison

* feat(srvpro2): add TimerState and response time utilities

- Add TimerState class for managing duel timer (from srvpro2)
  - leftMs, compensatorMs, backedMs tracking
  - start/stop/reset methods
  - elapsed time calculation

- Add response-time-utils.ts for response time calculations

OCGCore:
- Enhance timer management with TimerState integration
- Add timer compensation logic
- Improve response timeout handling

MercuryDuelingState:
- Refactor response handling with timer utilities
- Add timer state management

* feat(srvpro2): add deck reversal tracking and related messages

OCGCore:
- Add _deckReversed property to track deck reversal state
- Add middleware handler for YGOProMsgReverseDeck
- Add imports for YGOProMsgReverseDeck, YGOProMsgDeckTop, OcgcoreCommonConstants

MercuryDuelingState:
- Minor update

* fix: use swapped position in typeChange during reconnection

- Fix inverted cards bug when player reconnects during duel
- Use ingame position (swapped if applicable) in typeChange message
- Clear reconnecting state after UPDATE_DECK so player can send game messages
- Add sendReconnectTimeLimitAndResponseState() to restore timer/response state

This ensures typeChange and MSG_START use consistent position mapping,
preventing client confusion about which side of the field belongs to them.

* fix: use ingame position for MSG_START to match swap logic

- Fix perspective issue when opponent chooses to go first
- Change from getTeamPlayers() to getPlayersAtIngamePosition()
- Expose getPlayersAtIngamePosition() as public method
- This ensures players receive correct playerType in MSG_START when positions are swapped

Previously, players received MSG_START with incorrect playerType when
isPositionSwapped=true (opponent went first), causing perspective
issues on their side of the field.

* feat(mercury): add captain-based RPS for team games and improve reconnection

* feat(mercury): implement win handling via middleware and improve side decking state

* refactor: rename _clients to _players to distinguish from spectators

* feat(mercury): add YGOProBanListLoader and lflist loading from YGOPro resources

- Add YGOProBanListLoader that loads ban lists from lflist.conf via YGOProResourceLoader
- Add normalizeName() to convert single-digit months/days to two-digit format
  - 2026.1 → 2026.01
  - 2013.3.1 → 2013.03.01
- Add logLFLists() to YGOProResourceLoader for debugging startup

* fix: add missing path aliases to tsconfig.eslint.json

- Add @shared/* and @ygopro/* path aliases to resolve import errors in ESLint

* refactor(mercury): continue srvpro2 migration - YGOPro resources and ban lists

- Migrate YGOProResourceLoader and YGOProBanListLoader from old mercury module
- Add path aliases @shared/* and @ygopro/* to tsconfig.eslint.json
- Various other srvpro2 migration changes

* chore: add resources/ to gitignore

* fix(mercury): implement getFirstTCGIndex to find TCG banlist dynamically

- Rename getLastTCGIndex to getFirstTCGIndex for accuracy
- Implement to find first banlist with ' TCG' in name (matching srvpro2 logic)
- Add logging to YGOProBanListLoader.load()

* refactor(mercury): continue srvpro2 migration - room and state refactoring

- Rename MercuryRoom to YGOProRoom
- Update rule mappings and join handlers
- Various state and emitter updates

* feat(mercury): add YGOProMessageRepository and update MessageRepository

- Add YGOProMessageRepository for creating YGOPro protocol messages
- Add abstract deckCountMessage<T> to MessageRepository for type-specific implementations
- Update YGOProRoom and handlers to use new message repository

* fix(mercury): update YGOProRoom state handling

* feat(logger): add warn method to Logger interface and implementations

* refactor: continue srvpro2 migration - shared modules and fixes

- Move deck errors and validators to shared
- Move card domain to shared
- Add logLFLists method to YGOProResourceLoader
- Fix hostInfo/mode infinite loop bug
- Update card and deck repositories for mercury

* fix(tests): refactor test infrastructure for shared modules migration

- Update imports from edopro to shared (MessageProcessor, Deck, Card, CardTypes, Rule)
- Change clients getter to players across all test files
- Rename MercuryWaitingState to YGOProWaitingState
- Update default time_limit from 180 to 450 in YGOProRoom
- Add MessageRepositoryMock for YGOProRoom testing
- Add YGOProRoomMother test factory
- Create YGOProRoom.test.ts replacing MercuryRoom.test.ts
- Add warn() method to LoggerMock
- Add shouldValidateDeck() to SimpleRoomMother
- Update all EDOPro room tests to use new player API
- Update mercury tests with snake_case HostInfo properties
- Fix MercuryClient tests: remove messages param, add team param
- Update MercuryClient tests imports (YGOProRoom, shared/MessageProcessor)

* refactor(mercury): continue YGOPro room and state renaming

- Remove unused RoomState interface (keep only from shared/room)
- Add YGOProRoomState as specific state interface for YGOPro
- Rename MercuryRockPaperScissorsState to YGOProRockPaperScissorState
- Update imports to use YGOProRockPaperScissorState
- Simplify RuleMappings with better formatting
- Add getFirstTCGIndex helper to MercuryBanListMemoryRepository
- Update YGOProMessageRepository with new message handling
- Add getLastSentMessage to MessageRepository interface
- Fix YGOProWaitingState constructor signature

* refactor(mercury): rename MercuryChoosingOrderState to YGOProChoosingOrderState

- Rename state file and update all imports
- Update YGOProRoom to use new state class name
- Fix YGOProRockPaperScissorState imports

* fix(mercury): convert Deck to YGOProDeck in generateDuelRecord

- Re-enable generateDuelRecord() function
- Convert shared/Deck (Card[]) to YGOProDeck (number[])
- Extract card codes using parseInt(card.code, 16)
- Apply shuffle after conversion to maintain compatibility

* refactor: reorganize dueling state and duel record generation

- Replace MercuryDuelingState with YGOProDuelingState for better naming consistency
- Move duel record generation logic from YGOProRoom to OCGCore.init()
- Add support for YGOPRO_EXTRA_SCRIPTS environment variable
- Refactor MercurySideDeckingState to use DeckCreator properly
- Update errorMessage() signature to accept type and code parameters
- Add changeSideMessage() to MessageRepository
- Clean up path aliases to use @edopro, @shared, @ygopro

* refactor(mercury): rename MercurySideDeckingState to YGOProSideDeckingState and update references

* feat: add match finalization with replay sending (Judgment Day v2)

Judgment Day Round 2 - Approved 

Changes:
- Add DuelRecord getter in YGOProRoom (expose _duelRecords)
- Refactor handleWinCondition into smaller, focused methods
- Extract processDuelEnd, broadcastWinMessage, updateDuelRecord
- Extract determineNextPhase, transitionToSideDecking, assignSideDeckChoice
- Refactor finalizeWithReplays into focused methods
- Extract disposeCore, sendAllReplays, generateReplayBuffer
- Extract broadcastReplay, sendDuelEndAndDisconnect
- Add try-catch around toYrp to prevent match hang
- Follow srvpro2 pattern for match termination

Architecture improvements:
- Single Responsibility Principle - each method does one thing
- DRY - extracted repeated logic into reusable methods
- Early returns for better control flow
- Descriptive method names for readability

* refactor: improve client handling and OCGCore cleanup

- Add socket close listener and cleanup logic in MercuryClient
- Improve OCGCore disposal and cleanup methods
- Enhance room client removal logic in YGOProRoom
- Update DisconnectHandler for better socket cleanup

* fix: resolve spectator replay identity loss

- Refactor dispatchGameMsg to save artificial messages.
- Save MSG_UPDATE_DATA and MSG_UPDATE_CARD to DuelRecord.
- Remove forced sendFieldStateToSpectator reset.
- Route refresh queries via dispatchGameMsg to capture in history.

* fix(mercury): implement active player rotation for tag duels in ocgcore

* refactor: streamline team handling and improve code readability across multiple states

* refactor: streamline deck validation and remove legacy check-deck utility

* chore: update Docker configuration and remove mercury symlinks

* refactor: remove SyncRepositoriesController and simplify HTTP server setup

* build: update CMakeLists with Threads and jsoncpp CONFIG mode

* refactor: rename MercuryRoomList to YGOProRoomList and simplify SQLite setup

* chore: stop tracking resources/ygopro/base/script submodule

* chore: update build and setup scripts

* build: update duel.cpp and remove vcpkg.json

* refactor: update YGOPro resource loading and banlist handling

* chore: remove version specification from docker-compose.yaml

* refactor: improve ocgcore worker handling and duel state management

* feat: implement side deck handling in YGOProSideDeckingState

* feat: add duel end handling in YGOProDuelingState

* feat: enhance duel result handling with detailed outcomes

* feat: improve ocgcore worker process management and event handling

* test: simplify MercuryClient tests and update mock

* fix: correct formatRuleMappings property names and add TCG command alias

formatRuleMappings used camelCase (duelRule, timeLimit, maxDeckPoints)
instead of snake_case (duel_rule, time_limit, max_deck_points) matching
HostInfo interface, so format-specific values were silently ignored.
Also adds "tcg" as alias for "ot" (rule: 5) matching srvpro2 behavior,
and fixes lflist tests to verify banlist hash instead of internal index.

* fix: add oo and ocgonly as aliases for oor command in room rules

* fix: reject pre-release cards when room format is not PRE

CardAvailabilityValidationHandler bitwise check allowed pre-release
cards (ot 0x102) through TCG-only validation because (0x102 & 0x2)
still matches. Now explicitly rejects PRERELEASE-flagged cards unless
the room rule is PRE_RELEASE or ALL. Adds protocol-to-Rule mapping
in YGOProRoom to correctly translate srvpro2 rule values to the Rule
enum. PRE format now uses rule 3 (PRE_RELEASE) instead of rule 5.
Also removes stray console.log from YGOProWaitingState.

* Revert "fix: reject pre-release cards when room format is not PRE"

This reverts commit a20048d8c6.

* feat: dual card storage to separate standard and extended card pools

YGOProResourceLoader now maintains two CardStorage instances: standard
(YGOPRO_FOLDERS) and extended (YGOPRO_FOLDERS + YGOPRO_EXTRA_DB_FOLDERS).
Room commands like PRE, TCGPRE, OCGART etc. use the extended pool while
standard formats use only the base pool. Unknown cards in deck building
now return UnknownCardError instead of being silently ignored.

Simplifies Dockerfile by removing the TypeORM merge step for prereleases
since YGOProResourceLoader loads .cdb files directly from directories.

* test: add useExtendedCardPool detection tests for room formats

Verify that PRE, TCGPRE, OCGPRE, TCGART, OCGART formats enable the
extended card pool while standard formats like M and OT do not.

* fix: restrict tcgpre and ocgpre to their respective card regions

TCGPRE now sets rule 1 (TCG only) and OCGPRE sets rule 0 (OCG only)
instead of rule 5 (ALL). Both still use the extended card pool for
pre-release cards but restrict the region scope as their names imply.

* fix: correct rule values for tcgart, ocgart, otto and md alias

TCGART now uses rule 1 (TCG only) and OCGART uses rule 0 (OCG only)
with duel_rule 5 instead of incorrect values. OTTO now sets lflist 0
for OCG banlist. MD alias changed from "masterduel" to "md" to match
actual banlist name "2026.03 MD", removing hardcoded fallback index.

* test: add room command tests for all promoted web formats

Add tests for OTTO, TOOT, Edison, MD, JTP, Tengu, HAT, GX and
extended card pool detection for TCGART/OCGART formats.

* refactor: rename mercury module to ygopro

* refactor: rename Mercury references to YGOPro and update related classes

* docs: rename Mercury to YGOPro across README and AGENTS.md files

Update all documentation to reflect the mercury → ygopro module rename.
Add Card Database Architecture section to README explaining the dual
card pool system. Remove empty skill symlinks from .agent/ and .claude/.

* fix: update brace-expansion, handlebars, and path-to-regexp versions in package-lock.json

* refactor: reorganize .env.example for better readability and structure

* refactor: update mercury port configuration to use YGOPRO_PORT environment variable

* refactor: change edoBanListHash to private and update its assignment logic

* feat: add damage, recovery, and LP cost handling in YGOProDuelingState

* fix: map Mercury duel_rule to EDOPro lobby duel flags

Mercury rooms showed "Custom" in the EDOPro lobby Rule column because
toPresentation() hardcoded duel_flag: 0 and forbidden_types: 0.
The client's GetMasterRule() needs exact DUEL_MODE_MRx flag values to
display "MR 5", "MR 4", etc.

* chore: bump koishipro-core.js to ^1.4.4

* fix: parse unrestricted cards in whitelist banlists

ygopro-lflist-encode silently discards entries with limit >= 3.
Whitelist banlists (like Edison) list ALL allowed cards including
unrestricted ones. Without parsing those entries, the deck validator
rejected valid cards as CARD_UNKNOWN.

* chore: bump koishipro-core.js to ^1.4.4

* feat: add chat message handling for YGOPro rooms
2026-04-02 21:46:03 -04:00

31 lines
810 B
CMake

cmake_minimum_required(VERSION 3.18)
project(CoreIntegrator LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Boost REQUIRED COMPONENTS system)
find_package(CURL REQUIRED)
find_package(jsoncpp REQUIRED CONFIG)
find_package(nlohmann_json REQUIRED)
find_package(SQLite3 REQUIRED)
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
add_executable(CoreIntegrator ${SOURCES})
find_package(Threads REQUIRED)
target_link_libraries(CoreIntegrator PRIVATE
Boost::system
CURL::libcurl
jsoncpp_lib
nlohmann_json::nlohmann_json
SQLite::SQLite3
Threads::Threads
${CMAKE_DL_LIBS}
)
# Output binary to the core directory as per original behavior
set_target_properties(CoreIntegrator PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")