Upload from upload_mods.ps1

This commit is contained in:
Nathaniel Cosford
2025-06-04 16:13:32 +09:30
commit 7345f42201
470 changed files with 51966 additions and 0 deletions

View File

@@ -0,0 +1,1731 @@
using HarmonyLib;
using KFCommonUtilityLib;
using KFCommonUtilityLib.Scripts.StaticManagers;
using KFCommonUtilityLib.Scripts.Utilities;
using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Xml.Linq;
using UniLinq;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Animations.Rigging;
[HarmonyPatch]
static class AnimationRiggingPatches
{
[HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.setupEquipmentCommon))]
[HarmonyPrefix]
private static bool Prefix_setupEquipmentCommon_SDCSUtils(GameObject _rigObj, out bool __state)
{
__state = false;
if (_rigObj.TryGetComponent<Animator>(out var animator))
{
__state = true;
animator.UnbindAllStreamHandles();
animator.UnbindAllSceneHandles();
}
return true;
}
[HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.setupEquipmentCommon))]
[HarmonyPostfix]
private static void Postfix_setupEquipmentCommon_SDCSUtils(GameObject _rigObj, bool __state)
{
if (__state && _rigObj.TryGetComponent<Animator>(out var animator))
{
animator.Rebind();
}
}
[HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.setupRig))]
[HarmonyPrefix]
private static bool Prefix_setupRig_SDCSUtils(ref RuntimeAnimatorController animController, ref GameObject _rigObj)
{
if (_rigObj && _rigObj.TryGetComponent<AnimationGraphBuilder>(out var builder) && builder.HasWeaponOverride)
{
animController = null;
}
return true;
}
//[HarmonyPatch(typeof(UMACharacterBodyAnimator), nameof(UMACharacterBodyAnimator.assignLayerWeights))]
//[HarmonyPrefix]
//private static bool Prefix_assignLayerWeights_UMACharacterBodyAnimator(UMACharacterBodyAnimator __instance)
//{
// if (__instance.Animator && __instance.Animator.TryGetComponent<AnimationGraphBuilder>(out var builder) && builder.HasWeaponOverride)
// {
// return false;
// }
// return true;
//}
//[HarmonyPatch(typeof(AvatarSDCSController), nameof(AvatarSDCSController.setLayerWeights))]
//[HarmonyPrefix]
//private static bool Prefix_setLayerWeights_AvatarSDCSController(AvatarSDCSController __instance)
//{
// if (__instance.anim && __instance.anim.TryGetComponent<AnimationGraphBuilder>(out var builder) && builder.HasWeaponOverride)
// {
// return false;
// }
// return true;
//}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.OnModificationsChanged))]
[HarmonyPostfix]
private static void Postfix_OnModificationChanged_ItemActionRanged(ItemActionData _data)
{
ItemActionRanged.ItemActionDataRanged rangedData = (ItemActionRanged.ItemActionDataRanged)_data;
if (rangedData.IsDoubleBarrel)
{
rangedData.muzzle = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, "Muzzle_L");
rangedData.muzzle2 = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, "Muzzle_R");
}
else
{
rangedData.muzzle = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, "Muzzle");
}
rangedData.Laser = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, "laser");
ItemActionLauncher.ItemActionDataLauncher launcherData = _data as ItemActionLauncher.ItemActionDataLauncher;
if (launcherData != null)
{
launcherData.projectileJoint = AnimationRiggingManager.GetTransformOverrideByName(launcherData.invData.model, "ProjectileJoint");
}
}
/// <summary>
/// attachment path patch, only apply to MinEventActionSetTransformActive!
/// </summary>
/// <param name="instructions"></param>
/// <returns></returns>
[HarmonyPatch(typeof(MinEventActionSetTransformActive), nameof(MinEventActionSetTransformActive.Execute))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Execute_MinEventActionSetTransformActive(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_find = AccessTools.Method(typeof(GameUtils), nameof(GameUtils.FindDeepChild));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_find))
{
codes.RemoveAt(i);
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Self)),
CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetAttachmentReferenceOverrideTransform))
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(MinEventActionSetTransformChildrenActive), nameof(MinEventActionSetTransformChildrenActive.Execute))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Execute_MinEventActionSetTransformChildrenActive(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_find = AccessTools.Method(typeof(GameUtils), nameof(GameUtils.FindDeepChildActive));
var fld_trans = AccessTools.Field(typeof(MinEventActionSetTransformChildrenActive), nameof(MinEventActionSetTransformChildrenActive.transformPath));
for (int i = 1; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_find) && codes[i - 1].LoadsField(fld_trans))
{
codes.RemoveAt(i);
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Self)),
CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetAttachmentReferenceOverrideTransformActive))
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(MinEventActionAddPart), nameof(MinEventActionAddPart.Execute))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Execute_MinEventActionAddPart(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_idx = AccessTools.PropertyGetter(typeof(Inventory), nameof(Inventory.holdingItemIdx));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_idx))
{
codes.InsertRange(i + 2, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(MinEventActionAddPart),nameof(MinEventActionAddPart.partName)),
new CodeInstruction(OpCodes.Ldc_I4_1),
CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetAddPartTransformOverride))
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(MinEventActionAttachPrefabToHeldItem), nameof(MinEventActionAttachPrefabToHeldItem.Execute))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Execute_MinEventActionAttachPrefabToHeldItem(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
var mtd_find = AccessTools.Method(typeof(GameUtils), nameof(GameUtils.FindDeepChild));
var fld_trans = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.Transform));
var mtd_layer = AccessTools.Method(typeof(Utils), nameof(Utils.SetLayerRecursively));
var lbd_targets = generator.DeclareLocal(typeof(AnimationTargetsAbs));
for (int i = 1; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Stloc_0)
{
if (codes[i - 1].Calls(mtd_find))
{
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldc_I4_0),
CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetAddPartTransformOverride))
});
codes.RemoveAt(i - 1);
i += 1;
}
else if (codes[i - 1].LoadsField(fld_trans))
{
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(MinEventActionAttachPrefabToHeldItem), nameof(MinEventActionAttachPrefabToHeldItem.parent_transform)),
new CodeInstruction(OpCodes.Ldc_I4_0),
CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetAddPartTransformOverride))
});
i += 4;
}
}
else if (codes[i].opcode == OpCodes.Stloc_2)
{
var lbl = generator.DefineLabel();
var lbls = codes[i + 1].ExtractLabels();
codes[i + 1].WithLabels(lbl);
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_1).WithLabels(lbls),
CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Transform)),
new CodeInstruction(OpCodes.Ldnull),
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UnityEngine.Object), "op_Inequality")),
new CodeInstruction(OpCodes.Brfalse_S, lbl),
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Transform)),
CodeInstruction.Call(typeof(Transform), nameof(Transform.GetComponent), new Type[0], new Type[]{ typeof(AnimationTargetsAbs)}),
new CodeInstruction(OpCodes.Stloc_S, lbd_targets)
});
i += 9;
}
else if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 4)
{
codes.RemoveAt(i - 1);
codes.InsertRange(i - 1, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, lbd_targets),
new CodeInstruction(OpCodes.Ldloc_2),
CodeInstruction.Call(typeof(AnimationRiggingPatches), nameof(CreateOrMoveAttachment))
});
i += 2;
}
else if (codes[i].Calls(mtd_layer))
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, lbd_targets),
new CodeInstruction(OpCodes.Ldloc_S, 4),
CodeInstruction.Call(typeof(AnimationRiggingPatches), nameof(CheckAttachmentRefMerge))
});
i += 3;
}
else if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 5)
{
var lbl = generator.DefineLabel();
var lbls = codes[i + 1].ExtractLabels();
codes[i + 1].WithLabels(lbl);
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldloc_3).WithLabels(lbls),
CodeInstruction.Call(typeof(Transform), nameof(Transform.GetComponent), new Type[0], new Type[]{ typeof(IgnoreTint)}),
new CodeInstruction(OpCodes.Ldnull),
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UnityEngine.Object), "op_Inequality")),
new CodeInstruction(OpCodes.Brfalse_S, lbl),
new CodeInstruction(OpCodes.Ret)
});
i += 6;
}
}
codes.InsertRange(0, new[]
{
new CodeInstruction(OpCodes.Ldnull),
new CodeInstruction(OpCodes.Stloc_S, lbd_targets)
});
return codes;
}
private static GameObject CreateOrMoveAttachment(GameObject go, AnimationTargetsAbs targets, string name)
{
GameObject res = null;
if (targets)
{
res = targets.GetPrefab(name);
}
if (!res)
{
res = GameObject.Instantiate(go);
}
return res;
}
private static void CheckAttachmentRefMerge(AnimationTargetsAbs targets, GameObject attachmentReference)
{
if (targets)
{
targets.AttachPrefab(attachmentReference);
}
}
/// <summary>
/// reload logging patch
/// </summary>
/// <param name="stateInfo"></param>
[HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateEnter))]
[HarmonyPostfix]
private static void Postfix_OnStateEnter_AnimatorRangedReloadState(AnimatorStateInfo stateInfo)
{
if (ConsoleCmdReloadLog.LogInfo)
{
Log.Out(string.Format("ANIMATION LENGTH: length {0} speed {1} speedMultiplier {2} original length {3}", stateInfo.length, stateInfo.speed, stateInfo.speedMultiplier, stateInfo.length * stateInfo.speedMultiplier));
}
}
[HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.OnHoldingItemChanged))]
[HarmonyPostfix]
private static void Postfix_OnHoldingItemChanged_EntityAlive(EntityAlive __instance)
{
AnimationRiggingManager.OnHoldingItemIndexChanged(__instance as EntityPlayer);
}
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.OnHoldingItemChanged))]
[HarmonyPostfix]
private static void Postfix_OnHoldingItemChanged_EntityPlayerLocal(EntityPlayerLocal __instance)
{
AnimationRiggingManager.OnHoldingItemIndexChanged(__instance);
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.SaveAndCleanupWorld))]
[HarmonyPostfix]
private static void Postfix_SaveAndCleanupWorld_GameManager()
{
AnimationRiggingManager.Clear();
}
private static void ParseTakeOverReloadTime(XElement _node)
{
string itemName = _node.GetAttribute("name");
if (string.IsNullOrEmpty(itemName))
{
return;
}
ItemClass item = ItemClass.GetItemClass(itemName);
if (item.Properties.GetBool("TakeOverReloadTime"))
{
AnimationRiggingManager.AddReloadTimeTakeOverItem(item.Name);
//Log.Out($"take over reload time: {item.Name} {item.Id}");
}
}
[HarmonyPatch(typeof(ItemClassesFromXml), nameof(ItemClassesFromXml.parseItem))]
[HarmonyPostfix]
private static void Postfix_parseItem_ItemClassesFromXml(XElement _node)
{
ParseTakeOverReloadTime(_node);
}
//[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.StopHolding))]
//[HarmonyPostfix]
//private static void Postfix_StopHolding_ItemClass(Transform _modelTransform)
//{
// if (_modelTransform != null && _modelTransform.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed)
// {
// targets.SetEnabled(false);
// }
//}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.createHeldItem))]
[HarmonyPostfix]
private static void Postfix_createHeldItem_Inventory(Inventory __instance, Transform __result)
{
if (__result && __result.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed)
{
if (GameManager.IsDedicatedServer || !(__instance.entity is EntityPlayer player))
{
targets.Destroy();
}
else
{
if (player is EntityPlayerLocal localPlayer)
{
targets.Init(localPlayer.emodel.avatarController.GetActiveModelRoot(), localPlayer.bFirstPersonView);
}
else
{
targets.DestroyFpv();
targets.Init(player.emodel.avatarController.GetActiveModelRoot(), false);
}
}
}
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.ForceHoldingItemUpdate))]
[HarmonyPrefix]
private static bool Prefix_ForceHoldingItemUpdate(Inventory __instance)
{
if (__instance.entity is EntityPlayer)
AnimationRiggingManager.OnClearInventorySlot(__instance, __instance.holdingItemIdx);
return true;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ItemActionEffects))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ItemActionEffects_ItemActionRanged(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
var fld_fpv = AccessTools.Field(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.bFirstPersonView));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_fpv))
{
codes.InsertRange(i + 4, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, codes[i + 3].operand),
new CodeInstruction(OpCodes.Ldarg_2),
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.particlesMuzzleFire))),
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.particlesMuzzleFireFpv))),
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.particlesMuzzleSmoke))),
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.particlesMuzzleSmokeFpv))),
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.SpawnFpvParticles))),
new CodeInstruction(OpCodes.Brtrue_S, codes[i - 5].operand)
});
break;
}
}
//FieldInfo fld_muzzle = AccessTools.Field(typeof(ItemActionRanged.ItemActionDataRanged), nameof(ItemActionRanged.ItemActionDataRanged.muzzle));
//FieldInfo fld_muzzle2 = AccessTools.Field(typeof(ItemActionRanged.ItemActionDataRanged), nameof(ItemActionRanged.ItemActionDataRanged.muzzle2));
//MethodInfo mtd_getmuzzle = AccessTools.Method(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetMuzzleOverrideFPV));
//MethodInfo mtd_getmuzzle2 = AccessTools.Method(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetMuzzle2OverrideFPV));
//for (int i = 0; i < codes.Count; i++)
//{
// if (codes[i].LoadsField(fld_muzzle))
// {
// codes.InsertRange(i + 1, new[]
// {
// new CodeInstruction(OpCodes.Ldloc_S, 4),
// new CodeInstruction(OpCodes.Call, mtd_getmuzzle)
// });
// }
// else if (codes[i].LoadsField(fld_muzzle2))
// {
// codes.InsertRange(i + 1, new[]
// {
// new CodeInstruction(OpCodes.Ldloc_S, 4),
// new CodeInstruction(OpCodes.Call, mtd_getmuzzle2)
// });
// }
//}
return codes;
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.clearSlotByIndex))]
[HarmonyPrefix]
private static bool Prefix_clearSlotByIndex(Inventory __instance, int _idx)
{
if (__instance.entity is EntityPlayer)
AnimationRiggingManager.OnClearInventorySlot(__instance, _idx);
return true;
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.Update))]
[HarmonyPostfix]
private static void Postfix_Update_AvatarMultiBodyController(AvatarMultiBodyController __instance)
{
AnimationRiggingManager.UpdatePlayerAvatar(__instance);
if (__instance is AvatarLocalPlayerController avatarLocalPlayer)
{
//if ((avatarLocalPlayer.entity as EntityPlayerLocal).bFirstPersonView && !avatarLocalPlayer.entity.inventory.GetIsFinishedSwitchingHeldItem())
//{
// avatarLocalPlayer.UpdateInt(AvatarController.weaponHoldTypeHash, -1, false);
// avatarLocalPlayer.UpdateBool("Holstered", false, false);
// avatarLocalPlayer.FPSArms.Animator.Play("idle", 0, 0f);
//}
var mapping = MultiActionManager.GetMappingForEntity(__instance.entity.entityId);
if (mapping != null)
{
avatarLocalPlayer.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, mapping.CurActionIndex, true);
}
if (__instance.entity.inventory?.holdingItemData?.actionData != null)
{
foreach (var actionData in __instance.entity.inventory.holdingItemData.actionData)
{
if (actionData is IModuleContainerFor<ActionModuleFireModeSelector.FireModeData> data)
{
avatarLocalPlayer.UpdateInt(ActionModuleFireModeSelector.FireModeParamHashes[actionData.indexInEntityOfAction], data.Instance.currentFireMode, true);
}
}
}
}
if (__instance.entity.AttachedToEntity)
{
__instance.SetVehicleAnimation(AvatarController.vehiclePoseHash, __instance.entity.vehiclePoseMode);
}
}
[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController.Update))]
[HarmonyPostfix]
private static void Postfix_Update_LegacyAvatarController(LegacyAvatarController __instance)
{
AnimationRiggingManager.UpdatePlayerAvatar(__instance);
if (__instance.entity && __instance.entity.AttachedToEntity)
{
__instance.SetVehicleAnimation(AvatarController.vehiclePoseHash, __instance.entity.vehiclePoseMode);
}
}
//[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController.LateUpdate))]
//[HarmonyPostfix]
//private static void Postfix_LateUpdate_AvatarLocalPlayerController(AvatarLocalPlayerController __instance)
//{
// var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(__instance.entity as EntityPlayer);
// if (targets && !targets.Destroyed)
// {
// targets.UpdateTpvSpineRotation(__instance.entity as EntityPlayer);
// }
//}
//[HarmonyPatch(typeof(AvatarSDCSController), nameof(AvatarSDCSController.LateUpdate))]
//[HarmonyPostfix]
//private static void Postfix_LateUpdate_AvatarSDCSController(AvatarSDCSController __instance)
//{
// var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(__instance.entity as EntityPlayer);
// if (targets && !targets.Destroyed)
// {
// targets.UpdateTpvSpineRotation(__instance.entity as EntityPlayer);
// }
//}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.StartAnimationReloading))]
[HarmonyPrefix]
private static bool Prefix_StartAnimationReloding_AvatarController(AvatarMultiBodyController __instance)
{
__instance.Entity?.FireEvent(CustomEnums.onReloadAboutToStart);
return true;
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.StartAnimationReloading))]
[HarmonyPostfix]
private static void Postfix_StartAnimationReloading_AvatarMultibodyController(AvatarMultiBodyController __instance)
{
if (__instance.HeldItemTransform != null && __instance.HeldItemTransform.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed)
{
EntityAlive entity = __instance.Entity;
ItemValue holdingItemItemValue = entity.inventory.holdingItemItemValue;
//#if DEBUG
// float x = 1, y = 1;
// var tags = entity.inventory.holdingItem.ItemTags;
// var tags_prev = tags;
// MultiActionManager.ModifyItemTags(entity.inventory.holdingItemItemValue, entity.MinEventContext.ItemActionData, ref tags);
// entity.Progression.ModifyValue(PassiveEffects.ReloadSpeedMultiplier, ref x, ref y, tags);
// Log.Out($"item {entity.inventory.holdingItem.Name} action index {entity.MinEventContext.ItemActionData.indexInEntityOfAction} progression base {x} perc {y} has tag {tags.Test_AnySet(FastTags.Parse("perkMachineGunner"))} \ntags prev {tags_prev} \ntags after {tags}");
//#endif
float reloadSpeed = EffectManager.GetValue(PassiveEffects.ReloadSpeedMultiplier, holdingItemItemValue, 1f, entity);
float reloadSpeedRatio = EffectManager.GetValue(CustomEnums.ReloadSpeedRatioFPV2TPV, holdingItemItemValue, 1f, entity);
float partialReloadMultiplier = EffectManager.GetValue(CustomEnums.PartialReloadCount, holdingItemItemValue, 0, entity);
float partialReloadRatio = 1f;
if (partialReloadMultiplier <= 0)
{
partialReloadMultiplier = 1;
}
else
{
int magSize = (int)EffectManager.GetValue(PassiveEffects.MagazineSize, holdingItemItemValue, ((ItemActionRanged)entity.inventory.holdingItem.Actions[MultiActionManager.GetActionIndexForEntity(entity)]).BulletsPerMagazine, entity);
//how many partial reload is required to fill an empty mag
partialReloadRatio = Mathf.Ceil(magSize / partialReloadMultiplier);
//how many partial reload is required to finish this reload
partialReloadMultiplier = Mathf.Ceil((magSize - holdingItemItemValue.Meta) / partialReloadMultiplier);
//reload time percentage of this reload
partialReloadRatio = partialReloadMultiplier / partialReloadRatio;
}
float localMultiplier, remoteMultiplier;
bool isFPV = entity as EntityPlayerLocal != null && (entity as EntityPlayerLocal).emodel.IsFPV;
bool takeOverReloadTime = AnimationRiggingManager.IsReloadTimeTakeOverItem(holdingItemItemValue.type);
if (isFPV && !takeOverReloadTime)
{
localMultiplier = reloadSpeed / reloadSpeedRatio;
}
else if (!isFPV && takeOverReloadTime)
{
localMultiplier = reloadSpeed * reloadSpeedRatio / partialReloadMultiplier;
}
else if(isFPV && takeOverReloadTime)
{
localMultiplier = reloadSpeed;
}
else
{
localMultiplier = reloadSpeed * partialReloadRatio;
}
if (takeOverReloadTime)
{
remoteMultiplier = reloadSpeed * reloadSpeedRatio / partialReloadMultiplier;
}
else
{
remoteMultiplier = reloadSpeed * partialReloadRatio;
}
if (ConsoleCmdReloadLog.LogInfo)
Log.Out($"Set reload multiplier: isFPV {isFPV}, reloadSpeed {reloadSpeed}, reloadSpeedRatio {reloadSpeedRatio}, finalMultiplier {localMultiplier}, remoteMultiplier {remoteMultiplier}, partialMultiplier {partialReloadMultiplier}, partialRatio {partialReloadRatio}");
__instance.UpdateFloat(AvatarController.reloadSpeedHash, localMultiplier, false);
SetDataFloat(__instance, (AvatarController.DataTypes)AvatarController.reloadSpeedHash, remoteMultiplier, true);
}
}
/// <summary>
/// sets float only on remote clients but not on local client.
/// </summary>
/// <param name="__instance"></param>
/// <param name="_type"></param>
/// <param name="_value"></param>
/// <param name="_netsync"></param>
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController.SetDataFloat))]
[HarmonyReversePatch(HarmonyReversePatchType.Original)]
private static void SetDataFloat(AvatarController __instance, AvatarController.DataTypes _type, float _value, bool _netsync = true)
{
IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (instructions == null)
return null;
var codes = instructions.ToList();
codes.RemoveRange(0, 5);
codes[0].labels.Clear();
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsConstant(AnimParamData.ValueTypes.DataFloat))
{
codes[i].opcode = OpCodes.Ldc_I4;
codes[i].operand = (int)AnimParamData.ValueTypes.Float;
break;
}
}
return codes;
}
_ = Transpiler(null);
}
//[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.StartAnimationAttack))]
//[HarmonyPostfix]
//private static void Postfix_StartAnimationAttack_AvatarMultiBodyController(AvatarMultiBodyController __instance)
//{
// if (__instance is AvatarLocalPlayerController)
// AnimationRiggingManager.FpvWeaponFire();
//}
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.SetFirstPersonView))]
[HarmonyPrefix]
private static bool Prefix_SetFirstPersonView_EntityPlayerLocal(EntityPlayerLocal __instance, bool _bFirstPersonView)
{
var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(__instance);
if (_bFirstPersonView != __instance.bFirstPersonView && targets && !targets.Destroyed && targets.IsAnimationSet)
{
//targets.SetEnabled(false);
//targets.GraphBuilder.SetCurrentTarget(null);
Log.Out($"Switch view destroy slot {__instance.inventory.holdingItemIdx}");
targets.Destroy();
}
return true;
}
[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController.SwitchModelAndView))]
[HarmonyPostfix]
private static void Postfix_SwitchModelAndView_AvatarLocalPlayerController(AvatarLocalPlayerController __instance, bool _bFPV)
{
if (_bFPV)
{
__instance.hasTurnRate = false;
}
}
[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController.SetInRightHand))]
[HarmonyPostfix]
private static void Postfix_SetInRightHand_AvatarLocalPlayerController(Transform _transform, AvatarLocalPlayerController __instance)
{
if (_transform != null && _transform.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed && targets.ItemCurrent)
{
//targets.SetEnabled(true);
targets.GraphBuilder.SetCurrentTarget(targets);
}
else if (__instance.PrimaryBody?.Animator && __instance.PrimaryBody.Animator.TryGetComponent<AnimationGraphBuilder>(out var builder))
{
builder.SetCurrentTarget(null);
}
}
[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController.SetInRightHand))]
[HarmonyPostfix]
private static void Postfix_SetInRightHand_LegacyAvatarController(Transform _transform, LegacyAvatarController __instance)
{
if (_transform != null && _transform.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed && targets.ItemCurrent)
{
//targets.SetEnabled(true);
targets.GraphBuilder.SetCurrentTarget(targets);
}
else if (__instance.anim && __instance.anim.TryGetComponent<AnimationGraphBuilder>(out var builder))
{
builder.SetCurrentTarget(null);
}
}
//[HarmonyPatch(typeof(Inventory), nameof(Inventory.setHoldingItemTransform))]
//[HarmonyPrefix]
//private static bool Prefix_setHoldingItemTransform_Inventory(Inventory __instance)
//{
// if (__instance.lastdrawnHoldingItemTransform && __instance.lastdrawnHoldingItemTransform.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed)
// {
// targets.SetEnabled(false);
// }
// return true;
//}
[HarmonyPatch(typeof(vp_FPWeapon), nameof(vp_FPWeapon.Start))]
[HarmonyPostfix]
private static void Postfix_Start_vp_FPWeapon(vp_FPWeapon __instance)
{
var player = __instance.GetComponentInParent<EntityPlayerLocal>();
if (player && player.inventory != null)
{
for (int i = 0; i < player.inventory.models.Length; i++)
{
Transform model = player.inventory.models[i];
if (model != null && model.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed)
{
if (i == player.inventory.holdingItemIdx)
{
player.inventory.ForceHoldingItemUpdate();
}
else
{
targets.Init(__instance.transform, true);
}
}
}
}
}
#region temporary fix for arm glitch on switching weapon
[HarmonyPatch(typeof(Inventory), nameof(Inventory.updateHoldingItem))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_updateHoldingItem_Inventory(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_setparent = AccessTools.Method(typeof(Transform), nameof(Transform.SetParent), new[] { typeof(Transform), typeof(bool) });
var mtd_startholding = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.StartHolding));
var mtd_showrighthand = AccessTools.Method(typeof(Inventory), nameof(Inventory.ShowRightHand));
var mtd_holdingchanged = AccessTools.Method(typeof(EntityAlive), nameof(EntityAlive.OnHoldingItemChanged));
var prop_holdingitem = AccessTools.PropertyGetter(typeof(Inventory), nameof(Inventory.holdingItem));
var fld_transform = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.Transform));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_setparent))
{
codes[i - 1].opcode = OpCodes.Ldc_I4_1;
}
else if (codes[i].Calls(mtd_startholding))
{
for (int j = i - 1; j >= 0; j--)
{
if (codes[j].Calls(prop_holdingitem))
{
for (int k = i + 1; k < codes.Count; k++)
{
if (codes[k].StoresField(fld_transform))
{
codes.InsertRange(k + 1, new[]
{
new CodeInstruction(OpCodes.Ldloc_0).WithLabels(codes[k + 1].ExtractLabels()),
CodeInstruction.LoadField(typeof(CustomEnums), nameof(CustomEnums.onSelfHoldingItemAssemble)),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(Inventory), nameof(Inventory.entity)),
CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)),
CodeInstruction.Call(typeof(ItemValue), nameof(ItemValue.FireEvent)),
});
k += 6;
}
else if (codes[k].Calls(mtd_showrighthand))
{
codes.InsertRange(k + 1, codes.GetRange(j - 1, i - j + 2));
codes[i + 1].WithLabels(codes[j - 1].ExtractLabels());
codes.RemoveRange(j - 1, i - j + 2);
break;
}
}
break;
}
}
i += 6;
}
else if (codes[i].Calls(mtd_holdingchanged))
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(codes[i + 1].ExtractLabels()),
CodeInstruction.Call(typeof(Inventory), nameof(Inventory.syncHeldItem))
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.setHoldingItemTransform))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setHoldingItemTransform_Inventory(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_sync = AccessTools.Method(typeof(Inventory), nameof(Inventory.syncHeldItem));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_sync))
{
codes[i + 1].WithLabels(codes[i - 1].ExtractLabels());
codes.RemoveRange(i - 1, 2);
break;
}
}
return codes;
}
//private static Coroutine delayShowWeaponCo;
//private static IEnumerator DelayShowWeapon(Camera camera)
//{
// Log.Out($"Delay show weapon!");
// camera.cullingMask &= ~(1 << 10);
// yield return new WaitForSeconds(0.5f);
// if (camera)
// {
// camera.cullingMask |= 1 << 10;
// }
// delayShowWeaponCo = null;
// Log.Out($"Show weapon!");
// yield break;
//}
//[HarmonyPatch(typeof(Inventory), nameof(Inventory.setHeldItemByIndex))]
//[HarmonyPrefix]
//private static bool Prefix_setHeldItemByIndex_Inventory(Inventory __instance, out bool __state)
//{
// __state = __instance.holdingItemData?.model && __instance.holdingItemData.model.GetComponent<RigTargets>();
// return true;
//}
//[HarmonyPatch(typeof(Inventory), nameof(Inventory.setHeldItemByIndex))]
//[HarmonyPostfix]
//private static void Postfix_setHeldItemByIndex_Inventory(Inventory __instance, bool __state)
//{
// if (__state && __instance.entity is EntityPlayerLocal player && player.bFirstPersonView && (!__instance.holdingItemData?.model || !__instance.holdingItemData.model.GetComponent<RigTargets>()))
// {
// if (delayShowWeaponCo != null)
// {
// ThreadManager.StopCoroutine(delayShowWeaponCo);
// }
// if (__instance.holdingItemIdx == __instance.DUMMY_SLOT_IDX)
// {
// player.ShowHoldingItem(true);
// }
// else
// {
// delayShowWeaponCo = ThreadManager.StartCoroutine(DelayShowWeapon(player.playerCamera));
// }
// }
//}
//[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.ShowHoldingItem))]
//[HarmonyPrefix]
//private static bool Prefix_ShowHoldingItem_EntityPlayerLocal(bool show)
//{
// if (delayShowWeaponCo != null)
// {
// if (show)
// {
// return false;
// }
// ThreadManager.StopCoroutine(delayShowWeaponCo);
// }
// return true;
//}
/*
[HarmonyPatch(typeof(Inventory), nameof(Inventory.setHoldingItemTransform))]
[HarmonyPostfix]
private static void Postfix_setHoldingItemTransform_Inventory(Transform _t, Inventory __instance)
{
if (_t != null && _t.TryGetComponent<RigTargets>(out var targets) && !targets.Destroyed)
{
targets.SetEnabled(__instance.entity.emodel.IsFPV);
}
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.SetItem), new[] {typeof(int), typeof(ItemValue), typeof(int), typeof(bool)})]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SetItem_Inventory(IEnumerable<CodeInstruction> instructions)
{
MethodInfo mtd_update = AccessTools.Method(typeof(Inventory), nameof(Inventory.updateHoldingItem));
foreach (var code in instructions)
{
yield return code;
if (code.Calls(mtd_update))
{
yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Ldc_I4_1);
yield return new CodeInstruction(OpCodes.Ldc_R4, 0f);
yield return CodeInstruction.Call(typeof(Inventory), nameof(Inventory.ShowHeldItem));
}
}
}
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.ShowWeaponCamera))]
[HarmonyPostfix]
private static void Postfix_ShowWeaponCamera_EntityPlayerLocal(EntityPlayerLocal __instance, bool show)
{
if (__instance.bFirstPersonView)
{
__instance.weaponCamera.cullingMask &= ~(1 << 10);
if (delayShowWeaponCo != null)
{
ThreadManager.StopCoroutine(delayShowWeaponCo);
}
if (show)
{
delayShowWeaponCo = ThreadManager.StartCoroutine(DelayShowWeapon(__instance.weaponCamera));
}
}
}
*/
#endregion
[HarmonyPatch(typeof(World), nameof(World.SpawnEntityInWorld))]
[HarmonyPrefix]
private static bool Prefix_SpawnEntityInWorld_World(Entity _entity)
{
if (_entity is EntityItem _entityItem)
{
var targets = _entityItem.GetComponentInChildren<AnimationTargetsAbs>(true);
if (targets && !targets.Destroyed)
{
targets.Destroy();
}
}
return true;
}
[HarmonyPatch(typeof(World), nameof(World.SpawnEntityInWorld))]
[HarmonyPostfix]
private static void Postfix_SpawnEntityInWorld_World(Entity _entity)
{
if (_entity is EntityPlayer player && !(_entity is EntityPlayerLocal) && player.inventory != null)
{
foreach (var model in player.inventory.models)
{
if (model && model.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed)
{
targets.DestroyFpv();
targets.Init(player.emodel.avatarController.GetActiveModelRoot(), false);
}
}
}
}
[HarmonyPatch(typeof(EntityItem), nameof(EntityItem.createMesh))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_createMesh_EntityItem(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
codes[codes.Count - 1].WithLabels(codes[codes.Count - 11].labels);
codes.RemoveRange(codes.Count - 11, 10);
return codes;
}
[HarmonyPatch(typeof(EntityItem), nameof(EntityItem.createMesh))]
[HarmonyPostfix]
private static void Postfix_createMesh_EntityItem(EntityItem __instance)
{
if (__instance.itemTransform)
{
__instance.itemTransform.tag = "Item";
if (__instance.itemTransform.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed)
{
targets.Destroy();
}
}
__instance.meshRenderers = __instance.itemTransform.GetComponentsInChildren<Renderer>(true);
__instance.VisiblityCheck(0, false);
}
[HarmonyPatch(typeof(EModelBase), nameof(EModelBase.SwitchModelAndView))]
[HarmonyPostfix]
private static void Postfix_SwitchModelAndView_EModelBase(EModelBase __instance)
{
if (__instance.entity is EntityPlayerLocal player && player.inventory != null)
{
foreach (var model in player.inventory.models)
{
if (model && model.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed)
{
targets.Init(player.emodel.avatarController.GetActiveModelRoot(), player.bFirstPersonView);
}
}
}
}
[HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.Detach))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Detach_EntityAlive(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_inv = AccessTools.Field(typeof(EntityAlive), nameof(EntityAlive.inventory));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].StoresField(fld_inv))
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.Call(typeof(AnimationRiggingPatches), nameof(AnimationRiggingPatches.DetachInitInventory))
});
break;
}
}
return codes;
}
private static void DetachInitInventory(EntityAlive __instance)
{
if (!(__instance is EntityPlayer player))
{
return;
}
if (__instance.inventory != null)
{
foreach (var model in __instance.inventory.models)
{
if (model && model.TryGetComponent<AnimationTargetsAbs>(out var targets) && !targets.Destroyed)
{
targets.Init(__instance.emodel.avatarController.GetActiveModelRoot(), player is EntityPlayerLocal localPlayer ? localPlayer.bFirstPersonView : false);
}
}
}
}
[HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.cleanupEquipment))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_cleanupEquipment_SDCSUtils(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_removeat = AccessTools.Method(typeof(List<RigLayer>), nameof(List<RigLayer>.RemoveAt));
var mtd_destroy = AccessTools.Method(typeof(GameUtils), nameof(GameUtils.DestroyAllChildrenBut), new[] {typeof(Transform), typeof(List<string>)});
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_removeat))
{
codes.InsertRange(i - 2, new[]
{
new CodeInstruction(OpCodes.Ldloc_2),
new CodeInstruction(OpCodes.Ldloc_3),
CodeInstruction.Call(typeof(List<RigLayer>), "get_Item"),
CodeInstruction.Call(typeof(RigLayer), "get_name"),
CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.ShouldExcludeRig)),
new CodeInstruction(OpCodes.Brtrue_S, codes[i - 3].operand)
});
i += 6;
}
else if (codes[i].Calls(mtd_destroy))
{
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Dup),
CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetExcludeRigs)),
CodeInstruction.Call(typeof(List<string>), nameof(List<string>.AddRange)),
});
i += 3;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SwapSelectedAmmo))]
[HarmonyPrefix]
private static bool Prefix_SwapSelectedAmmo_ItemActionRanged(ItemActionRanged __instance, EntityAlive _entity, int _ammoIndex)
{
if (_ammoIndex == (int)_entity.inventory.holdingItemItemValue.SelectedAmmoTypeIndex && __instance is IModuleContainerFor<ActionModuleInspectable> inspectable && _entity is EntityPlayerLocal player)
{
ItemActionRanged.ItemActionDataRanged _actionData = _entity.inventory.holdingItemData.actionData[__instance.ActionIndex] as ItemActionRanged.ItemActionDataRanged;
if (!_entity.MovementRunning && !_entity.AimingGun && !player.bLerpCameraFlag && _actionData != null && !_entity.inventory.holdingItem.IsActionRunning(_entity.inventory.holdingItemData) && !__instance.CanReload(_actionData) && (_entity.inventory.holdingItemItemValue.Meta > 0 || inspectable.Instance.allowEmptyInspect))
{
_entity.emodel.avatarController._setTrigger("weaponInspect", true);
return false;
}
}
return true;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ExecuteAction))]
[HarmonyPostfix]
private static void Postfix_ExecuteAction_ItemActionRanged(ItemActionRanged __instance, ItemActionData _actionData)
{
if (_actionData is ItemActionRanged.ItemActionDataRanged rangedData)
{
int burstCount = __instance.GetBurstCount(_actionData);
_actionData.invData.holdingEntity.emodel.avatarController._setBool("TriggerPulled", rangedData.bPressed && rangedData.curBurstCount < burstCount, true);
}
}
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.LateInitAll))]
[HarmonyPostfix]
private static void Postfix_LateInitAll_ItemClass()
{
AnimationRiggingManager.ParseItemIDs();
}
[HarmonyPatch(typeof(Animator), nameof(Animator.Rebind), new Type[0])]
[HarmonyReversePatch(HarmonyReversePatchType.Original)]
public static void RebindNoDefault(this Animator __instance)
{
IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (instructions == null)
{
yield break;
}
foreach (var ins in instructions)
{
if (ins.opcode == OpCodes.Ldc_I4_1)
{
yield return new CodeInstruction(OpCodes.Ldc_I4_0);
}
else
{
yield return ins;
}
}
}
_ = Transpiler(null);
}
//[HarmonyPatch(typeof(ItemActionDynamic), nameof(ItemActionDynamic.GetExecuteActionGrazeTarget))]
//[HarmonyPostfix]
//private static void Postfix_Test2(WorldRayHitInfo[] __result)
//{
// Log.Out($"World ray info count: {__result.Length}");
//}
//[HarmonyPatch(typeof(ItemActionDynamic), nameof(ItemActionDynamic.hitTarget))]
//[HarmonyPostfix]
//private static void Postfix_hittest(ItemActionData _actionData, WorldRayHitInfo hitInfo, bool _isGrazingHit = false)
//{
// Log.Out($"HIT TARGET! IsGrazing: {_isGrazingHit}\n{StackTraceUtility.ExtractStackTrace()}");
//}
//[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._setTrigger))]
//[HarmonyPostfix]
//private static void Postfix_AvatarLocalPlayerController_SetTrigger(int _pid, AvatarLocalPlayerController __instance)
//{
// AnimationRiggingManager.SetTrigger(_pid, __instance.entity as EntityPlayer);
//}
//[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._resetTrigger))]
//[HarmonyPostfix]
//private static void Postfix_AvatarLocalPlayerController_ResetTrigger(int _pid, AvatarLocalPlayerController __instance)
//{
// AnimationRiggingManager.ResetTrigger(_pid, __instance.entity as EntityPlayer);
//}
//[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._setFloat))]
//[HarmonyPostfix]
//private static void Postfix_AvatarLocalPlayerController_SetFloat(int _pid, float _value, AvatarLocalPlayerController __instance)
//{
// AnimationRiggingManager.SetFloat(_pid, _value, __instance.entity as EntityPlayer);
//}
//[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._setBool))]
//[HarmonyPostfix]
//private static void Postfix_AvatarLocalPlayerController_SetBool(int _pid, bool _value, AvatarLocalPlayerController __instance)
//{
// AnimationRiggingManager.SetBool(_pid, _value, __instance.entity as EntityPlayer);
//}
//[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._setInt))]
//[HarmonyPostfix]
//private static void Postfix_AvatarLocalPlayerController_SetInt(int _pid, int _value, AvatarLocalPlayerController __instance)
//{
// AnimationRiggingManager.SetInt(_pid, _value, __instance.entity as EntityPlayer);
//}
//[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController._setTrigger))]
//[HarmonyPostfix]
//private static void Postfix_LegacyAvatarController_SetTrigger(int _propertyHash, LegacyAvatarController __instance)
//{
// AnimationRiggingManager.SetTrigger(_propertyHash, __instance.entity as EntityPlayer);
//}
//[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController._resetTrigger))]
//[HarmonyPostfix]
//private static void Postfix_LegacyAvatarController_ResetTrigger(int _propertyHash, LegacyAvatarController __instance)
//{
// AnimationRiggingManager.ResetTrigger(_propertyHash, __instance.entity as EntityPlayer);
//}
//[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController._setFloat))]
//[HarmonyPostfix]
//private static void Postfix_LegacyAvatarController_SetFloat(int _propertyHash, float _value, LegacyAvatarController __instance)
//{
// AnimationRiggingManager.SetFloat(_propertyHash, _value, __instance.entity as EntityPlayer);
//}
//[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController._setBool))]
//[HarmonyPostfix]
//private static void Postfix_LegacyAvatarController_SetBool(int _propertyHash, bool _value, LegacyAvatarController __instance)
//{
// AnimationRiggingManager.SetBool(_propertyHash, _value, __instance.entity as EntityPlayer);
//}
//[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController._setInt))]
//[HarmonyPostfix]
//private static void Postfix_LegacyAvatarController_SetInt(int _propertyHash, int _value, LegacyAvatarController __instance)
//{
// AnimationRiggingManager.SetInt(_propertyHash, _value, __instance.entity as EntityPlayer);
//}
[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._resetTrigger), typeof(int), typeof(bool))]
[HarmonyReversePatch(HarmonyReversePatchType.Original)]
public static void VanillaResetTrigger(AvatarLocalPlayerController __instance, int _pid, bool _netsync = true)
{
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController.TryGetTrigger), new[] { typeof(int), typeof(bool) }, new[] { ArgumentType.Normal, ArgumentType.Out })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_TryGetTrigger_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController.TryGetBool), new[] { typeof(int), typeof(bool) }, new[] { ArgumentType.Normal, ArgumentType.Out })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_TryGetBool_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController.TryGetInt), new[] { typeof(int), typeof(int) }, new[] { ArgumentType.Normal, ArgumentType.Out })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_TryGetInt_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController.TryGetFloat), new[] { typeof(int), typeof(float) }, new[] { ArgumentType.Normal, ArgumentType.Out })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_TryGetFloat_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat)));
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.TryGetTrigger), new[] { typeof(int), typeof(bool) }, new[] { ArgumentType.Normal, ArgumentType.Out })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_TryGetTrigger_AvatarMultiBodyController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)));
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.TryGetBool), new[] { typeof(int), typeof(bool) }, new[] { ArgumentType.Normal, ArgumentType.Out })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_TryGetBool_AvatarMultiBodyController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)));
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.TryGetInt), new[] { typeof(int), typeof(int) }, new[] { ArgumentType.Normal, ArgumentType.Out })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_TryGetInt_AvatarMultiBodyController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt)));
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.TryGetFloat), new[] { typeof(int), typeof(float) }, new[] { ArgumentType.Normal, ArgumentType.Out })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_TryGetFloat_AvatarMultiBodyController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController._setBool), new[] { typeof(int), typeof(bool), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setBool_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetBool), new[] { typeof(int), typeof(bool) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedBool)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController._setTrigger), new[] { typeof(int), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setTrigger_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetTrigger), new[] { typeof(int)}),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedTrigger)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController._resetTrigger), new[] { typeof(int), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_resetTrigger_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.ResetTrigger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.ResetWrappedTrigger)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController._setInt), new[] { typeof(int), typeof(int), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setInt_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetInteger), new[] { typeof(int), typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedInt)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController._setFloat), new[] { typeof(int), typeof(float), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setFloat_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetFloat), new[] { typeof(int), typeof(float) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedFloat)));
}
[HarmonyPatch(typeof(AvatarCharacterController), nameof(AvatarCharacterController._setBool), new[] { typeof(int), typeof(bool), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setBool_AvatarCharacterController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetBool), new[] { typeof(int), typeof(bool) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedBool)));
}
[HarmonyPatch(typeof(AvatarCharacterController), nameof(AvatarCharacterController._setTrigger), new[] { typeof(int), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setTrigger_AvatarCharacterController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetTrigger), new[] { typeof(int)}),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedTrigger)));
}
[HarmonyPatch(typeof(AvatarCharacterController), nameof(AvatarCharacterController._resetTrigger), new[] { typeof(int), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_resetTrigger_AvatarCharacterController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.ResetTrigger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.ResetWrappedTrigger)));
}
[HarmonyPatch(typeof(AvatarCharacterController), nameof(AvatarCharacterController._setInt), new[] { typeof(int), typeof(int), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setInt_AvatarCharacterController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetInteger), new[] { typeof(int), typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedInt)));
}
[HarmonyPatch(typeof(AvatarCharacterController), nameof(AvatarCharacterController._setFloat), new[] { typeof(int), typeof(float), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setFloat_AvatarCharacterController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetFloat), new[] { typeof(int), typeof(float) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedFloat)));
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._setBool), new[] { typeof(int), typeof(bool), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setBool_AvatarMultiBodyController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetBool), new[] { typeof(int), typeof(bool) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedBool)));
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._setTrigger), new[] { typeof(int), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setTrigger_AvatarMultiBodyController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetTrigger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedTrigger)));
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._resetTrigger), new[] { typeof(int), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_resetTrigger_AvatarMultiBodyController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.ResetTrigger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.ResetWrappedTrigger)));
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._setInt), new[] { typeof(int), typeof(int), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setInt_AvatarMultiBodyController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetInteger), new[] { typeof(int), typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedInt)));
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._setFloat), new[] { typeof(int), typeof(float), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setFloat_AvatarMultiBodyController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetFloat), new[] { typeof(int), typeof(float) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedFloat)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController.GetParameterName))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_GetParameterName_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.PropertyGetter(typeof(Animator), nameof(Animator.parameters)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedParameters)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController.SyncAnimParameters))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SyncAnimParameters_AvatarController(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.MethodReplacer(
AccessTools.PropertyGetter(typeof(Animator), nameof(Animator.parameters)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedParameters)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat)))
.ToList();
//var lbd_wrapper = generator.DeclareLocal(typeof(IAnimatorWrapper));
//var fld_anim = AccessTools.Field(typeof(AvatarController), nameof(AvatarController.anim));
//for (int i = 1; i < codes.Count; i++)
//{
// if (codes[i].opcode == OpCodes.Stloc_0)
// {
// codes.InsertRange(i + 1, new[]
// {
// new CodeInstruction(OpCodes.Ldarg_0),
// CodeInstruction.LoadField(typeof(AvatarController), nameof(AvatarController.anim)),
// CodeInstruction.Call(typeof(KFExtensions), nameof(KFExtensions.GetAnimatorWrapper)),
// new CodeInstruction(OpCodes.Stloc_S, lbd_wrapper)
// });
// i += 4;
// }
// else if (codes[i].opcode == OpCodes.Ldloc_3 && codes[i - 1].LoadsField(fld_anim))
// {
// codes.Insert(i - 2, new CodeInstruction(OpCodes.Ldloc_S, lbd_wrapper).WithLabels(codes[i - 2].ExtractLabels()));
// codes.RemoveRange(i - 1, 2);
// i--;
// }
//}
return codes;
}
[HarmonyPatch(typeof(AvatarSDCSController), nameof(AvatarSDCSController.LateUpdate))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_LateUpdate_AvatarSDCSController(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var mtd_getbool = AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) });
var mtd_getint = AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) });
var mtd_getfloat = AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) });
var mtd_istransition = AccessTools.Method(typeof(Animator),nameof(Animator.IsInTransition), new[] { typeof(int) });
var mtd_updatespine = AccessTools.Method(typeof(LegacyAvatarController), nameof(LegacyAvatarController.updateSpineRotation));
var fld_reload = AccessTools.Field(typeof(AvatarController), nameof(AvatarController.reloadHash));
var mtd_getvanillabool = AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool));
var mtd_getvanillaint = AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt));
var mtd_getvanillafloat = AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat));
var mtd_isvanillatransition = AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.IsVanillaInTransition));
var codes = instructions.Manipulator(ins => ins.opcode == OpCodes.Ldstr, ins =>
{
switch (ins.operand)
{
case "Reload":
ins.opcode = OpCodes.Ldsfld;
ins.operand = fld_reload;
break;
}
}).MethodReplacer(AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(string) }), mtd_getbool)
.MethodReplacer(AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(string) }), mtd_getint)
.MethodReplacer(AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(string) }), mtd_getfloat)
.MethodReplacer(AccessTools.Method(typeof(Animator), nameof(Animator.SetBool), new[] { typeof(string), typeof(bool) }), AccessTools.Method(typeof(Animator), nameof(Animator.SetBool), new[] { typeof(int), typeof(bool) }))
.MethodReplacer(mtd_getbool, mtd_getvanillabool)
.MethodReplacer(mtd_getint, mtd_getvanillaint)
.MethodReplacer(mtd_getfloat, mtd_getvanillafloat)
.MethodReplacer(mtd_istransition, mtd_isvanillatransition)
.ToList();
//var lbd_wrapper = generator.DeclareLocal(typeof(IAnimatorWrapper));
//for (var i = 0; i < codes.Count; i++)
//{
// if (codes[i].Calls(mtd_updatespine))
// {
// codes.InsertRange(i + 1, new[]
// {
// new CodeInstruction(OpCodes.Ldarg_0),
// CodeInstruction.LoadField(typeof(AvatarController), nameof(AvatarController.anim)),
// CodeInstruction.Call(typeof(KFExtensions), nameof(KFExtensions.GetItemAnimatorWrapper)),
// new CodeInstruction(OpCodes.Stloc_S, lbd_wrapper)
// });
// i += 4;
// }
// else if (codes[i].Calls(mtd_getvanillabool) || codes[i].Calls(mtd_getvanillafloat) || codes[i].Calls(mtd_getvanillaint) || codes[i].Calls(mtd_isvanillatransition))
// {
// codes.Insert(i - 3, new CodeInstruction(OpCodes.Ldloc_S, lbd_wrapper).WithLabels(codes[i - 3].ExtractLabels()));
// codes.RemoveRange(i - 2, 2);
// i--;
// }
//}
//foreach (var code in codes)
//{
// Log.Out(code.ToString());
//}
return codes;
}
[HarmonyPatch(typeof(AvatarSDCSController), nameof(AvatarSDCSController.updateLayerStateInfo))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_updateLayerStateInfo_AvatarSDCSController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetCurrentAnimatorStateInfo)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetCurrentVanillaStateInfo)));
}
[HarmonyPatch(typeof(AvatarUMAController), nameof(AvatarUMAController.updateLayerStateInfo))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_updateLayerStateInfo_AvatarUMAController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetCurrentAnimatorStateInfo)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetCurrentVanillaStateInfo)));
}
[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController.updateLayerStateInfo))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_updateLayerStateInfo_LegacyAvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetCurrentAnimatorStateInfo)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetCurrentVanillaStateInfo)));
}
[HarmonyPatch(typeof(AvatarSDCSController), nameof(AvatarSDCSController.setLayerWeights))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setLayerWeights_AvatarSDCSController(IEnumerable<CodeInstruction> instructions)
{
int id = Animator.StringToHash("MinibikeIdle");
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.IsInTransition)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.IsVanillaInTransition)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(string) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)))
.Manipulator(ins => ins.opcode == OpCodes.Ldstr, ins => { ins.opcode = OpCodes.Ldc_I4; ins.operand = id; });
}
[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController.setLayerWeights))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setLayerWeights_LegacyAvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight)));
}
[HarmonyPatch(typeof(AvatarUMAController), nameof(AvatarUMAController.setLayerWeights))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_setLayerWeights_AvatarUMAController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.IsInTransition)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.IsVanillaInTransition)));
}
[HarmonyPatch(typeof(UMACharacterBodyAnimator), nameof(UMACharacterBodyAnimator.assignLayerWeights))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_assignLayerWeights_UMACharacterBodyAnimator(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt)))
.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.IsInTransition)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.IsVanillaInTransition)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController.Update))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Update_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight)));
}
[HarmonyPatch(typeof(AvatarController), nameof(AvatarController.InitHitDuration))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_InitHitDuration_AvatarController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight)));
}
private static int drunkHash = Animator.StringToHash("drunk");
[HarmonyPatch(typeof(FirstPersonAnimator), nameof(FirstPersonAnimator.SetDrunk))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SetDrunk_FirstPersonAnimator(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetFloat), new[] { typeof(string), typeof(float) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedFloat)))
.Manipulator(ins => ins.LoadsConstant("drunk"),
ins =>
{
ins.opcode = OpCodes.Ldsfld;
ins.operand = AccessTools.Field(typeof(AnimationRiggingPatches), nameof(AnimationRiggingPatches.drunkHash));
});
}
[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.SetVehicleAnimation))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SetVehicleAnimation_AvatarMultiBodyController(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(
AccessTools.Method(typeof(Animator), nameof(Animator.SetInteger), new[] { typeof(string), typeof(int) }),
AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedInt)));
}
//BodyAnimator.LateUpdate
//UMACharacterBodyAnimator.LateUpdate
//BodyAnimator.cacheLayerStateInfo
//UMACharacterBodyAnimator.cacheLayerStateInfo
//not used
}

