-
-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This has been lingering for a while, as I needed it for a compat I never finished. I've finally decided to clean it up and publish it. It contains compat for all components (I believe) needed compat. I was only able to test `AbilityUser` component, as none of the mods I had installed user the other components of JecsTools.
- Loading branch information
1 parent
9f0541b
commit b7ab56d
Showing
1 changed file
with
143 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
using System.Collections; | ||
using System.Linq; | ||
using HarmonyLib; | ||
using Multiplayer.API; | ||
using Verse; | ||
|
||
namespace Multiplayer.Compat | ||
{ | ||
/// <summary>JecsTools by jecrell and contributors</summary> | ||
/// <see href="https://github.com/jecrell/JecsTools"/> | ||
/// <see href="https://steamcommunity.com/sharedfiles/filedetails/?id=932008009"/> | ||
[MpCompatFor("jecrell.jecstools")] | ||
public class JecsTools | ||
{ | ||
#region Main patch | ||
|
||
public JecsTools(ModContentPack mod) | ||
{ | ||
// AbilityUser | ||
PatchAbilities(); | ||
|
||
// CompActivatableEffect | ||
{ | ||
// Deactivate/Activate gizmo | ||
MpCompat.RegisterLambdaMethod("CompActivatableEffect.CompActivatableEffect", "EquippedGizmos", 0, 1); | ||
} | ||
|
||
// CompInstalledPart | ||
{ | ||
MpCompat.RegisterLambdaDelegate("CompInstalledPart.InstalledPartFloatMenuPatch", "GetFloatMenus", 3); | ||
// Looking at the code, it seems there's no built-in way to uninstall those? | ||
} | ||
|
||
// CompSlotLoadable | ||
{ | ||
var type = AccessTools.TypeByName("CompSlotLoadable.CompSlotLoadable"); | ||
MP.RegisterSyncMethod(type, "TryCancel"); // Gizmo -> cancel | ||
MP.RegisterSyncMethod(type, "TryGiveLoadSlotJob"); // Gizmo -> float menu -> load option | ||
MP.RegisterSyncMethod(type, "TryEmptySlot"); // Gizmo -> float menu -> empty option | ||
MpCompat.RegisterLambdaDelegate("CompSlotLoadable.SloatLoadbleFloatMenuPatch", "GetFloatMenus", 1); | ||
} | ||
|
||
// CompToggleDef | ||
{ | ||
MP.RegisterSyncMethod(AccessTools.Method("CompToggleDef.ToggleDefCardUtility:SwapThing")).SetContext(SyncContext.MapSelected); | ||
} | ||
} | ||
|
||
#endregion | ||
|
||
#region Abilities | ||
|
||
// PawnAbility | ||
private static AccessTools.FieldRef<object, ThingComp> pawnAbilityUserField; | ||
|
||
// CompAbilityUser | ||
private static AccessTools.FieldRef<object, object> compAbilityUserAbilityDataField; | ||
|
||
// AbilityData | ||
private static FastInvokeHandler abilityDataAllPowersGetter; | ||
|
||
// AbilityUserUtility | ||
private static FastInvokeHandler abilityUserUtilityGetCompsMethod; | ||
|
||
private static void PatchAbilities() | ||
{ | ||
// PawnAbility | ||
var type = AccessTools.TypeByName("AbilityUser.PawnAbility"); | ||
pawnAbilityUserField = AccessTools.FieldRefAccess<ThingComp>(type, "abilityUser"); | ||
|
||
MP.RegisterSyncMethod(type, "UseAbility").SetPostInvoke(StopTargeting); | ||
MP.RegisterSyncWorker<object>(SyncPawnAbility, type); | ||
|
||
// CompAbilityUser | ||
compAbilityUserAbilityDataField = AccessTools.FieldRefAccess<object>("AbilityUser.CompAbilityUser:abilityData"); | ||
|
||
// AbilityData | ||
abilityDataAllPowersGetter = MethodInvoker.GetHandler(AccessTools.PropertyGetter("AbilityUser.AbilityData:AllPowers")); | ||
|
||
// AbilityUserUtility | ||
abilityUserUtilityGetCompsMethod = MethodInvoker.GetHandler(AccessTools.Method("AbilityUser.AbilityUserUtility:GetCompAbilityUsers")); | ||
} | ||
|
||
private static void StopTargeting(object instance, object[] args) | ||
{ | ||
// The job driver is assigning Find.Targeter.targetingSource, starting targeting again. | ||
// We need to stop targeting after casting or we'll start targeting again after casting. | ||
if (MP.IsExecutingSyncCommandIssuedBySelf) | ||
Find.Targeter.StopTargeting(); | ||
} | ||
|
||
private static void SyncPawnAbility(SyncWorker sync, ref object ability) | ||
{ | ||
if (sync.isWriting) | ||
{ | ||
// The comp.props seems null, at least in some cases - which is what MP sync worker uses for syncing. | ||
// We need to sync it differently. | ||
var abilityUserComp = pawnAbilityUserField(ability); | ||
var comps = ((IEnumerable)abilityUserUtilityGetCompsMethod(null, abilityUserComp.parent)).Cast<ThingComp>().ToArray(); | ||
|
||
var foundMatch = false; | ||
for (var index = 0; index < comps.Length; index++) | ||
{ | ||
var comp = comps[index]; | ||
var data = compAbilityUserAbilityDataField(comp); | ||
var allPowers = (IList)abilityDataAllPowersGetter(data); | ||
var innerIndex = allPowers.IndexOf(ability); | ||
|
||
if (innerIndex >= 0) | ||
{ | ||
foundMatch = true; | ||
sync.Write(index); | ||
sync.Write(innerIndex); | ||
sync.Write(abilityUserComp.parent); // Parent pawn | ||
break; | ||
} | ||
} | ||
|
||
if (!foundMatch) | ||
sync.Write(-1); | ||
} | ||
else | ||
{ | ||
var index = sync.Read<int>(); | ||
|
||
if (index < 0) | ||
return; | ||
|
||
var innerIndex = sync.Read<int>(); | ||
var pawn = sync.Read<Pawn>(); | ||
|
||
var allComps = ((IEnumerable)abilityUserUtilityGetCompsMethod(null, pawn)).Cast<ThingComp>().ToArray(); | ||
var comp = allComps[index]; | ||
var data = compAbilityUserAbilityDataField(comp); | ||
var all = (IList)abilityDataAllPowersGetter(data); | ||
|
||
ability = all[innerIndex]; | ||
} | ||
} | ||
|
||
#endregion | ||
} | ||
} |