Skip to content

Commit

Permalink
Sync rename dialogs (sync IRenameable.RenamableLabel setter) (#443)
Browse files Browse the repository at this point in the history
* Sync rename dialogs (sync IRenameable.RenamableLabel setter)

Synced all implementations of `IRenameable.RenamableLabel` setter for types that can be synced.

I've decided to only apply the sync worker for types that can be synced for safety, as the rename dialogs are of low enough importance that encountering errors or other issues because of them would not be desirable. After all, if rename dialog is not synced then it should not cause any issues besides a minor visual desync (unless there's a mod that does something special with the name, which I've not really encountered).

I've wrapped the portion of the code registering it in a double call to `LongEventHandler.ExecuteWhenFinished` to ensure it runs after MP Compat's late patches, ensuring all Sync Workers will be registered by it at this point.

Because of no logging when there's `IRenameable` that can't be synced, I've included a debug action which will list all types implementing `IRenameable.RenamableLabel` setter, separated into synced and unsynced ones. This will allow us to easily check if we need to create a sync worker for any of the `IRenameable` implementations.

* Synced Dialog_RenameBuildingStorage_CreateNew:OnRenamed

`Dialog_RenameBuildingStorage_CreateNew:OnRenamed` creates a storage group, which requires syncing on top of renaming. No other vanilla dialog needs syncing dialogs like those, but some mods may require it as well.
  • Loading branch information
SokyranTheDragon authored May 24, 2024
1 parent 29a4dca commit 9002361
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 0 deletions.
28 changes: 28 additions & 0 deletions Source/Client/Debug/DebugActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

using HarmonyLib;
using LudeonTK;
using Multiplayer.Client.Util;
using RimWorld;
using RimWorld.Planet;
using UnityEngine;
Expand Down Expand Up @@ -175,6 +176,33 @@ public static void DumpDefTypes()
}
}

[DebugAction(MultiplayerCategory, "Dump IRenameable Types", allowedGameStates = AllowedGameStates.Entry)]
static void DumpIRenameableTypes()
{
var synced = new List<Type>();
var unsynced = new List<Type>();
var methods = typeof(IRenameable).AllImplementing()
.Select(t => AccessTools.DeclaredPropertySetter(t, nameof(IRenameable.RenamableLabel)))
.AllNotNull();

foreach (var method in methods)
{
// Check if a method is synced or not
if (Sync.methodBaseToInternalId.ContainsKey(method))
synced.Add(method.DeclaringType);
else
unsynced.Add(method.DeclaringType);
}

Log.Warning("== Synced IRenameable types ==");
Log.Message(!synced.Any() ? "No types" : synced.Select(GetNameWithNamespace).Join(delimiter: "\n"));

Log.Warning("== Unsynced IRenameable types ==");
Log.Message(!unsynced.Any() ? "No types" : unsynced.Select(GetNameWithNamespace).Join(delimiter: "\n"));

static string GetNameWithNamespace(Type t) => t.Namespace.NullOrEmpty() ? t.Name : $"{t.Namespace}.{t.Name}";
}

[DebugAction(MultiplayerCategory, allowedGameStates = AllowedGameStates.Playing)]
static void LogAllPatch()
{
Expand Down
22 changes: 22 additions & 0 deletions Source/Client/Syncing/Game/SyncMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,28 @@ public static void Init()
SyncMethod.Register(typeof(Building_BioferriteHarvester), nameof(Building_BioferriteHarvester.EjectContents)); // Eject contents
SyncMethod.Lambda(typeof(Building_BioferriteHarvester), nameof(Building_BioferriteHarvester.GetGizmos), 1); // Toggle unload
SyncMethod.Lambda(typeof(Building_BioferriteHarvester), nameof(Building_BioferriteHarvester.GetGizmos), 3).SetDebugOnly(); // Dev add +1

// Double ExecuteWhenFinished ensures it'll load after MP Compat late patches,
// so it will have registered all its sync workers already.
LongEventHandler.ExecuteWhenFinished(() => LongEventHandler.ExecuteWhenFinished(() =>
{
// Only get methods for types which we can sync. The syncing of renaming is of low enough importance
// that we don't need to worry about having errors if there's any that can't be synced
var methods = typeof(IRenameable).AllImplementing()
.Where(t => Multiplayer.serialization.CanHandle(t))
.Select(t => AccessTools.DeclaredPropertySetter(t, nameof(IRenameable.RenamableLabel)))
.AllNotNull();

foreach (var method in methods)
MP.RegisterSyncMethod(method);

// This OnRenamed method will create a storage group, which needs to be synced.
// No other vanilla rename dialogs need syncing OnRenamed, but modded ones potentially could need it.
MP.RegisterSyncMethod(typeof(Dialog_RenameBuildingStorage_CreateNew), nameof(Dialog_RenameBuildingStorage_CreateNew.OnRenamed))
.TransformTarget(Serializer.New(
(Dialog_RenameBuildingStorage_CreateNew dialog) => dialog.building,
(IStorageGroupMember member) => new Dialog_RenameBuildingStorage_CreateNew(member)));
}));
}

[MpPrefix(typeof(PawnColumnWorker_CopyPasteTimetable), nameof(PawnColumnWorker_CopyPasteTimetable.PasteTo))]
Expand Down

0 comments on commit 9002361

Please sign in to comment.