View File

@@ -0,0 +1,51 @@
using HarmonyLib;
using KFCommonUtilityLib.Scripts.StaticManagers;
namespace KFCommonUtilityLib.Harmony
{
[HarmonyPatch]
public class BackgroundInventoryUpdatePatch
{
[HarmonyPatch(typeof(Inventory), nameof(Inventory.clearSlotByIndex))]
[HarmonyPostfix]
private static void Postfix_clearSlotByIndex_Inventory(Inventory __instance, int _idx)
{
BackgroundInventoryUpdateManager.UnregisterUpdater(__instance.entity, _idx);
}
[HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.OnEntityDeath))]
[HarmonyPostfix]
private static void Postfix_OnEntityDeath_EntityAlive(EntityAlive __instance)
{
BackgroundInventoryUpdateManager.UnregisterUpdater(__instance);
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.OnUpdate))]
[HarmonyPostfix]
private static void Postfix_OnUpdate_Inventory(Inventory __instance)
{
BackgroundInventoryUpdateManager.Update(__instance.entity);
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.SaveAndCleanupWorld))]
[HarmonyPostfix]
private static void Postfix_SaveAndCleanupWorld_GameManager()
{
BackgroundInventoryUpdateManager.Cleanup();
}
[HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.AttachToEntity))]
[HarmonyPostfix]
private static void Postfix_AttachToEntity_EntityAlive(EntityAlive __instance)
{
BackgroundInventoryUpdateManager.DisableUpdater(__instance);
}
[HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.Detach))]
[HarmonyPostfix]
private static void Postfix_Detach_EntityAlive(EntityAlive __instance)
{
BackgroundInventoryUpdateManager.EnableUpdater(__instance);
}
}
}

174
Harmony/DamagePatches.cs Normal file
View File

