Skip to content

Commit

Permalink
Updated Work Tab to work with forks, minor changes (#497)
Browse files Browse the repository at this point in the history
- Made the compat run if Work Tab 1.5 Temp (by arof) is active
- Made the compat run if Work Tab - 1.5 Unofficial (by DomB) is active
- Replaced `ConstructorInfo.Invoke` with `Activator.CreateInstance` (if I recall correctly, it tends to be faster)
- Wrapped synced paste to with `try/finally` block to ensure the player's clipboard won't be replaced in case of errors
- Minor formatting changes
  - Changed array creation from `new[] {}` to `[]`
  - Removed double indentation for array creation
  - Split `{ }` into 2 separate lines for consistency with the rest of the project
    - This was 1 of the 3 files where an empty code block was written like that
  • Loading branch information
SokyranTheDragon authored Nov 29, 2024
1 parent c9db9a1 commit 04b2bec
Showing 1 changed file with 30 additions and 20 deletions.
50 changes: 30 additions & 20 deletions Source/Mods/WorkTab.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ namespace Multiplayer.Compat
/// <summary>Work Tab by Fluffy</summary>
/// <see href="https://github.com/fluffy-mods/WorkTab"/>
/// <see href="https://steamcommunity.com/sharedfiles/filedetails/?id=725219116"/>
/// <see href="https://steamcommunity.com/sharedfiles/filedetails/?id=2552065963"/>
/// <see href="https://steamcommunity.com/sharedfiles/filedetails/?id=3253535347"/>
[MpCompatFor("Fluffy.WorkTab")]
[MpCompatFor("arof.fluffy.worktab")]
[MpCompatFor("arof.fluffy.worktab.continued")]
internal class WorkTab
{
// Delegates
private delegate void PasteTo(PawnColumnWorker_CopyPasteWorkPriorities instance, Pawn pawn);

// Changing priorities
private static ConstructorInfo copyPasteColumnWorkerConstructor;
private static Type copyPasteColumnWorkerType;
private static AccessTools.FieldRef<Dictionary<WorkGiverDef, int[]>> clipboardField;
private static PasteTo pasteToMethod;

Expand All @@ -29,10 +33,10 @@ public WorkTab(ModContentPack mod)
MP.RegisterSyncMethod(AccessTools.PropertySetter(type, "ShowPriorities"));

type = AccessTools.TypeByName("WorkTab.Pawn_Extensions");
MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", new[] { typeof(Pawn), typeof(WorkTypeDef), typeof(int), typeof(List<int>) }));
MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", new[] { typeof(Pawn), typeof(WorkTypeDef), typeof(int), typeof(int), typeof(bool) }));
MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", new[] { typeof(Pawn), typeof(WorkGiverDef), typeof(int), typeof(List<int>) }));
MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", new[] { typeof(Pawn), typeof(WorkGiverDef), typeof(int), typeof(int), typeof(bool) }));
MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", [typeof(Pawn), typeof(WorkTypeDef), typeof(int), typeof(List<int>)]));
MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", [typeof(Pawn), typeof(WorkTypeDef), typeof(int), typeof(int), typeof(bool)]));
MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", [typeof(Pawn), typeof(WorkGiverDef), typeof(int), typeof(List<int>)]));
MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", [typeof(Pawn), typeof(WorkGiverDef), typeof(int), typeof(int), typeof(bool)]));
// This one not needed as it calls SetPriority, but it'll
// end up calling it numerous times - let's just do it in one command.
MP.RegisterSyncMethod(type, "DisableAll");
Expand All @@ -41,8 +45,7 @@ public WorkTab(ModContentPack mod)
// But well, it ends up being called almost 2000 times in vanilla with DLCs alone...
// So I felt like it'll be smarter to sync it as a single command instead of potentially
// couple thousand with mods.
type = AccessTools.TypeByName("WorkTab.PawnColumnWorker_CopyPasteDetailedWorkPriorities");
copyPasteColumnWorkerConstructor = AccessTools.DeclaredConstructor(type);
type = copyPasteColumnWorkerType = AccessTools.TypeByName("WorkTab.PawnColumnWorker_CopyPasteDetailedWorkPriorities");
clipboardField = AccessTools.StaticFieldRefAccess<Dictionary<WorkGiverDef, int[]>>(AccessTools.Field(type, "clipboard"));
var method = AccessTools.Method(type, "PasteTo");
pasteToMethod = AccessTools.MethodDelegate<PasteTo>(method);
Expand All @@ -56,15 +59,15 @@ public WorkTab(ModContentPack mod)
// Sadly, there isn't a call like that in case of checkbox priorities - only numeric ones
var types = new (string typeName, Type parameterType)[]
{
("WorkTab.WorkType_Extensions", typeof(WorkTypeDef)),
("WorkTab.WorkGiver_Extensions", typeof(WorkGiverDef)),
("WorkTab.WorkType_Extensions", typeof(WorkTypeDef)),
("WorkTab.WorkGiver_Extensions", typeof(WorkGiverDef)),
};

foreach (var (typeName, parameterType) in types)
{
type = AccessTools.TypeByName(typeName);
MP.RegisterSyncMethod(AccessTools.Method(type, "DecrementPriority", new[] { parameterType, typeof(List<Pawn>), typeof(int), typeof(List<int>), typeof(bool) }));
MP.RegisterSyncMethod(AccessTools.Method(type, "IncrementPriority", new[] { parameterType, typeof(List<Pawn>), typeof(int), typeof(List<int>), typeof(bool) }));
MP.RegisterSyncMethod(AccessTools.Method(type, "DecrementPriority", [parameterType, typeof(List<Pawn>), typeof(int), typeof(List<int>), typeof(bool)]));
MP.RegisterSyncMethod(AccessTools.Method(type, "IncrementPriority", [parameterType, typeof(List<Pawn>), typeof(int), typeof(List<int>), typeof(bool)]));
}

// Same deal as before, stops the call from being synced hundreds of times
Expand All @@ -90,18 +93,25 @@ private static bool PrePasteTo(Pawn pawn)
private static void SyncedPasteTo(Pawn pawn, Dictionary<WorkGiverDef, int[]> targetClipboard)
{
var current = clipboardField();
clipboardField() = targetClipboard;
// Too much effort to try and find the existing instance, so create one
// It doesn't really matter, as it doesn't have anything important
// besides the static field
var tab = (PawnColumnWorker_CopyPasteWorkPriorities)copyPasteColumnWorkerConstructor.Invoke(Array.Empty<object>());
pasteToMethod(tab, pawn);
clipboardField() = current;
try
{
clipboardField() = targetClipboard;
// Too much effort to try and find the existing instance, so create one
// It doesn't really matter, as it doesn't have anything important
// besides the static field
var tab = (PawnColumnWorker_CopyPasteWorkPriorities)Activator.CreateInstance(copyPasteColumnWorkerType);
pasteToMethod(tab, pawn);
}
finally
{
clipboardField() = current;
}
}

// Blank sync worker - we don't have anything to sync and only care about the
// object being initialized so we can call the synced method on something
private static void SyncPawnColumnLabel(SyncWorker sync, ref PawnColumnWorker_Label obj)
{ }
{
}
}
}
}

0 comments on commit 04b2bec

Please sign in to comment.