2910 lines
132 KiB
C#
2910 lines
132 KiB
C#
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
|
|
}
|