@@ -0,0 +1,174 @@
using HarmonyLib;
using System.Collections.Generic;
using System.Reflection.Emit;
using UniLinq;
using UnityEngine;
[HarmonyPatch]
public static class DamagePatches
{
[HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.damageEntityLocal))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_damageEntityLocal_EntityAlive(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_calc = AccessTools.Method(typeof(Equipment), nameof(Equipment.CalcDamage));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_calc))
{
codes[i] = CodeInstruction.Call(typeof(DamagePatches), nameof(DamagePatches.CalcEquipmentDamage));
codes.RemoveRange(i - 12, 12);
codes.InsertRange(i - 12, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)),
CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Other))
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionAttack), nameof(ItemActionAttack.Hit))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Hit_ItemActionAttack(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_getdamagegroup = AccessTools.Method(typeof(DamageSource), nameof(DamageSource.GetEntityDamageEquipmentSlotGroup));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_getdamagegroup))
{
codes.InsertRange(i + 3, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, codes[i - 2].operand),
new CodeInstruction(OpCodes.Ldloc_S, codes[i - 1].operand),
CodeInstruction.Call(typeof(DamageSource), nameof(DamageSource.GetEntityDamageBodyPart)),
CodeInstruction.Call(typeof(DamagePatches), nameof(DamagePatches.GetBodyPartTags)),
CodeInstruction.Call(typeof(FastTags<TagGroup.Global>), "op_BitwiseOr")
});
break;
}
}
return codes;
}
private static void CalcEquipmentDamage(Equipment equipment, ref DamageResponse damageResponse, EntityAlive attacker)
{
damageResponse.ArmorDamage = damageResponse.Strength;
if (damageResponse.Source.DamageTypeTag.Test_AnySet(Equipment.physicalDamageTypes))
{
if (damageResponse.Strength > 0)
{
float totalPhysicalArmorResistPercent = GetTotalPhysicalArmorResistPercent(equipment, in damageResponse, attacker) * .01f;
damageResponse.ArmorDamage = Utils.FastMax((totalPhysicalArmorResistPercent > 0f) ? 1 : 0, Mathf.RoundToInt((float)damageResponse.Strength * totalPhysicalArmorResistPercent));
damageResponse.Strength -= damageResponse.ArmorDamage;
return;
}
}
else
{
damageResponse.Strength = Mathf.RoundToInt(Utils.FastMax(0f, (float)damageResponse.Strength * (1f - EffectManager.GetValue(PassiveEffects.ElementalDamageResist, null, 0f, equipment.m_entity, null, damageResponse.Source.DamageTypeTag) * .01f)));
damageResponse.ArmorDamage = Mathf.RoundToInt((float)Utils.FastMax(0, damageResponse.ArmorDamage - damageResponse.Strength));
}
}
private static float GetTotalPhysicalArmorResistPercent(Equipment equipment, in DamageResponse damageResponse, EntityAlive attacker)
{
if (!equipment?.m_entity)
return 0f;
FastTags<TagGroup.Global> bodyPartTags = GetBodyPartTags(damageResponse.HitBodyPart);
float resist = EffectManager.GetValue(PassiveEffects.PhysicalDamageResist, null, 0f, equipment.m_entity, null, Equipment.coreDamageResist | bodyPartTags);
if (attacker)
{
attacker.MinEventContext.Other = equipment.m_entity;
attacker.MinEventContext.ItemValue = damageResponse.Source.AttackingItem ?? ItemValue.None;
if (damageResponse.Source.AttackingItem != null)
{
if (damageResponse.Source.AttackingItem.ItemClass.Actions[1] is ItemActionProjectile)
{
return MultiActionReversePatches.ProjectileGetValue(PassiveEffects.TargetArmor, damageResponse.Source.AttackingItem, resist, attacker, null, damageResponse.Source.AttackingItem.ItemClass.ItemTags | bodyPartTags);
}
return EffectManager.GetValue(PassiveEffects.TargetArmor, damageResponse.Source.AttackingItem, resist, attacker, null, damageResponse.Source.AttackingItem.ItemClass.ItemTags | bodyPartTags);
}
return EffectManager.GetValue(PassiveEffects.TargetArmor, null, resist, attacker, null, bodyPartTags);
}
return resist;
}
public static FastTags<TagGroup.Global> GetBodyPartTags(EnumBodyPartHit bodyparts)
{
if ((bodyparts & EnumBodyPartHit.LeftUpperArm) > EnumBodyPartHit.None)
{
return LeftUpperArmTags;
}
if ((bodyparts & EnumBodyPartHit.LeftLowerArm) > EnumBodyPartHit.None)
{
return LeftLowerArmTags;
}
if ((bodyparts & EnumBodyPartHit.RightUpperArm) > EnumBodyPartHit.None)
{
return RightUpperArmTags;
}
if ((bodyparts & EnumBodyPartHit.RightLowerArm) > EnumBodyPartHit.None)
{
return RightLowerArmTags;
}
if ((bodyparts & EnumBodyPartHit.LeftUpperLeg) > EnumBodyPartHit.None)
{
return LeftUpperLegTags;
}
if ((bodyparts & EnumBodyPartHit.LeftLowerLeg) > EnumBodyPartHit.None)
{
return LeftLowerLegTags;
}
if ((bodyparts & EnumBodyPartHit.RightUpperLeg) > EnumBodyPartHit.None)
{
return RightUpperLegTags;
}
if ((bodyparts & EnumBodyPartHit.RightLowerLeg) > EnumBodyPartHit.None)
{
return RightLowerLegTags;
}
if ((bodyparts & EnumBodyPartHit.Head) > EnumBodyPartHit.None)
{
return HeadTags;
}
if ((bodyparts & EnumBodyPartHit.Torso) > EnumBodyPartHit.None)
{
return TorsoTags;
}
if ((bodyparts & EnumBodyPartHit.Special) > EnumBodyPartHit.None)
{
return SpecialTags;
}
return FastTags<TagGroup.Global>.none;
}
private static FastTags<TagGroup.Global> TorsoTags = FastTags<TagGroup.Global>.Parse("torso");
private static FastTags<TagGroup.Global> HeadTags = FastTags<TagGroup.Global>.Parse("head");
private static FastTags<TagGroup.Global> SpecialTags = FastTags<TagGroup.Global>.Parse("special");
private static FastTags<TagGroup.Global> ArmsTags = FastTags<TagGroup.Global>.Parse("arms");
private static FastTags<TagGroup.Global> UpperArmsTags = FastTags<TagGroup.Global>.Parse("upperArms");
private static FastTags<TagGroup.Global> LowerArmsTags = FastTags<TagGroup.Global>.Parse("lowerArms");
private static FastTags<TagGroup.Global> LeftArmTags = FastTags<TagGroup.Global>.Parse("leftArms");
private static FastTags<TagGroup.Global> RightArmTags = FastTags<TagGroup.Global>.Parse("rightArms");
private static FastTags<TagGroup.Global> LeftUpperArmTags = FastTags<TagGroup.Global>.Parse("leftUpperArms") | LeftArmTags | UpperArmsTags | ArmsTags;
private static FastTags<TagGroup.Global> LeftLowerArmTags = FastTags<TagGroup.Global>.Parse("leftLowerArms") | LeftArmTags | LowerArmsTags | ArmsTags;
private static FastTags<TagGroup.Global> RightUpperArmTags = FastTags<TagGroup.Global>.Parse("rightUpperArms") | RightArmTags | UpperArmsTags | ArmsTags;
private static FastTags<TagGroup.Global> RightLowerArmTags = FastTags<TagGroup.Global>.Parse("rightLowerArms") | RightArmTags | LowerArmsTags | ArmsTags;
private static FastTags<TagGroup.Global> LegsTags = FastTags<TagGroup.Global>.Parse("legs");
private static FastTags<TagGroup.Global> UpperLegsTags = FastTags<TagGroup.Global>.Parse("upperLegs");
private static FastTags<TagGroup.Global> LowerLegsTags = FastTags<TagGroup.Global>.Parse("lowerLegs");
private static FastTags<TagGroup.Global> LeftLegTags = FastTags<TagGroup.Global>.Parse("leftLegs");
private static FastTags<TagGroup.Global> RightLegTags = FastTags<TagGroup.Global>.Parse("rightLegs");
private static FastTags<TagGroup.Global> LeftUpperLegTags = FastTags<TagGroup.Global>.Parse("leftUpperLegs") | LeftLegTags | UpperLegsTags | LegsTags;
private static FastTags<TagGroup.Global> LeftLowerLegTags = FastTags<TagGroup.Global>.Parse("leftLowerLegs") | LeftLegTags | LowerLegsTags | LegsTags;
private static FastTags<TagGroup.Global> RightUpperLegTags = FastTags<TagGroup.Global>.Parse("rightUpperLegs") | RightLegTags | UpperLegsTags | LegsTags;
private static FastTags<TagGroup.Global> RightLowerLegTags = FastTags<TagGroup.Global>.Parse("rightLowerLegs") | RightLegTags | LowerLegsTags | LegsTags;
}

View File

@@ -0,0 +1,21 @@
using HarmonyLib;
namespace KFCommonUtilityLib.Harmony
{
[HarmonyPatch]
public static class DisplayMetaAsBuffPatch
{
[HarmonyPatch(typeof(XUiM_PlayerBuffs), nameof(XUiM_PlayerBuffs.GetBuffDisplayInfo))]
[HarmonyPrefix]
private static bool Prefix_GetBuffDisplayInfo_XUiM_PlayerBuffs(EntityUINotification notification, ref string __result)
{
if (notification is DisplayAsBuffEntityUINotification && notification.Buff != null)
{
__result = notification.CurrentValue.ToString();
return false;
}
return true;
}
}
}

34
Harmony/FPVLegPatches.cs Normal file
View File

@@ -0,0 +1,34 @@
using HarmonyLib;
using System.Collections.Generic;
using UniLinq;
using System.Reflection.Emit;
namespace KFCommonUtilityLib.Harmony
{
//[HarmonyPatch]
public static class FPVLegPatches
{
[HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.CreateVizTP))]
[HarmonyPrefix]
private static void Prefix_SDCSUtils_CreateTP(EntityAlive entity, ref bool isFPV, out bool __state)
{
__state = isFPV;
if (entity is EntityPlayerLocal)
{
entity.emodel.IsFPV = false;
isFPV = false;
}
}
[HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.CreateVizTP))]
[HarmonyPostfix]
private static void Postfix_SDCSUtils_CreateTP(EntityAlive entity, ref bool isFPV, bool __state)
{
if (entity is EntityPlayerLocal)
{
entity.emodel.IsFPV = __state;
isFPV = __state;
}
}
}
}

View File

@@ -0,0 +1,45 @@
using HarmonyLib;
using UnityEngine;
[HarmonyPatch]
public class HideMarkerOnAimPatch
{
[HarmonyPatch(typeof(XUiC_OnScreenIcons), nameof(XUiC_OnScreenIcons.Init))]
[HarmonyPostfix]
private static void Postfix_Init_XUiC_OnScreenIcons(XUiC_OnScreenIcons __instance)
{
GameObject iconParent = new GameObject("AllIconParent");
iconParent.transform.SetParent(__instance.ViewComponent.UiTransform);
iconParent.transform.localScale = Vector3.one;
}
[HarmonyPatch(typeof(XUiC_OnScreenIcons), nameof(XUiC_OnScreenIcons.CreateIcon))]
[HarmonyPostfix]
private static void Postfix_CreateIcon_XUiC_OnScreenIcons(XUiC_OnScreenIcons __instance)
{
if (__instance.ViewComponent?.UiTransform)
{
__instance.screenIconList[__instance.screenIconList.Count - 1].Transform.SetParent(__instance.ViewComponent.UiTransform.Find("AllIconParent"));
}
}
[HarmonyPatch(typeof(XUiC_OnScreenIcons), nameof(XUiC_OnScreenIcons.Update))]
[HarmonyPrefix]
private static bool Prefix_Update_XUiC_OnScreenIcons(XUiC_OnScreenIcons __instance)
{
GameObject iconParent = __instance.ViewComponent.UiTransform.Find("AllIconParent").gameObject;
if (!iconParent)
{
return true;
}
if (__instance.xui.playerUI.entityPlayer.bAimingGun)
{
iconParent.SetActive(false);
}
else
{
iconParent.SetActive(true);
}
return true;
}
}

96
Harmony/Init.cs Normal file
View File

@@ -0,0 +1,96 @@
using GearsAPI.Settings;
using GearsAPI.Settings.Global;
using GearsAPI.Settings.World;
using HarmonyLib;
using KFCommonUtilityLib;
using KFCommonUtilityLib.Scripts.StaticManagers;
using KFCommonUtilityLib.Scripts.Utilities;
using System.Reflection;
using System.Runtime.InteropServices;
public class CommonUtilityLibInit : IModApi
{
private static bool inited = false;
internal static Harmony HarmonyInstance { get; private set; }
public void InitMod(Mod _modInstance)
{
if (inited)
return;
inited = true;
Log.Out(" Loading Patch: " + GetType());
unsafe
{
Log.Out($"size of MultiActionIndice: {sizeof(MultiActionIndice)} marshal size: {Marshal.SizeOf<MultiActionIndice>()}");
Log.Out($"{AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.StartHolding)).FullDescription()}");
}
//QualitySettings.streamingMipmapsMemoryBudget = 4096;
DelayLoadModuleManager.RegisterDelayloadDll("FullautoLauncher", "FullautoLauncherAnimationRiggingCompatibilityPatch");
//DelayLoadModuleManager.RegisterDelayloadDll("SMXcore", "SMXMultiActionCompatibilityPatch");
//DelayLoadModuleManager.RegisterDelayloadDll("SCore", "SCoreEntityHitCompatibilityPatch");
CustomEffectEnumManager.RegisterEnumType<MinEventTypes>();
CustomEffectEnumManager.RegisterEnumType<PassiveEffects>();
ModuleManagers.ClearOutputFolder();
ItemClassModuleManager.Init();
ItemActionModuleManager.Init();
ModEvents.GameAwake.RegisterHandler(CommonUtilityPatch.InitShotStates);
ModEvents.GameAwake.RegisterHandler(CustomEffectEnumManager.InitDefault);
ModEvents.GameAwake.RegisterHandler(DelayLoadModuleManager.DelayLoad);
//ModEvents.GameAwake.RegisterHandler(AssemblyLocator.Init);
ModEvents.GameAwake.RegisterHandler(MultiActionUtils.SetMinEventArrays);
ModEvents.GameStartDone.RegisterHandler(RegisterKFEnums);
//DOES NOT WORK ON MULTIPLAYER? Patch to ItemClass.LateInitAll
//ModEvents.GameStartDone.RegisterHandler(AnimationRiggingManager.ParseItemIDs);
ModEvents.GameStartDone.RegisterHandler(MultiActionManager.PostloadCleanup);
//ModEvents.GameStartDone.RegisterHandler(CustomEffectEnumManager.PrintResults);
//ModEvents.GameUpdate.RegisterHandler(CommonUtilityPatch.ForceUpdateGC);
HarmonyInstance = new Harmony(GetType().ToString());
HarmonyInstance.PatchAll(Assembly.GetExecutingAssembly());
}
private static void RegisterKFEnums()
{
CustomEnums.onSelfMagzineDeplete = CustomEffectEnumManager.RegisterOrGetEnum<MinEventTypes>("onSelfMagzineDeplete");
CustomEnums.onReloadAboutToStart = CustomEffectEnumManager.RegisterOrGetEnum<MinEventTypes>("onReloadAboutToStart");
CustomEnums.onRechargeValueUpdate = CustomEffectEnumManager.RegisterOrGetEnum<MinEventTypes>("onRechargeValueUpdate");
CustomEnums.onSelfItemSwitchMode = CustomEffectEnumManager.RegisterOrGetEnum<MinEventTypes>("onSelfItemSwitchMode");
CustomEnums.onSelfBurstModeChanged = CustomEffectEnumManager.RegisterOrGetEnum<MinEventTypes>("onSelfBurstModeChanged");
CustomEnums.onSelfFirstCVarSync = CustomEffectEnumManager.RegisterOrGetEnum<MinEventTypes>("onSelfFirstCVarSync");
CustomEnums.onSelfHoldingItemAssemble = CustomEffectEnumManager.RegisterOrGetEnum<MinEventTypes>("onSelfHoldingItemAssemble");
CustomEnums.ReloadSpeedRatioFPV2TPV = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("ReloadSpeedRatioFPV2TPV");
CustomEnums.RecoilSnappiness = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("RecoilSnappiness");
CustomEnums.RecoilReturnSpeed = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("RecoilReturnSpeed");
//CustomEnums.ProjectileImpactDamagePercentBlock = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("ProjectileImpactDamagePercentBlock");
//CustomEnums.ProjectileImpactDamagePercentEntity = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("ProjectileImpactDamagePercentEntity");
CustomEnums.PartialReloadCount = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("PartialReloadCount");
CustomEnums.CustomTaggedEffect = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("CustomTaggedEffect");
CustomEnums.KickDegreeHorizontalModifier = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("KickDegreeHorizontalModifier");
CustomEnums.KickDegreeVerticalModifier = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("KickDegreeVerticalModifier");
CustomEnums.WeaponErgonomics = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("WeaponErgonomics");
CustomEnums.RecoilCameraShakeStrength = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("RecoilCameraShakeStrength");
CustomEnums.BurstShotInterval = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("BurstShotInterval");
CustomEnums.MaxWeaponSpread = CustomEffectEnumManager.RegisterOrGetEnum<PassiveEffects>("MaxWeaponSpread");
}
}
public class GearsImpl : IGearsModApi
{
public void InitMod(IGearsMod modInstance)
{
}
public void OnGlobalSettingsLoaded(IModGlobalSettings modSettings)
{
RecoilManager.InitRecoilSettings(modSettings);
}
public void OnWorldSettingsLoaded(IModWorldSettings worldSettings)
{
}
}

View File

@@ -0,0 +1,73 @@
using HarmonyLib;
using KFCommonUtilityLib.Scripts.StaticManagers;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
namespace KFCommonUtilityLib.Harmony
{
[HarmonyPatch]
public static class InvariableRPMPatches
{
//added as a transpiler so that it's applied before all post processing
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.OnHoldingUpdate))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_OnHoldingUpdate_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_getvalue))
{
int start = -1;
for (int j = i; j >= 0; j--)
{
if (codes[j].opcode == OpCodes.Stloc_0)
{
start = j + 2;
break;
}
}
if (start >= 0)
{
codes.InsertRange(i + 2, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldloc_0),
CodeInstruction.Call(typeof(InvariableRPMPatches), nameof(InvariableRPMPatches.CalcFixedRPM))
});
codes.RemoveRange(start, i - start + 2);
Log.Out("Invariable RPM Patch applied!");
}
break;
}
}
return codes;
}
private static float CalcFixedRPM(ItemActionRanged rangedAction, ItemActionRanged.ItemActionDataRanged rangedData)
{
float res;
if (rangedAction is IModuleContainerFor<ActionModuleInvariableRPM> actionModule)
{
float rpm = 60f / rangedData.OriginalDelay;
float perc = 1f;
var tags = rangedData.invData.item.ItemTags;
MultiActionManager.ModifyItemTags(rangedData.invData.itemValue, rangedData, ref tags);
rangedData.invData.item.Effects.ModifyValue(rangedData.invData.holdingEntity, PassiveEffects.RoundsPerMinute, ref rpm, ref perc, rangedData.invData.itemValue.Quality, tags);
res = rpm * perc;
//Log.Out($"fixed RPM {res}");
}
else
{
res = EffectManager.GetValue(PassiveEffects.RoundsPerMinute, rangedData.invData.itemValue, 60f / rangedData.OriginalDelay, rangedData.invData.holdingEntity);
}
res = 60f / res;
return res;
}
}
}

View File

@@ -0,0 +1,41 @@
using HarmonyLib;
using HarmonyLib.Public.Patching;
using KFCommonUtilityLib.Scripts.StaticManagers;
using System.Reflection;
namespace KFCommonUtilityLib.Harmony
{
[HarmonyPatch]
public static class ItemActionModulePatch
{
[HarmonyPatch(typeof(GameManager), nameof(GameManager.StartGame))]
[HarmonyPrefix]
private static bool Prefix_StartGame_GameManager()
{
ItemActionModuleManager.InitNew();
return true;
}
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.Init))]
[HarmonyPostfix]
private static void Postfix_Init_ItemClass(ItemClass __instance)
{
ItemActionModuleManager.CheckItem(__instance);
}
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.LateInitAll))]
[HarmonyPrefix]
private static bool Prefix_LateInitAll_ItemClass()
{
ItemActionModuleManager.FinishAndLoad();
return true;
}
[HarmonyPatch(typeof(PatchManager), "GetRealMethod")]
[HarmonyReversePatch]
public static MethodBase GetRealMethod(MethodInfo method, bool useReplacement)
{
return null;
}
}
}

343
Harmony/ModularPatches.cs Normal file
View File

@@ -0,0 +1,343 @@
using HarmonyLib;
using HarmonyLib.Public.Patching;
using System.Collections.Generic;
using UniLinq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System;
namespace KFCommonUtilityLib.Harmony
{
[HarmonyPatch]
public static class ModularPatches
{
[HarmonyPatch(typeof(GameManager), nameof(GameManager.StartGame))]
[HarmonyPrefix]
private static bool Prefix_StartGame_GameManager()
{
ModuleManagers.InitNew();
return true;
}
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.Init))]
[HarmonyPostfix]
private static void Postfix_Init_ItemClass(ItemClass __instance)
{
ItemClassModuleManager.CheckItem(__instance);
ItemActionModuleManager.CheckItem(__instance);
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.worldInfoCo), MethodType.Enumerator)]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_worldInfoCo_GameManager(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_all = AccessTools.Method(typeof(WorldStaticData), nameof(WorldStaticData.AllConfigsReceivedAndLoaded));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_all))
{
codes.Insert(i + 2, CodeInstruction.Call(typeof(ModuleManagers), nameof(ModuleManagers.FinishAndLoad)).WithLabels(codes[i + 2].ExtractLabels()));
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ConnectionManager), nameof(ConnectionManager.ServerReady))]
[HarmonyPrefix]
private static void Prefix_ServerReady_ConnectionManager()
{
ModuleManagers.FinishAndLoad();
}
[HarmonyPatch(typeof(WorldStaticData), nameof(WorldStaticData.ReloadAllXmlsSync))]
[HarmonyPrefix]
private static void Prefix_ReloadAllXmlsSync_WorldStaticData()
{
ModuleManagers.InitNew();
}
[HarmonyPatch(typeof(WorldStaticData), nameof(WorldStaticData.ReloadAllXmlsSync))]
[HarmonyPostfix]
private static void Postfix_ReloadAllXmlsSync_WorldStaticData()
{
ModuleManagers.FinishAndLoad();
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.Disconnect))]
[HarmonyPostfix]
private static void Postfix_Disconnect_GameManager()
{
ModuleManagers.Cleanup();
}
[HarmonyPatch(typeof(PatchManager), "GetRealMethod")]
[HarmonyReversePatch]
public static MethodBase GetRealMethod(MethodInfo method, bool useReplacement)
{
IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (instructions == null)
{
return null;
}
return new CodeInstruction[]
{
CodeInstruction.LoadField(typeof(PatchManager), "ReplacementToOriginals"),
CodeInstruction.LoadField(typeof(PatchManager), "ReplacementToOriginalsMono"),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.Call(typeof(ModularPatches), nameof(ModularPatches.GetPatched)),
new CodeInstruction(OpCodes.Ret)
};
}
_ = Transpiler(null);
return null;
}
private static MethodBase GetPatched(ConditionalWeakTable<MethodBase, MethodBase> ReplacementToOriginals, Dictionary<long, MethodBase[]> ReplacementToOriginalsMono, MethodInfo method)
{
MethodInfo methodInfo = method.Identifiable();
ConditionalWeakTable<MethodBase, MethodBase> replacementToOriginals = ReplacementToOriginals;
lock (replacementToOriginals)
{
foreach (var pair in replacementToOriginals)
{
if (pair.Value == method)
{
Log.Out($"Found method replacement {pair.Key.FullDescription()} for method {method.FullDescription()}");
return pair.Key;
}
}
}
if (AccessTools.IsMonoRuntime)
{
long num = (long)method.MethodHandle.GetFunctionPointer();
Dictionary<long, MethodBase[]> replacementToOriginalsMono = ReplacementToOriginalsMono;
lock (replacementToOriginalsMono)
{
foreach (var pair in replacementToOriginalsMono)
{
if (pair.Value[0] == method)
{
Log.Out($"Found MONO method replacement {pair.Value[1].FullDescription()} for method {method.FullDescription()}");
return pair.Value[1];
}
}
}
}
return method;
}
[HarmonyPatch(typeof(PatchManager), nameof(PatchManager.ToPatchInfo))]
[HarmonyReversePatch]
public static PatchInfo ToPatchInfoDontAdd(this MethodBase methodBase)
{
IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (instructions == null)
{
return null;
}
var codes = instructions.ToList();
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Dup)
{
codes[i - 1].WithLabels(codes[i - 3].ExtractLabels());
codes.RemoveAt(i + 2);
codes.RemoveAt(i);
codes.RemoveRange(i - 3, 2);
break;
}
}
return codes;
}
_ = Transpiler(null);
return null;
}
[HarmonyPatch(typeof(PatchInfo), "AddTranspilers")]
[HarmonyReversePatch]
public static void AddTranspilers(this PatchInfo self, string owner, params HarmonyMethod[] methods)
{
}
public static PatchInfo Copy(this PatchInfo self)
{
var res = new PatchInfo();
res.prefixes = new Patch[self.prefixes.Length];
res.postfixes = new Patch[self.postfixes.Length];
res.transpilers = new Patch[self.transpilers.Length];
res.finalizers = new Patch[self.finalizers.Length];
res.ilmanipulators = new Patch[self.ilmanipulators.Length];
Array.Copy(self.prefixes, res.prefixes, res.prefixes.Length);
Array.Copy(self.postfixes, res.postfixes, res.postfixes.Length);
Array.Copy(self.transpilers, res.transpilers, res.transpilers.Length);
Array.Copy(self.finalizers, res.finalizers, res.finalizers.Length);
Array.Copy(self.ilmanipulators, res.ilmanipulators, res.ilmanipulators.Length);
return res;
}
//public static MethodBase GetOriginalMethod(this HarmonyMethod attr)
//{
// try
// {
// MethodType? methodType = attr.methodType;
// if (methodType != null)
// {
// switch (methodType.GetValueOrDefault())
// {
// case MethodType.Normal:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes, null);
// case MethodType.Getter:
// {
// if (attr.methodName == null)
// {
// PropertyInfo propertyInfo = AccessTools.DeclaredIndexer(attr.declaringType, attr.argumentTypes);
// return (propertyInfo != null) ? propertyInfo.GetGetMethod(true) : null;
// }
// PropertyInfo propertyInfo2 = AccessTools.DeclaredProperty(attr.declaringType, attr.methodName);
// return (propertyInfo2 != null) ? propertyInfo2.GetGetMethod(true) : null;
// }
// case MethodType.Setter:
// {
// if (attr.methodName == null)
// {
// PropertyInfo propertyInfo3 = AccessTools.DeclaredIndexer(attr.declaringType, attr.argumentTypes);
// return (propertyInfo3 != null) ? propertyInfo3.GetSetMethod(true) : null;
// }
// PropertyInfo propertyInfo4 = AccessTools.DeclaredProperty(attr.declaringType, attr.methodName);
// return (propertyInfo4 != null) ? propertyInfo4.GetSetMethod(true) : null;
// }
// case MethodType.Constructor:
// return AccessTools.DeclaredConstructor(attr.declaringType, attr.argumentTypes, false);
// case MethodType.StaticConstructor:
// return AccessTools.GetDeclaredConstructors(attr.declaringType, null).FirstOrDefault((ConstructorInfo c) => c.IsStatic);
// case MethodType.Enumerator:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.EnumeratorMoveNext(AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes, null));
// case MethodType.Async:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.AsyncMoveNext(AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes, null));
// }
// }
// }
// catch (AmbiguousMatchException ex)
// {
// throw new Exception("Ambiguous match for HarmonyMethod[" + attr.ToString() + "]", ex.InnerException ?? ex);
// }
// return null;
//}
//public static MethodBase GetBaseMethod(this HarmonyMethod attr)
//{
// try
// {
// MethodType? methodType = attr.methodType;
// if (methodType != null)
// {
// switch (methodType.GetValueOrDefault())
// {
// case MethodType.Normal:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.Method(attr.declaringType, attr.methodName, attr.argumentTypes, null);
// case MethodType.Getter:
// {
// if (attr.methodName == null)
// {
// PropertyInfo propertyInfo = AccessTools.Indexer(attr.declaringType, attr.argumentTypes);
// return (propertyInfo != null) ? propertyInfo.GetGetMethod(true) : null;
// }
// PropertyInfo propertyInfo2 = AccessTools.Property(attr.declaringType, attr.methodName);
// return (propertyInfo2 != null) ? propertyInfo2.GetGetMethod(true) : null;
// }
// case MethodType.Setter:
// {
// if (attr.methodName == null)
// {
// PropertyInfo propertyInfo3 = AccessTools.Indexer(attr.declaringType, attr.argumentTypes);
// return (propertyInfo3 != null) ? propertyInfo3.GetSetMethod(true) : null;
// }
// PropertyInfo propertyInfo4 = AccessTools.Property(attr.declaringType, attr.methodName);
// return (propertyInfo4 != null) ? propertyInfo4.GetSetMethod(true) : null;
// }
// case MethodType.Constructor:
// return AccessTools.Constructor(attr.declaringType, attr.argumentTypes, false);
// case MethodType.StaticConstructor:
// return AccessTools.GetDeclaredConstructors(attr.declaringType, null).FirstOrDefault((ConstructorInfo c) => c.IsStatic);
// case MethodType.Enumerator:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.EnumeratorMoveNext(AccessTools.Method(attr.declaringType, attr.methodName, attr.argumentTypes, null));
// case MethodType.Async:
// if (attr.methodName == null)
// {
// return null;
// }
// return AccessTools.AsyncMoveNext(AccessTools.Method(attr.declaringType, attr.methodName, attr.argumentTypes, null));
// }
// }
// }
// catch (AmbiguousMatchException ex)
// {
// throw new Exception("Ambiguous match for HarmonyMethod[" + attr.ToString() + "]", ex.InnerException ?? ex);
// }
// return null;
//}
}
[HarmonyPatch]
public static class PatchToolsPatches
{
public static MethodBase TargetMethod()
{
return AccessTools.DeclaredMethod(AccessTools.TypeByName("HarmonyLib.PatchTools"), "GetOriginalMethod");
}
[HarmonyReversePatch]
public static MethodBase GetOriginalMethod(this HarmonyMethod attr)
{
return null;
}
[HarmonyReversePatch]
public static MethodBase GetBaseMethod(this HarmonyMethod attr)
{
IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (instructions == null)
return null;
return instructions.MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredMethod), new[] { typeof(Type), typeof(string), typeof(Type[]), typeof(Type[]) }),
AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Method), new[] { typeof(Type), typeof(string), typeof(Type[]), typeof(Type[]) }))
.MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredIndexer)),
AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Indexer)))
.MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredProperty), new[] { typeof(Type), typeof(string) }),
AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Property), new[] { typeof(Type), typeof(string) }))
.MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredConstructor)),
AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Constructor)));
}
_ = Transpiler(null);
return null;
}
}
}

View File

