Skip to content

Commit

Permalink
Update current sync methods and delegates (#436)
Browse files Browse the repository at this point in the history
- Updated lambda ordinals for `FloatMenuMakerMap` and `MechanitorUtility` delegates
- Changed syncing of carry to shuttle lambda delegate to a local func
- Removed syncing of `RoyalTitlePermitWorker_CallLaborers.CallLaborers`, as it's no longer needed since it'll be synced from `ITargetingSource.OrderForceTarget`
- Added a sync worker for `RoyalTitlePermitWorker_CallLaborers`, as using that permit would otherwise desync
- Added syncing of non-virtual `Verb.TryStartCastOn` method
  - It's required for ability syncing, as it can be called from `Ability.QueueCastingJob` (the `LocalTargetInfo` variant) if `verbProps.nonInterruptingSelfCast` is true
- Modified `Targeter.BeginTargeting` patch to not handle `Verb.TryStartCastOn` calls
  - This is due to the previous change handling syncing of this specific case
- Updated `SyncDelegates` and `SyncMethods` classes to use C# 12's collection expression
- Added a sync worker for `IReloadableComp`, as it's needed by one of the `FloatMenuMakerMap` delegates
  - We could change it in the future to `Write/ReadWithImpl` - however, it seems there's a very limited amount of vanilla types implementing this interface
  • Loading branch information
SokyranTheDragon authored Apr 10, 2024
1 parent b61a92b commit 87ff20a
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 34 deletions.
11 changes: 11 additions & 0 deletions Source/Client/Syncing/Dict/SyncDictDlc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ public static class SyncDictDlc
}
}, true // Implicit
},
{
// Parent: RoyalTitlePermitWorker_Targeted
(SyncWorker sync, ref RoyalTitlePermitWorker_CallLaborers dropResources) => {
if (sync.isWriting) {
sync.Write(dropResources.calledFaction);
}
else {
dropResources.calledFaction = sync.Read<Faction>();
}
}, true // Implicit
},
{
(ByteWriter data, Command_BestowerCeremony cmd) => {
WriteSync(data, cmd.job.lord);
Expand Down
13 changes: 13 additions & 0 deletions Source/Client/Syncing/Dict/SyncDictRimWorld.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Multiplayer.Common;
using RimWorld;
using RimWorld.Planet;
using RimWorld.Utility;
using Verse;
using Verse.AI;
using Verse.AI.Group;
Expand Down Expand Up @@ -1162,6 +1163,18 @@ public static class SyncDictRimWorld
return ReadWithImpl<IThingHolder>(data, supportedThingHolders);
}
},
{
(ByteWriter data, IReloadableComp obj) =>
{
if (obj is null)
WriteSync(data, (ThingComp)null);
else if (obj is ThingComp comp)
WriteSync(data, comp);
else
throw new SerializationException($"Unknown {nameof(IReloadableComp)} type: {obj.GetType()}");
},
(ByteReader data) => (IReloadableComp)ReadSync<ThingComp>(data)
},
#endregion

#region Storage
Expand Down
44 changes: 23 additions & 21 deletions Source/Client/Syncing/Game/SyncDelegates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ public static void Init()
{
const SyncContext mouseKeyContext = SyncContext.QueueOrder_Down | SyncContext.MapMouseCell;

SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.GotoLocationOption), 0).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Goto
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 1).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Arrest
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 8).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Rescue
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 7).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Capture slave
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 9).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Capture prisoner
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 10).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Carry to cryptosleep casket
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 12).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Carry to shuttle
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 42).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Reload
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddDraftedOrders), 3).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Drafted carry to bed
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddDraftedOrders), 4).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Drafted carry to bed (arrest)
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddDraftedOrders), 5).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Drafted carry to transport shuttle
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddDraftedOrders), 6).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Drafted carry to cryptosleep casket
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.GotoLocationOption), 0).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Goto
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 0).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Arrest
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 6).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Rescue
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 7).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Capture slave
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 8).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Capture prisoner
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 9).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Carry to cryptosleep casket
SyncDelegate.LocalFunc(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), "CarryToShuttleAct").CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Carry to shuttle
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddHumanlikeOrders), 50).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Reload
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddDraftedOrders), 3).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Drafted carry to bed
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddDraftedOrders), 4).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Drafted carry to bed (arrest)
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddDraftedOrders), 6).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Drafted carry to transport shuttle
SyncDelegate.Lambda(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.AddDraftedOrders), 7).CancelIfAnyFieldNull().SetContext(mouseKeyContext); // Drafted carry to cryptosleep casket

