Files
7d2dXG/Mods/0A-KFCommonUtilityLib/Scripts/Items/ModularClasses/ItemModuleMultiItem.cs
Nathaniel Cosford 062dfab2cd Patched
2025-05-30 01:04:40 +09:30

462 lines
20 KiB
C#

using HarmonyLib;
using KFCommonUtilityLib;
using KFCommonUtilityLib.Scripts.Attributes;
using KFCommonUtilityLib.Scripts.StaticManagers;
using System.Collections.Generic;
using System.Reflection.Emit;
using UniLinq;
using UnityEngine;
using static ItemModuleMultiItem;
[TypeTarget(typeof(ItemClass)), TypeDataTarget(typeof(MultiItemInvData))]
public class ItemModuleMultiItem
{
private string boundItemName;
private ItemClass boundItemClass;
private ItemClass itemClass;
public ItemClass BoundItemClass
{
get
{
if (boundItemClass == null && !string.IsNullOrEmpty(boundItemName))
{
boundItemClass = ItemClass.GetItemClass(boundItemName, true);
}
return boundItemClass;
}
}
[HarmonyPatch(nameof(ItemClass.Init)), MethodTargetPostfix]
public void Postfix_Init(ItemClass __instance)
{
itemClass = __instance;
__instance.Properties.ParseString("BoundItemName", ref boundItemName);
}
[HarmonyPatch(nameof(ItemClass.StartHolding)), MethodTargetPrefix]
public bool Prefix_StartHolding(ItemInventoryData _data, MultiItemInvData __customData)
{
var boundInvData = __customData.boundInvData;
ItemValue boundItemValue = boundInvData.itemStack.itemValue;
boundItemValue.Quality = _data.itemValue.Quality;
boundItemValue.Metadata = _data.itemValue.Metadata;
boundItemValue.Modifications = _data.itemValue.Modifications;
boundItemValue.CosmeticMods = _data.itemValue.CosmeticMods;
return true;
}
[HarmonyPatch(nameof(ItemClass.CleanupHoldingActions)), MethodTargetPostfix]
public void Postfix_CleanupHoldingActions(MultiItemInvData __customData)
{
BoundItemClass?.CleanupHoldingActions(__customData.boundInvData);
}
[HarmonyPatch(nameof(ItemClass.ConsumeScrollWheel)), MethodTargetPrefix]
public bool Prefix_ConsumeScrollWheel(MultiItemInvData __customData, float _scrollWheelInput, PlayerActionsLocal _playerInput, ref bool __result)
{
if (__customData.useBound && BoundItemClass != null)
{
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__result = boundItemClass.ConsumeScrollWheel(__customData.boundInvData, _scrollWheelInput, _playerInput);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
return false;
}
return true;
}
[HarmonyPatch(nameof(ItemClass.ExecuteAction)), MethodTargetPrefix]
public bool Prefix_ExecuteAction(bool _bReleased, MultiItemInvData __customData)
{
if (!_bReleased)
{
bool flag = IsBoundActionRunning(__customData);
return !flag;
}
return true;
}
public bool IsBoundActionRunning(MultiItemInvData __customData)
{
bool useBound = __customData.useBound;
__customData.useBound = true;
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
bool flag = __customData.boundInvData.item.IsActionRunning(__customData.boundInvData);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__customData.useBound = useBound;
return flag;
}
[HarmonyPatch(nameof(ItemClass.GetCameraShakeType)), MethodTargetPrefix]
public bool Prefix_GetCameraShakeType(MultiItemInvData __customData, ref EnumCameraShake __result)
{
if (__customData.useBound && BoundItemClass != null)
{
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__result = boundItemClass.GetCameraShakeType(__customData.boundInvData);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
return false;
}
return true;
}
[HarmonyPatch(nameof(ItemClass.GetFocusType)), MethodTargetPrefix]
public bool Prefix_GetFocusType(MultiItemInvData __customData, ref RenderCubeType __result)
{
if (__customData.useBound && BoundItemClass != null)
{
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__result = boundItemClass.GetFocusType(__customData.boundInvData);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
return false;
}
return true;
}
[HarmonyPatch(nameof(ItemClass.GetIronSights)), MethodTargetPrefix]
public bool Prefix_GetIronSights(MultiItemInvData __customData, ref float _fov)
{
if (__customData.useBound && BoundItemClass != null)
{
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
boundItemClass.GetIronSights(__customData.boundInvData, out _fov);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
return false;
}
return true;
}
[HarmonyPatch(nameof(ItemClass.IsActionRunning)), MethodTargetPostfix]
public void Postfix_IsActionRunning(MultiItemInvData __customData, ref bool __result)
{
if (!__result && BoundItemClass != null)
{
bool useBound = __customData.useBound;
__customData.useBound = true;
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__result |= boundItemClass.IsActionRunning(__customData.boundInvData);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__customData.useBound = useBound;
}
}
[HarmonyPatch(nameof(ItemClass.IsHUDDisabled)), MethodTargetPostfix]
public void Postfix_IsHUDDisabled(MultiItemInvData __customData, ref bool __result)
{
if (!__result && BoundItemClass != null)
{
bool useBound = __customData.useBound;
__customData.useBound = true;
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__result |= boundItemClass.IsHUDDisabled(__customData.boundInvData);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__customData.useBound = useBound;
}
}
[HarmonyPatch(nameof(ItemClass.OnHoldingItemActivated)), MethodTargetPostfix]
public void Postfix_OnHoldingItemActivated(MultiItemInvData __customData)
{
if (BoundItemClass != null)
{
bool useBound = __customData.useBound;
__customData.useBound = true;
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
boundItemClass.OnHoldingItemActivated(__customData.boundInvData);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__customData.useBound = useBound;
}
}
[HarmonyPatch(nameof(ItemClass.OnHoldingReset)), MethodTargetPostfix]
public void Postfix_OnHoldingReset(MultiItemInvData __customData)
{
if (BoundItemClass != null)
{
bool useBound = __customData.useBound;
__customData.useBound = true;
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
boundItemClass.OnHoldingReset(__customData.boundInvData);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__customData.useBound = useBound;
}
}
[HarmonyPatch(nameof(ItemClass.OnHoldingUpdate)), MethodTargetPostfix]
public void Postfix_OnHoldingUpdate(MultiItemInvData __customData)
{
if (BoundItemClass != null)
{
bool useBound = __customData.useBound;
__customData.useBound = true;
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
boundItemClass.OnHoldingUpdate(__customData.boundInvData);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__customData.useBound = useBound;
}
}
[HarmonyPatch(nameof(ItemClass.OnHUD)), MethodTargetPrefix]
public bool Prefix_OnHUD(MultiItemInvData __customData, int _x, int _y)
{
if (__customData.useBound && BoundItemClass != null)
{
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
boundItemClass.OnHUD(__customData.boundInvData, _x, _y);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
return false;
}
return true;
}
[HarmonyPatch(nameof(ItemClass.OnScreenOverlay)), MethodTargetPrefix]
public bool Prefix_OnScreenOverlay(MultiItemInvData __customData)
{
if (__customData.useBound && BoundItemClass != null)
{
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
boundItemClass.OnScreenOverlay(__customData.boundInvData);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
return false;
}
return true;
}
[HarmonyPatch(nameof(ItemClass.StartHolding)), MethodTargetPostfix]
public void Postfix_StartHolding(MultiItemInvData __customData, Transform _modelTransform)
{
if (BoundItemClass != null)
{
bool useBound = __customData.useBound;
__customData.useBound = true;
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
boundItemClass.StartHolding(__customData.boundInvData, _modelTransform);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
__customData.useBound = useBound;
}
}
[HarmonyPatch(nameof(ItemClass.StopHolding)), MethodTargetPostfix]
public void Postfix_StopHolding(MultiItemInvData __customData, Transform _modelTransform)
{
if (BoundItemClass != null)
{
bool useBound = __customData.useBound;
__customData.useBound = true;
SetBoundParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
boundItemClass.StopHolding(__customData.boundInvData, _modelTransform);
RestoreParams(__customData.originalData.holdingEntity.MinEventContext, __customData);
MultiActionManager.SetMappingForEntity(__customData.originalData.holdingEntity.entityId, null);
__customData.useBound = useBound;
}
}
public void SetBoundParams(MinEventParams param, MultiItemInvData data)
{
param.ItemInventoryData = data.boundInvData;
param.ItemValue = data.boundInvData.itemStack.itemValue;
if (data.originalData.actionData[0] is IModuleContainerFor<ActionModuleAlternative.AlternativeData> dataModule)
{
MultiActionManager.SetMappingForEntity(data.originalData.holdingEntity.entityId, null);
}
}
public void RestoreParams(MinEventParams param, MultiItemInvData data)
{
param.ItemInventoryData = data.originalData;
param.ItemValue = data.originalData.itemStack.itemValue;
if (data.originalData.actionData[0] is IModuleContainerFor<ActionModuleAlternative.AlternativeData> dataModule)
{
MultiActionManager.SetMappingForEntity(data.originalData.holdingEntity.entityId, dataModule.Instance.mapping);
}
}
public class MultiItemInvData
{
public ItemInventoryData originalData;
public ItemInventoryData boundInvData;
public ItemModuleMultiItem itemModule;
public bool useBound;
public MultiItemInvData(ItemInventoryData _invData, ItemClass _item, ItemStack _itemStack, IGameManager _gameManager, EntityAlive _holdingEntity, int _slotIdx, ItemModuleMultiItem module)
{
itemModule = module;
originalData = _invData;
if (module.BoundItemClass != null)
{
boundInvData = module.BoundItemClass.CreateInventoryData(new ItemStack(new ItemValue(module.BoundItemClass.Id), 1), _gameManager, _holdingEntity, _slotIdx);
}
}
}
}
[HarmonyPatch]
public static class MultiItemPatches
{
[HarmonyPatch(typeof(Inventory), nameof(Inventory.holdingCount), MethodType.Getter)]
[HarmonyPrefix]
public static bool Prefix_holdingCount_Inventory(ItemInventoryData[] ___slots, int ___m_HoldingItemIdx, ref int __result)
{
if (___slots[___m_HoldingItemIdx] is IModuleContainerFor<MultiItemInvData> multiInvData && multiInvData.Instance.useBound)
{
__result = multiInvData.Instance.boundInvData.itemStack.count;
return false;
}
return true;
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.holdingItem), MethodType.Getter)]
[HarmonyPrefix]
public static bool Prefix_holdingItem_Inventory(ItemInventoryData[] ___slots, int ___m_HoldingItemIdx, ref ItemClass __result)
{
if (___slots[___m_HoldingItemIdx] is IModuleContainerFor<MultiItemInvData> multiInvData && multiInvData.Instance.useBound)
{
__result = multiInvData.Instance.boundInvData.item;
return false;
}
return true;
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.holdingItemData), MethodType.Getter)]
[HarmonyPrefix]
public static bool Prefix_holdingItemData_Inventory(ItemInventoryData[] ___slots, int ___m_HoldingItemIdx, ref ItemInventoryData __result)
{
if (___slots[___m_HoldingItemIdx] is IModuleContainerFor<MultiItemInvData> multiInvData && multiInvData.Instance.useBound)
{
__result = multiInvData.Instance.boundInvData;
return false;
}
return true;
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.holdingItemItemValue), MethodType.Getter)]
[HarmonyPrefix]
public static bool Prefix_holdingItemItemValue_Inventory(ItemInventoryData[] ___slots, int ___m_HoldingItemIdx, ref ItemValue __result)
{
if (___slots[___m_HoldingItemIdx] is IModuleContainerFor<MultiItemInvData> multiInvData && multiInvData.Instance.useBound)
{
__result = multiInvData.Instance.boundInvData.itemStack.itemValue;
return false;
}
return true;
}
[HarmonyPatch(typeof(Inventory), nameof(Inventory.holdingItemStack), MethodType.Getter)]
[HarmonyPrefix]
public static bool Prefix_holdingItemStack_Inventory(ItemInventoryData[] ___slots, int ___m_HoldingItemIdx, ref ItemStack __result)
{
if (___slots[___m_HoldingItemIdx] is IModuleContainerFor<MultiItemInvData> multiInvData && multiInvData.Instance.useBound)
{
__result = multiInvData.Instance.boundInvData.itemStack;
return false;
}
return true;
}
[HarmonyPatch(typeof(Inventory), "Item", MethodType.Getter)]
[HarmonyPrefix]
public static bool Prefix_Item_Inventory(ItemInventoryData[] ___slots, int _idx, ref ItemValue __result)
{
if (___slots[_idx] is IModuleContainerFor<MultiItemInvData> multiInvData && multiInvData.Instance.useBound)
{
__result = multiInvData.Instance.boundInvData.itemStack.itemValue;
return false;
}
return true;
}
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SwapSelectedAmmo))]
[HarmonyPrefix]
private static bool Prefix_SwapSelectedAmmo_ItemActionRanged(EntityAlive _entity, int _ammoIndex)
{
if (_entity.inventory?.holdingItemData is IModuleContainerFor<MultiItemInvData> dataModule && dataModule.Instance.itemModule.IsBoundActionRunning(dataModule.Instance))
{
return false;
}
return true;
}
[HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler_Update_PlayerMoveController(IEnumerable<CodeInstruction> instructions)
{
var codes = instructions.ToList();
for (int i = 0; i < codes.Count; i++)
{
//ItemAction
if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 39)
{
codes.InsertRange(i + 1, new[]
{
new CodeInstruction(OpCodes.Ldarg_0),
CodeInstruction.Call(typeof(MultiItemPatches), nameof(CheckAltMelee))
});
break;
}
}
return codes;
}
private static void CheckAltMelee(PlayerMoveController controller)
{
if (DroneManager.Debug_LocalControl || !controller.gameManager.gameStateManager.IsGameStarted() || GameStats.GetInt(EnumGameStats.GameState) != 1)
return;
bool isUIOpen = controller.windowManager.IsCursorWindowOpen() || controller.windowManager.IsInputActive() || controller.windowManager.IsModalWindowOpen();
if (isUIOpen || controller.entityPlayerLocal.emodel.IsRagdollActive || controller.entityPlayerLocal.IsDead() || controller.entityPlayerLocal.AttachedToEntity != null)
{
return;
}
EntityPlayerLocal player = controller.entityPlayerLocal;
if (PlayerActionKFLib.Instance.Enabled && (PlayerActionKFLib.Instance.AltMelee.WasPressed || PlayerActionKFLib.Instance.AltMelee.WasReleased) && player.inventory.holdingItemData is IModuleContainerFor<MultiItemInvData> dataModule)
{
bool isReloading = player.IsReloading();
int actionIndex = MultiActionManager.GetActionIndexForEntity(player);
var reloadModule = player.inventory.holdingItem.Actions[actionIndex] as IModuleContainerFor<ActionModuleInterruptReload>;
MultiItemInvData multiInvData = dataModule.Instance;
if (multiInvData.itemModule.BoundItemClass?.Actions?[0] is ItemActionDynamicMelee dynamicAction && !multiInvData.itemModule.IsBoundActionRunning(multiInvData) && ((player.inventory.IsHoldingGun() && (!isReloading || reloadModule != null)) || !player.inventory.IsHoldingItemActionRunning()) && !player.AimingGun && !multiInvData.originalData.IsAnyActionLocked())
{
multiInvData.useBound = true;
multiInvData.itemModule.SetBoundParams(player.MinEventContext, multiInvData);
bool canRun = dynamicAction.canStartAttack(multiInvData.boundInvData.actionData[0] as ItemActionDynamicMelee.ItemActionDynamicMeleeData);
multiInvData.itemModule.RestoreParams(player.MinEventContext, multiInvData);
multiInvData.useBound = false;
if (!canRun)
{
return;
}
if (isReloading)
{
var itemActionData = player.inventory.holdingItemData.actionData[actionIndex] as ItemActionRanged.ItemActionDataRanged;
itemActionData.m_LastShotTime = Time.time;
reloadModule.Instance.Postfix_ExecuteAction(itemActionData, ((IModuleContainerFor<ActionModuleInterruptReload.InterruptData>)itemActionData).Instance, new ActionModuleInterruptReload.State
{
executed = true,
lastShotTime = -1,
isReloading = true,
isWeaponReloading = true,
});
}
player.emodel.avatarController.UpdateBool(AvatarController.reloadHash, false);
multiInvData.boundInvData.itemStack.itemValue.UseTimes = 0;
multiInvData.useBound = true;
multiInvData.itemModule.SetBoundParams(player.MinEventContext, multiInvData);
multiInvData.itemModule.BoundItemClass.ExecuteAction(0, multiInvData.boundInvData, PlayerActionKFLib.Instance.AltMelee.WasReleased, controller.playerInput);
player.emodel.avatarController.UpdateBool("UseAltMelee", true);
multiInvData.itemModule.RestoreParams(player.MinEventContext, multiInvData);
multiInvData.useBound = false;
}
}
}
//[HarmonyPatch(typeof(Animator), nameof(Animator.ResetTrigger), new[] {typeof(string)})]
//[HarmonyPrefix]
//private static void Prefix(Animator __instance, string name)
//{
// if (name == "PowerAttack" && __instance.GetBool(name))
// {
// Log.Warning($"RESETTING POWER ATTACK TRIGGER\n{StackTraceUtility.ExtractStackTrace()}");
// }
//}
}