@@ -0,0 +1,2909 @@
using GameEvent.SequenceActions;
using HarmonyLib;
using KFCommonUtilityLib.Scripts.NetPackages;
using KFCommonUtilityLib.Scripts.StaticManagers;
using KFCommonUtilityLib.Scripts.Utilities;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using UniLinq;
using UnityEngine;
namespace KFCommonUtilityLib.Harmony
{
//done?: patch all accesses to ItemClass.Actions so that they process all actions
//done?: patch ItemClass.ExecuteAction, MinEvent triggers
//done: replace GameManager.ItemReload*
//done: patch ItemActionRanged.ConsumeAmmo
//todo: patch passive effect handling and trigger effect firing, in ItemValue.ModifyValue set action index from tags
//todo: patch trigger action index enum/ or just let it use secondary and tag check?
//todo: handle ItemActionAttack.GetDamageEntity/GetDamageBlock and call sites actionIndex
//todo: sell, assemble, scrap remove ammo
//nope, not gonna work
//try old style action toggle,
//replace meta and ammo index when toggling, => solves ammo issue
//provide requirement for checking current mode, => solves effect group condition issue
//replace hardcoded action index with current mode => bulk patch is enough?
//ItemClass subclass? maybe not
//is inventory update on remote client really needed? put off
//todo: figure out when is meta and ammo index used, how to set their value in minimum patches
//ExecuteAction, Reload, what's more?
//safe to work within ItemAction scope
//even if meta and ammo index is set accordingly, better keep checking them in reload script
[HarmonyPatch]
public static class MultiActionPatches
{
#region Run Correct ItemAction
#region Ranged Reload
//Replace reload action index with animator item action index parameter
//set MinEventParams.ItemActionData before getting passive value
[HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateEnter))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_OnStateEnter_AnimatorRangedReloadState(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
LocalBuilder lbd_index = generator.DeclareLocal(typeof(int));
FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions));
FieldInfo fld_actionData = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.actionData));
FieldInfo fld_meta = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Meta));
FieldInfo fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex));
MethodInfo mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue));
bool firstRet = true;
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if ((code.LoadsField(fld_action) || code.LoadsField(fld_actionData)) && codes[i + 1].opcode == OpCodes.Ldc_I4_0)
{
//get correct ItemAction and data
codes[i + 1].opcode = OpCodes.Ldloc_S;
codes[i + 1].operand = lbd_index;
}
else if (code.Calls(mtd_getvalue))
{
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(AnimatorRangedReloadState), "actionData"),
CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)),
CodeInstruction.LoadField(typeof(ItemInventoryData), nameof(ItemInventoryData.holdingEntity)),
CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(AnimatorRangedReloadState), "actionData"),
CodeInstruction.StoreField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData))
});
break;
}
else if (code.opcode == OpCodes.Ret && firstRet)
{
firstRet = false;
var insert = new[]
{
new CodeInstruction(OpCodes.Ldloc_0),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity)),
new CodeInstruction(OpCodes.Stloc_S, lbd_index)
};
insert[0].MoveLabelsFrom(codes[i + 1]);
codes.InsertRange(i + 1, insert);
}
}
return codes;
}
[HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateExit))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_OnStateExit_AnimatorRangedReloadState(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
MethodInfo mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.Calls(mtd_getvalue))
{
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.actionData)),
CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)),
CodeInstruction.LoadField(typeof(ItemInventoryData), nameof(ItemInventoryData.holdingEntity)),
CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.actionData)),
CodeInstruction.StoreField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData))
});
break;
}
}
return codes;
}
#endregion
//KEEP
#region Aiming
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.IsAimingGunPossible))]
[HarmonyPrefix]
private static bool Prefix_IsAimingGunPossible_EntityPlayerLocal(ref bool __result, EntityPlayerLocal __instance)
{
__result = true;
for (int i = 0; i < __instance.inventory.holdingItem.Actions.Length; i++)
{
ItemAction action = __instance.inventory.holdingItem.Actions[i];
ItemActionData actionData = __instance.inventory.holdingItemData.actionData[i];
__result &= (action == null || action.IsAimingGunPossible(actionData));
}
return false;
}
#endregion
//KEEP
#region Cancel bow draw
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.TryCancelBowDraw))]
[HarmonyPrefix]
private static bool Prefix_TryCancelBowDraw(EntityPlayerLocal __instance)
{
for (int i = 0; i < __instance.inventory.holdingItem.Actions.Length; i++)
{
ItemAction action = __instance.inventory.holdingItem.Actions[i];
ItemActionData actionData = __instance.inventory.holdingItemData.actionData[i];
if (action is ItemActionCatapult catapult)
{
action.CancelAction(actionData);
actionData.HasExecuted = false;
}
}
return false;
}
#endregion
//KEEP
#region Consume wheel scroll
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.ConsumeScrollWheel))]
[HarmonyPrefix]
private static bool Prefix_ConsumeScrollWheel_ItemClass(ItemClass __instance, ItemInventoryData _data, float _scrollWheelInput, PlayerActionsLocal _playerInput, ref bool __result)
{
__result = false;
for (int i = 0; i < __instance.Actions.Length; i++)
{
ItemAction action = __instance.Actions[i];
if (action != null && action.ConsumeScrollWheel(_data.actionData[i], _scrollWheelInput, _playerInput))
{
__result = true;
break;
}
}
return false;
}
#endregion
//KEEP
#region Create modifier data for more actions
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.CreateInventoryData))]
[HarmonyPostfix]
private static void Postfix_CreateInventoryData_ItemClass(ItemInventoryData __result, ItemClass __instance)
{
int prevCount = __result.actionData.Count;
while (__result.actionData.Count < __instance.Actions.Length)
{
__result.actionData.Add(null);
}
for (; prevCount < __instance.Actions.Length; prevCount++)
{
if (__instance.Actions[prevCount] != null)
__result.actionData[prevCount] = __instance.Actions[prevCount].CreateModifierData(__result, prevCount);
}
}
#endregion
//todo: should I patch ItemClass.ExecuteAction for melee actions?
//KEEP
#region IsFocusBlockInside?
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.IsFocusBlockInside))]
[HarmonyPrefix]
private static bool Prefix_IsFocusBlockInside_ItemClass(ItemClass __instance, ref bool __result)
{
__result = __instance.Actions.All(action => action != null && action.IsFocusBlockInside());
return false;
}
#endregion
//KEEP
#region IsHUDDisabled
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.IsHUDDisabled))]
[HarmonyPrefix]
private static bool Prefix_IsHUDDisabled_ItemClass(ItemClass __instance, ref bool __result, ItemInventoryData _data)
{
__result = false;
for (int i = 0; i < __instance.Actions.Length; i++)
{
__result |= __instance.Actions[i] != null && __instance.Actions[i].IsHUDDisabled(_data.actionData[i]);
}
return false;
}
#endregion
//KEEP
#region OnHUD
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.OnHUD))]
[HarmonyPrefix]
private static bool Prefix_OnHUD_ItemClass(ItemInventoryData _data, int _x, int _y, ItemClass __instance)
{
for (int i = 0; i < __instance.Actions.Length; i++)
{
__instance.Actions[i]?.OnHUD(_data.actionData[i], _x, _y);
}
return false;
}
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.GetCrosshairType))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_GetCrosshairType_ItemClass(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
LocalBuilder lbd_index = generator.DeclareLocal(typeof(int));
FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.LoadsField(fld_action) && codes[i + 1].opcode == OpCodes.Ldc_I4_0)
{
codes[i + 1].opcode = OpCodes.Ldloc_S;
codes[i + 1].operand = lbd_index;
}
}
codes.InsertRange(0, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.LoadField(typeof(ItemInventoryData), nameof(ItemInventoryData.holdingEntity)),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity)),
new CodeInstruction(OpCodes.Stloc_S, lbd_index)
});
return codes;
}
#endregion
//KEEP
#region OnScreenOverlay
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.OnScreenOverlay))]
[HarmonyPrefix]
private static bool Prefix_OnScreenOverlay_ItemClass(ItemInventoryData _data, ItemClass __instance)
{
for (int i = 0; i < __instance.Actions.Length; i++)
{
__instance.Actions[i]?.OnScreenOverlay(_data.actionData[i]);
}
return false;
}
#endregion
#region inventory related
[HarmonyPatch(typeof(Inventory), nameof(Inventory.GetHoldingGun))]
[HarmonyPrefix]
private static bool Prefix_GetHoldingGun_Inventory(Inventory __instance, ref ItemActionAttack __result)
{
__result = __instance.holdingItem.Actions[MultiActionManager.GetActionIndexForEntity(__instance.entity)] as ItemActionAttack ?? __instance.holdingItem.Actions[0] as ItemActionAttack;
return false;
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.GetHoldingDynamicMelee))]
[HarmonyPrefix]
private static bool Prefix_GetHoldingDynamicMelee_Inventory(Inventory __instance, ref ItemActionDynamic __result)
{
__result = __instance.holdingItem.Actions[MultiActionManager.GetActionIndexForEntity(__instance.entity)] as ItemActionDynamic ?? __instance.holdingItem.Actions[0] as ItemActionDynamic;
return false;
}
//[HarmonyPatch(typeof(Inventory), "clearSlotByIndex")]
//[HarmonyPrefix]
//private static bool Prefix_clearSlotByIndex_Inventory(int _idx, Inventory __instance, EntityAlive ___entity)
//{
// if (__instance.holdingItemIdx == _idx && ___entity != null && !___entity.isEntityRemote)
// {
// var mapping = MultiActionManager.GetMappingForEntity(___entity.entityId);
// mapping?.SaveMeta();
// }
// return true;
//}
#endregion
#region GameManager.ItemReload*
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SetAmmoType))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SetAmmoType_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
MethodInfo mtd_reloadserver = AccessTools.Method(typeof(GameManager), nameof(GameManager.ItemReloadServer));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.Calls(mtd_reloadserver))
{
codes.RemoveAt(i);
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.FixedItemReloadServer))
});
codes.RemoveAt(i - 3);
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SwapAmmoType))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SwapAmmoType_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
MethodInfo mtd_reloadserver = AccessTools.Method(typeof(GameManager), nameof(GameManager.ItemReloadServer));
FieldInfo fld_actiondata = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.actionData));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.Calls(mtd_reloadserver))
{
codes.RemoveAt(i);
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.FixedItemReloadServer))
});
codes[i - 4].MoveLabelsFrom(codes[i - 5]);
codes.RemoveAt(i - 5);
break;
}
else if (code.LoadsField(fld_actiondata))
{
codes.RemoveAt(i + 1);
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex))
});
i += 1;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.SwapAmmoType))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SwapAmmoType_ItemActionLauncher(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
FieldInfo fld_actiondata = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.actionData));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.LoadsField(fld_actiondata))
{
codes.RemoveAt(i + 1);
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex))
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SwapSelectedAmmo))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SwapSelectedAmmo_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
MethodInfo mtd_reloadserver = AccessTools.Method(typeof(GameManager), nameof(GameManager.ItemReloadServer));
MethodInfo mtd_canreload = AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.CanReload));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.Calls(mtd_reloadserver))
{
codes.RemoveAt(i);
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.FixedItemReloadServer))
});
codes.RemoveAt(i - 3);
break;
}
else if (code.Calls(mtd_canreload))
{
codes.RemoveAt(i - 2);
codes.InsertRange(i - 2, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex))
});
codes.RemoveRange(i - 9, 3);
codes.Insert(i - 9, new CodeInstruction(OpCodes.Ldarg_0));
i--;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.loadNewAmmunition))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_loadNewAmmunition_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_actiondata = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.actionData));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_actiondata))
{
codes.RemoveAt(i + 1);
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_3),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity))
});
break;
}
}
return codes;
}
#endregion
//KEEP
#region Launcher logic
#region Launcher projectile meta and action index
[HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.StartHolding))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_StartHolding_ItemActionLauncher(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
var fld_meta = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Meta));
var mtd_delete = AccessTools.Method(typeof(ItemActionLauncher), nameof(ItemActionLauncher.DeleteProjectiles));
var prop_itemvalue = AccessTools.PropertyGetter(typeof(ItemInventoryData), nameof(ItemInventoryData.itemValue));
var lbd_meta = generator.DeclareLocal(typeof(int));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_delete))
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)),
new CodeInstruction(OpCodes.Callvirt, prop_itemvalue),
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.indexInEntityOfAction)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetMetaByActionIndex)),
new CodeInstruction(OpCodes.Stloc_S, lbd_meta)
});
i += 7;
}
else if (codes[i].LoadsField(fld_meta))
{
codes.Insert(i + 1, new CodeInstruction(OpCodes.Ldloc_S, lbd_meta));
codes.RemoveRange(i - 3, 4);
i -= 3;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.instantiateProjectile))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_instantiateProjectile_ItemActionLauncher_MetaIndex(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_ammoindex))
{
codes[i].opcode = OpCodes.Call;
codes[i].operand = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetSelectedAmmoIndexByActionIndex));
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.indexInEntityOfAction))
});
break;
}
}
return codes;
}
#endregion
[HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.instantiateProjectile))]
[HarmonyTranspiler]
//use custom script
private static IEnumerable<CodeInstruction> Transpiler_instantiateProjectile_ItemActionLauncher_ReplaceScript(IEnumerable<CodeInstruction> instructions)
{
MethodInfo mtd_addcomponent = AccessTools.Method(typeof(GameObject), nameof(GameObject.AddComponent), Array.Empty<Type>());
MethodInfo mtd_addcomponentprev = mtd_addcomponent.MakeGenericMethod(typeof(ProjectileMoveScript));
MethodInfo mtd_addcomponentnew = mtd_addcomponent.MakeGenericMethod(typeof(CustomProjectileMoveScript));
foreach (var code in instructions)
{
if (code.Calls(mtd_addcomponentprev))
{
Log.Out("replacing launcher projectile script...");
code.operand = mtd_addcomponentnew;
}
yield return code;
}
}
//copy ItemValue to projectile
[HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.instantiateProjectile))]
[HarmonyPostfix]
private static void Postfix_instantiateProjectile_ItemActionLauncher(Transform __result)
{
var script = __result.GetComponent<ProjectileMoveScript>();
var projectileValue = script.itemValueProjectile;
var launcherValue = script.itemValueLauncher;
projectileValue.Activated = (byte)(Mathf.Clamp01(script.actionData.strainPercent) * byte.MaxValue);
MultiActionUtils.CopyLauncherValueToProjectile(launcherValue, projectileValue, script.actionData.indexInEntityOfAction);
}
//
[HarmonyPatch(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.Fire))]
[HarmonyPrefix]
private static bool Prefix_Fire_ProjectileMoveScript(ProjectileMoveScript __instance, Vector3 _idealStartPosition, Vector3 _flyDirection, Entity _firingEntity, int _hmOverride, float _radius)
{
if (_firingEntity is EntityAlive entityAlive)
entityAlive.MinEventContext.ItemActionData = __instance.actionData;
if (__instance is CustomProjectileMoveScript)
{
__instance.ProjectileFire(_idealStartPosition, _flyDirection, _firingEntity, _hmOverride, _radius);
return false;
}
return true;
}
#endregion
#endregion
#region FireEvent patches, set params
//KEEP
#region Ranged ExecuteAction FireEvent params
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.ExecuteAction))]
[HarmonyPrefix]
private static bool Prefix_ExecuteAction_ItemClass(ref int _actionIdx, ItemInventoryData _data, PlayerActionsLocal _playerActions)
{
if (_actionIdx != 0 || _playerActions == null || !(_data.holdingEntity is EntityPlayerLocal player))
{
return true;
}
_actionIdx = MultiActionManager.GetActionIndexForEntity(player);
player.MinEventContext.ItemActionData = _data.actionData[_actionIdx];
return true;
}
//why? ask TFP the fuck they are doing
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ExecuteAction))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ExecuteAction_ItemActionRanged(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
FieldInfo fld_itemactiondata = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.ItemActionData));
MethodInfo mtd_reloadserver = AccessTools.Method(typeof(IGameManager), nameof(IGameManager.ItemReloadServer));
FieldInfo fld_gamemanager = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.gameManager));
MethodInfo mtd_getkickback = AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.GetKickbackForce));
MethodInfo mtd_getmaxammo = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.GetMaxAmmoCount));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.StoresField(fld_itemactiondata))
{
codes.Insert(i, new CodeInstruction(OpCodes.Ldarg_1));
codes.RemoveRange(i - 5, 5);
i -= 4;
}
else if (code.Calls(mtd_reloadserver))
{
int j = i;
while (!codes[j].LoadsField(fld_gamemanager))
{
j--;
}
codes.RemoveAt(i);
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldloc_0),
CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.indexInEntityOfAction)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.FixedItemReloadServer))
});
codes.RemoveRange(j - 2, 3);
i--;
}
//else if (code.Calls(mtd_getmaxammo))
//{
// int j = i + 1;
// for (; j < codes.Count; j++)
// {
// if (codes[j].Calls(mtd_getkickback))
// {
// break;
// }
// }
// if (j < codes.Count)
// {
// var jumpto = codes[j - 2];
// var label = generator.DefineLabel();
// jumpto.labels.Add(label);
// codes.Insert(i - 2, new CodeInstruction(OpCodes.Br_S, label));
// codes[i - 2].MoveLabelsFrom(codes[i - 1]);
// i++;
// }
//}
}
return codes;
}
#endregion
#region ItemAction.CancelAction
[HarmonyPatch(typeof(ItemActionCatapult), nameof(ItemActionCatapult.CancelAction))]
[HarmonyPrefix]
private static bool Prefix_CancelAction_ItemActionCatapult(ItemActionData _actionData)
{
_actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData;
return true;
}
#endregion
#region ItemActionDynamicMelee.Raycast
[HarmonyPatch(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.Raycast))]
[HarmonyPrefix]
private static bool Prefix_Raycast_ItemActionDynamicMelee(ItemActionDynamic.ItemActionDynamicData _actionData)
{
_actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData;
return true;
}
#endregion
#region Inventory.FireEvent, set current action
[HarmonyPatch(typeof(Inventory), nameof(Inventory.FireEvent))]
[HarmonyPrefix]
private static bool Prefix_FireEvent_Inventory(Inventory __instance)
{
MultiActionUtils.SetMinEventParamsByEntityInventory(__instance.entity);
return true;
}
#endregion
#region Inventory.syncHeldItem, set current action
[HarmonyPatch(typeof(Inventory), nameof(Inventory.syncHeldItem))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_syncHeldItem_Inventory(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_test = AccessTools.Method(typeof(FastTags<TagGroup.Global>), nameof(FastTags<TagGroup.Global>.Test_AnySet));
var fld_itemvalue = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.ItemValue));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].StoresField(fld_itemvalue) && codes[i - 7].Calls(mtd_test))
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(Inventory), nameof(Inventory.entity)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.SetMinEventParamsByEntityInventory))
});
break;
}
}
return codes;
}
#endregion
#region ItemValue.FireEvent, read current action
[HarmonyPatch(typeof(ItemValue), nameof(ItemValue.FireEvent))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_FireEvent_ItemValue(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
LocalBuilder lbd_index = generator.DeclareLocal(typeof(int));
FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions));
FieldInfo fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex));
MethodInfo mtd_fireevent = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.FireEvent));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.LoadsField(fld_action) && codes[i + 1].opcode == OpCodes.Ldc_I4_0)
{
codes[i + 1].opcode = OpCodes.Ldloc_S;
codes[i + 1].operand = lbd_index;
if (codes[i - 9].opcode == OpCodes.Ret)
{
codes.InsertRange(i - 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_2),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetActionIndexByEventParams)),
new CodeInstruction(OpCodes.Stloc_S, lbd_index)
});
i += 3;
}
}
else if (code.LoadsField(fld_ammoindex))
{
code.opcode = OpCodes.Call;
code.operand = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetSelectedAmmoIndexByActionIndex));
codes.Insert(i, new CodeInstruction(OpCodes.Ldloc_S, lbd_index));
i++;
}
//action exclude mods
else if (code.Calls(mtd_fireevent) && codes[i + 1].opcode != OpCodes.Ldloc_0)
{
for (int j = i; j >= 0; j--)
{
if (codes[j].opcode == OpCodes.Brfalse_S || codes[j].opcode == OpCodes.Brfalse)
{
var label = codes[j].operand;
codes.InsertRange(j + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)),
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, codes[j + 2].operand),
new CodeInstruction(codes[j + 3].opcode, codes[j + 3].operand),
new CodeInstruction(OpCodes.Ldelem_Ref),
CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)),
new CodeInstruction(OpCodes.Ldloc_S, lbd_index),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ShouldExcludeTrigger)),
new CodeInstruction(OpCodes.Brtrue_S, label)
});
i += 10;
break;
}
}
}
}
return codes;
}
#endregion
//onSelfEquipStop, onSelfHoldingItemCreated, onSelfEquipStart are not available for individual action,
//some are already set in update or execute action
#endregion
#region EffectManager.GetValue patches, set params
//set correct action index for ItemValue
[HarmonyPatch(typeof(ItemValue), nameof(ItemValue.ModifyValue))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ModifyValue_ItemValue(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
LocalBuilder lbd_index = generator.DeclareLocal(typeof(int));
FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions));
FieldInfo fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex));
FieldInfo fld_mods = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Modifications));
FieldInfo fld_cos = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.CosmeticMods));
MethodInfo mtd_modify = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.ModifyValue));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.opcode == OpCodes.Stloc_1)
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetActionIndexByEntityEventParams)),
new CodeInstruction(OpCodes.Stloc_S, lbd_index)
});
}
else if (code.LoadsField(fld_action) && codes[i + 1].opcode == OpCodes.Ldc_I4_0)
{
codes[i + 1].opcode = OpCodes.Ldloc_S;
codes[i + 1].operand = lbd_index;
}
else if (code.LoadsField(fld_ammoindex))
{
code.opcode = OpCodes.Call;
code.operand = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetSelectedAmmoIndexByActionIndex));
codes.Insert(i, new CodeInstruction(OpCodes.Ldloc_S, lbd_index));
i++;
}
else if (code.Calls(mtd_modify))
{
for (int j = i; j >= 0; j--)
{
if (codes[j].opcode == OpCodes.Brfalse_S || codes[j].opcode == OpCodes.Brfalse)
{
var label = codes[j].operand;
codes.InsertRange(j + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)),
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, codes[j + 2].operand),
new CodeInstruction(codes[j + 3].opcode, codes[j + 3].operand),
new CodeInstruction(OpCodes.Ldelem_Ref),
CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)),
new CodeInstruction(OpCodes.Ldloc_S, lbd_index),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ShouldExcludePassive)),
new CodeInstruction(OpCodes.Brtrue_S, label)
});
i += 10;
break;
}
}
}
}
return codes;
}
//only current mode should execute OnHUD
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.OnHUD))]
[HarmonyPrefix]
private static bool Prefix_OnHUD_EntityPlayerLocal(EntityPlayerLocal __instance, out ItemActionData __state)
{
__state = __instance.MinEventContext.ItemActionData;
MultiActionUtils.SetMinEventParamsByEntityInventory(__instance);
return true;
}
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.OnHUD))]
[HarmonyPostfix]
private static void Postfix_OnHUD_EntityPlayerLocal(EntityPlayerLocal __instance, ItemActionData __state)
{
__instance.MinEventContext.ItemActionData = __state;
}
//for passive value calc
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.guiDrawCrosshair))]
[HarmonyPrefix]
private static bool Prefix_guiDrawCrosshair_EntityPlayerLocal(EntityPlayerLocal __instance)
{
MultiActionUtils.SetMinEventParamsByEntityInventory(__instance);
return true;
}
//draw crosshair for current action
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.guiDrawCrosshair))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_guiDrawCrosshair_EntityPlayerLocal(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
LocalBuilder lbd_index = generator.DeclareLocal(typeof(int));
FieldInfo fld_actiondata = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.actionData));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Stloc_1)
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity)),
new CodeInstruction(OpCodes.Stloc_S, lbd_index)
});
i += 3;
}
else if (codes[i].LoadsField(fld_actiondata) && codes[i + 1].opcode == OpCodes.Ldc_I4_0)
{
codes[i + 1].opcode = OpCodes.Ldloc_S;
codes[i + 1].operand = lbd_index;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemAction), nameof(ItemAction.ExecuteBuffActions))]
[HarmonyPrefix]
private static bool Prefix_ExecuteBuffActions_ItemAction(int instigatorId, out (EntityAlive entity, ItemActionData actionData) __state)
{
__state = default;
EntityAlive entity = GameManager.Instance.World.GetEntity(instigatorId) as EntityAlive;
if (entity != null)
{
__state.entity = entity;
__state.actionData = entity.MinEventContext.ItemActionData;
MultiActionUtils.SetMinEventParamsByEntityInventory(entity);
}
else
return false;
return true;
}
[HarmonyPatch(typeof(ItemAction), nameof(ItemAction.ExecuteBuffActions))]
[HarmonyPostfix]
private static void Postfix_ExecuteBuffActions_ItemAction((EntityAlive entity, ItemActionData actionData) __state, bool __runOriginal)
{
if (__runOriginal && __state.entity != null)
__state.entity.MinEventContext.ItemActionData = __state.actionData;
}
//ItemAction.GetDismemberChance already set
//ItemActionDynamic.GetExecuteActionTarget not needed
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ItemActionEffects))]
[HarmonyPrefix]
private static bool Prefix_ItemActionEffects_ItemActionLauncher(ItemActionData _actionData, out ItemActionData __state)
{
__state = _actionData.invData.holdingEntity.MinEventContext.ItemActionData;
_actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData;
return true;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ItemActionEffects))]
[HarmonyPostfix]
private static void Postfix_ItemActionEffects_ItemActionLauncher(ItemActionData _actionData, ItemActionData __state)
{
_actionData.invData.holdingEntity.MinEventContext.ItemActionData = __state;
}
[HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.ClampAmmoCount))]
[HarmonyPrefix]
private static bool Prefix_ClampAmmoCount_ItemActionLauncher(ItemActionLauncher.ItemActionDataLauncher actionData, out ItemActionData __state)
{
__state = actionData.invData.holdingEntity.MinEventContext.ItemActionData;
actionData.invData.holdingEntity.MinEventContext.ItemActionData = actionData;
return true;
}
[HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.ClampAmmoCount))]
[HarmonyPostfix]
private static void Postfix_ClampAmmoCount_ItemActionLauncher(ItemActionLauncher.ItemActionDataLauncher actionData, ItemActionData __state)
{
actionData.invData.holdingEntity.MinEventContext.ItemActionData = __state;
}
#endregion
#region EffectManager.GetValuesAndSources patches, set params
[HarmonyPatch(typeof(EntityStats), nameof(EntityStats.Update))]
[HarmonyPrefix]
private static bool Prefix_Update_EntityStats(EntityStats __instance)
{
MultiActionUtils.SetMinEventParamsByEntityInventory(__instance.m_entity);
return true;
}
//set correct action index for ItemValue
[HarmonyPatch(typeof(ItemValue), nameof(ItemValue.GetModifiedValueData))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_GetModifiedValueData_ItemValue(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
LocalBuilder lbd_index = generator.DeclareLocal(typeof(int));
FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions));
FieldInfo fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex));
FieldInfo fld_mods = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Modifications));
FieldInfo fld_cos = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.CosmeticMods));
MethodInfo mtd_getvalue = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.GetModifiedValueData));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.opcode == OpCodes.Stloc_0)
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_3),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetActionIndexByEntityEventParams)),
new CodeInstruction(OpCodes.Stloc_S, lbd_index)
});
}
else if (code.LoadsField(fld_action) && codes[i + 1].opcode == OpCodes.Ldc_I4_0)
{
codes[i + 1].opcode = OpCodes.Ldloc_S;
codes[i + 1].operand = lbd_index;
}
else if (code.LoadsField(fld_ammoindex))
{
code.opcode = OpCodes.Call;
code.operand = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetSelectedAmmoIndexByActionIndex));
codes.Insert(i, new CodeInstruction(OpCodes.Ldloc_S, lbd_index));
i++;
}
else if (code.Calls(mtd_getvalue) && codes[i + 1].opcode != OpCodes.Ldloc_0)
{
for (int j = i; j >= 0; j--)
{
if (codes[j].opcode == OpCodes.Brfalse_S || codes[j].opcode == OpCodes.Brfalse)
{
var label = codes[j].operand;
codes.InsertRange(j + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)),
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, codes[j + 2].operand),
new CodeInstruction(codes[j + 3].opcode, codes[j + 3].operand),
new CodeInstruction(OpCodes.Ldelem_Ref),
CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)),
new CodeInstruction(OpCodes.Ldloc_S, lbd_index),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ShouldExcludePassive)),
new CodeInstruction(OpCodes.Brtrue_S, label)
});
i += 10;
break;
}
}
}
}
return codes;
}
#endregion
//KEEP
#region Misc
//load correct property for melee
[HarmonyPatch(typeof(AnimatorMeleeAttackState), nameof(AnimatorMeleeAttackState.OnStateEnter))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_OnStateEnter_AnimatorMeleeAttackState(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_actionindex = AccessTools.Field(typeof(AnimatorMeleeAttackState), nameof(AnimatorMeleeAttackState.actionIndex));
MethodInfo mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.LoadsField(fld_actionindex) && codes[i + 2].opcode == OpCodes.Ldstr)
{
string property = codes[i + 2].operand.ToString();
property = property.Split('.')[1];
codes.RemoveRange(i + 1, 4);
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldstr, property),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetPropertyName))
});
i -= 2;
}
else if (code.Calls(mtd_getvalue))
{
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(AnimatorMeleeAttackState), "entity"),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(AnimatorMeleeAttackState), "actionIndex"),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.SetMinEventParamsActionData))
});
i += 5;
}
}
return codes;
}
//make sure it's set to current action after for loop
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.OnHoldingUpdate))]
[HarmonyPostfix]
private static void Postfix_OnHoldingUpdate_ItemClass(ItemInventoryData _data)
{
MultiActionUtils.SetMinEventParamsByEntityInventory(_data.holdingEntity);
}
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.StopHolding))]
[HarmonyPostfix]
private static void Postfix_StopHolding_ItemClass(ItemInventoryData _data)
{
if (_data.holdingEntity != null)
{
MultiActionUtils.SetMinEventParamsByEntityInventory(_data.holdingEntity);
MultiActionManager.SetMappingForEntity(_data.holdingEntity.entityId, null);
}
}
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.StartHolding))]
[HarmonyPostfix]
private static void Postfix_StartHolding_ItemClass(ItemInventoryData _data)
{
MultiActionUtils.SetMinEventParamsByEntityInventory(_data.holdingEntity);
}
//should be fixed in Harmony 2.12.0.0
//[HarmonyPatch(typeof(ItemClassesFromXml), nameof(ItemClassesFromXml.parseItem))]
//[HarmonyPrefix]
//private static bool Prefix_parseItem_ItemClassesFromXml(XElement _node)
//{
// DynamicProperties dynamicProperties = new DynamicProperties();
// string attribute = _node.GetAttribute("name");
// if (attribute.Length == 0)
// {
// throw new Exception("Attribute 'name' missing on item");
// }
// //here
// List<IRequirement>[] array = new List<IRequirement>[ItemClass.cMaxActionNames];
// for (int i = 0; i < array.Length; i++)
// {
// array[i] = new List<IRequirement>();
// }
// foreach (XElement item in _node.Elements("property"))
// {
// dynamicProperties.Add(item);
// string attribute2 = item.GetAttribute("class");
// if (attribute2.StartsWith("Action"))
// {
// int num = attribute2[attribute2.Length - 1] - '0';
// array[num].AddRange(RequirementBase.ParseRequirements(item));
// }
// }
// if (dynamicProperties.Values.ContainsKey("Extends"))
// {
// string text = dynamicProperties.Values["Extends"];
// ItemClass itemClass = ItemClass.GetItemClass(text);
// if (itemClass == null)
// {
// throw new Exception($"Extends item {text} is not specified for item {attribute}'");
// }
// HashSet<string> hashSet = new HashSet<string> { Block.PropCreativeMode };
// if (dynamicProperties.Params1.ContainsKey("Extends"))
// {
// string[] array2 = dynamicProperties.Params1["Extends"].Split(new[] { ',' }, StringSplitOptions.None);
// foreach (string text2 in array2)
// {
// hashSet.Add(text2.Trim());
// }
// }
// DynamicProperties dynamicProperties2 = new DynamicProperties();
// dynamicProperties2.CopyFrom(itemClass.Properties, hashSet);
// dynamicProperties2.CopyFrom(dynamicProperties);
// dynamicProperties = dynamicProperties2;
// }
// ItemClass itemClass2;
// if (dynamicProperties.Values.ContainsKey("Class"))
// {
// string text3 = dynamicProperties.Values["Class"];
// if (!text3.Contains(","))
// {
// text3 += ",Assembly-CSharp";
// }
// try
// {
// itemClass2 = (ItemClass)Activator.CreateInstance(Type.GetType(text3));
// }
// catch (Exception)
// {
// throw new Exception("No item class '" + text3 + " found!");
// }
// }
// else
// {
// itemClass2 = new ItemClass();
// }
// itemClass2.Properties = dynamicProperties;
// if (dynamicProperties.Params1.ContainsKey("Extends"))
// {
// string text4 = dynamicProperties.Values["Extends"];
// if (ItemClass.GetItemClass(text4) == null)
// {
// throw new Exception($"Extends item {text4} is not specified for item {attribute}'");
// }
// }
// itemClass2.Effects = MinEffectController.ParseXml(_node, null, MinEffectController.SourceParentType.ItemClass, itemClass2.Id);
// itemClass2.SetName(attribute);
// itemClass2.setLocalizedItemName(Localization.Get(attribute));
// if (dynamicProperties.Values.ContainsKey("Stacknumber"))
// {
// itemClass2.Stacknumber = new DataItem<int>(int.Parse(dynamicProperties.Values["Stacknumber"]));
// }
// else
// {
// itemClass2.Stacknumber = new DataItem<int>(500);
// }
// if (dynamicProperties.Values.ContainsKey("Canhold"))
// {
// itemClass2.SetCanHold(StringParsers.ParseBool(dynamicProperties.Values["Canhold"]));
// }
// if (dynamicProperties.Values.ContainsKey("Candrop"))
// {
// itemClass2.SetCanDrop(StringParsers.ParseBool(dynamicProperties.Values["Candrop"]));
// }
// if (!dynamicProperties.Values.ContainsKey("Material"))
// {
// throw new Exception("Attribute 'material' missing on item '" + attribute + "'");
// }
// itemClass2.MadeOfMaterial = MaterialBlock.fromString(dynamicProperties.Values["Material"]);
// if (itemClass2.MadeOfMaterial == null)
// {
// throw new Exception("Attribute 'material' '" + dynamicProperties.Values["Material"] + "' refers to not existing material in item '" + attribute + "'");
// }
// if (!dynamicProperties.Values.ContainsKey("Meshfile") && itemClass2.CanHold())
// {
// throw new Exception("Attribute 'Meshfile' missing on item '" + attribute + "'");
// }
// itemClass2.MeshFile = dynamicProperties.Values["Meshfile"];
// DataLoader.PreloadBundle(itemClass2.MeshFile);
// StringParsers.TryParseFloat(dynamicProperties.Values["StickyOffset"], out itemClass2.StickyOffset);
// StringParsers.TryParseFloat(dynamicProperties.Values["StickyColliderRadius"], out itemClass2.StickyColliderRadius);
// StringParsers.TryParseSInt32(dynamicProperties.Values["StickyColliderUp"], out itemClass2.StickyColliderUp);
// StringParsers.TryParseFloat(dynamicProperties.Values["StickyColliderLength"], out itemClass2.StickyColliderLength);
// itemClass2.StickyMaterial = dynamicProperties.Values["StickyMaterial"];
// if (dynamicProperties.Values.ContainsKey("ImageEffectOnActive"))
// {
// itemClass2.ImageEffectOnActive = new DataItem<string>(dynamicProperties.Values["ImageEffectOnActive"]);
// }
// if (dynamicProperties.Values.ContainsKey("Active"))
// {
// itemClass2.Active = new DataItem<bool>(_startValue: false);
// }
// if (dynamicProperties.Values.ContainsKey(ItemClass.PropIsSticky))
// {
// itemClass2.IsSticky = StringParsers.ParseBool(dynamicProperties.Values[ItemClass.PropIsSticky]);
// }
// if (dynamicProperties.Values.ContainsKey("DropMeshfile") && itemClass2.CanHold())
// {
// itemClass2.DropMeshFile = dynamicProperties.Values["DropMeshfile"];
// DataLoader.PreloadBundle(itemClass2.DropMeshFile);
// }
// if (dynamicProperties.Values.ContainsKey("HandMeshfile") && itemClass2.CanHold())
// {
// itemClass2.HandMeshFile = dynamicProperties.Values["HandMeshfile"];
// DataLoader.PreloadBundle(itemClass2.HandMeshFile);
// }
// if (dynamicProperties.Values.ContainsKey("HoldType"))
// {
// string s = dynamicProperties.Values["HoldType"];
// int result = 0;
// if (!int.TryParse(s, out result))
// {
// throw new Exception("Cannot parse attribute hold_type for item '" + attribute + "'");
// }
// itemClass2.HoldType = new DataItem<int>(result);
// }
// if (dynamicProperties.Values.ContainsKey("RepairTools"))
// {
// string[] array3 = dynamicProperties.Values["RepairTools"].Replace(" ", "").Split(new[] { ',' }, StringSplitOptions.None);
// DataItem<string>[] array4 = new DataItem<string>[array3.Length];
// for (int k = 0; k < array3.Length; k++)
// {
// array4[k] = new DataItem<string>(array3[k]);
// }
// itemClass2.RepairTools = new ItemData.DataItemArrayRepairTools(array4);
// }
// if (dynamicProperties.Values.ContainsKey("RepairAmount"))
// {
// int result2 = 0;
// int.TryParse(dynamicProperties.Values["RepairAmount"], out result2);
// itemClass2.RepairAmount = new DataItem<int>(result2);
// }
// if (dynamicProperties.Values.ContainsKey("RepairTime"))
// {
// float _result = 0f;
// StringParsers.TryParseFloat(dynamicProperties.Values["RepairTime"], out _result);
// itemClass2.RepairTime = new DataItem<float>(_result);
// }
// else if (itemClass2.RepairAmount != null)
// {
// itemClass2.RepairTime = new DataItem<float>(1f);
// }
// if (dynamicProperties.Values.ContainsKey("Degradation"))
// {
// itemClass2.MaxUseTimes = new DataItem<int>(int.Parse(dynamicProperties.Values["Degradation"]));
// }
// else
// {
// itemClass2.MaxUseTimes = new DataItem<int>(0);
// itemClass2.MaxUseTimesBreaksAfter = new DataItem<bool>(_startValue: false);
// }
// if (dynamicProperties.Values.ContainsKey("DegradationBreaksAfter"))
// {
// itemClass2.MaxUseTimesBreaksAfter = new DataItem<bool>(StringParsers.ParseBool(dynamicProperties.Values["DegradationBreaksAfter"]));
// }
// else if (dynamicProperties.Values.ContainsKey("Degradation"))
// {
// itemClass2.MaxUseTimesBreaksAfter = new DataItem<bool>(_startValue: true);
// }
// if (dynamicProperties.Values.ContainsKey("EconomicValue"))
// {
// itemClass2.EconomicValue = StringParsers.ParseFloat(dynamicProperties.Values["EconomicValue"]);
// }
// if (dynamicProperties.Classes.ContainsKey("Preview"))
// {
// DynamicProperties dynamicProperties3 = dynamicProperties.Classes["Preview"];
// itemClass2.Preview = new PreviewData();
// if (dynamicProperties3.Values.ContainsKey("Zoom"))
// {
// itemClass2.Preview.Zoom = new DataItem<int>(int.Parse(dynamicProperties3.Values["Zoom"]));
// }
// if (dynamicProperties3.Values.ContainsKey("Pos"))
// {
// itemClass2.Preview.Pos = new DataItem<Vector2>(StringParsers.ParseVector2(dynamicProperties3.Values["Pos"]));
// }
// else
// {
// itemClass2.Preview.Pos = new DataItem<Vector2>(Vector2.zero);
// }
// if (dynamicProperties3.Values.ContainsKey("Rot"))
// {
// itemClass2.Preview.Rot = new DataItem<Vector3>(StringParsers.ParseVector3(dynamicProperties3.Values["Rot"]));
// }
// else
// {
// itemClass2.Preview.Rot = new DataItem<Vector3>(Vector3.zero);
// }
// }
// for (int l = 0; l < itemClass2.Actions.Length; l++)
// {
// string text5 = ItemClass.itemActionNames[l];
// if (dynamicProperties.Classes.ContainsKey(text5))
// {
// if (!dynamicProperties.Values.ContainsKey(text5 + ".Class"))
// {
// throw new Exception("No class attribute found on " + text5 + " in item with '" + attribute + "'");
// }
// string text6 = dynamicProperties.Values[text5 + ".Class"];
// ItemAction itemAction;
// try
// {
// itemAction = (ItemAction)Activator.CreateInstance(ReflectionHelpers.GetTypeWithPrefix("ItemAction", text6));
// }
// catch (Exception)
// {
// throw new Exception("ItemAction class '" + text6 + " could not be instantiated");
// }
// itemAction.item = itemClass2;
// itemAction.ActionIndex = l;
// itemAction.ReadFrom(dynamicProperties.Classes[text5]);
// if (array[l].Count > 0)
// {
// itemAction.ExecutionRequirements = array[l];
// }
// itemClass2.Actions[l] = itemAction;
// }
// }
// itemClass2.Init();
// return false;
//}
/// <summary>
/// fix requirement array count
/// </summary>
/// <param name="instructions"></param>
/// <returns></returns>
[HarmonyPatch(typeof(ItemClassesFromXml), nameof(ItemClassesFromXml.parseItem))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_parseItem_ItemClassesFromXml(IEnumerable<CodeInstruction> instructions)
{
bool isLastInsThrow = false;
foreach (var code in instructions)
{
if (isLastInsThrow)
{
isLastInsThrow = false;
if (code.opcode == OpCodes.Ldc_I4_3)
{
code.opcode = OpCodes.Ldc_I4_5;
}
}
if (code.opcode == OpCodes.Throw)
{
isLastInsThrow = true;
}
yield return code;
}
}
[HarmonyPatch(typeof(ItemModificationsFromXml), nameof(ItemModificationsFromXml.parseItem))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_parseItem_ItemModificationsFromXml(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
for (int i = 0; i < codes.Count - 1; i++)
{
if (codes[i].opcode == OpCodes.Ldc_I4_3 && codes[i + 1].opcode == OpCodes.Newarr)
{
codes[i].opcode = OpCodes.Ldc_I4_5;
break;
}
}
return codes;
}
/*
[HarmonyPatch(typeof(ItemClassesFromXml), nameof(ItemClassesFromXml.parseItem))]
[HarmonyPrefix]
private static bool Prefix_parseItem_ItemClassesFromXml(XElement _node)
{
//throw new Exception("Exception thrown from here!");
DynamicProperties dynamicProperties = new DynamicProperties();
string attribute = _node.GetAttribute("name");
if (attribute.Length == 0)
{
throw new Exception("Attribute 'name' missing on item");
}
//Log.Out($"Parsing item {attribute}...");
List<IRequirement>[] array = new List<IRequirement>[5];
for (int i = 0; i < array.Length; i++)
{
array[i] = new List<IRequirement>();
}
foreach (XElement item in _node.Elements("property"))
{
dynamicProperties.Add(item);
string attribute2 = item.GetAttribute("class");
if (attribute2.StartsWith("Action"))
{
int num = attribute2[attribute2.Length - 1] - 48;
array[num].AddRange(RequirementBase.ParseRequirements(item));
}
}
if (dynamicProperties.Values.ContainsKey("Extends"))
{
string text = dynamicProperties.Values["Extends"];
ItemClass itemClass = ItemClass.GetItemClass(text);
if (itemClass == null)
{
throw new Exception($"Extends item {text} is not specified for item {attribute}'");
}
HashSet<string> hashSet = new HashSet<string> { Block.PropCreativeMode };
if (dynamicProperties.Params1.ContainsKey("Extends"))
{
string[] array2 = dynamicProperties.Params1["Extends"].Split(',');
foreach (string text2 in array2)
{
hashSet.Add(text2.Trim());
}
}
DynamicProperties dynamicProperties2 = new DynamicProperties();
dynamicProperties2.CopyFrom(itemClass.Properties, hashSet);
dynamicProperties2.CopyFrom(dynamicProperties);
dynamicProperties = dynamicProperties2;
}
ItemClass itemClass2;
if (dynamicProperties.Values.ContainsKey("Class"))
{
string text3 = dynamicProperties.Values["Class"];
if (!text3.Contains(","))
{
text3 += ",Assembly-CSharp";
}
try
{
itemClass2 = (ItemClass)Activator.CreateInstance(Type.GetType(text3));
}
catch (Exception)
{
throw new Exception("No item class '" + text3 + "' found!");
}
}
else
{
itemClass2 = new ItemClass();
}
itemClass2.Properties = dynamicProperties;
if (dynamicProperties.Params1.ContainsKey("Extends"))
{
string text4 = dynamicProperties.Values["Extends"];
if (ItemClass.GetItemClass(text4) == null)
{
throw new Exception($"Extends item {text4} is not specified for item {attribute}'");
}
}
itemClass2.Effects = MinEffectController.ParseXml(_node, null, MinEffectController.SourceParentType.ItemClass, itemClass2.Id);
itemClass2.SetName(attribute);
itemClass2.setLocalizedItemName(Localization.Get(attribute));
if (dynamicProperties.Values.ContainsKey("Stacknumber"))
{
itemClass2.Stacknumber = new DataItem<int>(int.Parse(dynamicProperties.Values["Stacknumber"]));
}
else
{
itemClass2.Stacknumber = new DataItem<int>(500);
}
if (dynamicProperties.Values.ContainsKey("Canhold"))
{
itemClass2.SetCanHold(StringParsers.ParseBool(dynamicProperties.Values["Canhold"]));
}
if (dynamicProperties.Values.ContainsKey("Candrop"))
{
itemClass2.SetCanDrop(StringParsers.ParseBool(dynamicProperties.Values["Candrop"]));
}
if (!dynamicProperties.Values.ContainsKey("Material"))
{
throw new Exception("Attribute 'material' missing on item '" + attribute + "'");
}
itemClass2.MadeOfMaterial = MaterialBlock.fromString(dynamicProperties.Values["Material"]);
if (itemClass2.MadeOfMaterial == null)
{
throw new Exception("Attribute 'material' '" + dynamicProperties.Values["Material"] + "' refers to not existing material in item '" + attribute + "'");
}
if (!dynamicProperties.Values.ContainsKey("Meshfile") && itemClass2.CanHold())
{
throw new Exception("Attribute 'Meshfile' missing on item '" + attribute + "'");
}
itemClass2.MeshFile = dynamicProperties.Values["Meshfile"];
DataLoader.PreloadBundle(itemClass2.MeshFile);
StringParsers.TryParseFloat(dynamicProperties.Values["StickyOffset"], out itemClass2.StickyOffset);
StringParsers.TryParseFloat(dynamicProperties.Values["StickyColliderRadius"], out itemClass2.StickyColliderRadius);
StringParsers.TryParseSInt32(dynamicProperties.Values["StickyColliderUp"], out itemClass2.StickyColliderUp);
StringParsers.TryParseFloat(dynamicProperties.Values["StickyColliderLength"], out itemClass2.StickyColliderLength);
itemClass2.StickyMaterial = dynamicProperties.Values["StickyMaterial"];
if (dynamicProperties.Values.ContainsKey("ImageEffectOnActive"))
{
itemClass2.ImageEffectOnActive = new DataItem<string>(dynamicProperties.Values["ImageEffectOnActive"]);
}
if (dynamicProperties.Values.ContainsKey("Active"))
{
itemClass2.Active = new DataItem<bool>(_startValue: false);
}
if (dynamicProperties.Values.ContainsKey(ItemClass.PropIsSticky))
{
itemClass2.IsSticky = StringParsers.ParseBool(dynamicProperties.Values[ItemClass.PropIsSticky]);
}
if (dynamicProperties.Values.ContainsKey("DropMeshfile") && itemClass2.CanHold())
{
itemClass2.DropMeshFile = dynamicProperties.Values["DropMeshfile"];
DataLoader.PreloadBundle(itemClass2.DropMeshFile);
}
if (dynamicProperties.Values.ContainsKey("HandMeshfile") && itemClass2.CanHold())
{
itemClass2.HandMeshFile = dynamicProperties.Values["HandMeshfile"];
DataLoader.PreloadBundle(itemClass2.HandMeshFile);
}
if (dynamicProperties.Values.ContainsKey("HoldType"))
{
string s = dynamicProperties.Values["HoldType"];
int result = 0;
if (!int.TryParse(s, out result))
{
throw new Exception("Cannot parse attribute hold_type for item '" + attribute + "'");
}
itemClass2.HoldType = new DataItem<int>(result);
}
if (dynamicProperties.Values.ContainsKey("RepairTools"))
{
string[] array3 = dynamicProperties.Values["RepairTools"].Replace(" ", "").Split(',');
DataItem<string>[] array4 = new DataItem<string>[array3.Length];
for (int k = 0; k < array3.Length; k++)
{
array4[k] = new DataItem<string>(array3[k]);
}
itemClass2.RepairTools = new ItemData.DataItemArrayRepairTools(array4);
}
if (dynamicProperties.Values.ContainsKey("RepairAmount"))
{
int result2 = 0;
int.TryParse(dynamicProperties.Values["RepairAmount"], out result2);
itemClass2.RepairAmount = new DataItem<int>(result2);
}
if (dynamicProperties.Values.ContainsKey("RepairTime"))
{
float _result = 0f;
StringParsers.TryParseFloat(dynamicProperties.Values["RepairTime"], out _result);
itemClass2.RepairTime = new DataItem<float>(_result);
}
else if (itemClass2.RepairAmount != null)
{
itemClass2.RepairTime = new DataItem<float>(1f);
}
if (dynamicProperties.Values.ContainsKey("Degradation"))
{
itemClass2.MaxUseTimes = new DataItem<int>(int.Parse(dynamicProperties.Values["Degradation"]));
}
else
{
itemClass2.MaxUseTimes = new DataItem<int>(0);
itemClass2.MaxUseTimesBreaksAfter = new DataItem<bool>(_startValue: false);
}
if (dynamicProperties.Values.ContainsKey("DegradationBreaksAfter"))
{
itemClass2.MaxUseTimesBreaksAfter = new DataItem<bool>(StringParsers.ParseBool(dynamicProperties.Values["DegradationBreaksAfter"]));
}
else if (dynamicProperties.Values.ContainsKey("Degradation"))
{
itemClass2.MaxUseTimesBreaksAfter = new DataItem<bool>(_startValue: true);
}
if (dynamicProperties.Values.ContainsKey("EconomicValue"))
{
itemClass2.EconomicValue = StringParsers.ParseFloat(dynamicProperties.Values["EconomicValue"]);
}
if (dynamicProperties.Classes.ContainsKey("Preview"))
{
DynamicProperties dynamicProperties3 = dynamicProperties.Classes["Preview"];
itemClass2.Preview = new PreviewData();
if (dynamicProperties3.Values.ContainsKey("Zoom"))
{
itemClass2.Preview.Zoom = new DataItem<int>(int.Parse(dynamicProperties3.Values["Zoom"]));
}
if (dynamicProperties3.Values.ContainsKey("Pos"))
{
itemClass2.Preview.Pos = new DataItem<Vector2>(StringParsers.ParseVector2(dynamicProperties3.Values["Pos"]));
}
else
{
itemClass2.Preview.Pos = new DataItem<Vector2>(Vector2.zero);
}
if (dynamicProperties3.Values.ContainsKey("Rot"))
{
itemClass2.Preview.Rot = new DataItem<Vector3>(StringParsers.ParseVector3(dynamicProperties3.Values["Rot"]));
}
else
{
itemClass2.Preview.Rot = new DataItem<Vector3>(Vector3.zero);
}
}
for (int l = 0; l < itemClass2.Actions.Length; l++)
{
string text5 = ItemClass.itemActionNames[l];
if (dynamicProperties.Classes.ContainsKey(text5))
{
if (!dynamicProperties.Values.ContainsKey(text5 + ".Class"))
{
throw new Exception("No class attribute found on " + text5 + " in item with '" + attribute + "'");
}
string text6 = dynamicProperties.Values[text5 + ".Class"];
ItemAction itemAction;
try
{
itemAction = (ItemAction)Activator.CreateInstance(ReflectionHelpers.GetTypeWithPrefix("ItemAction", text6));
}
catch (Exception)
{
throw new Exception("ItemAction class '" + text6 + " could not be instantiated");
}
itemAction.item = itemClass2;
itemAction.ActionIndex = l;
itemAction.ReadFrom(dynamicProperties.Classes[text5]);
if (array[l].Count > 0)
{
itemAction.ExecutionRequirements = array[l];
}
itemClass2.Actions[l] = itemAction;
}
}
itemClass2.Init();
return false;
}
*/
[HarmonyPatch(typeof(Inventory), nameof(Inventory.onInventoryChanged))]
[HarmonyPrefix]
private static bool Prefix_onInventoryChanged_Inventory(Inventory __instance)
{
if (__instance.entity != null)
MultiActionManager.UpdateLocalMetaSave(__instance.entity.entityId);
return true;
}
#endregion
//KEEP
#region Action mode handling
[HarmonyPatch(typeof(NetPackagePlayerStats), nameof(NetPackagePlayerStats.ProcessPackage))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ProcessPackage_NetPackagePlayerStats(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_entityid = AccessTools.Field(typeof(NetPackagePlayerStats), nameof(NetPackagePlayerStats.entityId));
var fld_itemstack = AccessTools.Field(typeof(NetPackagePlayerStats), nameof(NetPackagePlayerStats.holdingItemStack));
codes.InsertRange(codes.Count - 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, fld_entityid),
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, fld_itemstack),
CodeInstruction.Call(typeof(MultiActionPatches), nameof(CheckItemValueMode))
});
return codes;
}
[HarmonyPatch(typeof(NetPackageHoldingItem), nameof(NetPackageHoldingItem.ProcessPackage))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ProcessPackage_NetPackageHoldingItem(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_entityid = AccessTools.Field(typeof(NetPackagePlayerStats), nameof(NetPackageHoldingItem.entityId));
var fld_itemstack = AccessTools.Field(typeof(NetPackagePlayerStats), nameof(NetPackageHoldingItem.holdingItemStack));
codes.InsertRange(codes.Count - 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, fld_entityid),
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, fld_itemstack),
CodeInstruction.Call(typeof(MultiActionPatches), nameof(CheckItemValueMode))
});
return codes;
}
private static void CheckItemValueMode(int entityId, ItemStack holdingItemStack)
{
ItemValue itemValue = holdingItemStack.itemValue;
if (itemValue.HasMetadata(MultiActionMapping.STR_MULTI_ACTION_INDEX))
{
int mode = (int)itemValue.GetMetadata(MultiActionMapping.STR_MULTI_ACTION_INDEX);
if (MultiActionManager.SetModeForEntity(entityId, mode) && ConnectionManager.Instance.IsServer)
{
ConnectionManager.Instance.SendPackage(NetPackageManager.GetPackage<NetPackageEntityActionIndex>().Setup(entityId, mode), false, -1, entityId);
}
}
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.UpdateTick))]
[HarmonyPostfix]
private static void Postfix_UpdateTick_GameManager(GameManager __instance)
{
if (MultiActionManager.LocalModeChanged && __instance.m_World != null)
{
MultiActionManager.LocalModeChanged = false;
int playerID = __instance.m_World.GetPrimaryPlayerId();
if (ConnectionManager.Instance.IsClient)
{
ConnectionManager.Instance.SendToServer(NetPackageManager.GetPackage<NetPackageEntityActionIndex>().Setup(playerID, MultiActionManager.GetModeForEntity(playerID)));
}
else
{
ConnectionManager.Instance.SendPackage(NetPackageManager.GetPackage<NetPackageEntityActionIndex>().Setup(playerID, MultiActionManager.GetModeForEntity(playerID)), false, -1, playerID);
}
}
}
#endregion
#region Input Handling
[HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))]
[HarmonyPrefix]
private static bool Prefix_Update_PlayerMoveController(PlayerMoveController __instance)
{
if (DroneManager.Debug_LocalControl || !__instance.gameManager.gameStateManager.IsGameStarted() || GameStats.GetInt(EnumGameStats.GameState) != 1)
return true;
bool isUIOpen = __instance.windowManager.IsCursorWindowOpen() || __instance.windowManager.IsInputActive() || __instance.windowManager.IsModalWindowOpen();
MultiActionManager.UpdateLocalInput(__instance.entityPlayerLocal, __instance.playerInput, isUIOpen, Time.deltaTime);
return true;
}
#endregion
#region HUD display
/// <summary>
/// redirect check to alternative action module
/// </summary>
/// <param name="instructions"></param>
/// <returns></returns>
[HarmonyPatch(typeof(XUiC_HUDStatBar), nameof(XUiC_HUDStatBar.HasChanged))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_HasChanged_XUiC_HUDStatBar(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
MethodInfo mtd_edittool = AccessTools.Method(typeof(ItemAction), nameof(ItemAction.IsEditingTool));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.Calls(mtd_edittool))
{
codes.RemoveRange(i - 1, 3);
break;
}
}
return codes;
}
[HarmonyPatch(typeof(XUiC_HUDStatBar), nameof(XUiC_HUDStatBar.SetupActiveItemEntry))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SetupActiveItemEntry_XUiC_HUDStatBar(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
var lbd_index = generator.DeclareLocal(typeof(int));
FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions));
FieldInfo fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_action))
{
codes.RemoveAt(i + 1);
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldloc_2),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetActionIndexByMetaData)),
new CodeInstruction(OpCodes.Dup),
new CodeInstruction(OpCodes.Stloc_S, lbd_index)
});
i += 3;
}
else if (codes[i].LoadsField(fld_ammoindex))
{
codes[i].opcode = OpCodes.Call;
codes[i].operand = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetSelectedAmmoIndexByActionIndex));
codes.Insert(i, new CodeInstruction(OpCodes.Ldloc_S, lbd_index));
break;
}
}
return codes;
}
[HarmonyPatch(typeof(XUiC_Radial), nameof(XUiC_Radial.handleActivatableItemCommand))]
[HarmonyPrefix]
private static bool Prefix_handleActivatableItemCommand_XUiC_Radial(XUiC_Radial _sender)
{
EntityPlayerLocal entityPlayer = _sender.xui.playerUI.entityPlayer;
MultiActionUtils.SetMinEventParamsByEntityInventory(entityPlayer);
return true;
}
[HarmonyPatch(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.GetBindingValue))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_GetBindingValue_XUiC_ItemInfoWindow(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_actions = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_actions) && codes[i + 1].opcode == OpCodes.Ldc_I4_0)
{
codes.RemoveAt(i + 1);
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.itemStack)),
CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetActionIndexByMetaData))
});
i += 3;
}
}
return codes;
}
#endregion
#region Cancel reload on switching item
//redirect these calls to action 0 and handle them in alternative module
//may change in the future
[HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Update_PlayerMoveController(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
MethodInfo mtd_getgun = AccessTools.Method(typeof(Inventory), nameof(Inventory.GetHoldingGun));
MethodInfo mtd_getprimary = AccessTools.Method(typeof(Inventory), nameof(Inventory.GetHoldingPrimary));
FieldInfo fld_reload = AccessTools.Field(typeof(PlayerActionsPermanent), nameof(PlayerActionsPermanent.Reload));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_getgun))
{
codes[i].operand = mtd_getprimary;
//codes.RemoveAt(i - 2);
//codes.InsertRange(i - 2, new[]
//{
// new CodeInstruction(OpCodes.Ldarg_0),
// CodeInstruction.LoadField(typeof(PlayerMoveController), "entityPlayerLocal"),
// CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity))
//});
//i += 2;
}
else if (codes[i].LoadsField(fld_reload))
{
var label = codes[i + 6].operand;
codes.InsertRange(i + 7, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(PlayerMoveController), nameof(PlayerMoveController.entityPlayerLocal)),
CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.inventory)),
CodeInstruction.Call(typeof(Inventory), nameof(Inventory.GetIsFinishedSwitchingHeldItem)),
new CodeInstruction(OpCodes.Brfalse, label)
});
i += 5;
}
}
return codes;
}
#endregion
#region Underwater check
//skip underwater check if action is not current action
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.OnHoldingUpdate))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_OnHoldingUpdate_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_ammonames = AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.MagazineItemNames));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_ammonames) && (codes[i + 1].opcode == OpCodes.Brfalse_S || codes[i + 1].opcode == OpCodes.Brfalse))
{
var jumpto = codes[i + 1].operand;
codes.InsertRange(i - 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_1).WithLabels(codes[i - 1].ExtractLabels()),
CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.indexInEntityOfAction)),
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)),
CodeInstruction.LoadField(typeof(ItemInventoryData), nameof(ItemInventoryData.holdingEntity)),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity)),
new CodeInstruction(OpCodes.Bne_Un_S, jumpto)
});
break;
}
}
return codes;
}
#endregion
#region GameEvent
[HarmonyPatch(typeof(ActionUnloadItems), nameof(ActionUnloadItems.HandleItemStackChange))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_HandleItemStackChange_ActionUnloadItems(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
var fld_actions = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions));
for (var i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_actions))
{
var label = generator.DefineLabel();
codes[i - 1].WithLabels(label);
codes.InsertRange(i - 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
new CodeInstruction(OpCodes.Ldind_Ref),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ActionUnloadItems), nameof(ActionUnloadItems.ItemStacks)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.MultiActionRemoveAmmoFromItemStack)),
new CodeInstruction(OpCodes.Brfalse_S, label),
new CodeInstruction(OpCodes.Ldc_I4_1),
new CodeInstruction(OpCodes.Ret)
});
break;
}
}
return codes;
}
#endregion
#region fast toolbelt item switching issue fix
private static Coroutine switchHoldingItemCo;
[HarmonyPatch(typeof(Inventory), nameof(Inventory.ShowHeldItem))]
[HarmonyPrefix]
private static bool Prefix_ShowHeldItem_Inventory(bool show, Inventory __instance)
{
//Log.Out($"ShowHeldItem {show} on entity {__instance.entity.entityName}\n{StackTraceUtility.ExtractStackTrace()}");
if (show && __instance.entity is EntityPlayerLocal && switchHoldingItemCo != null)
{
GameManager.Instance.StopCoroutine(switchHoldingItemCo);
switchHoldingItemCo = null;
__instance.SetIsFinishedSwitchingHeldItem();
}
return true;
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.ShowHeldItem))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ShowHeldItem_Inventory(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Pop)
{
var label = generator.DefineLabel();
codes[i].WithLabels(label);
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
new CodeInstruction(OpCodes.Brfalse_S, label),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(Inventory), nameof(Inventory.entity)),
new CodeInstruction(OpCodes.Isinst, typeof(EntityPlayerLocal)),
new CodeInstruction(OpCodes.Brfalse_S, label),
CodeInstruction.StoreField(typeof(MultiActionPatches), nameof(switchHoldingItemCo)),
new CodeInstruction(OpCodes.Ret)
});
break;
}
}
return codes;
}
#endregion
#region item info display fix
[HarmonyPatch(typeof(XUiM_ItemStack), nameof(XUiM_ItemStack.GetStatItemValueTextWithModInfo))]
[HarmonyPrefix]
private static bool Prefix_GetStatItemValueTextWithModInfo_XUiM_ItemStack(ItemStack itemStack)
{
MultiActionUtils.SetCachedEventParamsDummyAction(itemStack);
return true;
}
[HarmonyPatch(typeof(XUiM_ItemStack), nameof(XUiM_ItemStack.GetStatItemValueTextWithModColoring))]
[HarmonyPrefix]
private static bool Prefix_GetStatItemValueTextWithModColoring_XUiM_ItemStack(ItemStack itemStack)
{
MultiActionUtils.SetCachedEventParamsDummyAction(itemStack);
return true;
}
[HarmonyPatch(typeof(XUiM_ItemStack), nameof(XUiM_ItemStack.GetStatItemValueTextWithCompareInfo))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_GetStatItemValueTextWithCompareInfo_XUiM_ItemStack(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue));
var fld_seed = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.Seed));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_getvalue))
{
codes.InsertRange(i + 2, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.SetCachedEventParamsDummyAction)),
});
for (int j = i; j >= 0; j--)
{
if (codes[j].StoresField(fld_seed))
{
codes.InsertRange(j + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.SetCachedEventParamsDummyAction))
});
codes.RemoveRange(j - 8, 9);
break;
}
}
break;
}
}
return codes.Manipulator(static ins => ins.IsLdarg(2), static ins => ins.opcode = OpCodes.Ldnull);
}
[HarmonyPatch(typeof(XUiC_ItemStack), nameof(XUiC_ItemStack.GetBindingValue))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_GetBindingValue_XUiC_ItemStack(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var prop_perc = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.PercentUsesLeft));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(prop_perc))
{
codes.InsertRange(i - 3, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(XUiC_ItemStack), nameof(XUiC_ItemStack.itemStack)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.SetCachedEventParamsDummyAction))
});
break;
}
}
return codes;
}
#endregion
#region ItemAction exclude tags
[HarmonyPatch(typeof(GameManager), nameof(GameManager.StartGame))]
[HarmonyPrefix]
private static bool Prefix_StartGame_GameManager()
{
MultiActionManager.PreloadCleanup();
return true;
}
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.LateInit))]
[HarmonyPostfix]
private static void Postfix_LateInit_ItemClass(ItemClass __instance)
{
MultiActionManager.ParseItemActionExcludeTagsAndModifiers(__instance);
}
/// <summary>
///
/// </summary>
/// <param name="instructions"></param>
/// <returns></returns>
[HarmonyPatch(typeof(EffectManager), nameof(EffectManager.GetValue))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_GetValue_EffectManager(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].IsStarg(5))
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_1).WithLabels(codes[i + 1].ExtractLabels()),
CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.CachedEventParam)),
CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)),
new CodeInstruction(OpCodes.Ldarga_S, 5),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ModifyItemTags))
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(EffectManager), nameof(EffectManager.GetValuesAndSources))]
[HarmonyPrefix]
private static bool Prefix_GetValuesAndSources_EffectManager(ItemValue _originalItemValue, EntityAlive _entity, ref FastTags<TagGroup.Global> tags)
{
MultiActionManager.ModifyItemTags(_originalItemValue, _entity?.MinEventContext?.ItemActionData, ref tags);
return true;
}
#endregion
#region ItemAction exclude modifiers
//see Transpiler_ModifyValue_ItemValue
//see Transpiler_GetModifiedValueData_ItemValue
//see MultiActionProjectileRewrites.ProjectileValueModifyValue
//see MultiActionUtils.GetPropertyOverrideForAction
//see MultiActionManager.ParseItemActionExcludeTagsAndModifiers
#endregion
#region requirement tags exclude
//[HarmonyPatch(typeof(TriggerHasTags), nameof(TriggerHasTags.IsValid))]
//[HarmonyTranspiler]
//private static IEnumerable<CodeInstruction> Transpiler_IsValid_TriggerHasTags(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
//{
// var codes = instructions.ToList();
// var lbd_tags = generator.DeclareLocal(typeof(FastTags<TagGroup.Global>));
// FieldInfo fld_tags = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.Tags));
// bool firstRet = true;
// for (int i = 0; i < codes.Count; i++)
// {
// if (codes[i].opcode == OpCodes.Ret && firstRet)
// {
// firstRet = false;
// codes.InsertRange(i + 1, new[]
// {
// new CodeInstruction(OpCodes.Ldarg_1),
// new CodeInstruction(OpCodes.Ldfld, fld_tags),
// new CodeInstruction(OpCodes.Stloc_S, lbd_tags),
// new CodeInstruction(OpCodes.Ldarg_1),
// CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.ItemValue)),
// new CodeInstruction(OpCodes.Ldarg_1),
// CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)),
// new CodeInstruction(OpCodes.Ldloca_S, lbd_tags),
// CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ModifyItemTags))
// });
// i += 9;
// }
// else if (codes[i].LoadsField(fld_tags))
// {
// codes[i].opcode = OpCodes.Ldloca_S;
// codes[i].operand = lbd_tags;
// codes[i].WithLabels(codes[i - 1].ExtractLabels());
// codes.RemoveAt(i - 1);
// i--;
// }
// }
// return codes;
//}
[HarmonyPatch(typeof(ItemHasTags), nameof(ItemHasTags.IsValid))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_IsValid_ItemHasTags(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
var lbd_tags = generator.DeclareLocal(typeof(FastTags<TagGroup.Global>));
FieldInfo fld_itemvalue = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.ItemValue));
FieldInfo fld_hasalltags = AccessTools.Field(typeof(ItemHasTags), nameof(ItemHasTags.hasAllTags));
MethodInfo prop_itemclass = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass));
MethodInfo mtd_hasanytags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags));
MethodInfo mtd_hasalltags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAllTags));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_hasalltags))
{
codes.InsertRange(i - 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
new CodeInstruction(OpCodes.Ldfld, fld_itemvalue),
new CodeInstruction(OpCodes.Callvirt, prop_itemclass),
CodeInstruction.LoadField(typeof(ItemClass), nameof(ItemClass.ItemTags)),
new CodeInstruction(OpCodes.Stloc_S, lbd_tags),
new CodeInstruction(OpCodes.Ldarg_1),
new CodeInstruction(OpCodes.Ldfld, fld_itemvalue),
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)),
new CodeInstruction(OpCodes.Ldloca_S, lbd_tags),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ModifyItemTags))
});
i += 11;
}
else if (codes[i].Calls(mtd_hasanytags))
{
codes[i].opcode = OpCodes.Call;
codes[i].operand = AccessTools.Method(typeof(FastTags<TagGroup.Global>), nameof(FastTags<TagGroup.Global>.Test_AnySet));
var labels = codes[i - 5].ExtractLabels();
codes.RemoveRange(i - 5, 3);
codes.Insert(i - 5, new CodeInstruction(OpCodes.Ldloca_S, lbd_tags).WithLabels(labels));
i -= 2;
}
else if (codes[i].Calls(mtd_hasalltags))
{
codes[i].opcode = OpCodes.Call;
codes[i].operand = AccessTools.Method(typeof(FastTags<TagGroup.Global>), nameof(FastTags<TagGroup.Global>.Test_AllSet));
var labels = codes[i - 5].ExtractLabels();
codes.RemoveRange(i - 5, 3);
codes.Insert(i - 5, new CodeInstruction(OpCodes.Ldloca_S, lbd_tags).WithLabels(labels));
i -= 2;
}
}
return codes;
}
[HarmonyPatch(typeof(HoldingItemHasTags), nameof(ItemHasTags.IsValid))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_IsValid_HoldingItemHasTags(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
var lbd_tags = generator.DeclareLocal(typeof(FastTags<TagGroup.Global>));
FieldInfo fld_itemvalue = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.ItemValue));
FieldInfo fld_hasalltags = AccessTools.Field(typeof(HoldingItemHasTags), nameof(HoldingItemHasTags.hasAllTags));
MethodInfo prop_itemclass = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass));
MethodInfo prop_itemvalue = AccessTools.PropertyGetter(typeof(Inventory), nameof(Inventory.holdingItemItemValue));
MethodInfo mtd_hasanytags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags));
MethodInfo mtd_hasalltags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAllTags));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_hasalltags))
{
codes.InsertRange(i - 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(HoldingItemHasTags), nameof(HoldingItemHasTags.target)),
CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.inventory)),
new CodeInstruction(OpCodes.Callvirt, prop_itemvalue),
new CodeInstruction(OpCodes.Callvirt, prop_itemclass),
CodeInstruction.LoadField(typeof(ItemClass), nameof(ItemClass.ItemTags)),
new CodeInstruction(OpCodes.Stloc_S, lbd_tags),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(HoldingItemHasTags), nameof(HoldingItemHasTags.target)),
CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.inventory)),
new CodeInstruction(OpCodes.Callvirt, prop_itemvalue),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(HoldingItemHasTags), nameof(HoldingItemHasTags.target)),
CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)),
CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)),
new CodeInstruction(OpCodes.Ldloca_S, lbd_tags),
CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ModifyItemTags))
});
i += 17;
}
else if (codes[i].Calls(mtd_hasanytags))
{
codes[i].opcode = OpCodes.Call;
codes[i].operand = AccessTools.Method(typeof(FastTags<TagGroup.Global>), nameof(FastTags<TagGroup.Global>.Test_AnySet));
var labels = codes[i - 6].ExtractLabels();
codes.RemoveRange(i - 6, 4);
codes.Insert(i - 6, new CodeInstruction(OpCodes.Ldloca_S, lbd_tags).WithLabels(labels));
i -= 3;
}
else if (codes[i].Calls(mtd_hasalltags))
{
codes[i].opcode = OpCodes.Call;
codes[i].operand = AccessTools.Method(typeof(FastTags<TagGroup.Global>), nameof(FastTags<TagGroup.Global>.Test_AllSet));
var labels = codes[i - 6].ExtractLabels();
codes.RemoveRange(i - 6, 4);
codes.Insert(i - 6, new CodeInstruction(OpCodes.Ldloca_S, lbd_tags).WithLabels(labels));
i -= 3;
}
}
return codes;
}
#endregion
#region Inventory make ItemValue valid on creating inventory data
[HarmonyPatch(typeof(Inventory), nameof(Inventory.SetItem), new[] { typeof(int), typeof(ItemValue), typeof(int), typeof(bool) })]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SetItem_Inventory(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_clone = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.Clone));
var mtd_create = AccessTools.Method(typeof(Inventory), nameof(Inventory.createHeldItem));
var mtd_invdata = AccessTools.Method(typeof(Inventory), nameof(Inventory.createInventoryData));
for (int i = 0; i < codes.Count; i++)
{
//if (codes[i].opcode == OpCodes.Ldarg_3 && (codes[i + 1].opcode == OpCodes.Brtrue_S || codes[i + 1].opcode == OpCodes.Brtrue))
//{
// var label = codes[i + 4].ExtractLabels();
// codes.InsertRange(i + 4, new[]
// {
// new CodeInstruction(OpCodes.Ldarg_2).WithLabels(label),
// new CodeInstruction(OpCodes.Callvirt, mtd_clone),
// new CodeInstruction(OpCodes.Starg_S, 2)
// });
// i += 7;
//}
//else
if (codes[i].Calls(mtd_create))
{
codes.InsertRange(i - 12, new[]
{
new CodeInstruction(OpCodes.Ldarg_2),
CodeInstruction.StoreField(typeof(ActionModuleAlternative), nameof(ActionModuleAlternative.InventorySetItemTemp))
});
i += 4;
for (int j = i; j < codes.Count; j++)
{
if (codes[j].Calls(mtd_invdata))
{
codes.InsertRange(j + 2, new[]
{
new CodeInstruction(OpCodes.Ldnull),
CodeInstruction.StoreField(typeof(ActionModuleAlternative), nameof(ActionModuleAlternative.InventorySetItemTemp))
});
i = j + 4;
break;
}
}
break;
}
//else if (codes[i].Calls(mtd_clone))
//{
// codes.RemoveAt(i);
// break;
//}
}
return codes;
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.ForceHoldingItemUpdate))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ForceHoldingItemUpdate_Inventory(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_invdata = AccessTools.Method(typeof(Inventory), nameof(Inventory.createInventoryData));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_invdata))
{
codes.InsertRange(i + 2, new[]
{
new CodeInstruction(OpCodes.Ldnull),
CodeInstruction.StoreField(typeof(ActionModuleAlternative), nameof(ActionModuleAlternative.InventorySetItemTemp))
});
codes.InsertRange(i - 8, new[]
{
new CodeInstruction(OpCodes.Ldloc_0).WithLabels(codes[i - 8].ExtractLabels()),
CodeInstruction.StoreField(typeof(ActionModuleAlternative), nameof(ActionModuleAlternative.InventorySetItemTemp))
});
break;
}
}
return codes;
}
#endregion
#region Temporaty fix for hud ammo mismatch
[HarmonyPatch(typeof(XUiC_HUDStatBar), nameof(XUiC_HUDStatBar.Update))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Update_XUiC_HUDStatBar(IEnumerable<CodeInstruction> instructions)
{
MethodInfo mtd_getfocus = AccessTools.Method(typeof(Inventory), nameof(Inventory.GetFocusedItemIdx));
MethodInfo mtd_getholding = AccessTools.PropertyGetter(typeof(Inventory), nameof(Inventory.holdingItemIdx));
foreach (var ins in instructions)
{
if (ins.Calls(mtd_getfocus))
{
ins.operand = mtd_getholding;
}
yield return ins;
}
}
#endregion
}
//Moved to MultiActionFix
//#region Ranged Reload
//[HarmonyPatch]
//public static class RangedReloadPatches
//{
// private static IEnumerable<MethodBase> TargetMethods()
// {
// return new MethodInfo[]
// {
// AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.ReloadGun)),
// AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ReloadGun)),
// AccessTools.Method(typeof(ItemActionLauncher), nameof(ItemActionLauncher.ReloadGun))
// };
// }
// //Why? Ask TFP why they don't just call base.ReloadGun()
// [HarmonyPrefix]
// private static bool Prefix_ReloadGun(ItemActionData _actionData)
// {
// int reloadAnimationIndex = MultiActionManager.GetMetaIndexForActionIndex(_actionData.invData.holdingEntity.entityId, _actionData.indexInEntityOfAction);
// _actionData.invData.holdingEntity.emodel?.avatarController?.UpdateInt(AvatarController.itemActionIndexHash, reloadAnimationIndex, false);
// _actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData;
// return true;
// }
//}
//#endregion
//KEEP
#region Melee action tags
[HarmonyPatch]
public static class ActionTagPatches1
{
private static IEnumerable<MethodBase> TargetMethods()
{
return new MethodInfo[]
{
AccessTools.Method(typeof(AnimatorMeleeAttackState), nameof(AnimatorMeleeAttackState.OnStateEnter), new[] {typeof(Animator), typeof(AnimatorStateInfo), typeof(int)}),
AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.GetDamageBlock)),
AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.GetDamageEntity)),
AccessTools.Method(typeof(ItemActionDynamic), nameof(ItemActionDynamic.GetDamageBlock)),
AccessTools.Method(typeof(ItemActionDynamic), nameof(ItemActionDynamic.GetDamageEntity)),
AccessTools.Method(typeof(ItemActionThrownWeapon), nameof(ItemActionThrownWeapon.GetDamageBlock)),
AccessTools.Method(typeof(ItemActionThrownWeapon), nameof(ItemActionThrownWeapon.GetDamageEntity))
};
}
//set correct tag for action index above 2
//only action 1 uses secondary tag, others still use primary
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
FieldInfo fld_tag = AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.SecondaryTag));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.LoadsField(fld_tag))
{
codes.InsertRange(i - 1, new[]
{
new CodeInstruction(OpCodes.Ldc_I4_1),
new CodeInstruction(OpCodes.Ceq)
});
i += 2;
}
}
return codes;
}
}
[HarmonyPatch]
public static class ActionTagPatches2
{
private static IEnumerable<MethodBase> TargetMethods()
{
return new MethodInfo[]
{
AccessTools.Method(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.Raycast)),
AccessTools.Method(typeof(ItemActionDynamic), nameof(ItemActionDynamic.GetExecuteActionGrazeTarget)),
AccessTools.Method(typeof(ItemActionDynamic), nameof(ItemActionDynamic.hitTarget)),
AccessTools.Method(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.canStartAttack)),
AccessTools.Method(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.OnHoldingUpdate)),
AccessTools.Method(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.SetAttackFinished)),
AccessTools.Method(typeof(ItemActionMelee), nameof(ItemActionMelee.OnHoldingUpdate)),
AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ExecuteAction)),
AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.fireShot)),
AccessTools.Method(typeof(ItemActionThrownWeapon), nameof(ItemActionThrownWeapon.throwAway)),
AccessTools.Method(typeof(ItemActionUseOther), nameof(ItemActionUseOther.ExecuteAction)),
};
}
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
FieldInfo fld_index = AccessTools.Field(typeof(ItemActionData), nameof(ItemActionData.indexInEntityOfAction));
for (int i = 0; i < codes.Count - 1; i++)
{
var code = codes[i];
if (code.LoadsField(fld_index) && (codes[i + 1].opcode == OpCodes.Brfalse_S || codes[i + 1].opcode == OpCodes.Brfalse))
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldc_I4_1),
new CodeInstruction(OpCodes.Ceq)
});
i += 2;
}
}
return codes;
}
}
#endregion
//KEEP
#region 3
[HarmonyPatch]
public static class ThreePatches
{
private static IEnumerable<MethodBase> TargetMethods()
{
return new MethodInfo[]
{
AccessTools.Method(typeof(ItemClass), nameof(ItemClass.OnHoldingUpdate)),
AccessTools.Method(typeof(ItemClass), nameof(ItemClass.CleanupHoldingActions)),
AccessTools.Method(typeof(ItemClass), nameof(ItemClass.StartHolding)),
AccessTools.Method(typeof(ItemClass), nameof(ItemClass.StopHolding)),
AccessTools.Method(typeof(ItemClass), nameof(ItemClass.IsActionRunning))
};
}
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Three(IEnumerable<CodeInstruction> instructions)
{
foreach (var instruction in instructions)
{
if (instruction.opcode == OpCodes.Ldc_I4_3)
instruction.opcode = OpCodes.Ldc_I4_5;
yield return instruction;
}
}
}
#endregion
#region ItemAction property override
[HarmonyPatch]
public static class ItemActionPropertyOverridePatches
{
private static IEnumerable<MethodBase> TargetMethods()
{
return AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a =>
{
try
{
return a.GetTypes();
}
catch
{
return new Type[0];
}
})
.Where(t => t.IsSubclassOf(typeof(ItemAction)))
.Select(t => AccessTools.Method(t, nameof(ItemAction.OnModificationsChanged)))
.Where(m => m.IsDeclaredMember());
}
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
{
Log.Out($"Patching property override method {__originalMethod.DeclaringType.Name}.{__originalMethod.Name}");
var codes = instructions.ToList();
var mtd_override = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.GetPropertyOverride));
var mtd_newoverride = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetPropertyOverrideForAction));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_override))
{
codes[i].opcode = OpCodes.Call;
codes[i].operand = mtd_newoverride;
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex))
});
i += 2;
}
}
return codes;
}
}
#endregion
#region Remove ammo
[HarmonyPatch]
public static class RemoveAmmoPatches
{
private static IEnumerable<MethodBase> TargetMethods()
{
return new[]
{
AccessTools.Method(typeof(ItemActionEntryAssemble), nameof(ItemActionEntryAssemble.HandleRemoveAmmo)),
AccessTools.Method(typeof(ItemActionEntryScrap), nameof(ItemActionEntryScrap.HandleRemoveAmmo)),
AccessTools.Method(typeof(ItemActionEntrySell), nameof(ItemActionEntrySell.HandleRemoveAmmo)),
};
}
[HarmonyPrefix]
private static bool Prefix(BaseItemActionEntry __instance, ItemStack stack, ref ItemStack __result)
{
List<ItemStack> list_ammo_stack = new List<ItemStack>();
if (!MultiActionUtils.MultiActionRemoveAmmoFromItemStack(stack, list_ammo_stack))
return true;
foreach (var ammoStack in list_ammo_stack)
{
if (!__instance.ItemController.xui.PlayerInventory.AddItem(ammoStack))
{
__instance.ItemController.xui.PlayerInventory.DropItem(ammoStack);
}
}
__result = stack;
return false;
}
}
#endregion
#region Generate initial meta
[HarmonyPatch]
public static class InitialMetaPatches
{
private static IEnumerable<MethodBase> TargetMethods()
{
return new MethodInfo[]
{
AccessTools.Method(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.SetupStartingItems)),
AccessTools.Method(typeof(ItemClass), nameof(ItemClass.CreateItemStacks))
};
}
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_initial = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.GetInitialMetadata));
var mtd_initialnew = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetMultiActionInitialMetaData));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_initial))
{
codes[i].opcode = OpCodes.Call;
codes[i].operand = mtd_initialnew;
break;
}
}
return codes;
}
}
#endregion
#region Item Info DisplayType
[HarmonyPatch]
public static class DisplayTypePatches
{
[HarmonyPatch(typeof(XUiC_AssembleWindow), nameof(XUiC_AssembleWindow.ItemStack), MethodType.Setter)]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ItemStack_XUiC_AssembleWindow(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_displaytype = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.DisplayType));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_displaytype))
{
codes.RemoveRange(i - 1, 2);
codes.InsertRange(i - 1, new[]
{
CodeInstruction.LoadField(typeof(XUiC_AssembleWindow), nameof(XUiC_AssembleWindow.itemStack)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetDisplayTypeForAction), new []{ typeof(ItemStack) })
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.SetInfo))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SetInfo_XUiC_ItemInfoWindow(IEnumerable<CodeInstruction> instructions, MethodBase originalMethod)
{
var codes = instructions.ToList();
var fld_displaytype = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.DisplayType));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_displaytype))
{
codes.RemoveRange(i - 1, 2);
codes.InsertRange(i - 1, new[]
{
CodeInstruction.LoadField(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.itemStack)),
CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetDisplayTypeForAction), new []{ typeof(ItemStack) })
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(XUiM_ItemStack), nameof(XUiM_ItemStack.HasItemStats))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_HasItemStats_XUiM_ItemStack(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_displaytype = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.DisplayType));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_displaytype))
{
codes.RemoveRange(i - 1, 2);
codes.Insert(i - 1, CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetDisplayTypeForAction), new []{ typeof(ItemValue) }));
break;
}
}
return codes;
}
[HarmonyPatch(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.HoverEntry), MethodType.Setter)]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_HoverEntry_XUiC_ItemInfoWindow(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_cancompare = AccessTools.Method(typeof(XUiM_ItemStack), nameof(XUiM_ItemStack.CanCompare));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_cancompare))
{
codes[i] = CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.CanCompare));
codes[i - 1] = CodeInstruction.LoadField(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.itemStack));
codes.Insert(i, CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)));
codes.RemoveAt(i - 3);
break;
}
}
return codes;
}
}
#endregion
}