SyncDelegate.Lambda(typeof(Command_SetPlantToGrow), nameof(Command_SetPlantToGrow.ProcessInput), 2); // Set plant to grow
SyncDelegate.Lambda(typeof(Building_Bed), nameof(Building_Bed.SetBedOwnerTypeByInterface), 0).RemoveNullsFromLists("bedsToAffect"); // Set bed owner type
Expand All @@ -53,11 +53,11 @@ public static void Init()
.TransformField("things", Serializer.SimpleReader(() => Find.CurrentMap.listerThings.AllThings)).SetContext(SyncContext.CurrentMap);
SyncDelegate.LambdaInGetter(typeof(Designator), nameof(Designator.RightClickFloatMenuOptions), 1).SetContext(SyncContext.CurrentMap); // Remove all designations

SyncDelegate.Lambda(typeof(CaravanAbandonOrBanishUtility), nameof(CaravanAbandonOrBanishUtility.TryAbandonOrBanishViaInterface), 1, new[] { typeof(Thing), typeof(Caravan) }).CancelIfAnyFieldNull(); // Abandon caravan thing
SyncDelegate.Lambda(typeof(CaravanAbandonOrBanishUtility), nameof(CaravanAbandonOrBanishUtility.TryAbandonOrBanishViaInterface), 0, new[] { typeof(TransferableImmutable), typeof(Caravan) }).CancelIfAnyFieldNull(); // Abandon caravan transferable
SyncDelegate.Lambda(typeof(CaravanAbandonOrBanishUtility), nameof(CaravanAbandonOrBanishUtility.TryAbandonOrBanishViaInterface), 1, [typeof(Thing), typeof(Caravan)]).CancelIfAnyFieldNull(); // Abandon caravan thing
SyncDelegate.Lambda(typeof(CaravanAbandonOrBanishUtility), nameof(CaravanAbandonOrBanishUtility.TryAbandonOrBanishViaInterface), 0, [typeof(TransferableImmutable), typeof(Caravan)]).CancelIfAnyFieldNull(); // Abandon caravan transferable

SyncDelegate.Lambda(typeof(CaravanAbandonOrBanishUtility), nameof(CaravanAbandonOrBanishUtility.TryAbandonSpecificCountViaInterface), 0, new[] { typeof(Thing), typeof(Caravan) }).CancelIfAnyFieldNull(); // Abandon thing specific count
SyncDelegate.Lambda(typeof(CaravanAbandonOrBanishUtility), nameof(CaravanAbandonOrBanishUtility.TryAbandonSpecificCountViaInterface), 0, new[] { typeof(TransferableImmutable), typeof(Caravan) }).CancelIfAnyFieldNull(); // Abandon transferable specific count
SyncDelegate.Lambda(typeof(CaravanAbandonOrBanishUtility), nameof(CaravanAbandonOrBanishUtility.TryAbandonSpecificCountViaInterface), 0, [typeof(Thing), typeof(Caravan)]).CancelIfAnyFieldNull(); // Abandon thing specific count
SyncDelegate.Lambda(typeof(CaravanAbandonOrBanishUtility), nameof(CaravanAbandonOrBanishUtility.TryAbandonSpecificCountViaInterface), 0, [typeof(TransferableImmutable), typeof(Caravan)]).CancelIfAnyFieldNull(); // Abandon transferable specific count

