Skip to content
Merged
Show file tree
Hide file tree
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
7 changes: 7 additions & 0 deletions Source/Client/MultiplayerStatic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public static class MultiplayerStatic
public static readonly Texture2D GiftModeIcon = ContentFinder<Texture2D>.Get("UI/Buttons/GiftMode");
public static readonly Texture2D TradeModeIcon = ContentFinder<Texture2D>.Get("UI/Buttons/TradeMode");

public const string MpHostReplayCmdLineArg = "mphostreplay";

static MultiplayerStatic()
{
Native.InitLmfPtr(
Expand Down Expand Up @@ -263,6 +265,11 @@ void TickBatch()
DirectXmlSaver.SaveDataObject(new SyncContainer(), "SyncHandlers.xml");
ExtendDirectXmlSaver.extend = false;
}

if (GenCommandLine.TryGetCommandLineArg(MpHostReplayCmdLineArg, out var path))
{
DoubleLongEvent(() => HostWindow.VerifyAndOpen(path), "Loading");
}
}

public class SyncContainer
Expand Down
11 changes: 11 additions & 0 deletions Source/Client/Windows/HostWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using RimWorld;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using Verse;
Expand Down Expand Up @@ -34,6 +35,16 @@ enum Tab

private ServerSettings serverSettings;

public static void VerifyAndOpen(string path)
{
FileInfo fileInfo = new(path);
var saveFile = SaveFile.ReadMpSave(fileInfo);
ServerBrowser.CheckGameVersionAndMods(
saveFile,
() => { Find.WindowStack.Add(new HostWindow(saveFile) { returnToServerBrowser = false }); }
);
}

