| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) RedWolf Design |
| 5 | * Copyright (c) 2017-2019, The LegacyClonk Team and contributors |
| 6 | * |
| 7 | * Distributed under the terms of the ISC license; see accompanying file |
| 8 | * "COPYING" for details. |
| 9 | * |
| 10 | * "Clonk" is a registered trademark of Matthes Bender, used with permission. |
| 11 | * See accompanying file "TRADEMARK" for details. |
| 12 | * |
| 13 | * To redistribute this file separately, substitute the full license texts |
| 14 | * for the above references. |
| 15 | */ |
| 16 | |
| 17 | /* control management */ |
| 18 | |
| 19 | #pragma once |
| 20 | |
| 21 | #include "C4Control.h" |
| 22 | #include "C4GameControlNetwork.h" |
| 23 | #include "C4Log.h" |
| 24 | #include "C4Network2Client.h" |
| 25 | #include "C4Record.h" |
| 26 | |
| 27 | enum C4ControlMode |
| 28 | { |
| 29 | CM_None, |
| 30 | CM_Local, // control = input |
| 31 | CM_Network, // control = input + network input |
| 32 | CM_Replay, // control = replay |
| 33 | }; |
| 34 | |
| 35 | #ifndef NDEBUG |
| 36 | const int32_t C4SyncCheckRate = 1, |
| 37 | #else |
| 38 | const int32_t C4SyncCheckRate = 100, |
| 39 | #endif |
| 40 | C4SyncCheckMaxKeep = 50; |
| 41 | |
| 42 | class C4GameControl |
| 43 | { |
| 44 | friend class C4ControlSyncCheck; |
| 45 | friend class C4GameControlNetwork; |
| 46 | |
| 47 | public: |
| 48 | C4GameControl(); |
| 49 | ~C4GameControl(); |
| 50 | |
| 51 | public: |
| 52 | C4Control Input; |
| 53 | C4GameControlNetwork Network; |
| 54 | |
| 55 | protected: |
| 56 | C4ControlMode eMode; |
| 57 | bool fPreInit, fInitComplete; |
| 58 | bool fHost; // (set for local, too) |
| 59 | bool fActivated; |
| 60 | bool fRecordNeeded; |
| 61 | int32_t iClientID; |
| 62 | |
| 63 | C4Record *pRecord; |
| 64 | C4Playback *pPlayback; |
| 65 | |
| 66 | C4Control SyncChecks; |
| 67 | |
| 68 | C4GameControlClient *pClients; |
| 69 | |
| 70 | C4Control *pExecutingControl; // Control that is in the process of being executed - needed by non-initial records |
| 71 | |
| 72 | private: |
| 73 | std::shared_ptr<spdlog::logger> logger; |
| 74 | |
| 75 | public: |
| 76 | // ticks |
| 77 | int32_t ControlRate; |
| 78 | int32_t ControlTick; |
| 79 | int32_t SyncRate; |
| 80 | bool DoSync; |
| 81 | |
| 82 | public: |
| 83 | // configuration |
| 84 | bool isLocal() const { return eMode == CM_Local; } |
| 85 | bool isNetwork() const { return eMode == CM_Network; } |
| 86 | bool isReplay() const { return eMode == CM_Replay; } |
| 87 | bool isCtrlHost() const { return fHost; } |
| 88 | bool isRecord() const { return !!pRecord; } |
| 89 | int32_t ClientID() const { return iClientID; } |
| 90 | bool SyncMode() const { return eMode != CM_Local || pRecord; } |
| 91 | |
| 92 | bool NoInput() const { return isReplay(); } |
| 93 | |
| 94 | // initialization |
| 95 | void InitLogger(); |
| 96 | bool InitLocal(C4Client *pLocal); |
| 97 | bool InitNetwork(C4Client *pLocal); |
| 98 | bool InitReplay(C4Group &rGroup); |
| 99 | |
| 100 | void ChangeToLocal(); |
| 101 | |
| 102 | void Clear(); |
| 103 | void Default(); |
| 104 | |
| 105 | // records |
| 106 | bool StartRecord(bool fInitial, bool fStreaming); |
| 107 | void StopRecord(StdStrBuf *pRecordName = nullptr, uint8_t *pRecordSHA1 = nullptr); |
| 108 | void RequestRuntimeRecord(); |
| 109 | bool IsRuntimeRecordPossible() const; |
| 110 | bool RecAddFile(const char *szLocalFilename, const char *szAddAs); |
| 111 | |
| 112 | // execution |
| 113 | bool Prepare(); |
| 114 | void Execute(); |
| 115 | void Ticks(); |
| 116 | |
| 117 | // public helpers |
| 118 | bool CtrlTickReached(int32_t iTick); |
| 119 | int32_t getCtrlTick(int32_t iFrame) const; |
| 120 | int32_t getNextControlTick() const; |
| 121 | |
| 122 | // control rate |
| 123 | void AdjustControlRate(int32_t iBy); |
| 124 | bool KeyAdjustControlRate(int32_t iBy) |
| 125 | { |
| 126 | AdjustControlRate(iBy); return true; |
| 127 | } |
| 128 | |
| 129 | // activation |
| 130 | void SetActivated(bool fActivated); |
| 131 | |
| 132 | // input |
| 133 | void DoInput(C4PacketType eCtrlType, C4ControlPacket *pPkt, C4ControlDeliveryType eDelivery); |
| 134 | void DbgRec(C4RecordChunkType eType, const uint8_t *pData = nullptr, size_t iSize = 0); // record debug stuff |
| 135 | C4ControlDeliveryType DecideControlDelivery(); |
| 136 | |
| 137 | // sync check |
| 138 | void DoSyncCheck(); |
| 139 | |
| 140 | // execute and record control (by self or C4GameControlNetwork) |
| 141 | void ExecControl(const C4Control &rCtrl); |
| 142 | void ExecControlPacket(C4PacketType eCtrlType, class C4ControlPacket *pPkt); |
| 143 | void OnGameSynchronizing(); // start record if desired |
| 144 | |
| 145 | const std::shared_ptr<spdlog::logger> &GetLogger() const noexcept { return logger; } |
| 146 | |
| 147 | protected: |
| 148 | // sync checks |
| 149 | C4ControlSyncCheck *GetSyncCheck(int32_t iTick); |
| 150 | void RemoveOldSyncChecks(); |
| 151 | }; |
| 152 | |
| 153 | C4LOGGERCONFIG_NAME_TYPE(C4GameControl); |
| 154 | |