diff --git a/GameServer.cs b/GameServer.cs
index be556c3..3619d59 100644
--- a/GameServer.cs
+++ b/GameServer.cs
@@ -1392,7 +1392,7 @@ public sealed class GameServer
SaveWorld();
Log($"New save game uploaded by {by} ({found.Count} files) - it is also the new reset point");
ReconnectAll($"{by} uploaded a new save game - reconnecting...");
- return $"Save game uploaded ({found.Count} files) - everyone reconnects";
+ return $"Save game uploaded ({found.Count} files) - everyone reconnects" + SaveStore.MissingItemsWarning(found);
}
/// Aktuellen Spielstand als ZIP.
diff --git a/MSCO.Server.csproj b/MSCO.Server.csproj
index 302889d..524fbb6 100644
--- a/MSCO.Server.csproj
+++ b/MSCO.Server.csproj
@@ -7,7 +7,7 @@
enable
MSCO.Server
MSCO.Server
- 2.10.1
+ 2.10.2
MBM
MSCO Dedicated Server
true
diff --git a/SaveStore.cs b/SaveStore.cs
index bb999c0..80ceb95 100644
--- a/SaveStore.cs
+++ b/SaveStore.cs
@@ -216,6 +216,16 @@ public static class SaveStore
return null;
}
+ ///
+ /// Hinweis, wenn im Spielstand items.txt fehlt: dort stehen alle gekauften Teile und Gegenstände (Ölfilter,
+ /// Zündkerzen, Keilriemen, Batterie ...) samt "eingebaut". Ohne die Datei fehlen sie am Auto - z.B. läuft Öl aus,
+ /// weil kein Ölfilter da ist. Im Einzelspieler fällt das nicht auf, wenn dort noch eine alte items.txt liegt.
+ ///
+ public static string MissingItemsWarning(IReadOnlyDictionary files) =>
+ files.ContainsKey("items.txt") ? ""
+ : " - WARNING: items.txt is missing in this save. Bought parts (oil filter, spark plugs, fan belt, battery ...) are " +
+ "stored there, so they are missing on the car (e.g. oil runs out without the oil filter). Upload the save with items.txt.";
+
/// Aktuellen Spielstand als ZIP.
public static byte[] ExportZip(string dataDir)
{
@@ -247,7 +257,7 @@ public static class SaveStore
}
catch (Exception e) { return "Could not write the save game: " + e.Message; }
GameServer.Log($"New save game uploaded by {by} ({files.Count} files, server stopped) - it is also the new reset point");
- return $"Save game uploaded ({files.Count} files) - start the server to use it";
+ return $"Save game uploaded ({files.Count} files) - start the server to use it" + MissingItemsWarning(files);
}
/// Server aus: Backup wiederherstellen.
diff --git a/Tests/Program.cs b/Tests/Program.cs
index 37d33f4..5bf4bd6 100644
--- a/Tests/Program.cs
+++ b/Tests/Program.cs
@@ -537,8 +537,10 @@ async Task PanelTests()
up.Headers.Add("X-MSCO-Panel", "1");
up.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/zip");
var upRes = await owner.SendAsync(up);
+ string upText = await upRes.Content.ReadAsStringAsync();
Check(upRes.IsSuccessStatusCode && File.ReadAllText(Path.Combine(dir, "save", "defaultES2File.txt")) == "ZIPPED SAVE",
- "A save game ZIP can be uploaded: " + await upRes.Content.ReadAsStringAsync());
+ "A save game ZIP can be uploaded: " + upText);
+ Check(upText.Contains("items.txt is missing"), "Uploading a save without items.txt warns (bought parts like the oil filter would be missing)");
Check(!File.Exists(Path.Combine(dir, "..", "evil.txt")) && !File.Exists(Path.Combine(dir, "evil.txt")), "Paths inside the ZIP are never used");
Check(File.ReadAllText(Path.Combine(dir, "save_original", "defaultES2File.txt")) == "ZIPPED SAVE", "The uploaded save is the new reset point");
// RAR (mit WinRAR gepackt, "solid", Unterordner, zusätzliche fremde Datei)
@@ -550,6 +552,7 @@ async Task PanelTests()
Check(rarRes.IsSuccessStatusCode && File.ReadAllText(Path.Combine(dir, "save", "defaultES2File.txt")) == "RAR SAVE"
&& File.ReadAllText(Path.Combine(dir, "save", "items.txt")) == "rar items" && !File.Exists(Path.Combine(dir, "save", "readme.txt")),
"A RAR archive can be uploaded (only the save files are taken): " + await rarRes.Content.ReadAsStringAsync());
+ Check(!(await rarRes.Content.ReadAsStringAsync()).Contains("items.txt is missing"), "No items.txt warning when the save has items.txt");
var junk = new HttpRequestMessage(HttpMethod.Post, "api/save/upload") { Content = new ByteArrayContent(System.Text.Encoding.UTF8.GetBytes("this is no archive")) };
junk.Headers.Add("X-MSCO-Panel", "1");
var junkRes = await owner.SendAsync(junk);