Files
0A-KFCommonUtilityLib/Scripts/Items/ModularActions/ActionModuleProceduralAiming.cs
2025-06-04 16:13:32 +09:30

271 lines
12 KiB
C#

using HarmonyLib;
using KFCommonUtilityLib;
using KFCommonUtilityLib.Scripts.Attributes;
using KFCommonUtilityLib.Scripts.StaticManagers;
using System.Collections.Generic;
using UnityEngine;
[TypeTarget(typeof(ItemActionZoom)), ActionDataTarget(typeof(ProceduralAimingData))]
public class ActionModuleProceduralAiming
{
[HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix]
public void Postfix_OnModificationsChanged(ItemActionZoom __instance, ItemActionData _data, ProceduralAimingData __customData)
{
if (_data is IModuleContainerFor<ActionModuleErgoAffected.ErgoData> dataModule)
{
__customData.zoomInTime = dataModule.Instance.module.zoomInTimeBase / dataModule.Instance.module.aimSpeedModifierBase;
__customData.ergoData = dataModule.Instance;
}
else
{
float zoomInTimeBase = 0.3f;
__instance.Properties.ParseFloat("ZoomInTimeBase", ref zoomInTimeBase);
float aimSpeedModifierBase = 1f;
__instance.Properties.ParseFloat("AimSpeedModifierBase", ref aimSpeedModifierBase);
__customData.zoomInTime = zoomInTimeBase / aimSpeedModifierBase;
__customData.ergoData = null;
}
__customData.playerOriginTransform = null;
__customData.playerCameraPosRef = _data.invData.holdingEntity is EntityPlayerLocal player && player.bFirstPersonView ? player.cameraTransform : null;
var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(_data.invData.holdingEntity);
if (__customData.playerCameraPosRef)
{
if (targets.ItemFpv)
{
if (targets is RigTargets)
{
__customData.isRigWeapon = true;
__customData.playerOriginTransform = targets.ItemAnimator.transform;
__customData.rigWeaponLocalPosition = __customData.playerOriginTransform.localPosition;
__customData.rigWeaponLocalRotation = __customData.playerOriginTransform.localRotation;
}
else
{
__customData.isRigWeapon = false;
__customData.playerOriginTransform = __customData.playerCameraPosRef.FindInAllChildren("Hips");
}
__customData.playerCameraPosRef = targets.ItemFpv.Find("PlayerCameraPositionReference");
}
else
{
__customData.playerCameraPosRef = null;
}
}
if (__customData.playerCameraPosRef)
{
__customData.aimRefTransform = targets.ItemFpv.Find("ScopeBasePositionReference");
if (__customData.aimRefTransform)
{
var scopeRefTrans = __customData.aimRefTransform.Find("ScopePositionReference");
if (!scopeRefTrans)
{
scopeRefTrans = new GameObject("ScopePositionReference").transform;
scopeRefTrans.SetParent(__customData.aimRefTransform, false);
}
scopeRefTrans.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
scopeRefTrans.localScale = Vector3.one;
__customData.aimRefTransform = scopeRefTrans;
}
}
else
{
__customData.aimRefTransform = null;
}
__customData.ResetAiming();
__customData.UpdateCurrentReference(true);
}
[HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPostfix]
public void Postfix_StopHolding(ProceduralAimingData __customData)
{
__customData.ResetAiming();
}
//[HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPostfix]
//public void Postfix_ExecuteAction(ProceduralAimingData __customData, ItemActionData _actionData)
//{
// if (__customData.isAiming != ((ItemActionZoom.ItemActionDataZoom)_actionData).aimingValue)
// {
// __customData.UpdateCurrentReference();
// __customData.isAiming = ((ItemActionZoom.ItemActionDataZoom)_actionData).aimingValue;
// }
//}
public class ProceduralAimingData
{
public ActionModuleErgoAffected.ErgoData ergoData;
public float zoomInTime;
public Transform aimRefTransform;
public Transform playerCameraPosRef;
public Transform playerOriginTransform;
public bool isRigWeapon;
public Vector3 rigWeaponLocalPosition;
public Quaternion rigWeaponLocalRotation;
public bool isAiming;
public int curAimRefIndex = -1;
//move curAimRefOffset towards aimRefOffset first, then move curAimOffset towards curAimRefOffset
public Vector3 aimRefPosOffset;
public Quaternion aimRefRotOffset;
public Vector3 curAimPosOffset;
public Quaternion curAimRotOffset;
private Vector3 curAimPosVelocity;
private Quaternion curAimRotVelocity;
private Vector3 targetSwitchPosVelocity;
private Quaternion targetSwitchRotVelocity;
public List<AimReference> registeredReferences = new List<AimReference>();
private EntityPlayerLocal holdingEntity;
private int CurAimRefIndex
{
get
{
for (int i = registeredReferences.Count - 1; i >= 0; i--)
{
if (registeredReferences[i].gameObject.activeInHierarchy)
{
return i;
}
}
return -1;
}
}
private AimReference CurAimRef => curAimRefIndex >= 0 && curAimRefIndex < registeredReferences.Count ? registeredReferences[curAimRefIndex] : null;
public ProceduralAimingData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleProceduralAiming _module)
{
holdingEntity = _invData.holdingEntity as EntityPlayerLocal;
}
public void ResetAiming()
{
isAiming = false;
curAimRefIndex = -1;
aimRefPosOffset = Vector3.zero;
aimRefRotOffset = Quaternion.identity;
if (aimRefTransform)
{
aimRefTransform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
}
curAimPosOffset = Vector3.zero;
curAimRotOffset = Quaternion.identity;
curAimPosVelocity = Vector3.zero;
curAimRotVelocity = Quaternion.identity;
targetSwitchPosVelocity = Vector3.zero;
targetSwitchRotVelocity = Quaternion.identity;
if (isRigWeapon && playerOriginTransform)
{
playerOriginTransform.localPosition = rigWeaponLocalPosition;
playerOriginTransform.localRotation = rigWeaponLocalRotation;
}
}
public bool RegisterGroup(AimReference[] group, string name)
{
if (holdingEntity && holdingEntity.bFirstPersonView)
{
foreach (var reference in group)
{
if (reference.index == -1)
{
reference.index = registeredReferences.Count;
registeredReferences.Add(reference);
}
}
UpdateCurrentReference();
//Log.Out($"Register group {name}\n{StackTraceUtility.ExtractStackTrace()}");
return true;
}
return false;
}
public void UpdateCurrentReference(bool snapTo = false)
{
curAimRefIndex = CurAimRefIndex;
AimReference curAimRef = CurAimRef;
if (aimRefTransform && curAimRef)
{
aimRefPosOffset = curAimRef.positionOffset;
aimRefRotOffset = curAimRef.rotationOffset;
if (curAimRef.asReference)
{
aimRefPosOffset -= Vector3.Project(aimRefPosOffset - aimRefTransform.parent.InverseTransformPoint(playerCameraPosRef.position), aimRefRotOffset * Vector3.forward);
}
if (snapTo)
{
aimRefTransform.localPosition = aimRefPosOffset;
aimRefTransform.localRotation = aimRefRotOffset;
}
}
for (int i = 0; i < registeredReferences.Count; i++)
{
registeredReferences[i].UpdateEnableState(isAiming && curAimRefIndex == i);
}
}
public void LateUpdateAiming()
{
if (aimRefTransform && playerCameraPosRef && playerOriginTransform && CurAimRef)
{
if (isRigWeapon)
{
playerOriginTransform.SetLocalPositionAndRotation(rigWeaponLocalPosition, rigWeaponLocalRotation);
}
float zoomInTimeMod = ergoData == null ? zoomInTime : zoomInTime / ergoData.ModifiedErgo;
zoomInTimeMod *= 0.25f;
//move aimRef towards target
aimRefTransform.localPosition = Vector3.SmoothDamp(aimRefTransform.localPosition, aimRefPosOffset, ref targetSwitchPosVelocity, 0.075f);
aimRefTransform.localRotation = QuaternionUtil.SmoothDamp(aimRefTransform.localRotation, aimRefRotOffset, ref targetSwitchRotVelocity, 0.075f);
//calculate current target aim offset
Vector3 aimTargetPosOffset = playerCameraPosRef.InverseTransformDirection(playerCameraPosRef.position - aimRefTransform.position);
Quaternion aimTargetRotOffset = playerCameraPosRef.localRotation * Quaternion.Inverse(aimRefTransform.parent.localRotation * aimRefTransform.localRotation);
//move current aim offset towards target aim offset
if (isAiming)
{
curAimPosOffset = Vector3.SmoothDamp(curAimPosOffset, aimTargetPosOffset, ref curAimPosVelocity, zoomInTimeMod);
curAimRotOffset = QuaternionUtil.SmoothDamp(curAimRotOffset, aimTargetRotOffset, ref curAimRotVelocity, zoomInTimeMod);
}
else
{
curAimPosOffset = Vector3.SmoothDamp(curAimPosOffset, Vector3.zero, ref curAimPosVelocity, zoomInTimeMod);
curAimRotOffset = QuaternionUtil.SmoothDamp(curAimRotOffset, Quaternion.identity, ref curAimRotVelocity, zoomInTimeMod);
}
//apply offset to player
if (isRigWeapon)
{
(playerCameraPosRef.parent.rotation * curAimRotOffset * Quaternion.Inverse(playerCameraPosRef.parent.rotation)).ToAngleAxis(out var angle, out var axis);
playerOriginTransform.RotateAround(aimRefTransform.position, axis, angle);
playerOriginTransform.position += playerCameraPosRef.TransformDirection(curAimPosOffset);
}
else
{
playerOriginTransform.position += playerCameraPosRef.TransformDirection(curAimPosOffset);
(playerCameraPosRef.parent.rotation * curAimRotOffset * Quaternion.Inverse(playerCameraPosRef.parent.rotation)).ToAngleAxis(out var angle, out var axis);
playerOriginTransform.RotateAround(aimRefTransform.position, axis, angle);
}
}
}
}
}
[HarmonyPatch]
public static class ProceduralAimingPatches
{
[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.LateUpdate))]
[HarmonyPostfix]
private static void Postfix_LateUpdate_EntityPlayerLocal(EntityPlayerLocal __instance)
{
if (__instance.inventory?.holdingItemData?.actionData?[1] is IModuleContainerFor<ActionModuleProceduralAiming.ProceduralAimingData> module)
{
if (__instance.AimingGun != module.Instance.isAiming)
{
module.Instance.isAiming = __instance.AimingGun;
module.Instance.UpdateCurrentReference(true);
}
module.Instance.LateUpdateAiming();
}
}
}