View File

@@ -0,0 +1,68 @@
using HarmonyLib;
using KFCommonUtilityLib.Scripts.Utilities;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using UnityEngine;
[HarmonyPatch]
public static class MultiActionReversePatches
{
[HarmonyReversePatch(HarmonyReversePatchType.Snapshot)]
[HarmonyPatch(typeof(EffectManager), nameof(EffectManager.GetValue))]
public static float ProjectileGetValue(PassiveEffects _passiveEffect, ItemValue _originalItemValue = null, float _originalValue = 0f, EntityAlive _entity = null, Recipe _recipe = null, FastTags<TagGroup.Global> tags = default(FastTags<TagGroup.Global>), bool calcEquipment = true, bool calcHoldingItem = true, bool calcProgression = true, bool calcBuffs = true, bool calcChallenges = true, int craftingTier = 1, bool useMods = true, bool _useDurability = false)
{
IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (instructions == null)
return null;
var codes = instructions.ToList();
var mtd_modify = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.ModifyValue));
for (int i = 0; i < codes.Count; i++)
{
var code = codes[i];
if (code.Calls(mtd_modify) && codes[i - 9].opcode == OpCodes.Ldarg_1)
{
code.operand = AccessTools.Method(typeof(MultiActionProjectileRewrites), nameof(MultiActionProjectileRewrites.ProjectileValueModifyValue));
}
}
return codes;
}
_ = Transpiler(null);
return _originalValue;
}
[HarmonyReversePatch]
[HarmonyPatch(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.Fire))]
public static void ProjectileFire(this ProjectileMoveScript __instance, Vector3 _idealStartPosition, Vector3 _flyDirection, Entity _firingEntity, int _hmOverride = 0, float _radius = 0f)
{
IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (instructions == null)
return null;
var codes = instructions.ToList();
FieldInfo fld_launcher = AccessTools.Field(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.itemValueLauncher));
FieldInfo fld_projectile = AccessTools.Field(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.itemValueProjectile));
MethodInfo mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue));
MethodInfo mtd_getvaluenew = AccessTools.Method(typeof(MultiActionReversePatches), nameof(ProjectileGetValue));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_launcher))
{
codes[i].operand = fld_projectile;
}
else if (codes[i].Calls(mtd_getvalue))
{
codes[i].operand = mtd_getvaluenew;
}
}
return codes;
}
_ = Transpiler(null);
}
}

