Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 146 additions & 15 deletions Source/Client/Windows/SaveGameWindow.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
using System.IO;
using Multiplayer.Client.Util;
using Multiplayer.Client.Util;
using RimWorld;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using Verse;

namespace Multiplayer.Client;

public class SaveGameWindow : Window
{
public override Vector2 InitialSize => new(350f, 175f);
public override Vector2 InitialSize => new(400f, 500f);

private string curText = "";
private bool fileExists;
private bool filesRead;
private SaveFileReader reader;
private FileInfo selectedFile;
private static Vector2 saveListScroll;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couldn't this be a instance field? None of the other added fields are static

private float saveListHeight;

public SaveGameWindow(string gameName)
{
Expand All @@ -21,32 +28,154 @@ public SaveGameWindow(string gameName)
UpdateText(ref curText, GenFile.SanitizedFileName(gameName));
}

public override void DoWindowContents(Rect inRect)
private void ReloadFiles()
{
GUILayout.BeginArea(inRect.AtZero());
reader?.WaitTasks(); // Wait for the existing reader to finish

reader = new SaveFileReader();
reader.StartReading();
}

public override void DoWindowContents(Rect windowRect)
{
if (!filesRead)
{
ReloadFiles();
filesRead = true;
}

GUILayout.BeginArea(windowRect.AtZero());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
GUILayout.BeginArea(windowRect.AtZero());
GUILayout.BeginArea(windowRect);

nit: this is a pre-existing issue, but the .AtZero() is redundant, as the windowRect is already zeroed when called by the Window parent class

GUILayout.BeginVertical();

MpLayout.Label("MpSaveGameAs".Translate());
float margin = 10;

// Draw text and input box at the top of the window
using (MpStyle.Set(GameFont.Small))
{
Vector2 textSize = Text.CalcSize("MpSaveGameAs".Translate());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable textSize

GUILayout.Label("MpSaveGameAs".Translate());
}

UpdateText(ref curText, GUILayout.TextField(curText));

using (MpStyle.Set(GameFont.Tiny))
MpLayout.Label(fileExists ? "MpWillOverwrite".Translate() : "");
GUILayout.Label(fileExists ? "MpWillOverwrite".Translate() : "");

MpLayout.BeginHorizCenter();
{
if (MpLayout.Button("OK".Translate(), 120f))
Accept(false);
// Draw save buttons at the bottom of the window
int buttonWidth = 120;
int buttonHeight = 35;
int buttonGap = 5;
int button1x = Prefs.DevMode ?
(int)(windowRect.width / 2 - buttonWidth - buttonGap / 2) :
(int)(windowRect.width / 2 - buttonWidth / 2);
int button2x = (int)(windowRect.width / 2 + buttonGap / 2);
int buttonY = (int)(windowRect.yMax - 10 - buttonHeight);

if (Prefs.DevMode && MpLayout.Button("Dev: save replay", 120f))
Accept(true);
}
MpLayout.EndHorizCenter();
if (Widgets.ButtonText(new Rect(button1x, buttonY, buttonWidth, buttonHeight), "OK".Translate()))
Accept(false);
if (Prefs.DevMode && Widgets.ButtonText(new Rect(button2x, buttonY, buttonWidth, buttonHeight), "Dev: save replay"))
Accept(true);

// Draw save list
windowRect.y += 8;
Rect outerRect = new Rect(margin, windowRect.yMin + 75, windowRect.width - 2 * margin, windowRect.height - buttonHeight - 100);
Rect scrollRect = new Rect(0, 0, outerRect.width - 16f, saveListHeight);

Widgets.BeginScrollView(outerRect, ref saveListScroll, scrollRect, true);

float y = 0;
DrawSaveList(reader.MpSaves, scrollRect.width, ref y);

if (Event.current.type == EventType.Layout)
saveListHeight = y;

Widgets.EndScrollView();

GUILayout.EndVertical();
GUILayout.EndArea();
}

private void DrawSaveList(List<FileInfo> saves, float width, ref float y)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is almost the same as in ServerBrowser, except one small change. While I'm not a fan of this code duplication, I think it's fine for an intial version, and I wouldn't want to block this PR on it

{
for (int i = 0; i < saves.Count; i++)
{
var file = saves[i];
var data = reader.GetData(file);
Rect entryRect = new Rect(0, y, width, 40);

if (file == selectedFile)
{
Widgets.DrawRectFast(entryRect, new Color(1f, 1f, 0.7f, 0.1f));

var lineColor = new Color(1, 1, 1, 0.3f);
Widgets.DrawLine(entryRect.min, entryRect.TopRightCorner(), lineColor, 2f);
Widgets.DrawLine(entryRect.min - new Vector2(-1, -5), entryRect.BottomLeftCorner() - new Vector2(-1, -2), lineColor, 2f);
Widgets.DrawLine(entryRect.BottomLeftCorner(), entryRect.max, lineColor, 2f);
Widgets.DrawLine(entryRect.TopRightCorner() - new Vector2(1, -5), entryRect.max - new Vector2(1, -2), lineColor, 2f);
}
else if (i % 2 == 0)
{
Widgets.DrawAltRect(entryRect);
}

using (MpStyle.Set(TextAnchor.MiddleLeft))
Widgets.Label(entryRect.Right(10), data?.displayName ?? "Loading...");

using var _ = MpStyle.Set(new Color(0.6f, 0.6f, 0.6f));
using var __ = MpStyle.Set(GameFont.Tiny);

var infoText = new Rect(entryRect.xMax - 120, entryRect.yMin + 3, 120, entryRect.height);
Widgets.Label(infoText, file.LastWriteTime.ToString("yyyy-MM-dd HH:mm"));

if (data != null)
{
if (data.gameName != null)
{
Widgets.Label(infoText.Down(16), data.gameName.Truncate(110));
}
else
{
GUI.color = data.VersionColor;
Widgets.Label(infoText.Down(16), (data.rwVersion ?? "???").Truncate(110));
}

if (!data.HasRwVersion)
{
var rect = new Rect(infoText.x - 80, infoText.y + 8f, 80, 24f);
GUI.color = Color.red;

Widgets.Label(rect, $"({"EItemUpdateStatus_k_EItemUpdateStatusInvalid".Translate()})");
TooltipHandler.TipRegion(rect, new TipSignal("SaveIsUnknownFormat".Translate()));
}
else if (data.replay && !data.MajorAndMinorVerEqualToCurrent)
{
GUI.color = new Color(0.8f, 0.8f, 0, 0.6f);
var outdated = new Rect(infoText.x - 80, infoText.y + 8f, 80, 24f);
Widgets.Label(outdated, "MpSaveOutdated".Translate());

var text = "MpSaveOutdatedDesc".Translate(data.rwVersion, VersionControl.CurrentVersionString);
TooltipHandler.TipRegion(outdated, text);
}
}

Text.Font = GameFont.Small;
GUI.color = Color.white;

// Check data != null after drawing the button so draw order doesn't depend on data
// and IMGUI control ids are the same across frames
if (Widgets.ButtonInvisible(entryRect, false) && data != null)
{
if (Event.current.button == 0)
{
UpdateText(ref curText, file.Name[..file.Name.IndexOf('.')]);
selectedFile = file;
}
}

y += 40;
}
}

public override void OnAcceptKeyPressed()
{
Accept(false);
Expand All @@ -63,6 +192,8 @@ private void UpdateText(ref string value, string newValue)
if (!newValue.NullOrEmpty() && GenFile.SanitizedFileName(newValue) != newValue)
return;

// Clear selectedFile on text change
selectedFile = null;
fileExists = new FileInfo(Path.Combine(Multiplayer.ReplaysDir, $"{newValue}.zip")).Exists;
value = newValue;
}
Expand Down
Loading