-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathCompatibility.cs
More file actions
236 lines (217 loc) · 8.45 KB
/
Copy pathCompatibility.cs
File metadata and controls
236 lines (217 loc) · 8.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
using HarmonyLib;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
namespace PolyMod.Managers;
/// <summary>
/// Manages compatibility checks for mods, including checksum verification and version warnings.
/// </summary>
internal static class Compatibility
{
/// <summary>
/// The checksum of all loaded mods.
/// </summary>
internal static string checksum = string.Empty;
/// <summary>
/// Whether the game settings should be reset due to a change in mods.
/// </summary>
internal static bool shouldResetSettings = false;
private static bool sawSignatureWarning;
/// <summary>
/// Hashes the signatures of all loaded mods to create a checksum.
/// </summary>
/// <param name="checksumString">A string builder containing the signatures to hash.</param>
public static void HashSignatures(StringBuilder checksumString)
{
checksum = Util.Hash(checksumString);
}
/// <summary>
/// Checks the signature of a saved game to ensure it is compatible with the current mods.
/// </summary>
/// <returns>True if the signatures match or if the check is ignored, false otherwise.</returns>
private static bool CheckSignatures(Action action, Il2CppSystem.Guid gameId)
{
if (sawSignatureWarning)
{
sawSignatureWarning = false;
return true;
}
string stateChecksum = string.Empty;
try
{
Plugin.logger.LogInfo($"Getting checksum for state {gameId}");
stateChecksum = File.ReadAllText(Path.Combine(Application.persistentDataPath, $"{gameId}.signatures"));
Plugin.logger.LogInfo($"Checksum found.");
}
catch
{
Plugin.logger.LogInfo($"Failed to get checksum.");
}
if (stateChecksum == string.Empty)
{
Plugin.logger.LogInfo($"State checksum is empty, ignoring.");
return true;
}
bool doChecksumsMatch = stateChecksum == checksum;
Plugin.logger.LogInfo($"State checksum: '{stateChecksum}', global checksum: '{checksum}', comparison result : {doChecksumsMatch}");
if (Plugin.config.debug)
{
Plugin.logger.LogInfo($"Debug detected, ignoring.");
return true;
}
if (!doChecksumsMatch)
{
PopupManager.GetBasicPopupWithData(new(
Localization.Get("polymod.signature.mismatch"),
Localization.Get("polymod.signature.incompatible"),
new(new PopupBase.PopupButtonData[] {
new("OK")
})
)).Show();
return false;
}
return true;
}
/// <summary>
/// Performs compatibility checks when the start screen is shown.
/// </summary>
[HarmonyPostfix]
[HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.OnShow))]
private static void StartScreen_UI2_OnShow()
{
string lastChecksum = checksum;
try
{
lastChecksum = new(File.ReadAllText(Plugin.CHECKSUM_PATH));
}
catch (FileNotFoundException) { }
File.WriteAllText(
Plugin.CHECKSUM_PATH,
checksum
);
if (lastChecksum != checksum)
{
shouldResetSettings = true;
}
Version incompatibilityWarningLastVersion = new(PlayerPrefs.GetString(
Plugin.INCOMPATIBILITY_WARNING_LAST_VERSION_KEY,
Plugin.POLYTOPIA_VERSION.CutRevision().ToString()
));
if (VersionManager.SemanticVersion.Cast().CutRevision() > incompatibilityWarningLastVersion)
{
PlayerPrefs.SetString(
Plugin.INCOMPATIBILITY_WARNING_LAST_VERSION_KEY,
VersionManager.SemanticVersion.Cast().CutRevision().ToString()
);
PlayerPrefs.Save();
PopupManager.GetBasicPopupWithData(
new(
Localization.Get("polymod.version.mismatch"),
Localization.Get("polymod.version.mismatch.description"),
new PopupBase.PopupButtonData[] {
new("buttons.stay", customColorStates: ColorConstants.redButtonColorStates),
new(
"buttons.exitgame",
PopupBase.PopupButtonData.States.None,
(Il2CppSystem.Action)Application.Quit,
closesPopup: false
)
}
)
).Show();
}
}
/// <summary>
/// Checks the signature of a pass-and-play game before loading it.
/// </summary>
[HarmonyPrefix]
[HarmonyPatch(typeof(GameInfoPopup), nameof(GameInfoPopup.OnMainButtonClicked))]
private static bool GameInfoPopup_OnMainButtonClicked(GameInfoPopup __instance)
{
return CheckSignatures(__instance.OnMainButtonClicked, __instance.gameId);
}
/// <summary>
/// Checks the signature of a single-player game before resuming it.
/// </summary>
[HarmonyPrefix]
[HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.OnResumeButtonLongPress))]
private static bool StartScreen_OnResumeButtonClick(StartScreen_UI2 __instance)
{
return CheckSignatures(__instance.OnResumeButtonLongPress, LocalSaveFileUtils.GetSaveFiles(PolytopiaBackendBase.Game.GameType.SinglePlayer)[0]);
}
/// <summary>
/// Deletes the signature file of a pass-and-play game when it is deleted.
/// </summary>
[HarmonyPostfix]
[HarmonyPatch(typeof(GameInfoPopup), nameof(GameInfoPopup.DeletePaPGame))]
private static void GameInfoPopup_DeletePaPGame(GameInfoPopup __instance)
{
File.Delete(Path.Combine(Application.persistentDataPath, $"{__instance.gameId}.signatures"));
}
/// <summary>
/// Deletes the signature file of all singleplayer games when they are deleted.
/// </summary>
[HarmonyPrefix]
[HarmonyPatch(typeof(LocalSaveFileUtils), nameof(LocalSaveFileUtils.DeleteAllSaveFilesOfType))]
private static void LocalSaveFileUtils_DeleteAllSaveFilesOfType(PolytopiaBackendBase.Game.GameType gameType, bool localOnly)
{
if (gameType == PolytopiaBackendBase.Game.GameType.SinglePlayer)
{
foreach (var gameId in LocalSaveFileUtils.GetSaveFiles(PolytopiaBackendBase.Game.GameType.SinglePlayer))
{
File.Delete(Path.Combine(Application.persistentDataPath, $"{gameId}.signatures"));
}
}
}
/// <summary>
/// Deletes the signature file of a game when the match ends.
/// </summary>
[HarmonyPrefix]
[HarmonyPatch(typeof(GameManager), nameof(GameManager.MatchEnded))]
private static void GameManager_MatchEnded(bool localPlayerIsWinner, ScoreDetails scoreDetails, byte winnerId)
{
File.Delete(Path.Combine(Application.persistentDataPath, $"{GameManager.Client.gameId}.signatures"));
}
/// <summary>
/// Creates a signature file when a new game session is created.
/// </summary>
[HarmonyPostfix]
[HarmonyPatch(typeof(ClientBase), nameof(ClientBase.CreateSession), typeof(GameSettings), typeof(Il2CppSystem.Guid))]
private static void ClientBase_CreateSession(GameSettings settings, Il2CppSystem.Guid gameId)
{
File.WriteAllTextAsync(
Path.Combine(Application.persistentDataPath, $"{gameId}.signatures"),
checksum
);
}
/// <summary>
/// Resets game settings if necessary when the tribe selector screen is shown.
/// </summary>
[HarmonyPrefix]
[HarmonyPatch(typeof(TribeSelectorScreen), nameof(TribeSelectorScreen.Show))]
private static bool TribeSelectorScreen_Show(bool instant = false)
{
if (shouldResetSettings)
{
RestorePreliminaryGameSettings();
shouldResetSettings = false;
}
return true;
}
/// <summary>
/// Restores the preliminary game settings to their default values.
/// </summary>
internal static void RestorePreliminaryGameSettings()
{
GameManager.PreliminaryGameSettings.disabledTribes.Clear();
GameManager.PreliminaryGameSettings.selectedSkins.Clear();
GameManager.PreliminaryGameSettings.SaveToDisk();
}
/// <summary>
/// Initializes the Compatibility manager by patching the necessary methods.
/// </summary>
internal static void Init()
{
Harmony.CreateAndPatchAll(typeof(Compatibility));
}
}