SyncDelegate.Lambda(typeof(CaravanVisitUtility), nameof(CaravanVisitUtility.TradeCommand), 0).CancelIfAnyFieldNull(); // Caravan trade with settlement
SyncDelegate.Lambda(typeof(FactionGiftUtility), nameof(FactionGiftUtility.OfferGiftsCommand), 0).CancelIfAnyFieldNull(); // Caravan offer gifts
Expand Down Expand Up @@ -119,8 +119,10 @@ public static void Init()
SyncMethod.Lambda(typeof(CompRechargeable), nameof(CompRechargeable.CompGetGizmosExtra), 0).SetDebugOnly(); // Recharge
SyncMethod.Register(typeof(CompRechargeable), nameof(CompRechargeable.Discharge)).SetDebugOnly();

SyncDelegate.Lambda(typeof(Ability), nameof(Ability.QueueCastingJob), 0, new[] { typeof(LocalTargetInfo), typeof(LocalTargetInfo) });
SyncDelegate.Lambda(typeof(Ability), nameof(Ability.QueueCastingJob), 0, new[] { typeof(GlobalTargetInfo) });
// Abilities
SyncDelegate.Lambda(typeof(Ability), nameof(Ability.QueueCastingJob), 0, [typeof(LocalTargetInfo), typeof(LocalTargetInfo)]);
SyncDelegate.Lambda(typeof(Ability), nameof(Ability.QueueCastingJob), 0, [typeof(GlobalTargetInfo)]);
SyncMethod.Register(typeof(Verb), nameof(Verb.TryStartCastOn), [typeof(LocalTargetInfo), typeof(bool), typeof(bool), typeof(bool), typeof(bool)]);

// Style selection dialog
SyncDelegate.Lambda(typeof(Dialog_StyleSelection), nameof(Dialog_StyleSelection.DoWindowContents), 0); // Remove style
Expand All @@ -136,8 +138,8 @@ public static void Init()
SyncDelegate.Lambda(typeof(Gene_Deathrest), nameof(Gene_Deathrest.GetGizmos), 5).SetDebugOnly(); // Set capacity