View File

@@ -0,0 +1,155 @@
using HarmonyLib;
using KFCommonUtilityLib.Scripts.StaticManagers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
namespace KFCommonUtilityLib.Harmony
{
[HarmonyPatch]
public class MultiBarrelPatches
{
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ExecuteAction))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ExecuteAction_ItemActionRanged(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
var mtd_getmax = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.GetMaxAmmoCount));
var mtd_consume = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ConsumeAmmo));
Label loopStart = generator.DefineLabel();
Label loopCondi = generator.DefineLabel();
LocalBuilder lbd_data_module = generator.DeclareLocal(typeof(ActionModuleMultiBarrel.MultiBarrelData));
LocalBuilder lbd_ismb = generator.DeclareLocal(typeof(bool));
LocalBuilder lbd_i = generator.DeclareLocal(typeof(int));
LocalBuilder lbd_rounds = generator.DeclareLocal(typeof(int));
for (int i = 0; i < codes.Count; i++)
{
//prepare loop and store local variables
if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 6)
{
codes[i + 1].WithLabels(loopStart);
Label lbl = generator.DefineLabel();
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldnull),
new CodeInstruction(OpCodes.Stloc_S, lbd_data_module),
new CodeInstruction(OpCodes.Ldarg_1),
new CodeInstruction(OpCodes.Ldloca_S, lbd_data_module),
CodeInstruction.Call(typeof(MultiBarrelPatches), nameof(IsMultiBarrelData)),
new CodeInstruction(OpCodes.Stloc_S, lbd_ismb),
new CodeInstruction(OpCodes.Ldc_I4_0),
new CodeInstruction(OpCodes.Stloc_S, lbd_i),
new CodeInstruction(OpCodes.Ldloc_S, lbd_ismb),
new CodeInstruction(OpCodes.Brfalse_S, lbl),
new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module),
CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.roundsPerShot)),
new CodeInstruction(OpCodes.Stloc_S, lbd_rounds),
new CodeInstruction(OpCodes.Br_S, loopCondi),
new CodeInstruction(OpCodes.Ldc_I4_1).WithLabels(lbl),
new CodeInstruction(OpCodes.Stloc_S, lbd_rounds),
new CodeInstruction(OpCodes.Br_S, loopCondi),
});
i += 16;
}
//one round multi shot check
else if (codes[i].Calls(mtd_consume))
{
Label lbl = generator.DefineLabel();
codes[i - 2].WithLabels(lbl);
codes.InsertRange(i - 2, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, lbd_ismb),
new CodeInstruction(OpCodes.Brfalse_S, lbl),
new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module),
CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.oneRoundMultishot)),
new CodeInstruction(OpCodes.Brfalse_S, lbl),
new CodeInstruction(OpCodes.Ldloc_S, lbd_i),
new CodeInstruction(OpCodes.Ldc_I4_0),
new CodeInstruction(OpCodes.Bgt_S, codes[i - 3].operand)
});
i += 8;
}
//loop conditions and cycle barrels
else if (codes[i].Calls(mtd_getmax))
{
Label lbl_pre = generator.DefineLabel();
Label lbl_post = generator.DefineLabel();
CodeInstruction origin = codes[i - 2];
codes.InsertRange(i - 2, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, lbd_ismb).WithLabels(origin.ExtractLabels()),
new CodeInstruction(OpCodes.Brfalse_S, lbl_pre),
new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module),
CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.muzzleIsPerRound)),
new CodeInstruction(OpCodes.Brfalse_S, lbl_pre),
new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module),
CodeInstruction.Call(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.CycleBarrels)),
new CodeInstruction(OpCodes.Ldloc_S, lbd_i).WithLabels(lbl_pre),
//new CodeInstruction(OpCodes.Dup),
//new CodeInstruction(OpCodes.Ldloc_S, lbd_rounds),
//CodeInstruction.Call(typeof(MultiBarrelPatches), nameof(MultiBarrelPatches.LogInfo)),
new CodeInstruction(OpCodes.Ldc_I4_1),
new CodeInstruction(OpCodes.Add),
new CodeInstruction(OpCodes.Stloc_S, lbd_i),
new CodeInstruction(OpCodes.Ldloc_S, lbd_i).WithLabels(loopCondi),
new CodeInstruction(OpCodes.Ldloc_S, lbd_rounds),
new CodeInstruction(OpCodes.Blt_S, loopStart),
new CodeInstruction(OpCodes.Ldloc_S, lbd_ismb),
new CodeInstruction(OpCodes.Brfalse_S, lbl_post),
new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module),
CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.muzzleIsPerRound)),
new CodeInstruction(OpCodes.Brtrue_S, lbl_post),
new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module),
CodeInstruction.Call(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.CycleBarrels))
});
origin.WithLabels(lbl_post);
break;
}
}
return codes;
}
[HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateEnter))]
[HarmonyPostfix]
private static void Postfix_OnStateEnter_AnimatorRangedReloadState(AnimatorRangedReloadState __instance)
{
ItemActionLauncher.ItemActionDataLauncher launcherData = __instance.actionData as ItemActionLauncher.ItemActionDataLauncher;
if (launcherData != null && launcherData is IModuleContainerFor<ActionModuleMultiBarrel.MultiBarrelData> dataModule && dataModule.Instance.oneRoundMultishot && dataModule.Instance.roundsPerShot > 1)
{
int count = launcherData.projectileInstance.Count;
int times = dataModule.Instance.roundsPerShot - 1;
for (int i = 0; i < count; i++)
{
for (int j = 0; j < times; j++)
{
launcherData.projectileJoint = dataModule.Instance.projectileJoints[j + 1];
launcherData.projectileInstance.Insert(i * (times + 1) + j + 1,((ItemActionLauncher)__instance.actionRanged).instantiateProjectile(launcherData));
}
}
}
}
[HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateExit))]
[HarmonyPostfix]
private static void Postfix_OnStateExit_AnimatorRangedReloadState(AnimatorRangedReloadState __instance)
{
if (__instance.actionData is IModuleContainerFor<ActionModuleMultiBarrel.MultiBarrelData> dataModule)
{
dataModule.Instance.SetCurrentBarrel(__instance.actionData.invData.itemValue.Meta);
}
}
private static bool IsMultiBarrelData(ItemActionData data, out ActionModuleMultiBarrel.MultiBarrelData dataModule)
{
return (dataModule = (data as IModuleContainerFor<ActionModuleMultiBarrel.MultiBarrelData>)?.Instance) != null;
}
private static void LogInfo(int cur, int max) => Log.Out($"max rounds {max}, cur {cur}");
}
}

