Skip to content

Commit

Permalink
Update mods to use API version 0.5 (#397)
Browse files Browse the repository at this point in the history
Changes:

- `PatchingUtilities.InitCancelInInterface()` completely removed
- `PatchingUtilities.ShouldCancel` removed, calls to it replaced with `MP.InInterface`
- Use `MP.RegisterDefaultLetterChoice` instead of accessing MP types/methods directly
- `MP.RegisterSyncDelegate` using compiler-generated names replaced with `MP.RegisterSyncDelegateLambda`
- Vanilla Expanded Framework DoorTeleporter uses `TransformField` and `MP.TryGetThingById` instead of operating on compiler-generated classes/methods directly
- Vanilla Factions Expanded - Empire uses `TransformField` and `MP.CanUseDevMode`, removed the temporary patch

The one major thing that this doesn't cover is the usage of sessions as a replacement for pause locks.
  • Loading branch information
SokyranTheDragon authored Dec 29, 2023
1 parent 9e94208 commit 19b1294
Show file tree
Hide file tree
Showing 18 changed files with 52 additions and 278 deletions.
5 changes: 1 addition & 4 deletions Source/Mods/AllowTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,6 @@ public AllowTool(ModContentPack mod)

// Recache haul urgently deterministically (currently uses Time.unscaledTime)
{
// Used by DeterministicallyHandleReCaching
PatchingUtilities.InitCancelInInterface();

var type = AccessTools.TypeByName("AllowTool.HaulUrgentlyCacheHandler");
MpCompat.harmony.Patch(AccessTools.Method(type, "RecacheIfNeeded"),
prefix: new HarmonyMethod(typeof(AllowTool), nameof(DeterministicallyHandleReCaching)));
Expand Down Expand Up @@ -306,7 +303,7 @@ private static bool DeterministicallyHandleReCaching(ref float currentTime)
if (!MP.IsInMultiplayer)
return true;
// Can be called from MonoBehaviour.FixedUpdate and operates on a single map only, cancel in such cases
if (PatchingUtilities.ShouldCancel)
if (MP.InInterface)
return false;

currentTime = Find.TickManager.TicksGame;
Expand Down
14 changes: 4 additions & 10 deletions Source/Mods/MoreFactionInteraction.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Linq;
using HarmonyLib;
using Multiplayer.API;
using Verse;
Expand All @@ -14,16 +13,11 @@ internal class MoreFactionInteraction
{
public MoreFactionInteraction(ModContentPack mod)
{
Type type = AccessTools.TypeByName("Multiplayer.Client.Patches.CloseDialogsForExpiredLetters");
// We should probably add this to the API the next time we update it
// TODO: Expose in API
var registerAction = AccessTools.Method(type, "RegisterDefaultLetterChoice");

type = AccessTools.TypeByName("MoreFactionInteraction.ChoiceLetter_ReverseTradeRequest");
var type = AccessTools.TypeByName("MoreFactionInteraction.ChoiceLetter_ReverseTradeRequest");
var methods = MpMethodUtil.GetLambda(type, "Choices", MethodType.Getter, null, 0, 3).ToArray();
MP.RegisterSyncDelegate(type, methods[0].DeclaringType.Name, methods[0].Name);
MP.RegisterSyncMethod(methods[1]);
registerAction.Invoke(null, new object[] {methods[1], type});
MP.RegisterDefaultLetterChoice(methods[1], type);

var typeNames = new[]
{
Expand All @@ -38,7 +32,7 @@ public MoreFactionInteraction(ModContentPack mod)
methods = MpMethodUtil.GetLambda(type, "Choices", MethodType.Getter, null, 0, 1).ToArray();
MP.RegisterSyncMethod(methods[0]);
MP.RegisterSyncMethod(methods[1]);
registerAction.Invoke(null, new object[] {methods[1], type});
MP.RegisterDefaultLetterChoice(methods[1], type);
}

typeNames = new[]
Expand Down
2 changes: 1 addition & 1 deletion Source/Mods/PerformanceOptimizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ private static IDictionary ReturnCorrectCache(IDictionary simulationCache)
return null;

// If simulation, return normal cache
if (!PatchingUtilities.ShouldCancel)
if (!MP.InInterface)
return simulationCache;

// If interface, try to return the cache from our dictionary
Expand Down
2 changes: 1 addition & 1 deletion Source/Mods/ResearchPowl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ private static void SyncResearchNode(SyncWorker sync, ref object node)
private static bool PreSanityCheck(WorldComponent __instance, IList ____queue)
{
// Let it run normally in SP or in synced commands (or other contexts not needing syncing)
if (!PatchingUtilities.ShouldCancel)
if (!MP.InInterface)
return true;

foreach (var node in ____queue)
Expand Down
12 changes: 4 additions & 8 deletions Source/Mods/RimsentialSpaceports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,12 @@ public RimsentialSpaceports(ModContentPack mod)

// Choice letters
{
var type = AccessTools.TypeByName("Multiplayer.Client.Patches.CloseDialogsForExpiredLetters");
// We should probably add this to the API the next time we update it
var registerAction = AccessTools.DeclaredMethod(type, "RegisterDefaultLetterChoice");

type = AccessTools.TypeByName("Spaceports.Letters.PrisonerTransferLetter");
var type = AccessTools.TypeByName("Spaceports.Letters.PrisonerTransferLetter");
var methods = MpMethodUtil.GetLambda(type, "Choices", MethodType.Getter, null, 0, 1, 2).ToArray();
MP.RegisterSyncMethod(methods[0]);
MP.RegisterSyncMethod(methods[1]);
MP.RegisterSyncMethod(methods[2]);
registerAction.Invoke(null, new object[] { methods[2], type });
MP.RegisterDefaultLetterChoice(methods[2], type);

var typeNames = new[]
{
Expand All @@ -58,9 +54,9 @@ public RimsentialSpaceports(ModContentPack mod)
methods = MpMethodUtil.GetLambda(type, "Choices", MethodType.Getter, null, 0, 1).ToArray();
MP.RegisterSyncMethod(methods[0]);
MP.RegisterSyncMethod(methods[1]);
registerAction.Invoke(null, new object[] { methods[1], type });
MP.RegisterDefaultLetterChoice(methods[1], type);
}
}
}
}
}
}
2 changes: 1 addition & 1 deletion Source/Mods/RunandGun.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public RunandGun(ModContentPack mod)
{
Type type = AccessTools.TypeByName("RunAndGun.Harmony.Pawn_DraftController_GetGizmos_Patch");

MP.RegisterSyncDelegate(type, "<>c__DisplayClass0_0", "<Postfix>b__1");
MP.RegisterSyncDelegateLambda(type, "Postfix", 1);

PatchingUtilities.PatchSystemRand("RunAndGun.Harmony.MentalStateHandler_TryStartMentalState:shouldRunAndGun", false);
}
Expand Down
5 changes: 2 additions & 3 deletions Source/Mods/SRTSExpanded.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ private static void DelayedPatch(string modId)
var tryLaunch = AccessTools.Method(type, "TryLaunch");
tryLaunchMethod = MethodInvoker.GetHandler(tryLaunch);

PatchingUtilities.InitCancelInInterface();
MpCompat.harmony.Patch(tryLaunch, prefix: new HarmonyMethod(typeof(SRTSExpanded), nameof(PreTryLaunch)));
MP.RegisterSyncMethod(typeof(SRTSExpanded), nameof(SyncedLaunch)).ExposeParameter(2);

Expand All @@ -83,7 +82,7 @@ private static void PostSyncBombType()
private static bool PreTryLaunch(ThingComp __instance, int destinationTile, TransportPodsArrivalAction arrivalAction, Caravan cafr = null)
{
// Let the method run only if it's synced call
if (!PatchingUtilities.ShouldCancel)
if (!MP.InInterface)
return true;

var caravanFieldValue = caravanField(__instance);
Expand Down Expand Up @@ -142,7 +141,7 @@ private static void PatchCarryalls()
private static bool PreAddPawns(ThingComp __instance, List<Pawn> ___tmpAllowedPawns)
{
// Let the method run only if it's synced call
if (!PatchingUtilities.ShouldCancel)
if (!MP.InInterface)
return true;

SyncedAddPawns(__instance, ___tmpAllowedPawns);
Expand Down
2 changes: 1 addition & 1 deletion Source/Mods/SimpleSidearms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private static void HandleInteractionPostfix()
[MpCompatPrefix("PeteTimesSix.SimpleSidearms.Utilities.GettersFilters", "findBestRangedWeapon", 8)]
private static bool PrePrimaryVerbMethodCall(ThingWithComps __0, ref bool __result)
{
if (!PatchingUtilities.ShouldCancel)
if (!MP.InInterface)
return true;

var comp = __0.GetComp<CompEquippable>();
Expand Down
2 changes: 1 addition & 1 deletion Source/Mods/VanillaAnimalsEndangered.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public VanillaAnimalsEndangered(ModContentPack mod)
{
var type = AccessTools.TypeByName("VanillaAnimalsExpandedEndangered.Pawn_GetGizmos_Patch");

MP.RegisterSyncDelegate(type, "<>c__DisplayClass3_0", "<Postfix>b__1");
MP.RegisterSyncDelegateLambda(type, "Postfix", 1);
}
}
}
101 changes: 10 additions & 91 deletions Source/Mods/VanillaExpandedFramework.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,6 @@ public VanillaExpandedFramework(ModContentPack mod)

#region Shared sync workers and patches

// MP - ThingsById
private static Dictionary<int, Thing> thingsById;

// Right now only used by teleporter doors. Could potentially be used by other mods.
// It's a separate method instead of being always initialized in case this ever changes in MP and causes issues here.
private static void EnsureThingsByIdDictionaryActive() => thingsById ??= (Dictionary<int, Thing>)AccessTools.Field(AccessTools.TypeByName("Multiplayer.Client.ThingsById"), "thingsById").GetValue(null);

private static void SyncCommandWithBuilding(SyncWorker sync, ref Command command)
{
var traverse = Traverse.Create(command);
Expand Down Expand Up @@ -196,7 +189,6 @@ private static void PatchExtraPregnancyApproaches()

private static void PatchExpandableProjectile()
{
PatchingUtilities.InitCancelInInterface();
MpCompat.harmony.Patch(AccessTools.DeclaredPropertyGetter("VFECore.ExpandableProjectile:StartingPosition"),
prefix: new HarmonyMethod(typeof(VanillaExpandedFramework), nameof(PreStartingPositionGetter)),
postfix: new HarmonyMethod(typeof(VanillaExpandedFramework), nameof(PostStartingPositionGetter)));
Expand All @@ -205,7 +197,7 @@ private static void PatchExpandableProjectile()
private static void PreStartingPositionGetter(Vector3 ___startingPosition, bool ___pawnMoved, ref (Vector3, bool)? __state)
{
// If in interface, store the current values.
if (PatchingUtilities.ShouldCancel)
if (MP.InInterface)
__state = (___startingPosition, ___pawnMoved);
}

Expand Down Expand Up @@ -943,22 +935,21 @@ private static void SyncFactionDiscoveryDialog(SyncWorker sync, ref Window windo
private static ConstructorInfo renameDoorTeleporterDialogConstructor;
private static AccessTools.FieldRef<object, ThingWithComps> renameDoorTeleporterDialogThingField;

// DoorTeleporter.<>c__DisplayClass26_0
private static Type innerClassDoorTeleporterLocalsType;
private static AccessTools.FieldRef<object, ThingWithComps> innerClassDoorTeleporterThisField;
private static AccessTools.FieldRef<object, Pawn> innerClassDoorTeleporterPawnField;

// DoorTeleporter.<>c__DisplayClass26_1
private static AccessTools.FieldRef<object, object> innerClassDoorTeleporterLocalsField;
private static AccessTools.FieldRef<object, Thing> innerClassDoorTeleporterTargetField;

private static void PatchDoorTeleporter()
{
var type = AccessTools.TypeByName("VFECore.DoorTeleporter");
// Destroy
MpCompat.RegisterLambdaMethod(type, "GetDoorTeleporterGismoz", 0).SetContext(SyncContext.None);
// Teleport to x
MpCompat.RegisterLambdaDelegate(type, nameof(ThingWithComps.GetFloatMenuOptions), 0);
MpCompat.RegisterLambdaDelegate(type, nameof(ThingWithComps.GetFloatMenuOptions), 0)[0]
.TransformField("doorTeleporter", Serializer.New<Thing, int>(
t => t.thingIDNumber,
id =>
{
MP.TryGetThingById(id, out var thing);
return thing;
}),
true);

renameDoorTeleporterDialogType = AccessTools.TypeByName("VFECore.Dialog_RenameDoorTeleporter");
renameDoorTeleporterDialogConstructor = AccessTools.DeclaredConstructor(renameDoorTeleporterDialogType, new[] { type });
Expand All @@ -974,51 +965,6 @@ private static void PatchDoorTeleporter()
if (dialog is Window w)
Find.WindowStack.TryRemove(w);
});

var innerClassMethod = MpMethodUtil.GetLambda(type, nameof(ThingWithComps.GetFloatMenuOptions));

if (innerClassMethod == null)
Log.Error("Couldn't find inner class 1 for door teleporters, they won't work.");
else
{
var fields = AccessTools.GetDeclaredFields(innerClassMethod.DeclaringType);
if (fields.Count != 2)
Log.Error($"Found incorrect amount of fields while trying to register door teleporters (inner class 1) - found: {fields.Count}, expected: 2.");

foreach (var field in fields)
{
if (field.FieldType == type)
innerClassDoorTeleporterTargetField = AccessTools.FieldRefAccess<object, Thing>(field);
else
{
innerClassDoorTeleporterLocalsType = field.FieldType;
innerClassDoorTeleporterLocalsField = AccessTools.FieldRefAccess<object, object>(field);
}
}

if (innerClassDoorTeleporterLocalsType == null)
{
Log.Error("Couldn't find inner class 0 for door teleporters, they won't work.");
}
else
{
fields = AccessTools.GetDeclaredFields(innerClassDoorTeleporterLocalsType);
if (fields.Count != 2)
Log.Error($"Found incorrect amount of fields while trying to register door teleporters (inner class 0) - found: {fields.Count}, expected: 2.");

foreach (var field in fields)
{
if (field.FieldType == type)
innerClassDoorTeleporterThisField = AccessTools.FieldRefAccess<object, ThingWithComps>(field);
else if (field.FieldType == typeof(Pawn))
innerClassDoorTeleporterPawnField = AccessTools.FieldRefAccess<object, Pawn>(field);
}

EnsureThingsByIdDictionaryActive();
MP.RegisterSyncWorker<object>(SyncInnerDoorTeleporterClass, innerClassMethod.DeclaringType, shouldConstruct: true);
MP.RegisterSyncMethod(innerClassMethod);
}
}
}

private static void SyncDialogRenameDoorTeleporter(SyncWorker sync, ref Dialog_Rename dialog)
Expand All @@ -1043,33 +989,6 @@ private static void SyncDialogRenameDoorTeleporter(SyncWorker sync, ref Dialog_R
}
}

private static void SyncInnerDoorTeleporterClass(SyncWorker sync, ref object obj)
{
if (sync.isWriting)
{
var locals = innerClassDoorTeleporterLocalsField(obj);
var target = innerClassDoorTeleporterTargetField(obj);

// The target is on a different map, so we can't just sync it as MP does not allow it.
// We need to sync the ID number and manually get the target by ID instead.
sync.Write(target.thingIDNumber);
sync.Write(innerClassDoorTeleporterThisField(locals));
sync.Write(innerClassDoorTeleporterPawnField(locals));
}
else
{
// shouldConstruct: true, so obj is constructed
// but we need to construct the other object used for locals
var locals = Activator.CreateInstance(innerClassDoorTeleporterLocalsType);
innerClassDoorTeleporterLocalsField(obj) = locals;

// Get the target by ID.
innerClassDoorTeleporterTargetField(obj) = thingsById.GetValueSafe(sync.Read<int>());
innerClassDoorTeleporterThisField(locals) = sync.Read<ThingWithComps>();
innerClassDoorTeleporterPawnField(locals) = sync.Read<Pawn>();
}
}

#endregion

#region Special Terrain
Expand Down
3 changes: 1 addition & 2 deletions Source/Mods/VanillaFactionsPirates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ public VanillaFactionsPirates(ModContentPack mod)
// The code using the ability returns true, and we need to make sure it happens because
// as far as I understand, sync method on non-void methods returns default value (which
// would be false for bool)
PatchingUtilities.InitCancelInInterface();
MP.RegisterSyncMethod(typeof(VanillaFactionsPirates), nameof(SyncedShieldDetonation));
MpCompat.harmony.Patch(AccessTools.Method("VFEPirates.Verb_ShieldDetonation:TryCastShot"),
prefix: new HarmonyMethod(typeof(VanillaFactionsPirates), nameof(PreShieldDetonation)));
Expand Down Expand Up @@ -246,7 +245,7 @@ private static IEnumerable<CodeInstruction> ReplaceButton(IEnumerable<CodeInstru

private static bool PreShieldDetonation(Verb __instance, ref bool __result)
{
if (!PatchingUtilities.ShouldCancel)
if (!MP.InInterface)
return true;

// We need to sync as ThingComp, as MP only supports 2 comps - CompEquippable and CompReloadable
Expand Down
3 changes: 1 addition & 2 deletions Source/Mods/VanillaHairExpanded.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ public void LatePatch()
beardDefField = AccessTools.Field(type, "beardDef");
hairColourField = AccessTools.Field(type, "hairColour");

PatchingUtilities.InitCancelInInterface();
MpCompat.harmony.Patch(AccessTools.Method(typeof(WindowStack), nameof(WindowStack.TryRemove), new[] { typeof(Window), typeof(bool) }),
prefix: new HarmonyMethod(typeof(VanillaHairExpanded), nameof(PreTryRemoveWindow)));

Expand All @@ -77,7 +76,7 @@ private static void PostDoWindowContents()
private static bool PreTryRemoveWindow(Window window)
{
// Let the method run only if it's synced call
if (!PatchingUtilities.ShouldCancel || window.GetType() != changeHairstyleDialogType)
if (!MP.InInterface || window.GetType() != changeHairstyleDialogType)
return true;

SyncedTryRemoveWindow();
Expand Down
2 changes: 1 addition & 1 deletion Source/Mods/VanillaPlantsAutoPlowPatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ namespace Multiplayer.Compat
class VanillaPlantsAutoPlowPatch
{
public VanillaPlantsAutoPlowPatch(ModContentPack mod)
=> MP.RegisterSyncDelegate(AccessTools.TypeByName("VPEAutoPlow.Patch_Zone_Growing_GetGizmos"), "<>c__DisplayClass0_0", "<Add_AllowAutoPlow_Gizmo>b__1");
=> MP.RegisterSyncDelegateLambda(AccessTools.TypeByName("VPEAutoPlow.Patch_Zone_Growing_GetGizmos"), "Add_AllowAutoPlow_Gizmo", 1);
}
}
13 changes: 2 additions & 11 deletions Source/Mods/VanillaRacesAndroid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,7 @@ private static void LatePatch()
// https://github.com/rwmt/Multiplayer/blob/c7a673a63178257fbcbbe4812b0d48f0e8df2593/Source/Client/Syncing/Game/SyncDelegates.cs#L277-L279
// https://github.com/rwmt/Multiplayer/blob/c7a673a63178257fbcbbe4812b0d48f0e8df2593/Source/Client/Syncing/Game/SyncDelegates.cs#L331-L356

var type = AccessTools.TypeByName("Multiplayer.Client.Patches.CloseDialogsForExpiredLetters");
var registerAction = AccessTools.DeclaredMethod(type, "RegisterDefaultLetterChoice");

type = AccessTools.TypeByName("VREAndroids.ChoiceLetter_AndroidAwakened");
var type = AccessTools.TypeByName("VREAndroids.ChoiceLetter_AndroidAwakened");

var method = AccessTools.DeclaredMethod(type, "MakeChoices");
MP.RegisterSyncMethod(method).ExposeParameter(1);
Expand All @@ -243,13 +240,7 @@ private static void LatePatch()
passionChoicesField = AccessTools.FieldRefAccess<List<SkillDef>>(type, "passionChoices");
traitChoicesField = AccessTools.FieldRefAccess<List<Trait>>(type, "traitChoices");

registerAction.Invoke(
null,
new object[]
{
AccessTools.DeclaredMethod(typeof(VanillaRacesAndroid), nameof(DefaultDialogSelection)),
type
});
MP.RegisterDefaultLetterChoice(AccessTools.DeclaredMethod(typeof(VanillaRacesAndroid), nameof(DefaultDialogSelection)), type);

type = AccessTools.TypeByName("VREAndroids.Dialog_AndroidAwakenedChoices");
MpCompat.harmony.Patch(AccessTools.DeclaredMethod(type, nameof(Window.DoWindowContents)),
Expand Down
Loading

0 comments on commit 19b1294

Please sign in to comment.