// Mechanitor
SyncDelegate.Lambda(typeof(MechanitorUtility), nameof(MechanitorUtility.GetMechGizmos), 1).SetDebugOnly(); // Recruit
SyncDelegate.Lambda(typeof(MechanitorUtility), nameof(MechanitorUtility.GetMechGizmos), 2).SetDebugOnly(); // Kill
SyncDelegate.Lambda(typeof(MechanitorUtility), nameof(MechanitorUtility.GetMechGizmos), 2).SetDebugOnly(); // Recruit
SyncDelegate.Lambda(typeof(MechanitorUtility), nameof(MechanitorUtility.GetMechGizmos), 3).SetDebugOnly(); // Kill
SyncMethod.Register(typeof(MechanitorUtility), nameof(MechanitorUtility.ForceDisconnectMechFromOverseer)); // Disconnect from overseer, only called from FloatMenuMakerMap.<>c__DisplayClass10_19.<AddHumanlikeOrders>b__25
SyncDelegate.Lambda(typeof(Designator_MechControlGroup), nameof(Designator_MechControlGroup.ProcessInput), 1).SetContext(SyncContext.MapSelected); // Assign to group
SyncDelegate.Lambda(typeof(MechanitorControlGroupGizmo), nameof(MechanitorControlGroupGizmo.GetWorkModeOptions), 1); // Set work mode for group
Expand Down Expand Up @@ -522,7 +524,7 @@ static IEnumerable<CodeInstruction> HumanEmbryoTranspiler(IEnumerable<CodeInstru
[SyncMethod]
static void SyncedCreateImplantEmbryoBill(Pawn pawn, HumanEmbryo embryo)
{
HealthCardUtility.CreateSurgeryBill(pawn, RecipeDefOf.ImplantEmbryo, null, new List<Thing> { embryo });
HealthCardUtility.CreateSurgeryBill(pawn, RecipeDefOf.ImplantEmbryo, null, [embryo]);
embryo.implantTarget = pawn;
}

Expand Down
22 changes: 9 additions & 13 deletions Source/Client/Syncing/Game/SyncMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ public static void Init()
{
var types = typeof(CompAssignableToPawn).AllSubtypesAndSelf().ToArray();
var assignMethods = types
.Select(t => t.GetMethod(nameof(CompAssignableToPawn.TryAssignPawn), AccessTools.allDeclared, null, new[] { typeof(Pawn) }, null))
.Select(t => t.GetMethod(nameof(CompAssignableToPawn.TryAssignPawn), AccessTools.allDeclared, null, [typeof(Pawn)], null))
.AllNotNull();
var unassignMethods = types
.Select(t => t.GetMethod(nameof(CompAssignableToPawn.TryUnassignPawn), AccessTools.allDeclared, null, new[] { typeof(Pawn), typeof(bool), typeof(bool) }, null))
.Select(t => t.GetMethod(nameof(CompAssignableToPawn.TryUnassignPawn), AccessTools.allDeclared, null, [typeof(Pawn), typeof(bool), typeof(bool)], null))
.AllNotNull();

var unassignSerializer = Serializer.New(
Expand Down Expand Up @@ -140,7 +140,6 @@ public static void Init()
}
}

SyncMethod.Register(typeof(RoyalTitlePermitWorker_CallLaborers), nameof(RoyalTitlePermitWorker_CallLaborers.CallLaborers));
SyncMethod.Register(typeof(RoyalTitlePermitWorker_DropResources), nameof(RoyalTitlePermitWorker_DropResources.CallResourcesToCaravan));

SyncMethod.Register(typeof(Pawn_RoyaltyTracker), nameof(Pawn_RoyaltyTracker.AddPermit));
Expand Down Expand Up @@ -542,28 +541,25 @@ static void SyncDesiredGenepackState(Genepack genepack, CompGenepackContainer co
}
}

[MpPrefix(typeof(Targeter), nameof(Targeter.BeginTargeting), new []{ typeof(ITargetingSource), typeof(ITargetingSource), typeof(bool), typeof(Func<LocalTargetInfo, ITargetingSource>), typeof(Action), typeof(bool) })]
[MpPrefix(typeof(Targeter), nameof(Targeter.BeginTargeting), [typeof(ITargetingSource), typeof(ITargetingSource), typeof(bool), typeof(Func<LocalTargetInfo, ITargetingSource>), typeof(Action), typeof(bool)])]
static bool BeginTargeting(ITargetingSource source)
{
if (Multiplayer.Client == null || source.Targetable)
return true;

var verb = source.GetVerb;
// In case both Targetable and nonInterruptingSelfCast are false, targeter makes the caster use the verb.
// Before this change, we were syncing the cast method this ended up calling, like smokepop (and other belt) manual uses.

// In case both Targetable and nonInterruptingSelfCast are false, the targeter
// calls the non-vritual TryStartCastOn method, which we sync normally.
if (verb.verbProps.nonInterruptingSelfCast)
SyncTargeterNonInterruptingSelfCast(verb);
return true;

// In case Targetable is false and nonInterruptingSelfCast is true, targeter makes the pawn start a new job.
// At the moment, it seems to never be the case in vanilla. However, this can happen with mods.
else
SyncTargeterInterruptingSelfCast(verb, source.CasterPawn);

SyncTargeterInterruptingSelfCast(verb, source.CasterPawn);
return false;
}

[SyncMethod]
static void SyncTargeterNonInterruptingSelfCast(Verb verb) => verb.TryStartCastOn(verb.Caster);

[SyncMethod]
static void SyncTargeterInterruptingSelfCast(Verb verb, Pawn casterPawn)
{
Expand Down

0 comments on commit 87ff20a

Please sign in to comment.