public HostWindow(SaveFile file = null)
{
closeOnAccept = false;
Expand Down
141 changes: 73 additions & 68 deletions Source/Client/Windows/SaveFileReader.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#nullable enable
using Multiplayer.Common;
using RimWorld;
using System;
Expand All @@ -14,17 +15,17 @@ namespace Multiplayer.Client
{
public class SaveFileReader
{
public List<FileInfo> SpSaves { get; private set; }
public List<FileInfo> MpSaves { get; private set; }
public List<FileInfo> SpSaves { get; private set; } = [];
public List<FileInfo> MpSaves { get; private set; } = [];

private ConcurrentDictionary<FileInfo, SaveFile> data = new();
private Task spTask, mpTask;
private Task? spTask, mpTask;

public void StartReading()
{
SpSaves = GenFilePaths.AllSavedGameFiles.OrderByDescending(f => f.LastWriteTime).ToList();

var replaysDir = new DirectoryInfo(GenFilePaths.FolderUnderSaveData("MpReplays"));
var replaysDir = new DirectoryInfo(Multiplayer.ReplaysDir);
var toRead = replaysDir.GetFiles("*.zip", MpVersion.IsDebug ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
MpSaves = toRead.OrderByDescending(f => f.LastWriteTime).ToList();

Expand All @@ -37,18 +38,15 @@ public void StartReading()

public void WaitTasks()
{
spTask.Wait();
mpTask.Wait();
spTask?.Wait();
mpTask?.Wait();
}

private void ReadSpSave(FileInfo file)
{
try
{
var saveFile = new SaveFile(Path.GetFileNameWithoutExtension(file.Name), false, file);
using var stream = file.OpenRead();
ReadSaveInfo(stream, saveFile);
data[file] = saveFile;
data[file] = SaveFile.ReadSpSave(file);
}
catch (Exception ex)
{
Expand All @@ -60,58 +58,16 @@ private void ReadMpSave(FileInfo file)
{
try
{
var displayName = Path.ChangeExtension(Path.GetRelativePath(Multiplayer.ReplaysDir, file.FullName), null);
var saveFile = new SaveFile(displayName, true, file);

var replay = Replay.ForLoading(file);
if (!replay.LoadInfo()) return;

saveFile.gameName = replay.info.name;
saveFile.protocol = replay.info.protocol;
saveFile.replaySections = replay.info.sections.Count;

if (!replay.info.rwVersion.NullOrEmpty())
{
saveFile.rwVersion = replay.info.rwVersion;
saveFile.modIds = replay.info.modIds.ToArray();
saveFile.modNames = replay.info.modNames.ToArray();
saveFile.asyncTime = replay.info.asyncTime;
saveFile.multifaction = replay.info.multifaction;
}
else
{
using var zip = replay.OpenZipRead();
using var stream = zip.GetEntry("world/000_save")!.Open();
ReadSaveInfo(stream, saveFile);
}

data[file] = saveFile;
var saveFile = SaveFile.ReadMpSave(file);
if (saveFile != null) data[file] = saveFile;
}
catch (Exception ex)
{
Log.Warning($"Exception loading replay info of {file.Name}: {ex}");
}
}

private void ReadSaveInfo(Stream stream, SaveFile save)
{
using var reader = new XmlTextReader(stream);
reader.ReadToNextElement(); // savedGame
reader.ReadToNextElement(); // meta

if (reader.Name != "meta") return;

reader.ReadToDescendant("gameVersion");
save.rwVersion = VersionControl.VersionStringWithoutRev(reader.ReadString());

reader.ReadToNextSibling("modIds");
save.modIds = reader.ReadStrings();

reader.ReadToNextSibling("modNames");
save.modNames = reader.ReadStrings();
}

public SaveFile GetData(FileInfo file)
public SaveFile? GetData(FileInfo file)
{
data.TryGetValue(file, out var saveFile);
return saveFile;
Expand All @@ -124,26 +80,26 @@ public void RemoveFile(FileInfo info)
}
}

public class SaveFile
public class SaveFile(string displayName, bool replay, FileInfo file)
{
public string displayName;
public bool replay;
public string displayName = displayName;
public bool replay = replay;
public int replaySections;
public FileInfo file;
public FileInfo file = file;

public string gameName;
public string? gameName;

public string rwVersion;
public string[] modNames = Array.Empty<string>();
public string[] modIds = Array.Empty<string>();
public string? rwVersion;
public string[] modNames = [];
public string[] modIds = [];

public int protocol;
public bool asyncTime;
public bool multifaction;

public bool HasRwVersion => rwVersion != null;

public bool MajorAndMinorVerEqualToCurrent =>
public bool MajorAndMinorVerEqualToCurrent => rwVersion != null &&
VersionControl.MajorFromVersionString(rwVersion) == VersionControl.CurrentMajor &&
VersionControl.MinorFromVersionString(rwVersion) == VersionControl.CurrentMinor;

Expand All @@ -164,11 +120,60 @@ public Color VersionColor
}
}

public SaveFile(string displayName, bool replay, FileInfo file)
public static SaveFile ReadSpSave(FileInfo file)
{
var saveFile = new SaveFile(Path.GetFileNameWithoutExtension(file.Name), false, file);
using var stream = file.OpenRead();
ReadSaveInfo(stream, saveFile);
return saveFile;
}

public static SaveFile? ReadMpSave(FileInfo file)
{
this.displayName = displayName;
this.replay = replay;
this.file = file;
var displayName = Path.ChangeExtension(Path.GetRelativePath(Multiplayer.ReplaysDir, file.FullName), null);
var saveFile = new SaveFile(displayName, true, file);

var replay = Replay.ForLoading(file);
if (!replay.LoadInfo()) return null;

saveFile.gameName = replay.info.name;
saveFile.protocol = replay.info.protocol;
saveFile.replaySections = replay.info.sections.Count;

if (!replay.info.rwVersion.NullOrEmpty())
{
saveFile.rwVersion = replay.info.rwVersion;
saveFile.modIds = replay.info.modIds.ToArray();
saveFile.modNames = replay.info.modNames.ToArray();
saveFile.asyncTime = replay.info.asyncTime;
saveFile.multifaction = replay.info.multifaction;
}
else
{
using var zip = replay.OpenZipRead();
using var stream = zip.GetEntry("world/000_save")!.Open();
ReadSaveInfo(stream, saveFile);
}

return saveFile;
}

private static void ReadSaveInfo(Stream stream, SaveFile save)
{
using var reader = new XmlTextReader(stream);
reader.ReadToNextElement(); // savedGame
reader.ReadToNextElement(); // meta

if (reader.Name != "meta") return;

reader.ReadToDescendant("gameVersion");
save.rwVersion = VersionControl.VersionStringWithoutRev(reader.ReadString());

reader.ReadToNextSibling("modIds");
save.modIds = reader.ReadStrings();

reader.ReadToNextSibling("modNames");
save.modNames = reader.ReadStrings();
}
}
}
2 changes: 1 addition & 1 deletion Source/Client/Windows/ServerBrowser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ private void DrawFileButtons(SaveFile file, ref float width)
width += 120;
}

private static void CheckGameVersionAndMods(SaveFile file, Action action)
public static void CheckGameVersionAndMods(SaveFile file, Action action)
{
ScribeMetaHeaderUtility.lastMode = ScribeMetaHeaderUtility.ScribeHeaderMode.Map;
ScribeMetaHeaderUtility.loadedGameVersion = file.rwVersion;
Expand Down
Loading