1325
Harmony/Patches.cs Normal file
View File

@@ -0,0 +1,1325 @@
using HarmonyLib;
using KFCommonUtilityLib.Scripts.StaticManagers;
using KFCommonUtilityLib.Scripts.Utilities;
using System;
using System.Collections.Generic;
using UniLinq;
using System.Reflection;
using System.Reflection.Emit;
using System.Xml.Linq;
using UnityEngine;
using KFCommonUtilityLib.Scripts.NetPackages;
using KFCommonUtilityLib;
[HarmonyPatch]
public static class CommonUtilityPatch
{
//fix reloading issue and onSelfRangedBurstShot timing
public static void FakeReload(EntityAlive holdingEntity, ItemActionRanged.ItemActionDataRanged _actionData)
{
if (!holdingEntity)
return;
_actionData.isReloading = true;
_actionData.isWeaponReloading = true;
holdingEntity.MinEventContext.ItemActionData = _actionData;
holdingEntity.FireEvent(MinEventTypes.onReloadStart, true);
_actionData.isReloading = false;
_actionData.isWeaponReloading = false;
_actionData.isReloadCancelled = false;
_actionData.isWeaponReloadCancelled = false;
holdingEntity.FireEvent(MinEventTypes.onReloadStop);
AnimationAmmoUpdateState.SetAmmoCountForEntity(holdingEntity, holdingEntity.inventory.holdingItemIdx);
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SwapAmmoType))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SwapAmmoType_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = new List<CodeInstruction>(instructions);
for (int i = 0; i < codes.Count; ++i)
{
if (codes[i].opcode == OpCodes.Ret)
{
codes.InsertRange(i, new CodeInstruction[]
{
new CodeInstruction(OpCodes.Ldarg_1),
new CodeInstruction(OpCodes.Ldloc_0),
CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(FakeReload))
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ExecuteAction))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ExecuteAction_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = new List<CodeInstruction>(instructions);
var mtd_fire_event = AccessTools.Method(typeof(EntityAlive), nameof(EntityAlive.FireEvent));
var mtd_get_model_layer = AccessTools.Method(typeof(EntityAlive), nameof(EntityAlive.GetModelLayer));
var mtd_get_perc_left = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.PercentUsesLeft));
int take = -1, insert = -1;
for (int i = 0; i < codes.Count; ++i)
{
if (codes[i].opcode == OpCodes.Ldc_I4_S && codes[i].OperandIs((int)MinEventTypes.onSelfRangedBurstShotEnd) && codes[i + 2].Calls(mtd_fire_event))
take = i - 3;
else if (codes[i].Calls(mtd_get_model_layer))
insert = i + 2;
}
if (take < insert)
{
var list = codes.GetRange(take, 6);
codes.InsertRange(insert, list);
codes.RemoveRange(take, 6);
}
return codes;
}
//fix recoil animation does not match weapon RPM
private static int weaponFireHash = Animator.StringToHash("WeaponFire");
private static int aimHash = Animator.StringToHash("IsAiming");
private static HashSet<int> hash_shot_state = new HashSet<int>();
private static HashSet<int> hash_aimshot_state = new HashSet<int>();
public static void InitShotStates()
{
string[] weapons =
{
"fpvAK47",
"fpvMagnum",
"fpvRocketLauncher",
"fpvSawedOffShotgun",
"fpvBlunderbuss",
"fpvCrossbow",
"fpvPistol",
"fpvHuntingRifle",
"fpvSMG",
"fpvSniperRifle",
"M60",
"fpvDoubleBarrelShotgun",
//"fpvJunkTurret",
"fpvTacticalAssaultRifle",
"fpvDesertEagle",
"fpvAutoShotgun",
"fpvSharpShooterRifle",
"fpvPipeMachineGun",
"fpvPipeRifle",
"fpvPipeRevolver",
"fpvPipeShotgun",
"fpvLeverActionRifle",
};
foreach (string weapon in weapons)
{
hash_shot_state.Add(Animator.StringToHash(weapon + "Fire"));
hash_aimshot_state.Add(Animator.StringToHash(weapon + "AimFire"));
}
}
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.OnFired))]
[HarmonyPostfix]
private static void Postfix_OnFired_EntityPlayerLocal(EntityPlayerLocal __instance)
{
if (!__instance.bFirstPersonView)
return;
ItemActionRanged.ItemActionDataRanged _rangedData;
if ((_rangedData = __instance.inventory.holdingItemData.actionData[0] as ItemActionRanged.ItemActionDataRanged) == null && (_rangedData = __instance.inventory.holdingItemData.actionData[1] as ItemActionRanged.ItemActionDataRanged) == null)
return;
if (_rangedData.invData.model.TryGetComponent<AnimationTargetsAbs>(out var targets) && targets.ItemFpv)
return;
var anim = (__instance.emodel.avatarController as AvatarLocalPlayerController).FPSArms.Animator;
if (anim.IsInTransition(0))
return;
var curState = anim.GetCurrentAnimatorStateInfo(0);
if (curState.length > _rangedData.Delay)
{
bool aimState = anim.GetBool(aimHash);
short shotState = 0;
if (hash_shot_state.Contains(curState.shortNameHash))
shotState = 1;
else if (hash_aimshot_state.Contains(curState.shortNameHash))
shotState = 2;
if (shotState == 0 || (shotState == 1 && aimState) || (shotState == 2 && !aimState))
{
if (shotState > 0)
anim.ResetTrigger(weaponFireHash);
return;
}
//current state, layer 0, offset 0
anim.PlayInFixedTime(0, 0, 0);
anim.ResetTrigger(weaponFireHash);
if (_rangedData.invData.itemValue.Meta == 0)
{
__instance.emodel.avatarController.CancelEvent(weaponFireHash);
Log.Out("Cancel fire event because meta is 0");
}
}
}
//[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ItemActionEffects))]
//[HarmonyPostfix]
//private static void Postfix_ItemActionEffects_ItemActionRanged(ItemActionData _actionData, int _firingState)
//{
// if (_firingState == 0 && _actionData.invData.holdingEntity is EntityPlayerLocal && !(_actionData.invData.itemValue.ItemClass.Actions[0] is ItemActionCatapult))
// {
// _actionData.invData.holdingEntity?.emodel.avatarController.CancelEvent(weaponFireHash);
// //Log.Out("Cancel fire event because firing state is 0\n" + StackTraceUtility.ExtractStackTrace());
// }
//}
//[HarmonyPatch(typeof(GameManager), "gmUpdate")]
//[HarmonyTranspiler]
//private static IEnumerable<CodeInstruction> Transpiler_gmUpdate_GameManager(IEnumerable<CodeInstruction> instructions)
//{
// var codes = new List<CodeInstruction>(instructions);
// var mtd_unload = AccessTools.Method(typeof(Resources), nameof(Resources.UnloadUnusedAssets));
// var fld_duration = AccessTools.Field(typeof(GameManager), "unloadAssetsDuration");
// for (int i = 0; i < codes.Count; ++i)
// {
// if (codes[i].opcode == OpCodes.Call && codes[i].Calls(mtd_unload))
// {
// for (int j = i; j >= 0; --j)
// {
// if (codes[j].opcode == OpCodes.Ldfld && codes[j].LoadsField(fld_duration) && codes[j + 1].opcode == OpCodes.Ldc_R4)
// codes[j + 1].operand = (float)codes[j + 1].operand / 2;
// }
// break;
// }
// }
// return codes;
//}
//internal static void ForceUpdateGC()
//{
// if (GameManager.IsDedicatedServer)
// return;
// if (GameManager.frameCount % 18000 == 0)
// {
// long rss = GetRSS.GetCurrentRSS();
// if (rss / 1024 / 1024 > 6144)
// {
// Log.Out("Memory usage exceeds threshold, now performing garbage collection...");
// GC.Collect();
// }
// }
//}
//altmode workarounds
//deprecated by action module
private static void ParseAltRequirements(XElement _node)
{
string itemName = _node.GetAttribute("name");
if (string.IsNullOrEmpty(itemName))
{
return;
}
ItemClass item = ItemClass.GetItemClass(itemName);
for (int i = 0; i < item.Actions.Length; i++)
{
if (item.Actions[i] is ItemActionAltMode _alt)
_alt.ParseAltRequirements(_node, i);
}
}
[HarmonyPatch(typeof(ItemClassesFromXml), nameof(ItemClassesFromXml.parseItem))]
[HarmonyPostfix]
private static void Postfix_parseItem_ItemClassesFromXml(XElement _node)
{
ParseAltRequirements(_node);
}
[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.ExecuteAction))]
[HarmonyPrefix]
private static bool Prefix_ExecuteAction_ItemClass(ItemClass __instance, int _actionIdx, ItemInventoryData _data, bool _bReleased)
{
if (!_bReleased && __instance.Actions[_actionIdx] is ItemActionAltMode _alt)
_alt.SetAltRequirement(_data.actionData[_actionIdx]);
return true;
}
[HarmonyPatch(typeof(DynamicProperties), nameof(DynamicProperties.Parse))]
[HarmonyPrefix]
private static bool Prefix_Parse_DynamicProperties(XElement elementProperty)
{
if (elementProperty.Name.LocalName != "property")
return false;
return true;
}
//MinEventParams workarounds
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.fireShot))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_fireShot_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = new List<CodeInstruction>(instructions);
var fld_ranged_tag = AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.RangedTag));
var fld_params = AccessTools.Field(typeof(EntityAlive), nameof(EntityAlive.MinEventContext));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_ranged_tag))
{
if (!codes[i + 3].LoadsField(fld_params))
{
codes.InsertRange(i + 2, new CodeInstruction[]
{
new CodeInstruction(OpCodes.Ldloc_1),
CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)),
new CodeInstruction(OpCodes.Dup),
new CodeInstruction(OpCodes.Ldloc, 10),
CodeInstruction.LoadField(typeof(WorldRayHitInfo), nameof(WorldRayHitInfo.hit)),
CodeInstruction.LoadField(typeof(HitInfoDetails), nameof(HitInfoDetails.pos)),
CodeInstruction.StoreField(typeof(MinEventParams), nameof(MinEventParams.Position)),
new CodeInstruction(OpCodes.Ldloc_1),
CodeInstruction.Call(typeof(EntityAlive), nameof(EntityAlive.GetPosition)),
CodeInstruction.StoreField(typeof(MinEventParams), nameof(MinEventParams.StartPosition))
});
}
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.OnHoldingUpdate))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_OnHoldingUpdate_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var mtd_release = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.triggerReleased));
var codes = instructions.ToList();
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_release))
{
codes[i + 1].labels.Clear();
codes[i + 1].MoveLabelsFrom(codes[i - 20]);
codes.RemoveRange(i - 20, 21);
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.triggerReleased))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_triggerReleased_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var mtd_effect = AccessTools.Method(typeof(IGameManager), nameof(IGameManager.ItemActionEffectsServer));
var mtd_data = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.getUserData));
var codes = instructions.ToList();
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_effect))
{
codes.InsertRange(i, new CodeInstruction[]
{
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldarg_1),
new CodeInstruction(OpCodes.Callvirt, mtd_data)
});
codes.RemoveAt(i - 1);
break;
}
}
return codes;
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.StartGame))]
[HarmonyPrefix]
private static bool Prefix_StartGame_GameManager()
{
CustomEffectEnumManager.InitFinal();
return true;
}
[HarmonyPatch(typeof(PassiveEffect), nameof(PassiveEffect.ParsePassiveEffect))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ParsePassiveEffect_PassiveEffect(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
MethodInfo mtd_enum_parse = AccessTools.Method(typeof(EnumUtils), nameof(EnumUtils.Parse), new[] { typeof(string), typeof(bool) }, new[] { typeof(PassiveEffects) });
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_enum_parse))
{
codes.Insert(i + 1, CodeInstruction.Call(typeof(CustomEffectEnumManager), nameof(CustomEffectEnumManager.RegisterOrGetEnum), new[] { typeof(string), typeof(bool) }, new[] { typeof(PassiveEffects) }));
codes.RemoveAt(i);
break;
}
}
return codes;
}
[HarmonyPatch(typeof(MinEventActionBase), nameof(MinEventActionBase.ParseXmlAttribute))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ParseXmlAttribute_MinEventActionBase(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
MethodInfo mtd_enum_parse = AccessTools.Method(typeof(EnumUtils), nameof(EnumUtils.Parse), new[] { typeof(string), typeof(bool) }, new[] { typeof(MinEventTypes) });
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_enum_parse))
{
codes.Insert(i + 1, CodeInstruction.Call(typeof(CustomEffectEnumManager), nameof(CustomEffectEnumManager.RegisterOrGetEnum), new[] { typeof(string), typeof(bool) }, new[] { typeof(MinEventTypes) }));
codes.RemoveAt(i);
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.OnHoldingUpdate))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_OnHoldingUpdate_ItemActionDynamicMelee(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Is(OpCodes.Ldc_R4, 0.1f))
{
codes.RemoveRange(i, 2);
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.canStartAttack))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_canStartAttack_ItemActionDynamicMelee(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Is(OpCodes.Ldc_R4, 0.1f))
{
codes.RemoveRange(i, 2);
break;
}
}
return codes;
}
/// <summary>
/// projectile direct hit damage percent
/// removed due to new explosion damage passives
/// </summary>
/// <param name="instructions"></param>
/// <returns></returns>
//[HarmonyPatch(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.checkCollision))]
//[HarmonyTranspiler]
//private static IEnumerable<CodeInstruction> Transpiler_checkCollision_ProjectileMoveScript(IEnumerable<CodeInstruction> instructions)
//{
// var codes = instructions.ToList();
// var fld_strain = AccessTools.Field(typeof(ItemActionLauncher.ItemActionDataLauncher), nameof(ItemActionLauncher.ItemActionDataLauncher.strainPercent));
// var mtd_block = AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.GetDamageBlock));
// for (int i = 0; i < codes.Count; i++)
// {
// if (codes[i].LoadsField(fld_strain))
// {
// codes.InsertRange(i + 1, new CodeInstruction[]
// {
// new CodeInstruction(OpCodes.Ldarg_0),
// CodeInstruction.LoadField(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.itemValueProjectile)),
// new CodeInstruction(OpCodes.Ldloc_S, 4),
// CodeInstruction.Call(typeof(CommonUtilityPatch), codes[i - 3].Calls(mtd_block) ? nameof(GetProjectileBlockDamagePerc) : nameof(GetProjectileEntityDamagePerc)),
// new CodeInstruction(OpCodes.Mul)
// });
// }
// }
// return codes;
//}
//public static float GetProjectileBlockDamagePerc(ItemValue _itemValue, EntityAlive _holdingEntity)
//{
// return EffectManager.GetValue(CustomEnums.ProjectileImpactDamagePercentBlock, _itemValue, 1, _holdingEntity, null);
//}
//public static float GetProjectileEntityDamagePerc(ItemValue _itemValue, EntityAlive _holdingEntity)
//{
// return EffectManager.GetValue(CustomEnums.ProjectileImpactDamagePercentEntity, _itemValue, 1, _holdingEntity, null);
//}
/// <summary>
/// force tpv crosshair
/// </summary>
/// <param name="instructions"></param>
/// <returns></returns>
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.guiDrawCrosshair))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_guiDrawCrosshair_EntityPlayerLocal(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
FieldInfo fld_debug = AccessTools.Field(typeof(ItemAction), nameof(ItemAction.ShowDistanceDebugInfo));
for ( int i = 0; i < codes.Count; i++ )
{
if (codes[i].LoadsField(fld_debug))
{
var label = codes[i - 1].operand;
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.bFirstPersonView)),
new CodeInstruction(OpCodes.Brfalse_S, label)
});
break;
}
}
return codes;
}
/// <summary>
/// correctly apply muzzle flash silence with modifications
/// </summary>
/// <param name="_data"></param>
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.OnModificationsChanged))]
[HarmonyPostfix]
private static void Postfix_OnModificationsChanged_ItemActionRanged(ItemActionData _data)
{
ItemActionRanged.ItemActionDataRanged itemActionDataRanged = _data as ItemActionRanged.ItemActionDataRanged;
if (itemActionDataRanged.SoundStart.Contains("silenced"))
{
itemActionDataRanged.IsFlashSuppressed = true;
}
//should fix stuck on switching item?
itemActionDataRanged.isReloadCancelled = false;
itemActionDataRanged.isWeaponReloadCancelled = false;
itemActionDataRanged.isReloading = false;
itemActionDataRanged.isWeaponReloading = false;
itemActionDataRanged.isChangingAmmoType = false;
}
#region item tags modifier
/// <summary>
/// should handle swapping mod
/// first check if the mod to install can be installed after current mod is removed
/// then check if any other mod requires or conflicts current mod
/// </summary>
/// <param name="instructions"></param>
/// <param name="generator"></param>
/// <returns></returns>
[HarmonyPatch(typeof(XUiC_ItemPartStack), nameof(XUiC_ItemPartStack.CanSwap))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_CanSwap_XUiC_ItemPartStack(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
LocalBuilder lbd_tags_if_remove_prev = generator.DeclareLocal(typeof(FastTags<TagGroup.Global>));
LocalBuilder lbd_tags_if_install_new = generator.DeclareLocal(typeof(FastTags<TagGroup.Global>));
MethodInfo mtd_get_item_class = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass));
MethodInfo mtd_has_any_tags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags));
MethodInfo mtd_test_any_set = AccessTools.Method(typeof(FastTags<TagGroup.Global>), nameof(FastTags<TagGroup.Global>.Test_AnySet));
FieldInfo fld_mod = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Modifications));
FieldInfo fld_installable_tags = AccessTools.Field(typeof(ItemClassModifier), nameof(ItemClassModifier.InstallableTags));
for (int i = 3; i < codes.Count; i++)
{
//get current tags
if (codes[i].opcode == OpCodes.Stloc_2)
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldloc_1),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(XUiC_ItemPartStack), "itemValue"),
CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTagsAsIfNotInstalled)),
new CodeInstruction(OpCodes.Stloc_S, lbd_tags_if_remove_prev),
new CodeInstruction(OpCodes.Ldloc_1),
new CodeInstruction(OpCodes.Ldloc_0),
CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTagsAsIfInstalled)),
new CodeInstruction(OpCodes.Stloc_S, lbd_tags_if_install_new)
});
i += 10;
Log.Out("mod 1!!!");
}
//replace checking tags
else if (codes[i].Calls(mtd_has_any_tags) && codes[i - 3].opcode == OpCodes.Ldloc_2)
{
if (codes[i - 1].LoadsField(fld_installable_tags) && (codes[i + 1].opcode == OpCodes.Brtrue || codes[i + 1].opcode == OpCodes.Brtrue_S))
{
var lbl_prev = codes[i + 4].ExtractLabels();
var lbl_jump = generator.DefineLabel();
codes[i + 4].WithLabels(lbl_jump);
codes.InsertRange(i + 4, new[]
{
new CodeInstruction(OpCodes.Ldloc_1).WithLabels(lbl_prev),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(XUiC_ItemPartStack), "itemValue"),
new CodeInstruction(OpCodes.Ldloc_0),
CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.CanSwapMod)),
new CodeInstruction(OpCodes.Brtrue, lbl_jump),
new CodeInstruction(OpCodes.Ldc_I4_0),
new CodeInstruction(OpCodes.Ret)
});
}
codes[i - 3].opcode = OpCodes.Ldloca_S;
codes[i - 3].operand = lbd_tags_if_remove_prev;
codes[i].opcode = OpCodes.Call;
codes[i].operand = mtd_test_any_set;
Log.Out("mod 2!!!");
}
}
return codes;
}
[HarmonyPatch(typeof(XUiC_ItemCosmeticStack), nameof(XUiC_ItemCosmeticStack.CanSwap))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_CanSwap_XUiC_ItemCosmeticStack(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
LocalBuilder lbd_tags_if_remove_prev = generator.DeclareLocal(typeof(FastTags<TagGroup.Global>));
LocalBuilder lbd_tags_if_install_new = generator.DeclareLocal(typeof(FastTags<TagGroup.Global>));
LocalBuilder lbd_item_being_assembled = generator.DeclareLocal(typeof(ItemValue));
MethodInfo mtd_get_item_class = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass));
MethodInfo mtd_has_any_tags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags));
MethodInfo mtd_test_any_set = AccessTools.Method(typeof(FastTags<TagGroup.Global>), nameof(FastTags<TagGroup.Global>.Test_AnySet));
MethodInfo mtd_get_xui = AccessTools.PropertyGetter(typeof(XUiController), nameof(XUiController.xui));
MethodInfo mtd_get_cur_item = AccessTools.PropertyGetter(typeof(XUiM_AssembleItem), nameof(XUiM_AssembleItem.CurrentItem));
FieldInfo fld_cos = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.CosmeticMods));
FieldInfo fld_installable_tags = AccessTools.Field(typeof(ItemClassModifier), nameof(ItemClassModifier.InstallableTags));
for (int i = 3; i < codes.Count; i++)
{
//get current tags
if ((codes[i].opcode == OpCodes.Brtrue || codes[i].opcode == OpCodes.Brtrue_S) && codes[i - 1].opcode == OpCodes.Ldloc_0)
{
codes.InsertRange(i + 3, new[]
{
new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(codes[i + 3]),
new CodeInstruction(OpCodes.Call, mtd_get_xui),
CodeInstruction.LoadField(typeof(XUi), nameof(XUi.AssembleItem)),
new CodeInstruction(OpCodes.Callvirt, mtd_get_cur_item),
CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)),
new CodeInstruction(OpCodes.Stloc_S, lbd_item_being_assembled),
new CodeInstruction(OpCodes.Ldloc_S, lbd_item_being_assembled),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(XUiC_ItemCosmeticStack), "itemValue"),
CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTagsAsIfNotInstalled)),
new CodeInstruction(OpCodes.Stloc_S, lbd_tags_if_remove_prev),
new CodeInstruction(OpCodes.Ldloc_S, lbd_item_being_assembled),
new CodeInstruction(OpCodes.Ldloc_0),
CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTagsAsIfInstalled)),
new CodeInstruction(OpCodes.Stloc_S, lbd_tags_if_install_new)
});
i += 18;
Log.Out("cos 1!!!");
}
//replace checking tags
else if (codes[i].Calls(mtd_has_any_tags) && codes[i - 3].Calls(mtd_get_item_class))
{
if (codes[i - 1].LoadsField(fld_installable_tags) && (codes[i + 1].opcode == OpCodes.Brtrue || codes[i + 1].opcode == OpCodes.Brtrue_S))
{
var lbl_prev = codes[i + 4].ExtractLabels();
var lbl_jump = generator.DefineLabel();
codes[i + 4].WithLabels(lbl_jump);
codes.InsertRange(i + 4, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, lbd_item_being_assembled).WithLabels(lbl_prev),
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.LoadField(typeof(XUiC_ItemPartStack), "itemValue"),
new CodeInstruction(OpCodes.Ldloc_0),
CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.CanSwapMod)),
new CodeInstruction(OpCodes.Brtrue, lbl_jump),
new CodeInstruction(OpCodes.Ldc_I4_0),
new CodeInstruction(OpCodes.Ret)
});
}
codes[i - 8].MoveLabelsTo(codes[i - 3]);
codes[i - 3].opcode = OpCodes.Ldloca_S;
codes[i - 3].operand = lbd_tags_if_remove_prev;
codes[i].opcode = OpCodes.Call;
codes[i].operand = mtd_test_any_set;
codes.RemoveRange(i - 8, 5);
i -= 5;
Log.Out("cos 2!!!");
}
}
return codes;
}
/// <summary>
/// check if other mods relies on this one
/// </summary>
/// <param name="__result"></param>
/// <param name="__instance"></param>
/// <param name="___itemValue"></param>
[HarmonyPatch(typeof(XUiC_ItemPartStack), "CanRemove")]
[HarmonyPostfix]
private static void Postfix_CanRemove_XUiC_ItemPartStack(ref bool __result, XUiC_ItemPartStack __instance)
{
if (__result && __instance.xui?.AssembleItem?.CurrentItem?.itemValue is ItemValue itemValue)
{
ItemClass itemClass = itemValue.ItemClass;
FastTags<TagGroup.Global> tagsAfterRemove = LocalItemTagsManager.GetTagsAsIfNotInstalled(itemValue, __instance.itemValue);
if (tagsAfterRemove.IsEmpty)
{
__result = false;
return;
}
foreach (var mod in itemValue.Modifications)
{
if (mod.IsEmpty())
continue;
ItemClassModifier modClass = mod.ItemClass as ItemClassModifier;
if (modClass == null || !tagsAfterRemove.Test_AnySet(modClass.InstallableTags) || tagsAfterRemove.Test_AnySet(modClass.DisallowedTags))
{
__result = false;
return;
}
}
}
}
[HarmonyPatch(typeof(XUiC_ItemCosmeticStack), "CanRemove")]
[HarmonyPostfix]
private static void Postfix_CanRemove_XUiC_ItemCosmeticStack(ref bool __result, XUiC_ItemCosmeticStack __instance)
{
if (__result && __instance.xui?.AssembleItem?.CurrentItem?.itemValue is ItemValue itemValue)
{
ItemClass itemClass = itemValue.ItemClass;
FastTags<TagGroup.Global> tagsAfterRemove = LocalItemTagsManager.GetTagsAsIfNotInstalled(itemValue, __instance.itemValue);
if (tagsAfterRemove.IsEmpty)
{
__result = false;
return;
}
foreach (var mod in itemValue.CosmeticMods)
{
if (mod.IsEmpty())
continue;
ItemClassModifier modClass = mod.ItemClass as ItemClassModifier;
if (modClass == null || !tagsAfterRemove.Test_AnySet(modClass.InstallableTags) || tagsAfterRemove.Test_AnySet(modClass.DisallowedTags))
{
__result = false;
return;
}
}
}
}
/// <summary>
/// should update the gear icon?
/// </summary>
/// <param name="instructions"></param>
/// <param name="generator"></param>
/// <returns></returns>
[HarmonyPatch(typeof(XUiC_ItemStack), nameof(XUiC_ItemStack.updateLockTypeIcon))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_updateLockTypeIcon_XUiC_ItemStack(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
LocalBuilder lbd_tags = generator.DeclareLocal(typeof(FastTags<TagGroup.Global>));
MethodInfo mtd_has_any_tags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags));
MethodInfo mtd_test_any_set = AccessTools.Method(typeof(FastTags<TagGroup.Global>), nameof(FastTags<TagGroup.Global>.Test_AnySet));
MethodInfo mtd_get_item_class = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass));
MethodInfo mtd_get_cur_item = AccessTools.PropertyGetter(typeof(XUiM_AssembleItem), nameof(XUiM_AssembleItem.CurrentItem));
MethodInfo mtd_get_xui = AccessTools.PropertyGetter(typeof(XUiController), nameof(XUiController.xui));
for (int i = 3; i < codes.Count; i++)
{
//get current tags
if ((codes[i].opcode == OpCodes.Brfalse_S || codes[i].opcode == OpCodes.Brfalse) && codes[i - 1].Calls(mtd_get_cur_item))
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Call, mtd_get_xui),
CodeInstruction.LoadField(typeof(XUi), nameof(XUi.AssembleItem)),
new CodeInstruction(OpCodes.Callvirt, mtd_get_cur_item),
CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)),
CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTags)),
new CodeInstruction(OpCodes.Stloc_S, lbd_tags)
});
i += 7;
}
//do not touch check on the modification item
else if (codes[i].Calls(mtd_has_any_tags) && codes[i - 3].Calls(mtd_get_item_class))
{
codes[i].opcode = OpCodes.Call;
codes[i].operand = mtd_test_any_set;
var insert = new CodeInstruction(OpCodes.Ldloca_S, lbd_tags);
codes[i - 8].MoveLabelsTo(insert);
codes.RemoveRange(i - 8, 6);
codes.Insert(i - 8, insert);
i -= 5;
}
}
return codes;
}
/// <summary>
/// when installing new mod, use modified tags to check for compatibility
/// </summary>
/// <param name="instructions"></param>
/// <param name="generator"></param>
/// <returns></returns>
[HarmonyPatch(typeof(XUiM_AssembleItem), nameof(XUiM_AssembleItem.AddPartToItem))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_AddPartToItem_XUiM_AssembleItem(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
LocalBuilder lbd_tags_cur = generator.DeclareLocal(typeof(FastTags<TagGroup.Global>));
LocalBuilder lbd_tags_after_install = generator.DeclareLocal(typeof(FastTags<TagGroup.Global>));
MethodInfo mtd_has_any_tags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags));
MethodInfo mtd_test_any_set = AccessTools.Method(typeof(FastTags<TagGroup.Global>), nameof(FastTags<TagGroup.Global>.Test_AnySet));
MethodInfo mtd_get_item_class = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass));
MethodInfo mtd_get_cur_item = AccessTools.PropertyGetter(typeof(XUiM_AssembleItem), nameof(XUiM_AssembleItem.CurrentItem));
MethodInfo mtd_is_empty = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.IsEmpty));
FieldInfo fld_cos = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.CosmeticMods));
FieldInfo fld_mod = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Modifications));
FieldInfo fld_installable_tags = AccessTools.Field(typeof(ItemClassModifier), nameof(ItemClassModifier.InstallableTags));
for (int i = 3; i < codes.Count; i++)
{
//get current tags
if (codes[i].opcode == OpCodes.Stloc_0)
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Call, mtd_get_cur_item),
CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)),
new CodeInstruction(OpCodes.Dup),
CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTags)),
new CodeInstruction(OpCodes.Stloc_S, lbd_tags_cur),
new CodeInstruction(OpCodes.Ldloc_0),
CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTagsAsIfInstalled)),
new CodeInstruction(OpCodes.Stloc_S, lbd_tags_after_install)
});
i += 9;
}
//do not touch check on the modification item, check if current mod can be installed
else if (codes[i].Calls(mtd_has_any_tags) && codes[i - 3].Calls(mtd_get_item_class))
{
if (codes[i - 1].LoadsField(fld_installable_tags))
{
codes.InsertRange(i + 2, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Call, mtd_get_cur_item),
CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)),
new CodeInstruction(OpCodes.Ldloc_0),
CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.CanInstallMod)),
new CodeInstruction(OpCodes.Brfalse, codes[i + 1].operand)
});
}
codes[i].opcode = OpCodes.Call;
codes[i].operand = mtd_test_any_set;
var insert = new CodeInstruction(OpCodes.Ldloca_S, lbd_tags_cur);
codes[i - 6].MoveLabelsTo(insert);
codes.RemoveRange(i - 6, 4);
codes.Insert(i - 6, insert);
i -= 3;
}
}
return codes;
}
#endregion
//change when aiming events are fired
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.SetMoveState))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SetMoveState_EntityPlayerLocal(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
FieldInfo fld_msa = AccessTools.Field(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.moveStateAiming));
for (int i = 0; i < codes.Count - 2; i++)
{
if (codes[i].LoadsField(fld_msa) && codes[i + 2].opcode == OpCodes.Ldloc_1)
{
codes[i - 2].MoveLabelsTo(codes[i + 13]);
codes.RemoveRange(i - 2, 15);
break;
}
}
return codes;
}
[HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.AimingGun), MethodType.Setter)]
[HarmonyPrefix]
private static bool Prefix_AimingGun_EntityAlive(bool value, EntityAlive __instance)
{
if (__instance is EntityPlayerLocal && __instance.inventory != null)
{
bool isAimingGun = __instance.AimingGun;
if (value != isAimingGun)
{
__instance.FireEvent(value ? MinEventTypes.onSelfAimingGunStart : MinEventTypes.onSelfAimingGunStop, true);
#if DEBUG
Log.Out(value ? "START AIMING GUN FIRED" : "STOP AIMING GUN FIRED");
#endif
}
}
return true;
}
[HarmonyPatch(typeof(ItemActionAttack), nameof(ItemActionAttack.HasRadial))]
[HarmonyPostfix]
private static void Postfix_HasRadial_ItemActionAttack(ref bool __result)
{
EntityPlayerLocal player = GameManager.Instance.World?.GetPrimaryPlayer();
int index = MultiActionManager.GetActionIndexForEntity(player);
List<ItemActionData> actionDatas = player.inventory?.holdingItemData?.actionData;
if (actionDatas != null && actionDatas.Count > index && actionDatas[index] is ItemActionRanged.ItemActionDataRanged rangedData && (rangedData.isReloading || rangedData.isWeaponReloading))
{
__result = false;
}
}
[HarmonyPatch(typeof(ItemActionAttack), nameof(ItemActionAttack.SetupRadial))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SetupRadial_ItemActionAttack(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var codes = instructions.ToList();
var fld_usable = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.UsableUnderwater));
var lbd_states = generator.DeclareLocal(typeof(bool[]));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Stloc_0)
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldloc_0),
new CodeInstruction(OpCodes.Ldarg_2),
new CodeInstruction(OpCodes.Ldc_I4_M1),
CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(CommonUtilityPatch.GetUnusableItemEntries)),
new CodeInstruction(OpCodes.Stloc_S, lbd_states)
});
i += 4;
}
else if (codes[i].LoadsField(fld_usable))
{
codes.InsertRange(i + 2, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, lbd_states).WithLabels(codes[i + 2].ExtractLabels()),
new CodeInstruction(OpCodes.Ldloc_2),
CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(CommonUtilityPatch.IsAmmoDisabled)),
new CodeInstruction(OpCodes.Brtrue_S, codes[i + 1].operand)
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemAction), nameof(ItemAction.StartHolding))]
[HarmonyPostfix]
private static void Postfix_StartHolding_ItemAction(ItemActionData _data, ItemAction __instance)
{
if (__instance is ItemActionAttack itemActionAttack && _data.invData.holdingEntity is EntityPlayerLocal player)
{
var arr_disabled_ammo = GetUnusableItemEntries(itemActionAttack.MagazineItemNames, player, _data.indexInEntityOfAction);
if (arr_disabled_ammo == null)
{
return;
}
var itemValue = _data.invData.itemValue;
int cur_index = itemValue.GetSelectedAmmoIndexByActionIndex(_data.indexInEntityOfAction);
if (arr_disabled_ammo[cur_index])
{
int first_enabled_index = Mathf.Max(Array.IndexOf(arr_disabled_ammo, false), 0);
var mapping = MultiActionManager.GetMappingForEntity(player.entityId);
if (mapping != null)
{
if (_data.indexInEntityOfAction == mapping.CurMetaIndex)
{
itemValue.SelectedAmmoTypeIndex = (byte)first_enabled_index;
}
else
{
itemValue.SetMetadata(MultiActionUtils.ActionSelectedAmmoNames[mapping.indices.GetMetaIndexForActionIndex(_data.indexInEntityOfAction)], first_enabled_index, TypedMetadataValue.TypeTag.Integer);
}
_data.invData.holdingEntity.inventory.CallOnToolbeltChangedInternal();
}
else
{
itemValue.SelectedAmmoTypeIndex = (byte)(first_enabled_index);
}
}
}
}
public static bool[] GetUnusableItemEntries(string[] ammoNames, EntityPlayerLocal player, int actionIndex = -1)
{
if (ammoNames == null)
{
return null;
}
if (actionIndex < 0)
{
actionIndex = MultiActionManager.GetActionIndexForEntity(player);
}
string str_disabled_ammo_names = player.inventory.holdingItemItemValue.GetPropertyOverrideForAction("DisableAmmo", "", actionIndex);
//Log.Out($"checking disabled ammo: {str_disabled_ammo_names}\n{StackTraceUtility.ExtractStackTrace()}");
bool[] arr_disable_states = new bool[ammoNames.Length];
if(!string.IsNullOrEmpty(str_disabled_ammo_names))
{
string[] arr_disabled_ammo_names = str_disabled_ammo_names.Split(',', StringSplitOptions.RemoveEmptyEntries);
foreach (var name in arr_disabled_ammo_names)
{
int index = Array.IndexOf(ammoNames, name.Trim());
if (index >= 0)
{
arr_disable_states[index] = true;
if (ConsoleCmdReloadLog.LogInfo)
Log.Out($"ammo {ammoNames[index]} is disabled");
}
}
}
return arr_disable_states;
}
private static bool IsAmmoDisabled(bool[] ammoStates, int index)
{
if (ammoStates == null || ammoStates.Length <= index)
{
return false;
}
return ammoStates[index];
}
//dont spread onSelfItemActivate/onSelfItemDeactivate to attachments
//handle start holding
[HarmonyPatch(typeof(Inventory), nameof(Inventory.syncHeldItem))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_syncHeldItem_Inventory(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var prop_itemvalue = AccessTools.PropertyGetter(typeof(Inventory), nameof(Inventory.holdingItemItemValue));
var mtd_fireevent = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.FireEvent));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_fireevent) && codes[i - 5].Calls(prop_itemvalue))
{
codes[i] = CodeInstruction.Call(typeof(MinEffectController), nameof(MinEffectController.FireEvent));
codes.InsertRange(i - 4, new[]
{
CodeInstruction.Call(typeof(ItemValue), "get_ItemClass"),
CodeInstruction.LoadField(typeof(ItemClass), nameof(ItemClass.Effects))
});
i += 2;
}
}
return codes;
}
//handle radial activation
[HarmonyPatch(typeof(XUiC_Radial), nameof(XUiC_Radial.handleActivatableItemCommand))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_handleActivatableItemCommand_XUiC_Radial(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_fireevent = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.FireEvent));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_fireevent))
{
codes[i] = CodeInstruction.Call(typeof(MinEffectController), nameof(MinEffectController.FireEvent));
codes.InsertRange(i - 2, new[]
{
CodeInstruction.Call(typeof(ItemValue), "get_ItemClass"),
CodeInstruction.LoadField(typeof(ItemClass), nameof(ItemClass.Effects))
});
i += 2;
}
}
return codes;
}
//handle equipments
[HarmonyPatch(typeof(Equipment), nameof(Equipment.SetSlotItem))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_SetSlotItem_Equipment(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_fireevent = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.FireEvent));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_fireevent) && codes[i - 5].opcode == OpCodes.Ldloc_0 && codes[i - 4].OperandIs((int)MinEventTypes.onSelfItemDeactivate))
{
codes[i] = CodeInstruction.Call(typeof(MinEffectController), nameof(MinEffectController.FireEvent));
codes.InsertRange(i - 4, new[]
{
CodeInstruction.Call(typeof(ItemValue), "get_ItemClass"),
CodeInstruction.LoadField(typeof(ItemClass), nameof(ItemClass.Effects))
});
i += 2;
}
}
return codes;
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.DropContentOfLootContainerServer))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_DropContentOfLootContainerServer_GameManager(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var setter_localscale = AccessTools.PropertySetter(typeof(Transform), nameof(Transform.localScale));
for (var i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(setter_localscale))
{
codes.RemoveRange(i - 6, 7);
break;
}
}
return codes;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.onHoldingEntityFired))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_onHoldingEntityFired_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Ldc_R4 && codes[i].operand is 5f)
{
codes.RemoveAt(i);
codes.InsertRange(i, new[]
{
new CodeInstruction(OpCodes.Ldarg_1),
CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(CommonUtilityPatch.GetMaxSpread))
});
break;
}
}
return codes;
}
private static float GetMaxSpread(ItemActionData _data)
{
return EffectManager.GetValue(CustomEnums.MaxWeaponSpread, _data.invData.itemValue, 5f, _data.invData.holdingEntity);
}
[HarmonyPatch(typeof(NetEntityDistributionEntry), nameof(NetEntityDistributionEntry.getSpawnPacket))]
[HarmonyPrefix]
private static bool Prefix_getSpawnPacket_NetEntityDistributionEntry(NetEntityDistributionEntry __instance, ref NetPackage __result)
{
if (__instance.trackedEntity is EntityAlive ea)
{
__result = NetPackageManager.GetPackage<NetPackageEntitySpawnWithCVar>().Setup(new EntityCreationData(__instance.trackedEntity, true), (EntityAlive)__instance.trackedEntity);
return false;
}
return true;
}
[HarmonyPatch(typeof(World), nameof(World.SpawnEntityInWorld))]
[HarmonyPostfix]
private static void Postfix_SpawnEntityInWorld_World(Entity _entity)
{
if (_entity is EntityAlive ea && !ea.isEntityRemote)
{
ea.FireEvent(CustomEnums.onSelfFirstCVarSync);
}
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ItemActionEffects))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_ItemActionEffects_ItemActionRanged(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
for (int i = 0; i < codes.Count - 2; i++)
{
if (codes[i].opcode == OpCodes.Ldloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 9 && codes[i + 2].Branches(out _))
{
codes.InsertRange(i + 3, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, codes[i].operand).WithLabels(codes[i + 3].ExtractLabels()),
CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(AddTmpMuzzleFlash)),
});
i += 5;
}
else if (codes[i].opcode == OpCodes.Ldloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 12 && codes[i + 2].Branches(out _))
{
codes.InsertRange(i + 3, new[]
{
new CodeInstruction(OpCodes.Ldloc_S, codes[i].operand).WithLabels(codes[i + 3].ExtractLabels()),
CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(AddTmpMuzzleFlash)),
});
i += 5;
}
}
return codes;
}
private static void AddTmpMuzzleFlash(Transform trans)
{
if (trans.TryGetComponent<TemporaryObject>(out var tmp))
{
tmp.StopAllCoroutines();
Component.Destroy(tmp);
}
tmp = trans.AddMissingComponent<TemporaryMuzzleFlash>();
tmp.life = 5f;
}
[HarmonyPatch(typeof(vp_FPCamera), nameof(vp_FPCamera.UpdateShakes))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_UpdateShakes_vp_FPCamera(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var fld_shake = AccessTools.Field(typeof(vp_FPCamera), nameof(vp_FPCamera.m_Shake));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].StoresField(fld_shake))
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(CheckShakeNaN))
});
break;
}
}
return codes;
}
private static void CheckShakeNaN(vp_FPCamera fpcamera)
{
if (float.IsNaN(fpcamera.m_Shake.x) || float.IsNaN(fpcamera.m_Shake.y) || float.IsNaN(fpcamera.m_Shake.z))
{
Log.Warning("Shake1 NaN {0}, time {1}, speed {2}, amp {3}", new object[]
{
fpcamera.m_Shake,
Time.time,
fpcamera.ShakeSpeed,
fpcamera.ShakeAmplitude
});
fpcamera.ShakeSpeed = 0f;
fpcamera.m_Shake = Vector3.zero;
fpcamera.m_Pitch += -1f;
}
}
//[HarmonyPatch(typeof(EntityBuffs), nameof(EntityBuffs.AddBuff), typeof(string), typeof(Vector3i), typeof(int), typeof(bool), typeof(bool), typeof(float))]
//[HarmonyPostfix]
//private static void Postfix_AddBuff_EntityBuffs(string _name, EntityBuffs __instance, EntityBuffs.BuffStatus __result, bool _netSync)
//{
// if (_name.StartsWith("eftZombieRandomArmor") || _name.StartsWith("eftZombieArmor"))
// Log.Out($"AddBuff [{_name}] on entity {__instance.parent.GetDebugName()} should sync {_netSync} result {__result.ToStringCached()}\n{StackTraceUtility.ExtractStackTrace()}");
//}
//[HarmonyPatch(typeof(EntityBuffs), nameof(EntityBuffs.RemoveBuff))]
//[HarmonyPostfix]
//private static void Postfix_RemoveBuff_EntityBuffs(string _name, EntityBuffs __instance, bool _netSync)
//{
// if (_name.StartsWith("eftZombieRandomArmor") || _name.StartsWith("eftZombieArmor"))
// Log.Out($"RemoveBuff [{_name}] on entity {__instance.parent.GetDebugName()} should sync {_netSync}\n{StackTraceUtility.ExtractStackTrace()}");
//}
//[HarmonyPatch(typeof(Inventory), nameof(Inventory.Execute))]
//[HarmonyPrefix]
//private static void Prefix_Execute_Inventory(Inventory __instance, int _actionIdx, bool _bReleased, PlayerActionsLocal _playerActions = null)
//{
// Log.Out($"Execute Inventory holding item {__instance.holdingItem.Name} slot {__instance.holdingItemIdx} action index {_actionIdx} released {_bReleased} is holster delay {__instance.IsHolsterDelayActive()} is unholster delay {__instance.IsUnholsterDelayActive()}");
//}
//[HarmonyPatch(typeof(Inventory), nameof(Inventory.updateHoldingItem))]
//[HarmonyTranspiler]
//private static IEnumerable<CodeInstruction> Transpiler_updateHoldingItem_Inventory(IEnumerable<CodeInstruction> instructions)
//{
// var codes = instructions.ToList();
// var mtd_setholdingtrans = AccessTools.Method(typeof(Inventory), nameof(Inventory.setHoldingItemTransfrom));
// var mtd_showrighthand = AccessTools.Method(typeof(Inventory), nameof(Inventory.ShowRightHand));
// int insert = -1, take = -1;
// for (int i = 0; i < codes.Count; i++)
// {
// if (codes[i].Calls(mtd_showrighthand))
// {
// insert = i + 1;
// }
// else if (codes[i].Calls(mtd_setholdingtrans))
// {
// take = i - 6;
// }
// }
// if (take > insert)
// {
// var list_take = codes.GetRange(take, 7);
// codes.RemoveRange(take, 7);
// codes.InsertRange(insert, list_take);
// }
// return codes;
//}
//private static bool exported = false;
//[HarmonyPatch(typeof(EModelSDCS), nameof(EModelSDCS.createModel))]
//[HarmonyPostfix]
//private static void Postfix_test(EModelSDCS __instance)
//{
// if (!exported)
// {
// exported = true;
// var objects = new[] { __instance.entity.RootTransform.gameObject.GetComponentsInChildren<Animator>()[1] };
// Log.Out($"exporting objs: {objects.Length} avatar {objects[0].avatar.name} is human {objects[0].avatar.isHuman}");
// FbxExporter07.OnExport(objects, @"E:\Unity Projects\AnimationPlayground\Assets\ExportedProject\example_skinned_mesh_with_bones.fbx");
// Application.Quit();
// }
//}
}

