1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2004, Sven2
6 * Copyright (c) 2017-2020, The LegacyClonk Team and contributors
7 *
8 * Distributed under the terms of the ISC license; see accompanying file
9 * "COPYING" for details.
10 *
11 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12 * See accompanying file "TRADEMARK" for details.
13 *
14 * To redistribute this file separately, substitute the full license texts
15 * for the above references.
16 */
17
18// game saving functionality
19// merely controls what to save when how - actual saving procedures reside in the subclasses
20//
21// Game saving is done on the following occasions:
22// -scenario saving (C4GameSaveScenario) [SyncStateScenario; KeepFiles]
23// -savegames (C4GameSaveSavegame) [SyncStateSavegame; KeepFiles]
24// -records (C4GameSaveRecord) [SyncStateSynced; KeepFiles] - initially and while game is running
25// -network synchronizations (C4GameSaveNetwork) [SyncStateSynced] - in lobby and runtime mode
26// -network references (C4GameSaveNetReference) [SyncStateScenario]
27
28#pragma once
29
30#include <C4Scenario.h>
31#include <C4Group.h>
32#include <C4Components.h>
33
34class C4GameSave
35{
36private:
37 C4Scenario rC4S; // local scenario core copy
38
39protected:
40 C4Group *pSaveGroup; // group file written to
41 bool fOwnGroup; // whether group file is owned
42
43 // if set, the game is saved at initial (pre-frame0) state
44 // (lobby-dynamics, initial records and network references)
45 // no runtime data will be saved for initial-state-saves
46 // SafeGame/NoInitialize-core-settings will be kept in its current state for initial saves
47 bool fInitial;
48
49 // sync state describes what to save
50 enum SyncState
51 {
52 SyncNONE = 0,
53 SyncScenario = 1, // save (eventually static) landscape and objects only to play as a separate scenario later
54 SyncSavegame = 2, // save all runtime data, so the scenario can be continued at a future date
55 SyncSynchronized = 3, // save exact runtime data to be network- or replay-save
56 } Sync; // sync is set by ctor
57
58 // query functions
59 virtual bool GetSaveRuntimeData() { return !fInitial; } // save exact landscape, players, etc.
60 virtual bool GetKeepTitle() { return !IsExact(); } // whether original, localized title with image and icon shall be deleted
61 virtual bool GetSaveDesc() { return true; } // should WriteDescData be executed in Save()-call?
62 virtual bool GetCopyScenario() { return true; } // return whether the savegame depends on the game scenario file
63 virtual const char *GetSortOrder() { return C4FLS_Scenario; } // return nullptr to prevent sorting
64 virtual bool GetCreateSmallFile() { return false; } // return whether file size should be minimized
65 virtual bool GetForceExactLandscape() { return GetSaveRuntimeData() && IsExact(); } // whether exact landscape shall be saved
66 virtual bool GetSaveOrigin() { return false; } // return whether C4S.Head.Origin shall be set
67 virtual bool GetClearOrigin() { return !GetSaveOrigin(); } // return whether C4S.Head.Origin shall be cleared if it's set
68 virtual bool GetSaveUserPlayers() { return IsExact(); } // return whether joined user players shall be saved into SavePlayerInfos
69 virtual bool GetSaveScriptPlayers() { return IsExact(); } // return whether joined script players shall be saved into SavePlayerInfos
70 virtual bool GetSaveUserPlayerFiles() { return IsExact(); } // return whether .c4p files of joined user players shall be put into the scenario
71 virtual bool GetSaveScriptPlayerFiles() { return IsExact(); } // return whether .c4p files of joined script players shall be put into the scenario
72
73 // savegame specializations
74 virtual void AdjustCore(C4Scenario &rC4S) {} // set specific C4S values
75 virtual bool WriteDesc(std::string &desc) { return true; } // write desc (contents only)
76 virtual bool SaveComponents() { return true; } // save (or remove) custom components for specialization
77 virtual bool OnSaving() { return true; } // callback for special actions to be performed when saving (like, add sync)
78
79 // query sync level
80 bool IsExact() { return Sync >= SyncSavegame; } // exact save (players, always exact landscape, etc.)
81 bool IsSynced() { return Sync >= SyncSynchronized; } // synchronized
82
83 // protected constructor
84 C4GameSave(bool fAInitial, SyncState ASync) : pSaveGroup(nullptr), fOwnGroup(false), fInitial(fAInitial), Sync(ASync) {}
85
86protected:
87 // some desc writing helpers
88 void WriteDescLineFeed(std::string &desc); // append a line break to desc
89 void WriteDescDate(std::string &desc, bool fRecord = false); // append current date to desc buffer
90 void WriteDescGameTime(std::string &desc); // append game time to desc buffer, if it's >0
91 void WriteDescDefinitions(std::string &desc); // append used definition filenames to desc buffer
92 void WriteDescNetworkClients(std::string &desc); // append current network client list to desc buffer
93 void WriteDescPlayers(std::string &desc, bool fByTeam, int32_t idTeam); // helper func used by WriteDescPlayers: Write all players matching team
94 void WriteDescPlayers(std::string &desc); // append currently participating players to desc buffer
95 void WriteDescLeague(std::string &desc, bool fLeague, const char *strLeagueName); // append league status
96 void WriteDescEngine(std::string &desc); // append engine build
97
98private:
99 // saving subcalls
100 bool SaveCreateGroup(const char *szFilename, C4Group &hUseGroup); // create/copy group at target filename
101 bool SaveCore(); // save C4S core
102 bool SaveScenarioSections(); // save scenario sections
103 bool SaveLandscape(); // save current landscape
104 bool SaveRuntimeData(); // save any runtime data
105
106public:
107 virtual ~C4GameSave() { Close(); } // dtor: close group
108
109 bool Save(const char *szFilename); // create group at filename and do actual saving; group is kept open until dtor or Close()-call!
110 bool Save(C4Group &hToGroup, bool fKeepGroup); // save game directly to target group
111 bool SaveDesc(C4Group &hToGroup); // save scenario desc to file
112 bool Close(); // close scenario group
113
114 C4Group *GetGroup() { return pSaveGroup; } // get scenario saving group; only open between calls to Save() and Close()
115};
116
117class C4GameSaveScenario : public C4GameSave
118{
119public:
120 C4GameSaveScenario(bool fForceExactLandscape, bool fSaveOrigin) : C4GameSave(false, SyncScenario), fForceExactLandscape(fForceExactLandscape), fSaveOrigin(fSaveOrigin) {}
121
122protected:
123 bool fForceExactLandscape;
124 bool fSaveOrigin;
125 virtual bool GetSaveOrigin() override { return fSaveOrigin; }
126 virtual bool GetClearOrigin() override { return false; } // always keep existing origin
127 virtual bool GetSaveDesc() override { return false; } // should WriteDescData be executed in Save()-call?
128 virtual bool GetForceExactLandscape() override { return C4GameSave::GetForceExactLandscape() || fForceExactLandscape; }
129 virtual bool GetSaveScriptPlayers() override { return true; } // script players are also saved; but user players aren't!
130 virtual bool GetSaveScriptPlayerFiles() override { return true; } // script players are also saved; but user players aren't!
131};
132
133class C4GameSaveSavegame : public C4GameSave
134{
135public:
136 C4GameSaveSavegame() : C4GameSave(false, SyncSavegame) {}
137
138protected:
139 // savegame specializations
140 virtual bool GetSaveOrigin() override { return true; } // origin must be saved in savegames
141 virtual bool GetSaveUserPlayerFiles() override { return false; } // user player files are not needed in savegames, because they will be replaced by player files of resuming playerss
142 virtual void AdjustCore(C4Scenario &rC4S) override; // set specific C4S values
143 virtual bool WriteDesc(std::string &desc) override; // write savegame desc (contents only)
144 virtual bool SaveComponents() override; // custom savegame components (title)
145 virtual bool OnSaving() override; // add sync when saving
146};
147
148class C4GameSaveRecord : public C4GameSave
149{
150private:
151 int iNum; // record number
152 bool fLeague; // recording of a league game?
153 bool fCopyScenario; // copy scenario?
154
155public:
156 C4GameSaveRecord(bool fAInitial, int iANum, bool fLeague, bool fCopyScenario = true)
157 : C4GameSave(fAInitial, SyncSynchronized), iNum(iANum), fLeague(fLeague), fCopyScenario(fCopyScenario) {}
158
159protected:
160 // query functions
161 virtual bool GetSaveDesc() override { return false; } // desc is saved by external call when the record is finished
162 virtual bool GetCreateSmallFile() override { return true; } // no need to save players complete with portraits
163 virtual bool GetSaveOrigin() override { return true; } // origin must be saved to trace language packs, folder local material, etc. for records
164
165 virtual bool GetCopyScenario() override { return fCopyScenario; } // records without copied scenario are a lot smaller can be reconstructed later (used for streaming)
166
167 // savegame specializations
168 virtual void AdjustCore(C4Scenario &rC4S) override; // set specific C4S values
169 virtual bool WriteDesc(std::string &desc) override; // write desc (contents only) - using old-style unchecked string buffers here...
170 virtual bool SaveComponents() override; // custom components: PlayerInfos even if fInitial
171};
172
173class C4GameSaveNetwork : public C4GameSave
174{
175public:
176 C4GameSaveNetwork(bool fAInitial) : C4GameSave(fAInitial, SyncSynchronized) {}
177
178protected:
179 // query functions
180 virtual bool GetSaveOrigin() override { return true; } // clients must know where to get music and localization
181 virtual bool GetKeepTitle() override { return false; } // always delete title files (not used in dynamics)
182 virtual bool GetSaveDesc() override { return false; } // no desc in dynamics
183 virtual bool GetCreateSmallFile() override { return true; } // return whether file size should be minimized
184
185 virtual bool GetCopyScenario() override { return false; } // network dynamics do not base on normal scenario
186 // savegame specializations
187 virtual void AdjustCore(C4Scenario &rC4S) override; // set specific C4S values
188};
189