#pragma once #include "../GameState.h" #include "../external/nlohmann/json.hpp" #include #include #include #include #include namespace FRG { // Value-only view of authoritative state. It deliberately contains no runtime // pointers, callbacks, renderer objects, or mutable references, so the same // contract can later be transported over a network. struct ChatMessageSnapshot { std::string text; bool incoming = false; }; struct CharacterSnapshot { std::string id; CharacterState state; }; struct InteractiveObjectSnapshot { std::string id; InteractiveObjectState state; }; struct LocationSnapshot { std::string id; LocationNetworkState state; std::unordered_map npcs; std::unordered_map interactiveObjects; std::unordered_map triggerZones; std::unordered_map teleportZones; nlohmann::json dialogue; nlohmann::json scriptGlobals; }; struct GameSnapshot { std::uint64_t revision = 0; std::string campaignId; std::string currentLocationId; bool isDarklands = false; bool isNight = false; bool isDawn = false; int money = 0; TutorialStep tutorialStep = TutorialStep::Completed; bool tutorialPhoneChatScreenOpened = false; bool tutorialJournalScreenOpened = false; bool tutorialNeedOpenTaxiScreen = false; bool tutorialTaxiHintDone = false; bool taxiIsCalled = false; bool chatUnread[3] = {}; std::string chatPreview[3]; std::vector chatHistory[3]; std::vector inventoryItemIds; nlohmann::json questJournal; std::unordered_map globalInts; std::unordered_map globalFloats; std::unordered_map players; std::unordered_map locations; std::vector quests; bool isTutorialActive() const { return tutorialStep != TutorialStep::Completed; } }; struct SetWorldModeCommand { bool darklands; bool night; bool dawn; }; struct SetCurrentLocationCommand { std::string locationId; }; struct SetPlayerHealthCommand { float hp; float maxHp; }; struct SetMoneyCommand { int amount; }; struct SpendMoneyCommand { int amount; }; struct CompleteTutorialStepCommand { TutorialStep step; }; struct SetTutorialStepCommand { TutorialStep step; }; struct SetTutorialFlagsCommand { bool phoneChatOpened; bool journalOpened; bool needTaxiHint; bool taxiHintDone; }; struct SetChatCommand { int index; bool unread; std::string preview; }; struct AppendChatMessageCommand { int index; std::string text; bool incoming; }; struct SetTaxiCalledCommand { bool called; }; struct StartTaxiCommand { std::string locationId; }; struct ResetTaxiCommand { std::string locationId; }; struct SetLocationTargetsCommand { std::string locationId; std::string interactiveObjectId; std::string npcId; std::string teleportZoneId; }; struct SwitchLocationNavigationCommand { std::string locationId; int index; }; struct SetNavigationAreaAvailableCommand { std::string locationId; std::string areaName; bool available; }; struct AddNavigationObstacleCommand { std::string locationId; std::string name; std::vector polygon; }; struct AddInventoryItemCommand { std::string itemId; }; struct RemoveInventoryItemCommand { std::string itemId; }; struct UnlockQuestCommand { std::string questId; }; struct CompleteQuestCommand { std::string questId; }; struct FailQuestCommand { std::string questId; }; struct SetQuestObjectiveCompletedCommand { std::string questId; std::string objectiveId; bool completed; }; struct SetQuestObjectiveVisibleCommand { std::string questId; std::string objectiveId; bool visible; }; struct SetQuestActiveObjectiveCommand { std::string questId; int objectiveIndex; }; struct SetGlobalIntCommand { std::string key; int value; }; struct SetGlobalFloatCommand { std::string key; float value; }; struct SetCharacterPositionCommand { std::string locationId; std::string characterId; Eigen::Vector3f position; bool updateHomePosition = false; }; struct SetCharacterFacingAngleCommand { std::string locationId; std::string characterId; float angle; bool setCurrentAngle = false; }; struct SetCharacterHomePositionCommand { std::string locationId; std::string characterId; Eigen::Vector3f position; }; struct SetCharacterTargetCommand { std::string locationId; std::string characterId; std::string targetId; }; struct SetCharacterFaceTargetCommand { std::string locationId; std::string characterId; std::string targetId; }; struct SetCharacterEnabledCommand { std::string locationId; std::string characterId; bool enabled; }; struct ClearCharacterAttackTargetCommand { std::string locationId; std::string characterId; }; struct SetCharacterDestinationCommand { std::string locationId; std::string characterId; Eigen::Vector3f target; std::string callbackName; }; struct StopCharacterCommand { std::string locationId; std::string characterId; }; struct FaceCharacterCommand { std::string locationId; std::string characterId; std::string targetId; }; struct ReplanCharacterCommand { std::string locationId; std::string characterId; }; struct ResetCharacterAfterDeathCommand { std::string locationId; std::string characterId; }; struct TryCharacterAttackComboCommand { std::string locationId; std::string characterId; }; struct SetCharacterHealthCommand { std::string locationId; std::string characterId; float hp; }; struct SetCharacterAnimationMetadataCommand { std::string locationId; std::string characterId; AnimationState animationState; int startFrame; int frameCount; }; struct DamageCharacterCommand { std::string locationId; std::string characterId; float amount; std::string attackerId; }; struct SetInteractiveObjectActiveCommand { std::string locationId; std::string objectId; bool active; }; struct SetTriggerZoneEnabledCommand { std::string locationId; std::string zoneId; bool enabled; }; struct ReloadQuestDefinitionsCommand { std::string path; std::string zipFile; }; using GameCommand = std::variant< SetWorldModeCommand, SetCurrentLocationCommand, SetPlayerHealthCommand, SetMoneyCommand, SpendMoneyCommand, CompleteTutorialStepCommand, SetTutorialStepCommand, SetTutorialFlagsCommand, SetChatCommand, AppendChatMessageCommand, SetTaxiCalledCommand, StartTaxiCommand, ResetTaxiCommand, SetLocationTargetsCommand, SwitchLocationNavigationCommand, SetNavigationAreaAvailableCommand, AddNavigationObstacleCommand, AddInventoryItemCommand, RemoveInventoryItemCommand, UnlockQuestCommand, CompleteQuestCommand, FailQuestCommand, SetQuestObjectiveCompletedCommand, SetQuestObjectiveVisibleCommand, SetQuestActiveObjectiveCommand, SetGlobalIntCommand, SetGlobalFloatCommand, SetCharacterPositionCommand, SetCharacterFacingAngleCommand, SetCharacterHomePositionCommand, SetCharacterTargetCommand, SetCharacterFaceTargetCommand, SetCharacterEnabledCommand, ClearCharacterAttackTargetCommand, SetCharacterDestinationCommand, StopCharacterCommand, FaceCharacterCommand, ReplanCharacterCommand, ResetCharacterAfterDeathCommand, TryCharacterAttackComboCommand, SetCharacterHealthCommand, SetCharacterAnimationMetadataCommand, DamageCharacterCommand, SetInteractiveObjectActiveCommand, SetTriggerZoneEnabledCommand, ReloadQuestDefinitionsCommand>; struct InventoryItemAddedEvent { std::string itemId; }; struct InventoryItemRemovedEvent { std::string itemId; }; using GameServerEvent = std::variant< InventoryItemAddedEvent, InventoryItemRemovedEvent, Quest::QuestEvent>; class IGameServer { public: virtual ~IGameServer() = default; // Each returned object is immutable and remains valid after later commands. virtual std::shared_ptr snapshot() const = 0; // Client-relative identity assigned by this server connection. virtual const std::string& localPlayerId() const = 0; virtual void submit(const GameCommand& command) = 0; virtual std::vector drainEvents() = 0; virtual void update(std::int64_t deltaMs) = 0; // Persistence stays server-side. The JSON shape is GameState's established // save schema and is intentionally not the wire snapshot shape. virtual void save(nlohmann::json& out) const = 0; virtual void load(const nlohmann::json& in) = 0; }; } // namespace FRG