156
Harmony/RecoilPatch.cs Normal file
View File

@@ -0,0 +1,156 @@
using HarmonyLib;
using KFCommonUtilityLib.Scripts.StaticManagers;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using UnityEngine;
using CameraShake;
using System;
[HarmonyPatch]
class RecoilPatch
{
[HarmonyPatch(typeof(EntityPlayerLocal), "Awake")]
[HarmonyPostfix]
private static void Postfix_Awake_EntityPlayerLocal(EntityPlayerLocal __instance)
{
RecoilManager.InitPlayer(__instance);
}
[HarmonyPatch(typeof(vp_FPCamera), nameof(vp_FPCamera.LateUpdate))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_LateUpdate_vp_FPCamera(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
var mtd_update = AccessTools.Method(typeof(vp_FPCamera), nameof(vp_FPCamera.Update3rdPerson));
var prop_trans = AccessTools.PropertyGetter(typeof(vp_Component), nameof(vp_Component.transform));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].Calls(mtd_update))
{
codes.InsertRange(i - 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Call, prop_trans),
CodeInstruction.Call(typeof(KFExtensions), nameof(KFExtensions.AddMissingComponent), new Type[]{ typeof(Transform) }, new Type[]{ typeof(CameraShaker) }),
CodeInstruction.Call(typeof(CameraShaker), nameof(CameraShaker.UpdateShake))
});
break;
}
}
return codes;
}
[HarmonyPatch(typeof(GameManager), nameof(GameManager.SaveAndCleanupWorld))]
[HarmonyPostfix]
private static void Postfix_SaveAndCleanupWorld_GameManager()
{
RecoilManager.Cleanup();
}
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.OnFired))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_OnFired_EntityPlayerLocal(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
FieldInfo fld_isfpv = AccessTools.Field(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.bFirstPersonView));
ConstructorInfo mtd_ctor = AccessTools.Constructor(typeof(Vector2), new[] { typeof(float), typeof(float) });
for (int i = 0; i < codes.Count - 1; i++)
{
if (codes[i].Is(OpCodes.Call, mtd_ctor) && codes[i + 1].opcode == OpCodes.Ldloc_0)
{
for (int j = i + 1; j < codes.Count - 1; j++)
{
if (codes[j].opcode == OpCodes.Pop && codes[j + 1].opcode == OpCodes.Ldarg_0)
{
codes.RemoveRange(i + 1, j - i);
break;
}
}
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldloca_S, 0),
new CodeInstruction(OpCodes.Ldloca_S, 1),
CodeInstruction.Call(typeof(RecoilPatch), nameof(RecoilPatch.ModifyRecoil))
});
i += 4;
}
else if (codes[i].LoadsField(fld_isfpv))
{
codes.RemoveRange(i + 2, codes.Count - i - 3);
codes.InsertRange(i + 2, new[]
{
new CodeInstruction(OpCodes.Ldloc_0),
new CodeInstruction(OpCodes.Ldloc_1),
CodeInstruction.Call(typeof(RecoilManager), nameof(RecoilManager.AddRecoil))
});
break;
}
}
return codes;
}
private static void ModifyRecoil(EntityPlayerLocal player, ref Vector2 kickHor, ref Vector2 kickVer)
{
float multiplierHor = Mathf.Max(1 - EffectManager.GetValue(CustomEnums.KickDegreeHorizontalModifier, player.inventory.holdingItemItemValue, 0f, player), 0);
float multiplierVer = Mathf.Max(1 - EffectManager.GetValue(CustomEnums.KickDegreeVerticalModifier, player.inventory.holdingItemItemValue, 0f, player), 0);
kickHor *= multiplierHor;
kickVer *= multiplierVer;
}
[HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Update_PlayerMoveController(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
FieldInfo fld_rotation = AccessTools.Field(typeof(MovementInput), nameof(MovementInput.rotation));
FieldInfo fld_rx = AccessTools.Field(typeof(Vector3), nameof(Vector3.x));
FieldInfo fld_ry = AccessTools.Field(typeof(Vector3), nameof(Vector3.y));
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].LoadsField(fld_rotation, true))
{
if (codes[i + 1].LoadsField(fld_rx, true))
{
for (; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Stind_R4)
{
codes.Insert(i, CodeInstruction.Call(typeof(RecoilManager), nameof(RecoilManager.CompensateX)));
break;
}
}
}
else if (codes[i + 1].LoadsField(fld_ry, true))
{
for (; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Stind_R4)
{
codes.Insert(i, CodeInstruction.Call(typeof(RecoilManager), nameof(RecoilManager.CompensateY)));
break;
}
}
}
}
}
return codes;
}
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.MoveByInput))]
[HarmonyPrefix]
private static bool Prefix_MoveByInput_EntityPlayerLocal()
{
RecoilManager.ApplyRecoil();
return true;
}
}

View File

@@ -0,0 +1,6 @@
namespace KFCommonUtilityLib.Harmony
{
public static class SaveRescuePatches
{
}
}