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);