Skip to content

Commit 394ee53

Browse files
authored
Update VPE compat: sync hurricane toggle, fix tick RNG (#547)
Sync Command_AbilityToggle.ProcessInput which directly toggles Ability_Hurricane (spawning/destroying HurricaneMaker) without going through the synced ability job system. Fix FleckMaker.ThrowSmoke RNG desync in Vortex.Tick and GameCondition_PsychicFlashstorm.GameConditionTick by wrapping calls with Rand.PushState/PopState via transpiler.
1 parent f2674a5 commit 394ee53

1 file changed

Lines changed: 99 additions & 1 deletion

File tree

Source/Mods/VanillaPsycastsExpanded.cs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using HarmonyLib;
88
using Multiplayer.API;
99
using RimWorld;
10+
using UnityEngine;
1011
using Verse;
1112

1213
namespace Multiplayer.Compat
@@ -27,6 +28,7 @@ public VanillaPsycastsExpanded(ModContentPack mod)
2728
(PatchPsysets, "Psysets", false),
2829
(PatchPsyringDialog, "Psyring", false),
2930
(RegisterSyncGizmos, "General gizmos", true),
31+
(PatchAbilityToggle, "Ability toggle gizmo", true),
3032
(PatchPsychicStatusGizmo, "Psychic status gizmo", true),
3133
(PatchPsycasterHediff, "Skill point usage", true),
3234
(PatchMotesAndFlecks, "Motes and flecks", true),
@@ -139,7 +141,7 @@ private static void PatchPsysets()
139141
MP.RegisterSyncMethod(typeof(VanillaPsycastsExpanded), nameof(SyncEnsurePsysetExists));
140142
MP.RegisterSyncWorker<PsysetRenameHolder>(SyncPsysetRenameHolder);
141143

142-
var abilityDefType = AccessTools.TypeByName("VFECore.Abilities.AbilityDef");
144+
var abilityDefType = AccessTools.TypeByName("VEF.Abilities.AbilityDef");
143145
abilityDefHashSetType = typeof(HashSet<>).MakeGenericType(abilityDefType);
144146
abilityDefHashSetAddMethod = MethodInvoker.GetHandler(AccessTools.Method(abilityDefHashSetType, "Add"));
145147

@@ -422,6 +424,72 @@ private static void PatchPsycasterHediff()
422424

423425
#endregion
424426

427+
#region Ability toggle
428+
429+
// Command_AbilityToggle (Hurricane gizmo)
430+
private static AccessTools.FieldRef<object, object> commandAbilityFieldRef;
431+
private static Type iAbilityToggleType;
432+
private static PropertyInfo toggleToggleProperty;
433+
private static AccessTools.FieldRef<object, Pawn> abilityPawnFieldRef;
434+
private static AccessTools.FieldRef<object, object> abilityDefFieldRef;
435+
private static Type compAbilitiesLocalType;
436+
private static AccessTools.FieldRef<object, IEnumerable> learnedAbilitiesLocalField;
437+
438+
private static void PatchAbilityToggle()
439+
{
440+
var commandAbilityToggleType = AccessTools.TypeByName("VanillaPsycastsExpanded.Staticlord.Command_AbilityToggle");
441+
var commandAbilityType = AccessTools.TypeByName("VEF.Abilities.Command_Ability");
442+
443+
commandAbilityFieldRef = AccessTools.FieldRefAccess<object>(commandAbilityType, "ability");
444+
445+
iAbilityToggleType = AccessTools.TypeByName("VanillaPsycastsExpanded.Staticlord.IAbilityToggle");
446+
toggleToggleProperty = AccessTools.Property(iAbilityToggleType, "Toggle");
447+
448+
var abilityType = AccessTools.TypeByName("VEF.Abilities.Ability");
449+
abilityPawnFieldRef = AccessTools.FieldRefAccess<Pawn>(abilityType, "pawn");
450+
abilityDefFieldRef = AccessTools.FieldRefAccess<object>(abilityType, "def");
451+
452+
compAbilitiesLocalType = AccessTools.TypeByName("VEF.Abilities.CompAbilities");
453+
learnedAbilitiesLocalField = AccessTools.FieldRefAccess<IEnumerable>(compAbilitiesLocalType, "learnedAbilities");
454+
455+
MP.RegisterSyncMethod(typeof(VanillaPsycastsExpanded), nameof(SyncedAbilityToggle));
456+
457+
MpCompat.harmony.Patch(AccessTools.Method(commandAbilityToggleType, "ProcessInput"),
458+
prefix: new HarmonyMethod(typeof(VanillaPsycastsExpanded), nameof(PreAbilityToggleProcessInput)));
459+
}
460+
461+
private static bool PreAbilityToggleProcessInput(object __instance)
462+
{
463+
if (!MP.IsInMultiplayer)
464+
return true;
465+
466+
var ability = commandAbilityFieldRef(__instance);
467+
var pawn = abilityPawnFieldRef(ability);
468+
var def = (Def)abilityDefFieldRef(ability);
469+
470+
SyncedAbilityToggle(pawn, def);
471+
return false;
472+
}
473+
474+
private static void SyncedAbilityToggle(Pawn pawn, Def abilityDef)
475+
{
476+
var comp = pawn.AllComps.FirstOrDefault(c => compAbilitiesLocalType.IsInstanceOfType(c));
477+
if (comp == null)
478+
return;
479+
480+
foreach (var ability in learnedAbilitiesLocalField(comp))
481+
{
482+
if ((Def)abilityDefFieldRef(ability) == abilityDef && iAbilityToggleType.IsInstanceOfType(ability))
483+
{
484+
var current = (bool)toggleToggleProperty.GetValue(ability);
485+
toggleToggleProperty.SetValue(ability, !current);
486+
break;
487+
}
488+
}
489+
}
490+
491+
#endregion
492+
425493
#region Other
426494

427495
private static void RegisterSyncGizmos()
@@ -442,6 +510,36 @@ private static void PatchMotesAndFlecks()
442510
"VanillaPsycastsExpanded.FixedTemperatureZone:ThrowFleck",
443511
"VanillaPsycastsExpanded.Conflagrator.FireTornado:ThrowPuff",
444512
});
513+
514+
// FleckMaker.ThrowSmoke in tick methods uses RNG after visibility check
515+
var transpiler = new HarmonyMethod(typeof(VanillaPsycastsExpanded), nameof(TranspileThrowSmokeRandFix));
516+
MpCompat.harmony.Patch(
517+
AccessTools.Method("VanillaPsycastsExpanded.Staticlord.Vortex:Tick"),
518+
transpiler: transpiler);
519+
MpCompat.harmony.Patch(
520+
AccessTools.Method("VanillaPsycastsExpanded.Staticlord.GameCondition_PsychicFlashstorm:GameConditionTick"),
521+
transpiler: transpiler);
522+
}
523+
524+
private static IEnumerable<CodeInstruction> TranspileThrowSmokeRandFix(IEnumerable<CodeInstruction> instr)
525+
{
526+
var target = AccessTools.Method(typeof(FleckMaker), nameof(FleckMaker.ThrowSmoke),
527+
[typeof(Vector3), typeof(Map), typeof(float)]);
528+
var replacement = AccessTools.Method(typeof(VanillaPsycastsExpanded), nameof(ThrowSmokeRandSafe));
529+
530+
foreach (var ci in instr)
531+
{
532+
if (ci.operand is MethodInfo method && method == target)
533+
ci.operand = replacement;
534+
yield return ci;
535+
}
536+
}
537+
538+
private static void ThrowSmokeRandSafe(Vector3 loc, Map map, float size)
539+
{
540+
Rand.PushState();
541+
FleckMaker.ThrowSmoke(loc, map, size);
542+
Rand.PopState();
445543
}
446544

447545
private static void PatchITab()

0 commit comments

Comments
 (0)