ClientServer/Client/Assets/Scripts/Weapons/WeaponController.cs

444 lines
14 KiB
C#
Raw Normal View History

2025-09-06 17:17:39 +04:00
using System;
using System.Collections;
using UnityEngine;
using Random = UnityEngine.Random;
using UnityEngine.VFX;
using EZCameraShake;
using NaughtyAttributes;
using Util;
using Weapons;
//Thomas09
[RequireComponent(typeof(Animator))]
public class WeaponController : MonoBehaviour
{
private static readonly int Swing = Animator.StringToHash("Swing");
private static readonly int Aim = Animator.StringToHash("Aim");
#region Variables
private readonly RaycastHit[] _results = new RaycastHit[5];
private Animator anim;
private Weapon weapon;
private Camera playerCamera;
private Quaternion cameraRecoilRotation;
private GameObject sniperModel;
private GameObject leftArm;
private GameObject rightArm;
private VisualEffect muzzleFlash;
private ParticleSystem bulletEjection;
private float aimVelocity;
private int weaponID;
internal GameObject playTile;
//Recoil
[SerializeField] private Transform kickbackPivot;
private Vector3 positionVelocity;
private Vector3 rotationVelocity;
private readonly Color PURPLE = new Color(0.6f, 0.2f, 0.8f, 1f);
//crossbow variables
private CrossbowAnimation crossbow;
public bool hasAttackEffect = false;
public bool hasKikBack = true;
public ParticleSystem visualEffectObject;
//
private bool isScopped = false;
#endregion
private void Awake()
{
weapon = OnDemandLoader.Load<Weapon>("config/" + int.Parse(this.gameObject.name));
weaponID = int.Parse(this.gameObject.name);
weapon.cachedHorizontalSpread = weapon.horizontalSpread;
weapon.cachedVerticleSpread = weapon.verticleSpread;
if (weapon.isSniper)
{
sniperModel = transform.GetChild(0).gameObject;
leftArm = transform.Find("PlayerArms/left/LeftArmModel").gameObject;
rightArm = transform.Find("PlayerArms/right/RightArmModel").gameObject;
if (transform.Find("PlayTileStart"))
playTile = transform.Find("PlayTileStart").gameObject;
}
cameraRecoilRotation = new Quaternion(weapon.cameraRecoil[0], weapon.cameraRecoil[1], 0, 0);
playerCamera = Player.Instance.transform.Find("FirstPersonCamera_Holder").GetComponentInChildren<Camera>();
anim = GetComponent<Animator>();
Transform muzzleFlashTransform = transform.Find("MuzzleFlash/VFX_MuzzleFlash");
if (muzzleFlashTransform != null)
{
muzzleFlash = muzzleFlashTransform.GetComponent<VisualEffect>();
if (Player.Instance.PlayerEntity.IsFuturisticWeapon())
{
muzzleFlash.SetVector4("Colour", PURPLE);
}
}
else
{
//if (weaponID != 26) //disregard the crossbow for the muzzleflash.
//Debug.Log("Muzzle Flash is missing! Did you forget to put it on " + gameObject.name);
}
Transform bulletEjectionTransform = transform.Find("BulletShell_PS");
if (bulletEjectionTransform != null)
{
bulletEjection = bulletEjectionTransform.GetComponent<ParticleSystem>();
}
}
private void OnEnable()
{
crossbow =
GetComponentInChildren<CrossbowAnimation>(); //most of the time is null. so always check it before using!
CrosshairManager.Instance.SetSniperCrosshairAlpha(0.0f);
StartCoroutine(Player.Instance.EquipWeaponCoroutine(weapon, anim, this));
}
internal void PlayAttackLocalEffect()
{
visualEffectObject.gameObject.SetActive(true);
visualEffectObject.Play();
}
internal void UnPlayAttackLocalEffect()
{
visualEffectObject.Stop();
}
void ApplyKickback(GunRecoilConfig recoilParams)
{
kickbackPivot.localPosition -= new Vector3(0, 0, recoilParams.zKickback.Sample());
kickbackPivot.Rotate(recoilParams.xTwist.Sample(), recoilParams.yTwist.Sample(), 0);
positionVelocity = new Vector3(0, 0, -recoilParams.Push);
rotationVelocity = Vector3.zero;
}
public void Fire(bool isAimed)
{
EmitMuzzleFlash();
LerpCamera();
EjectBullet();
if (hasKikBack) ApplyKickback(isAimed ? weapon.aimedRecoil : weapon.hipFireRecoil);
ShakeCamera();
if (crossbow != null) crossbow.FireBow();
}
public void Mining()
{
anim.SetBool(Swing, true);
Debugger.Logger($"{weapon.name} mine swing", ContextDebug.Session, Process.Action);
}
private void EmitMuzzleFlash()
{
if (!(weapon.isSniper && Player.Instance.IsAiming) && muzzleFlash != null) muzzleFlash.Play();
}
private void LerpCamera()
{
if (weapon.isMeleeFlameAttack)
return;
StartCoroutine(LerpCameraRecoil());
}
private void EjectBullet()
{
if (bulletEjection != null && (!(weapon.isSniper && Player.Instance.IsAiming)))
{
bulletEjection.Play();
}
}
private void ShakeCamera()
{
if (weapon.Magnitude != 0 || weapon.Roughness != 0)
CameraShaker.Instance.ShakeOnce(weapon.Magnitude, weapon.Roughness, weapon.fadeInTime, weapon.fadeOutTime);
}
private void FixedUpdate()
{
float recoveryTime = Player.Instance.IsAiming
? weapon.aimedRecoil.recoveryTime
: weapon.hipFireRecoil.recoveryTime;
kickbackPivot.localPosition =
Vector3.SmoothDamp(kickbackPivot.localPosition, Vector3.zero, ref positionVelocity, recoveryTime);
kickbackPivot.localEulerAngles = Vector3Utility.SmoothDampAngle(kickbackPivot.localEulerAngles, Vector3.zero,
ref rotationVelocity, recoveryTime);
}
void Update()
{
if (Player.Instance.updatePlayer)
{
if (playerCamera.gameObject.activeSelf)
{
CrosshairManager.Instance.SetDynamicCrossHair(65, 150, 10, 15, Player.Instance, weapon.reticletype,
weaponID);
if (Time.time - Player.Instance.lastReload < Player.Instance.reloadTime)
{
if (weapon.isSniper)
{
DisableSniperCrosshair();
}
anim.SetBool(Aim, false);
}
else
{
anim.SetBool(Aim, Player.Instance.IsAiming);
}
}
else
{
CrosshairManager.Instance.SetDynamicCrossHair(65, 150, 10, 15, Player.Instance,
WeaponCrosshairType.No_Reticle, weaponID);
}
if (Player.Instance.IsAiming)
{
AimWeapon();
}
else
{
UnAimTheWeapon();
}
}
RunState();
BulletSpreadStates();
}
private void BulletSpreadStates()
{
if (Player.Instance.IsMoving)
{
weapon.horizontalSpread = weapon.cachedHorizontalSpread * 2;
weapon.verticleSpread = weapon.cachedVerticleSpread * 2;
}
else if (!Player.Instance.IsAiming && Player.Instance.hasFiredWeapon && !weapon.isShotgun)
{
weapon.horizontalSpread = weapon.cachedHorizontalSpread / 2;
weapon.verticleSpread = weapon.cachedVerticleSpread / 2;
}
else if (Player.Instance.IsAiming && !weapon.isShotgun)
{
weapon.horizontalSpread = 0.0f;
weapon.verticleSpread = 0.0f;
}
else
{
weapon.horizontalSpread = weapon.cachedHorizontalSpread;
weapon.verticleSpread = weapon.cachedVerticleSpread;
}
}
private void RunState()
{
anim.SetBool("Run", Player.Instance.CanPlayRunningEvents());
}
/// <summary>
/// Call from miner weapon animation event
/// </summary>
public void OnMinerWeaponMineCall()
{
bool status = false;
var playerFirstPersonCamera = Player.Instance.GetPlayerFirstPersonCamera();
Vector3 screenCenter = new Vector3(Screen.width / 2f, Screen.height / 2f, 0f);
Ray ray = playerFirstPersonCamera.ScreenPointToRay(screenCenter);
float maxDistance = 2.1f;
var size = Physics.RaycastNonAlloc(ray, _results, maxDistance);
if (size > 0)
{
for (int i = 0; i < size; i++)
{
RaycastHit hit = _results[i];
if (hit.collider.CompareTag("Mining"))
{
Debugger.Logger("Mine successfully rock founded", ContextDebug.Session, Process.Update);
var effector = CallToTryPlayEffector(hit);
if (effector)
PacketManager.sendMineRock((int)effector.typeAxe);
else
PacketManager.sendMineRock((int)OreItemType.DEFULT);
var sound = CallToTryPlaySound(effector);
status = true;
}
if(status) break;
}
}
if (!status)
Debugger.Logger("Mine failed any rock not found", ContextDebug.Session, Process.Info);
anim.SetBool(Swing, false);
string CallToTryPlaySound(MineEffectorTypingObject type)
{
if (type == null) return null;
var effect = type.TryGetEffectByName(type.type);
var soundToPlay = Effect.ChooseRandom(effect.listOfSounds);
AudioManager.Instance.playSound(soundToPlay);
return soundToPlay;
}
MineEffectorTypingObject CallToTryPlayEffector(RaycastHit raycastHit)
{
var effectTyping = raycastHit.collider.gameObject.GetComponent<MineEffectorTypingObject>();
if (effectTyping)
{
effectTyping.CreateEffectByRayHit(raycastHit);
return effectTyping;
}
Debugger.Logger("EffectTyping is not on the object of collision", ContextDebug.Session, Process.Info);
return null;
}
}
public void playAnimation(float speedMultiplier, string name)
{
//check if you're not currently in reload state.
if (!anim.GetCurrentAnimatorStateInfo(0).IsName("Reload"))
{
if (name.Contains("Reload"))
{
anim.speed *= speedMultiplier;
}
else
{
anim.speed = 1;
}
anim.Play(name);
}
}
public void SetAnimatorSpeedToDefault()
{
anim.speed = 1;
}
private Coroutine enableSniperCrosshairRoutine;
private void AimWeapon()
{
playerCamera.fieldOfView = Mathf.SmoothDamp(playerCamera.fieldOfView, weapon.scopedFOV, ref aimVelocity,
weapon.zoomSpeed * 0.025f);
if (weapon.isSniper)
{
if (Player.Instance.IsAiming && !isScopped)
{
isScopped = true;
if (enableSniperCrosshairRoutine != null)
{
StopCoroutine(enableSniperCrosshairRoutine);
enableSniperCrosshairRoutine = null;
}
enableSniperCrosshairRoutine = StartCoroutine(EnableSniperCrosshair());
}
}
}
private void UnAimTheWeapon()
{
playerCamera.fieldOfView = Mathf.SmoothDamp(playerCamera.fieldOfView, weapon.normalFOV, ref aimVelocity,
weapon.zoomSpeed * 0.025f);
if (weapon.isSniper)
{
isScopped = false;
DisableSniperCrosshair();
}
}
private IEnumerator EnableSniperCrosshair()
{
yield return new WaitForSeconds(weapon.crosshairChangeTime);
sniperModel.SetActive(false);
leftArm.SetActive(false);
rightArm.SetActive(false);
CrosshairManager.Instance.SetSniperCrosshair(weapon.reticletype);
CrosshairManager.Instance.SetSniperCrosshairAlpha(1.0f);
enableSniperCrosshairRoutine = null;
}
private void DisableSniperCrosshair()
{
if (weapon.isSniper)
{
CrosshairManager.Instance.SetSniperCrosshairAlpha(0.0f);
leftArm.SetActive(true);
rightArm.SetActive(true);
sniperModel.SetActive(true);
isScopped = false;
if (enableSniperCrosshairRoutine != null)
{
StopCoroutine(enableSniperCrosshairRoutine);
enableSniperCrosshairRoutine = null;
}
}
}
private IEnumerator LerpCameraRecoil()
{
float startTime = Time.time;
float endTime = startTime + weapon.recoilDuration;
float yawRecoil = cameraRecoilRotation[0];
float randomPitch = Random.Range(cameraRecoilRotation[1], Mathf.Abs(cameraRecoilRotation[1]));
while (Time.time < endTime)
{
Player.Instance.ApplyRecoil(randomPitch,
yawRecoil * Time.deltaTime *
65); //const value of 65. To make it normal again. since Time.delaTime makes the values very small.
yield return null;
}
}
}
[System.Serializable]
public struct Range
{
public float Min;
public float Max;
public float Sample() => Random.Range(Min, Max);
}
public static class Vector3Utility
{
public static Vector3 SmoothDampAngle(Vector3 from, Vector3 to, ref Vector3 velocity, float smoothTime)
{
return new Vector3(
Mathf.SmoothDampAngle(from.x, to.x, ref velocity.x, smoothTime),
Mathf.SmoothDampAngle(from.y, to.y, ref velocity.y, smoothTime),
Mathf.SmoothDampAngle(from.z, to.z, ref velocity.z, smoothTime)
);
}
}