using System; using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.Networking; using EZCameraShake; using UnityEngine.InputSystem; using UnityEngine.Rendering; using Weapons.Projectiles; using Random = UnityEngine.Random; /** * A script attached to every player to handle visual effects */ public class PlayerEntity : MonoBehaviour { [System.NonSerialized] public PlayableCharacterSkin CurrentlyEquippedSkin = null; internal Volume volumeMain; internal Volume volumeMashroom; internal Material skyMain; internal Material skyMashroom; public Transform FirstPersonCameraPivot; [SerializeField] private List skinList = new List(); [SerializeField] private GameObject playerRendererBackgroundObjects; private static RuntimeAnimatorController meleeController; private static RuntimeAnimatorController gunController; private static RuntimeAnimatorController pistolController; private static RuntimeAnimatorController bowController; private static RuntimeAnimatorController gloveController; private int playerFlags; //player looking private Vector3 currVelocity = Vector3.zero; private float lookAngleOffset = 20.0f; private float playerLookAngle; //animator caching private static readonly int animator_VerticalLook = Animator.StringToHash("VerticalLook"); private static readonly int animator_xAxis = Animator.StringToHash("xAxis"); private static readonly int animator_zAxis = Animator.StringToHash("zAxis"); private static readonly int animator_Magnitude = Animator.StringToHash("VelocityMagnitude"); //float caching private const float constSmooth = 10.0f; //player rotation private Quaternion playerYRotation; //player animation floats private float playerAnimX; private float playerAnimZ; private float playerMagnitude; public string[] playerTextureURLS = new string[1]; private Texture2D playerSkinTexture; private Transform _Skins; [HideInInspector] public PlayerEntity SpectatedPlayer; [System.NonSerialized] public Camera spectatedPlayersThirdPersonCamera; [System.NonSerialized] public GameObject thirdPersonCameraObject; [SerializeField] internal List listOfManualInitWeaponslot = new List(); private void Awake() { if (meleeController == null) meleeController = OnDemandLoader.Load("Models/Player/Player_MeleeStance_Controller"); if (gunController == null) gunController = OnDemandLoader.Load("Models/Player/Player_GunStance_Controller"); if (bowController == null) bowController = OnDemandLoader.Load("Models/Player/Player_bowStance_Controller"); if (pistolController == null) pistolController = OnDemandLoader.Load("Models/Player/Player_pistolStance_Controller"); if (gloveController == null) gloveController = OnDemandLoader.Load("Models/Player/Glove_Controller"); Transform pCanvas = transform.Find("Canvas"); if (pCanvas != null) { ChatBubble = pCanvas.Find("CanvasContainer/ChatBubbleContainer/ChatBubble").GetComponent(); Transform nameGOTMPro = pCanvas.Find("CanvasContainer/Name"); if (nameGOTMPro != null) { PlayerEntityName = nameGOTMPro.GetComponent(); } } _Skins = transform.Find("Skins"); } public void Start() { animator = gameObject.GetComponent(); targetPosition = transform.position; lastUpdate = Time.time; if (GetComponent() == null) { Destroy(GetComponent()); Destroy(GetComponent()); PlayerInput input = GetComponent(); input.DeactivateInput(); if (input != null) { Destroy(input); } Destroy(GetComponent()); Destroy(GetComponent()); Destroy(transform.Find("FirstPersonCamera_Holder").gameObject); Destroy(transform.Find("PlayerUICamera").gameObject); Destroy(GetComponent()); Destroy(GetComponent()); Destroy(playerRendererBackgroundObjects); } InitWeaponSystems(); thirdPersonCameraObject = transform.Find("ThirdPerson_Camera").gameObject; thirdPersonCameraObject.SetActive(false); } internal void InitWeaponSystems() { GameObject weaponSlot = transform.Find("Root/Hips/Spine_01/Spine_02/Spine_03/Clavicle_R/Shoulder_R/Elbow_R/Hand_R/Weapon").gameObject; foreach (Transform weapon in weaponSlot.transform) { thirdPersonWeaponList.Add(weapon.gameObject); } foreach (var weapon in listOfManualInitWeaponslot) { thirdPersonWeaponList.Add(weapon.gameObject); } foreach (GameObject weaponObj in thirdPersonWeaponList) { thirdPersonWeaponDictionary[int.Parse(weaponObj.name)] = weaponObj; } } private void Update() { //don't do processing for main player here.. do it in player.cs if (id == -1) { return; } //remove Entity if last update is over 5 seconds long. if (Time.time - lastUpdate > 5.0f) { PlayerManager.Instance.RemovePlayer(this); return; } InterpolateEntity(); } private void FixedUpdate() { if (id == -1) { return; } InterpolateAnimation(); terrainHeightFix(); } public void spectatePlayer(int playerId) { PlayerEntity player = PlayerManager.Instance.GetPlayer(playerId).GetComponent(); spectatedPlayersThirdPersonCamera = player.thirdPersonCameraObject.GetComponent(); spectatedPlayersThirdPersonCamera.gameObject.SetActive(true); } private void InterpolateEntity() { InterpolatePosition(); InterpolateRotation(); } public void ResetJumpTrigger() //used in animation event { animator.ResetTrigger("Jump"); } private void InterpolatePosition() { float distance = Vector3.Distance(transform.position, targetPosition); //Debug.Log($"Player: {gameObject.name} is {distance} units away from where they should be!"); if (distance >= 10f) { transform.position = targetPosition; } else { transform.position = Vector3.SmoothDamp(transform.position, targetPosition, ref currVelocity, 0.1f); } } private void InterpolateRotation() { Vector3 euler = transform.eulerAngles; euler.y = Mathf.LerpAngle(euler.y, playerYRotation.eulerAngles.y, constSmooth * Time.deltaTime); transform.eulerAngles = euler; } private void InterpolateAnimation() { animator.SetFloat(animator_VerticalLook, Mathf.Lerp(animator.GetFloat(animator_VerticalLook), playerLookAngle + lookAngleOffset, constSmooth * Time.deltaTime)); animator.SetFloat(animator_xAxis, Mathf.Lerp(animator.GetFloat(animator_xAxis), playerAnimX, constSmooth * Time.deltaTime)); animator.SetFloat(animator_zAxis, Mathf.Lerp(animator.GetFloat(animator_zAxis), playerAnimZ, constSmooth * Time.deltaTime)); animator.SetFloat(animator_Magnitude, Mathf.Lerp(animator.GetFloat(animator_Magnitude), playerMagnitude, constSmooth * Time.deltaTime)); if ((playerFlags & 0x02) == 0x02) { animator.SetTrigger("Jump"); } animator.SetBool("Aiming", (playerFlags & 0x01) == 0x01); } public void ProcessUpdateMessage(int id, float x, float y, float z, float rotationY, float lookAngle, string name, float animX, float animZ, float magnitude, int flags, string forceAnim) { if (PlayerEntityName != null) { Debug.Log(PlayerEntityName); PlayerEntityName.text = name; playerName = name; } lastPacketPosition = transform.position; targetPosition = new Vector3(x, y, z); velocity = targetPosition - lastPacketPosition; //playerYRotation is cached rotation and calculated outside of the 10 updates a second step. playerYRotation = Quaternion.Euler(transform.rotation.eulerAngles.x, rotationY, transform.rotation.eulerAngles.z); playerLookAngle = lookAngle; //animation interpolation caching playerAnimX = animX; playerAnimZ = animZ; playerMagnitude = magnitude; playerFlags = flags; if (forceAnim.Length > 0) { animator.Play(forceAnim); } lastUpdate = Time.time; } public void setWeapon(int itemId) { Weapon.WEAPON_TYPE weaponType = ItemDef.GetInstance().getType(itemId); lookAngleOffset = 20.0f; switch (weaponType) { case Weapon.WEAPON_TYPE.NONE: break; case Weapon.WEAPON_TYPE.GUN: animator.runtimeAnimatorController = gunController; break; case Weapon.WEAPON_TYPE.BOW: animator.runtimeAnimatorController = bowController; break; case Weapon.WEAPON_TYPE.SWORD: lookAngleOffset = 20f; //animations are angled down more. so decrease the offset. animator.runtimeAnimatorController = meleeController; break; case Weapon.WEAPON_TYPE.PISTOL: lookAngleOffset = 5f; //animations are angled down more. so decrease the offset. animator.runtimeAnimatorController = pistolController; break; case Weapon.WEAPON_TYPE.MINER: lookAngleOffset = 5f; animator.runtimeAnimatorController = meleeController; break; case Weapon.WEAPON_TYPE.GLOVE: animator.runtimeAnimatorController = gloveController; lookAngleOffset = 5f; break; } this.weaponId = itemId; this.projectileOrigin = null; GameObject weaponSlot = transform.Find("Root/Hips/Spine_01/Spine_02/Spine_03/Clavicle_R/Shoulder_R/Elbow_R/Hand_R/Weapon").gameObject; foreach (Transform child in weaponSlot.transform) { child.gameObject.SetActive(false); } foreach (var manualSlots in listOfManualInitWeaponslot) { manualSlots.gameObject.SetActive(false); } Debug.Log($"Activate {itemId}"); if (itemId != -1) { if (thirdPersonWeaponDictionary.TryGetValue(itemId, out var valWeapon)) { valWeapon.SetActive(true); currentWeapon = valWeapon; SetLayerRecursively(currentWeapon, "Default"); } } } private void SetLayerRecursively(GameObject obj, string newLayer) { if (obj == null) { return; } obj.layer = LayerMask.NameToLayer(newLayer); foreach (Transform child in obj.transform) { if (child == null) { continue; } SetLayerRecursively(child.gameObject, newLayer); } } public IEnumerator processWeaponFire(Vector3 direction, string projectile) { if (ItemDef.GetInstance().isThrowable(weaponId)) { animator.Play("3D_ThrowNade"); yield return new WaitForSeconds(0.7f); fireProjectile(direction, projectile); } else { fireProjectile(direction, projectile); animator.Play("3D_Shoot"); } } public Vector3 GetProjectileOrigin() { if (projectileOrigin) return projectileOrigin.transform.position; else { return Vector3.zero;; } } public void SetSkin(string skin) { //Debug.Log("setting skin " + skin); PlayableCharacterSkin currentlyEquiptSkin = _Skins.Find(skin).GetComponent(); CurrentlyEquippedSkin = currentlyEquiptSkin; for (int i = 0; i < skinList.Count; i++) { //Debug.Log($"Searching for {skins[i]}- result: {transform.Find(skins[i])}"); try { skinList[i].DeactivateSkin(); } catch (Exception e) { Debug.Log(e.ToString()); } } currentlyEquiptSkin.ActivateSkin(); if (GetComponent() != null && UIManager.Instance.IsGameLobbyCanvasesActive()) { //client side stats. Rest are server side. SetSpecialStat(skin); } } private void SetSpecialStat(string skin) { PreGameManager.Instance.SetSpecialStat(skin); } public IEnumerator GetAndSetPlayerTexture(GameObject mainPlayer) { int randTexture = Random.Range(0, 5); UnityWebRequest www = UnityWebRequestTexture.GetTexture(playerTextureURLS[0]); yield return www.SendWebRequest(); playerSkinTexture = DownloadHandlerTexture.GetContent(www); //Debug.Log("Decal successfully Loaded!" + texture); foreach (SkinnedMeshRenderer playerModel in mainPlayer.GetComponentsInChildren()) { if (!playerModel.enabled || !playerModel.gameObject.name.Contains("Character_")) { continue; } //Debug.Log($"{playerModel.gameObject.name} did not contain \"Character_\" and enable was {playerModel.enabled}"); playerModel.material.SetTexture("_BaseMap", playerSkinTexture); } } public bool IsFuturisticWeapon() { if (weaponId == 0 || weaponId == 4 || weaponId == 5 || weaponId == 6 || weaponId == 12) { return true; } return false; } public void fireProjectile(Vector3 direction, string projectile) { if (projectile == null) return; if (projectileOrigin == null) return; var qTargetRotateProjectile = Quaternion.identity; var isFlameProjectile = false; if (projectile == "Level_1_FlameAttack"|| projectile == "Level_2_FlameAttack"|| projectile == "Level_3_FlameAttack"|| projectile == "Level_4_FlameAttack"|| projectile == "Level_5_FlameAttack"|| projectile == "Level_6_FlameAttack"|| projectile == "Level_7_FlameAttack" ) { isFlameProjectile = true; qTargetRotateProjectile = projectileOrigin.transform.rotation; } GameObject pooledProjectile = null; if (!isFlameProjectile) pooledProjectile = NetworkPooler.Instance.PooledInstantiate(projectile, projectileOrigin.transform.position,qTargetRotateProjectile); if (projectile != "Grenade" && !isFlameProjectile) { pooledProjectile.GetComponent().ApplyForce(direction); } else if (isFlameProjectile) { var current = thirdPersonWeaponDictionary[weaponId]; projectileOrigin = current.transform.Find("projectileOrigin")?.gameObject; projectileOrigin.transform.GetComponent().InstantiateOrigin(this, projectileOrigin.transform, projectile); } else { pooledProjectile.GetComponent().ApplyForce(direction, 10); } if (id != -1) { //only create muzzleflashes for none-main player. Main player muzzleflash are handled seperately. if (IsFuturisticWeapon()) { NetworkPooler.Instance.PooledPlayEffect("FuturisticMuzzleFlash", projectileOrigin.transform.position, projectileOrigin.transform.rotation, 3.0f); } else { //Debug.Log("Not a futuristic weapon,"); //exclude rocket launcher and grenade from the muzzleflash. We can make it have it if neeed. Remove this if check. if (weaponId != 14 && weaponId != 23) { //Debug.Log("Playing MuzzleFlash!"); NetworkPooler.Instance.PooledPlayEffect("NormalMuzzleFlash", projectileOrigin.transform.position, projectileOrigin.transform.rotation, 3.0f); } } } //if bullet didnt hit anything. Disable it after 10 seconds. NetworkPooler.Instance.PooledDestroy(projectile, pooledProjectile, 10.0f); } private void terrainHeightFix() { Terrain terrain = Misc.GetClosestCurrentTerrain(transform.position); float height = terrain.SampleHeight(transform.position); if (transform.position.y < height) { transform.position = new Vector3(transform.position.x, height, transform.position.z); } } public int GetID() { return id; } public void SetID(int id) { this.id = id; } public string GetVoiceID() { return voiceID; } public void SetVoiceID(string voiceID) { this.voiceID = voiceID; } public int GetSkinID() { return skinList.IndexOf(CurrentlyEquippedSkin); } public void SetLastPositionAfterTeleportation(Vector3 vector3) { lastPacketPosition = vector3; targetPosition = vector3; } private void OnTriggerEnter(Collider other) { if (other.CompareTag("PPdetector")) { if (id == -1) { OnDetectPP?.Invoke(); volumeMain.gameObject.SetActive(false); volumeMashroom.gameObject.SetActive(true); RenderSettings.skybox = skyMashroom; } } } private void OnTriggerExit(Collider other) { if (other.CompareTag("PPdetector")) { if (id == -1) { OnDetectClosePP?.Invoke(); volumeMain.gameObject.SetActive(true); volumeMashroom.gameObject.SetActive(false); RenderSettings.skybox = skyMain; } } } public string GetName() => playerName; public static event Action OnDetectPP; public static event Action OnDetectClosePP; [HideInInspector] public GameObject projectileOrigin; [HideInInspector] public int weaponId; public ChatBubble ChatBubble { get; internal set; } private int id = -1; private string voiceID = "null"; [HideInInspector] public Animator animator; private float lastUpdate; private Vector3 lastPacketPosition; private Vector3 targetPosition; private Vector3 velocity; [System.NonSerialized] public TextMeshProUGUI PlayerEntityName; private string playerName; [HideInInspector] public GameObject currentWeapon; private List thirdPersonWeaponList = new List(); private readonly Dictionary thirdPersonWeaponDictionary = new Dictionary(); }