using System.Collections; using System.Collections.Generic; using Assets.HeroEditor4D.Common.Scripts.CharacterScripts; using Assets.HeroEditor4D.Common.Scripts.Enums; using Mirror; using TMPro; using Firebase.Firestore; using Firebase.Extensions; using Unity.VisualScripting; using UnityEngine; using UnityEngine.SceneManagement; using GooglePlayGames; using UnityEngine.SocialPlatforms; using Firebase.Auth; using UnityEngine.UI; using Newtonsoft.Json; public class playerNetwork : NetworkBehaviour { public const float ATTACK_COOLDOWN = 0.6f; [HideInInspector] public StatManager statManager; //public const int XPFORLEVEL = 10; [SyncVar(hook =nameof(OnHealthChanged))] public int health = 100; public Character4D character; public characterManager characterMan; [SyncVar(hook =nameof(OnDirectionChanged))] public Vector2 directionNetwork; [SyncVar(hook =nameof(OnAnimChanged))] public int animIntNetwork; [SyncVar(hook = nameof(onKillCountChange))] public int enemyKillCount; // public int xp { get{ // int val = 0; // for(int i =5; i <= enemyKillCount; i+=5){ // val = enemyKillCount; // } // return val; // }} [SyncVar(hook = nameof(OnXpChanged))] public int XP; public int lvl2 { get{ return GetLevelForKills2(enemyKillCount); }} public int GetLevelForKills2(int kills){ int val = 0; for(int i =10; i <= kills; i+=10){ val ++; } return val; } public int lvl{ get{ return GetLevelByXp(XP); } } public int GetLevelByXp(int xp){ // int level = Mathf.CeilToInt(Mathf.Sqrt(xp/100f)); // if(level <= 0){level = 1;} // return level; int level = Mathf.CeilToInt(Mathf.Log(xp / 100f,2) + 1); if(level <=0){level = 1;} return level; // int level = 1; // int xpNeeded = 100; // while (xp >= xpNeeded) // { // level++; // xpNeeded = 100 * (int)Mathf.Pow(2, level - 1); // } // return level - 1; } public int GetXpForLevel(int level){ if (level <= 0) level = 1; return Mathf.FloorToInt(100 * Mathf.Pow(2, level - 1)); } public float XpSliderVal{ get{ int nextLevelXp = GetXpForLevel(lvl); int prevLevelXp = GetXpForLevel(lvl-1); if(nextLevelXp == prevLevelXp){ prevLevelXp = 0; } int range = nextLevelXp - prevLevelXp; // Debug.Log($"{XP-prevLevelXp} / {range}"); //Debug.Log($"next : {nextLevelXp}, prev: {prevLevelXp}, xp:{XP}, xpSince:{XP-prevLevelXp}"); return ((float)(XP-prevLevelXp) / (float)range); // int nextLevel = lvl+1; // int curLevelXp = lvl * lvl; // int nextLevelXp = nextLevel * nextLevel; // // Debug.Log($"Xp Calc: {XP}-{curLevelXp}/{nextLevelXp} - {curLevelXp}"); // // Debug.Log($"{curLevelXp-XP}/{nextLevelXp - curLevelXp}"); // if(XP == 0){return 0;} // return 1f - ((float)(curLevelXp - XP) / (float)(nextLevelXp- curLevelXp)); } } [SyncVar] public string playerName; [SyncVar] public int playerCoin; public TMP_Text txtEnemyKillCount; public TMP_Text txtPlayerName; public TMP_Text questText; public GameObject questUI; public TMP_Text coinText; public TMP_Text xpText; public TMP_Text lvlText; public Slider xpSlider; public GameObject[] xpSliderSlots; public TMP_Text xpEnableTxt; //public TMP_Text attackDmgEnableTxt; public GameObject canvas; public Slider healthBar; public Slider armorBar; public Inventory inventory; public static Transform localPlayerTransform; public GameObject healthVfx; public GameObject damageVfx; public GameObject levelUpVfx; public QuestScriptable currentQuest; public List questActions; public List completedQuests; public GameObject projectile; public void QuestFunction(QuestScriptable questData){ currentQuest = questData; questText.text = questData.questTitle; questUI.SetActive(true); foreach(QuestAction quest in questActions){ if(quest.questData == questData){ quest.activate(); } } } public void CompleteQuest(QuestScriptable questData){ if(questData != currentQuest){ Debug.LogError("Completed a quest that wasnt even active"); return; } completedQuests.Add(currentQuest.name); currentQuest = null; questText.text = "Quest Completed! Found 1000 coins from Cave-Chest"; playerCoin += questData.rewardAmount; coinText.text = playerCoin.ToString(); //add delay StartCoroutine(DelayUI()); } IEnumerator DelayUI(){ yield return new WaitForSecondsRealtime(10f); questUI.SetActive(false); } public static void registerQuestAction(QuestAction action){ localPlayerTransform.GetComponent().questActions.Add(action); } void Start(){ // for(int i =0; i < 2000; i+=10){ // int level = GetLevelByXp(i); // int xp = GetXpForLevel(level); // Debug.Log($"{i} : {level} : {xp}"); // } if(!isLocalPlayer){ canvas.SetActive(false); }else{ localPlayerTransform = transform; cameraRPG.instance.SetTarget(transform); #if UNITY_EDITOR ResetHealthAndArmor(); #else LoadPlayerData(); #endif statManager.OnStatsChanged += ConfigArmorHealthSliders; if(isServer){ playerName = gplayAuth.userNameCloud; } else{ CmdSetName(gplayAuth.userNameCloud); } } } public void SavePlayerData(){ #if UNITY_EDITOR return; #endif Debug.Log("*** Save Method Got Called ! ***"); if(!isLoaded){ Debug.Log("*** Save Method Return ***"); return; } FirebaseFirestore db = FirebaseFirestore.DefaultInstance; //int playerCoin = int.Parse(coins.text); Dictionary saveValues = new Dictionary{ {"playerInventory" , JsonConvert.SerializeObject(inventory.inventoryManager.GetEntries())}, {"playerHealth" , health}, {"playerCoin", playerCoin}, {"killCount", enemyKillCount}, {"xp", XP}, {"completedQuest", completedQuests}, {"playerStats", statManager.PlayerStats}, }; DocumentReference docRef = db.Collection("PlayerData").Document(gplayAuth.userID); docRef.SetAsync(saveValues).ContinueWithOnMainThread(task => { if(task.IsCompleted){ Debug.Log("**** Save Completed Firestore ****"); } else{ Debug.Log("**** Failed to save data to firestore ****"); } }); } public bool isLoaded = false; public void LoadPlayerData(){ #if UNITY_EDITOR return; #endif Debug.Log("**** Data Load method got called ****"); FirebaseFirestore db = FirebaseFirestore.DefaultInstance; DocumentReference docRef = db.Collection("PlayerData").Document(gplayAuth.userID); docRef.GetSnapshotAsync().ContinueWithOnMainThread(task => { DocumentSnapshot snapshot = task.Result; if(snapshot.Exists){ Debug.Log("**** Found previous Data to load ****"); //load data // Dictionary dic = snapshot.ToDictionary(ServerTimestampBehavior.Estimate); // Debug.Log("Reading data"); // foreach(KeyValuePair item in dic){ // Debug.Log(item.Key + " : " +item.Value.ToString()); // } //saveNameTxt.text = snapshot.GetValue("playerName"); //load kills int _enemyKillCount = snapshot.GetValue("killCount"); SetEnemyKillCount(_enemyKillCount); //load XP XP = snapshot.GetValue("xp"); //Load coin int _playerCoin = snapshot.GetValue("playerCoin"); SetPlayerCoins(_playerCoin); // coinText.text = snapshot.GetValue("playerCoin").ToString(); //Load Health int savedHealth = snapshot.GetValue("playerHealth"); SetHealth(savedHealth); ResetHealthAndArmor(); healthBar.value =(savedHealth); armorBar.value = savedHealth; //load Inventory Dictionary inventoryGetData = JsonConvert.DeserializeObject>(snapshot.GetValue("playerInventory")); inventory.inventoryManager.SetInventory(inventoryGetData); completedQuests = snapshot.GetValue>("completedQuest"); statManager.loadFromCloudSave(snapshot.GetValue>("playerStats")); isLoaded = true; }else{ //show error previous data doesnt exists to load Debug.Log("**** No previous data to load ****"); isLoaded = true; } }); } void CmdSetName(string nameValue){ playerName = nameValue; } void OnDirectionChanged(Vector2 oldVal, Vector2 newVal){ character.SetDirection(newVal); } void OnAnimChanged(int oldVal, int newVal){ if(isLocalPlayer){return;} character.AnimationManager.SetState((CharacterState)newVal); } float attackTimer = 0; [HideInInspector] public PlayerAttack playerAttack; void Update(){ if(isLocalPlayer){ if(attackTimer >0){attackTimer-=Time.deltaTime;} if(isServer){ SetAnimationData(character.Direction, character.Animator.GetInteger("State")); }else{ CmdUpdateAnim(character.Direction, character.Animator.GetInteger("State")); } healthBar.value =(health); armorBar.value = health; txtEnemyKillCount.text = enemyKillCount.ToString(); coinText.text = playerCoin.ToString(); txtPlayerName.text = gplayAuth.userNameCloud; } ShowXP(); ShowLevel(); } [Command] void CmdUpdateAnim(Vector2 direction, int animState){ SetAnimationData(direction, animState); } void SetAnimationData(Vector2 direction, int animState){ directionNetwork = direction; animIntNetwork = animState; if(!isLocalPlayer){ character.AnimationManager.SetState((CharacterState)animState); character.SetDirection(direction); } } void OnHealthChanged(int oldVal, int newVal){ if(!isLocalPlayer){return;} // if(oldVal < newVal){ GameObject newObject = Instantiate(healthVfx , character.characterTransform()); newObject.transform.localPosition = Vector3.zero; newObject.transform.parent = transform; //StartCoroutine (Couroutine_autoDisableVFX(newObject)); vfxScript vfxSc = newObject.AddComponent(); }else if (oldVal > newVal ){ //damage VFX GameObject newObject = Instantiate(damageVfx , character.characterTransform()); newObject.transform.localPosition = new Vector3(0, 5f, 0); newObject.transform.parent = transform; //StartCoroutine (Couroutine_autoDisableVFX(newObject)); vfxScript vfxSc = newObject.AddComponent(); // vfxSc.offsetVFX = new Vector3(0, 5f, 0); // vfxSc.target = character.characterTransform(); } SavePlayerData(); healthBar.value =(newVal); armorBar.value = newVal; } // IEnumerator Couroutine_autoDisableVFX(GameObject go){ // yield return new WaitForSecondsRealtime(5f); // Destroy(go); // } void onKillCountChange(int oldval, int newval){ if(!isLocalPlayer){return;} // int prevLevel = GetLevelForKills(oldval); // int newLevel = GetLevelForKills(newval); SavePlayerData(); // if(newLevel > prevLevel){ // StartCoroutine(uiTxtDelay(25f)); // } // if(enemyKillCount == 5 ){ // //SavePlayerData(); // //QuestComplete(); // AddCoin(); // } } void OnXpChanged(int oldVal, int newVal){ if(!isLocalPlayer){return;} int prevLevel = GetLevelByXp(oldVal); int newLevle = GetLevelByXp(newVal); if(newLevle > prevLevel){ int levelChange = newLevle - prevLevel; GameObject newObject = Instantiate(levelUpVfx , character.characterTransform()); newObject.transform.localPosition = Vector3.zero; newObject.transform.parent = transform; StartCoroutine(uiTxtDelay(25f, levelChange)); } } public void SetHealth(int newvalue){ if(isServer){ health = newvalue; healthBar.value =(newvalue); armorBar.value = newvalue; }else{ CmdSetHealth(newvalue); } } public void SetEnemyKillCount(int newValue){ if(isServer){ enemyKillCount = newValue; }else{ CmdSetEnemyKillCount(newValue); } } public void SetPlayerCoins(int newVal){ if(isServer){ playerCoin = newVal; }else{ CmdSetPlayerCoin(newVal); } } [Command] void CmdSetPlayerCoin(int newVal){ playerCoin = newVal; } [Command] void CmdSetEnemyKillCount(int newValue){ enemyKillCount = newValue; } [Command] void CmdSetHealth(int newValue){ health = newValue; } public void TakeDamage(int attackDamage){ serverTakeDmg(attackDamage); // if(isLocalPlayer){ // takedmg(attackDamage); // }else if(isServer){ // RpcTakeDamage(attackDamage); // } } void serverTakeDmg(int damage){ health -= damage; if(health <=0){ RpcDeath(); death(); } } float xpTimer = 0; public void ShowXP(){ if(xpTimer >0){xpTimer -= Time.deltaTime;return;} xpTimer = 1; xpText.text = (Mathf.RoundToInt(XP/100f) * 100f).ToString(); xpSlider.value = XpSliderVal; for(int i=0; i < 10; i++){ float val = (float)i /10f; xpSliderSlots[i].SetActive(xpSlider.value > val); } } public void ShowLevel(){ lvlText.text = lvl.ToString(); } public void OnEnemyKilled(int enemyLevel){ //disable take damage and disable healthbar going backwards int prevValue = lvl; // SavePlayerData(); enemyKillCount++; //XP += (int)(enemyScript.XP_GAIN * (enemyLevel/2f)); XP += enemyScript.XP_GAIN_Base + Mathf.FloorToInt(enemyScript.XP_GAIN * (enemyLevel-1)); } IEnumerator uiTxtDelay (float delayTime, int levelChange){ //enable xpEnableTxt.gameObject.SetActive(true); //int attackDamageChange= 5 * levelChange; //attackDmgEnableTxt.gameObject.SetActive(true); //attackDmgEnableTxt.text = "Attack Damage + " + attackDamageChange; yield return new WaitForSecondsRealtime(delayTime); //disable xpEnableTxt.gameObject.SetActive(false); //attackDmgEnableTxt.gameObject.SetActive(false); } // public void QuestComplete(){ // //task completion logic // // Strikethrough the text // //questText.text = "Kill 5 Enemies to claim 100Golds Completed"; // Debug.Log("First quest completed"); // } public void AddCoin(){ playerCoin += 100; coinText.text = playerCoin.ToString(); } [ClientRpc] public void RpcDeath(){ death(); } public bool isDead = false; public void death(){ Debug.Log("Death called"); character.AnimationManager.Die(); isDead = true; StartCoroutine(CouroutineWaitDeath()); // throw new System.Exception(); } IEnumerator CouroutineWaitDeath (){ yield return new WaitForSecondsRealtime(3); isDead = false; playerRespawn(); } public void OnAttack(){ if(attackTimer > 0){ return; } characterMan.SetActiveWeapon(78); attackTimer = ATTACK_COOLDOWN; if(isLocalPlayer){ PlayAttackAnim(); playerAttack.Attack(false); if(isServer){ RpcPlayAttackAnim(); }else{ CmdPlayAttackAnim(); } } } public int MagicAttackWeaponIndex = 52; public void OnMagicAttack(){ if(attackTimer > 0){ return; } attackTimer = ATTACK_COOLDOWN; characterMan.SetActiveWeapon(MagicAttackWeaponIndex); if(isLocalPlayer){ PlayAttackAnim(); //? playerAttack.MagicalAttack(); playerAttack.Attack(true); if(isServer){ RpcPlayAttackAnim(); }else{ CmdPlayAttackAnim(); } } } [Command] void CmdPlayAttackAnim(){ PlayAttackAnim(); RpcPlayAttackAnim(); } [ClientRpc] void RpcPlayAttackAnim(){ if(isLocalPlayer){return;} PlayAttackAnim(); } void PlayAttackAnim(){ switch (character.WeaponType) { case WeaponType.Melee1H: case WeaponType.Paired: character.AnimationManager.Slash(twoHanded: false); break; case WeaponType.Melee2H: character.AnimationManager.Slash(twoHanded: true); break; case WeaponType.Bow: character.AnimationManager.ShotBow(); break; } } public void playerRespawn(){ Debug.Log("Respawning"); // healthBar.SetMaxHealth(statManager.GetEffectiveValue("health")); ResetHealthAndArmor(); healthBar.value = health; character.AnimationManager.SetState(CharacterState.Idle); Transform newSpawnLocationPlayer = GameManager.instance.spawnPointsPlayer.GetChild(Random.Range(0,GameManager.instance.spawnPointsPlayer.childCount)); transform.position = newSpawnLocationPlayer.position; } void ResetHealthAndArmor(){ healthBar.maxValue = statManager.GetEffectiveValue("health"); health = statManager.GetEffectiveValue("health") + statManager.GetEffectiveValue("defence"); // Debug.Log($"Setting armor bar, maxVal:{health}, minVal:{healthBar.maxValue}, val:{health}"); armorBar.maxValue = health; armorBar.minValue = healthBar.maxValue; armorBar.value = health; } void ConfigArmorHealthSliders(){ healthBar.maxValue = statManager.GetEffectiveValue("health"); float maxHealth = statManager.GetEffectiveValue("health") + statManager.GetEffectiveValue("defence"); // Debug.Log($"Setting armor bar, maxVal:{health}, minVal:{healthBar.maxValue}, val:{health}"); armorBar.maxValue = maxHealth; armorBar.minValue = healthBar.maxValue; armorBar.value = health; healthBar.value = health; } //Pickup public void PickupObject(pickup item){ if(!isServer){ Debug.LogError("Cant call command on client, 403"); return; } if(isLocalPlayer){ pickupObject(item.lootData.type); }else{ RpcPickupObject(item.lootData.type); } } [ClientRpc] void RpcPickupObject(string type){ if(isLocalPlayer){ pickupObject(type); } } void pickupObject(string type){ inventory.AddItem(type); } public void DropPickup(string type){ if(isServer){ GameManager.instance.SpawnPickup(type,transform.position + new Vector3(0.85f,0.6f)); }else{ CmdDropPickup(type); } } [Command] void CmdDropPickup(string type){ GameManager.instance.SpawnPickup(type,transform.position + new Vector3(4,0)); } int magicalDmg = 0; public void MagicalAttack(Vector3 direction, float magicalProjectileSpawnOffset, int dmg) { if (isServer) { magicalAttack(direction, magicalProjectileSpawnOffset, dmg); } else { CmdMagicalAttack(direction, magicalProjectileSpawnOffset, dmg); } } [Command] void CmdMagicalAttack(Vector3 direction, float magicalProjectileSpawnOffset, int dmg) { magicalAttack(direction, magicalProjectileSpawnOffset, dmg); } void magicalAttack(Vector3 direction, float magicalProjectileSpawnOffset, int dmg) { magicalDmg = dmg; GameObject projectileSpawned = Instantiate(projectile, transform.position + (direction * magicalProjectileSpawnOffset), Quaternion.identity); RangeProjectile _projectile = projectileSpawned.GetComponent(); _projectile.direction = direction; _projectile.OnHit.AddListener(OnMagicalHit); _projectile.shooterId = netId; NetworkServer.Spawn(projectileSpawned); } void OnMagicalHit(enemyScript victim) { int damageamount = magicalDmg + (lvl * 5); victim.TakeMagicalDamage(damageamount, netId); } public void GoBackMenu(){ startClient.instance.networkManager.StopClient(); SceneManager.LoadScene("GameLogin"); #if UNITY_EDITOR || UNITY_SERVER || UNITY_STANDALONE_WIN #else PlayGamesPlatform.Instance.SignOut(); Firebase.Auth.FirebaseAuth.DefaultInstance.SignOut(); #endif } }