question

hapygames avatar image
hapygames asked

Recieving the wrong Statistics

Good day,

I have (an issue / a problem) regarding to the Player Statistics.

In this scenario I have 2 Scripts called HealthSystem and CustomAccountManagement.


HealthSystem: This Script manages the Health of the Players

CustomAccountManagement: This Script has all the PlayFab requests.

My (issue / problem) looks in an example like this:

Device 1 (Player 1) recieves his statistic PlayerHealth, after logging in successfully, with a value of 5.

The Script HealthSystem has the float maxHealth which is being set equal to the statistic PlayerHealth, which means the float maxHealth is being set to a value of 5.

Device 2 (Player 2) recieves his statistic PlayerHealth, after logging in successfully, with a value of 2.

The Script HealthSystem has the float maxHealth which is being set equal to the statistic PlayerHealth of the first Device which means the float maxHealth is being also set to a value of 5.

And this shouldn´t happen because the float maxHealth of the second Device should be set to a value of 2.

HealthSystem Script:

using System;
using UnityEngine;
using Photon.Pun;
using TMPro;
using System.Collections;
using System.Collections.Generic;


public class HealthSystem : MonoBehaviourPunCallbacks, IPunObservable
{
    public event EventHandler OnHealthChanged;


    public HealthBar healthBar;


    private TMP_Text healthText;


    public float maxHealth;
    public float health;


    int spawnPickerPlayer;
    int spawnPickerEnemy;
    
    private void Start()
    {
        if (gameObject.CompareTag("Enemy"))
        {
            maxHealth = 1000;
            health = maxHealth;
        }
        
        if (gameObject.CompareTag("MeshPlayer"))
        {
            GetCharacterHealth();
        }
        StartCoroutine(GetNeededComponents());
        StartCoroutine(OnPlayerDeath());
    }


    public void GetCharacterHealth()
    {
        maxHealth = CustomAccountManagement.CSM.playerHealth;
        health = maxHealth;


        //healthText.text = "Health: " + health;


        //Debug.Log("Invoked GetCharacterHealth");
    }


    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        //synchronize Health
        if (stream.IsWriting)
        {
            stream.SendNext(health);
        }
        else
        {
            health = (float)stream.ReceiveNext();
        }
    }


    public float GetHealth()
    {
        return health;
    }


    public float GetHealthPercentage()
    {
        return health / maxHealth;
    }




    public void Damage(float damageAmount)
    {
        health -= damageAmount;
        if (health < 0) health = 0;
        if (OnHealthChanged != null) OnHealthChanged(this, EventArgs.Empty);
        healthBar.SetHealth();
        if (gameObject.CompareTag("Enemy")) { healthText.text = "Health: " + (int)health; }
    }


    public void Heal(float healAmount)
    {
        health += healAmount;
        if (health > maxHealth) health = maxHealth;
        if (OnHealthChanged != null) OnHealthChanged(this, EventArgs.Empty);
        healthBar.SetHealth();
        if(gameObject.CompareTag("Enemy")) { healthText.text = "Health: " + (int)health; }
    }


    IEnumerator GetNeededComponents()
    {
        yield return new WaitForSeconds(0.1f);


        if (gameObject.CompareTag("Enemy"))
        {
            healthText = GetComponentInChildren<TextMeshProUGUI>();
            healthText.text = "Health: " + (int)health;
        }
        healthBar = GetComponentInChildren<HealthBar>();
        healthBar.SetMaxHealth();
        StopCoroutine(GetNeededComponents());
        yield break;
    }


    private void RespawnPlayer()
    {
        if(this.CompareTag("MeshPlayer"))
        {
            this.gameObject.transform.position = GameSetup.GS.spawnPoints[spawnPickerPlayer].position;
        }
        else if(this.gameObject.CompareTag("Enemy"))
        {
            this.gameObject.transform.position = GameSetup.GS.wayPoints[spawnPickerEnemy].position;
        }


        Heal(maxHealth);


        if (gameObject.CompareTag("Enemy")) { healthText.text = "Health: " + (int)health; }


        this.gameObject.SetActive(true);


        StartCoroutine(OnPlayerDeath());
    }


    IEnumerator OnPlayerDeath()
    {
        yield return new WaitUntil(() => GetHealthPercentage() <= 0);
        {
            Debug.Log("Player Died");
            this.gameObject.SetActive(false);


            spawnPickerPlayer = UnityEngine.Random.Range(0, GameSetup.GS.spawnPoints.Length);
            spawnPickerEnemy = UnityEngine.Random.Range(0, GameSetup.GS.wayPoints.Length);


            Invoke("RespawnPlayer", 2);


            StopCoroutine(OnPlayerDeath());
        }
    }
}


CustomAccountManagement Script (only with the login functions and the Player Statistics request):

Important Detail to know: This Script is a Singleton and doesn´t destroy on load.

using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
using PlayFab.ClientModels;
using PlayFab;
using PlayFab.CloudScriptModels;
using TMPro;
using Photon.Pun;
using System;
using UnityEngine.SceneManagement;
using PlayFab.MultiplayerModels;
using System.Linq;


public class CustomAccountManagement : MonoBehaviourPunCallbacks
{

    public static CustomAccountManagement CSM;


    public LoginWithEmailAddressRequest loginWithEmail;


    public string userEmail;
    public string userPassword;
    public string username;


    public TMP_Text errorMessage;
    public TMP_Text reasonAndTime;


    //Virtual Currency
    public GetPlayerCombinedInfoRequestParams playerInfo;


    public int currentScene;
    private int loginScene = 1;


    [Header("Player Data")]
    public int HappyCoins;
    public int playerLevel;
    public int attackDamage;
    public int playerHealth;
    public int speedLevel;





    #region MobileGuestLogin
    //Mobile Guest Login
    private void MobileGuestLogin()
    {
#if UNITY_ANDROID
        var requestAndroid = new LoginWithAndroidDeviceIDRequest { AndroidDeviceId = ReturnMobileID(), CreateAccount = true };


        requestAndroid.InfoRequestParameters = playerInfo;


        PlayFabClientAPI.LoginWithAndroidDeviceID(requestAndroid, result =>
        {
            //Request VirtualCurrency, Stats, etc.
            requestAndroid.InfoRequestParameters = playerInfo;


            OnLoginResult(result);


        }, OnPlayFabError);
#endif


#if UNITY_IOS
            var requestIOS = new LoginWithIOSDeviceIDRequest { DeviceId = ReturnMobileID(), CreateAccount = true};
            PlayFabClientAPI.LoginWithIOSDeviceID(requestIOS, OnLoginMobileResult, OnPlayFabError);
#endif
    }


    public static string ReturnMobileID()
    {
        string deviceID = SystemInfo.deviceUniqueIdentifier;
        return deviceID;
    }


    public void OnClickGuest()
    {
        MobileGuestLogin();
    }
    #endregion MobileGuestLogin






    #region Login
    //Login
    private void Login()
    {
        loginWithEmail = new LoginWithEmailAddressRequest { Email = userEmail, Password = userPassword };
        loginWithEmail.TitleId = PlayFabSettings.TitleId;


        if (!PlayerPrefs.HasKey("EMAIL") && !PlayerPrefs.HasKey("PASSWORD"))
        {
            PlayerPrefs.SetString("EMAIL", userEmail);
            PlayerPrefs.SetString("PASSWORD", userPassword);
        }




        // Request Login to PlayFab API
        PlayFabClientAPI.LoginWithEmailAddress(loginWithEmail, result => 
        {
            HappyCoins = result.InfoResultPayload.UserVirtualCurrency["HC"];


            //Request VirtualCurrency, Stats, etc.
            loginWithEmail.InfoRequestParameters = playerInfo;


            OnLoginResult(result);




        }, OnPlayFabError);
    }


    private void OnLoginResult(LoginResult obj)
    {
        Debug.Log("Login was successful!");


        GetStatistics();


        PhotonNetwork.LoadLevel("Lobby");
    }


    public void OnClickLogin()
    {
        PlayerPrefs.SetString("EMAIL", userEmail);
        PlayerPrefs.SetString("PASSWORD", userPassword);


        var request = new LoginWithEmailAddressRequest { Email = userEmail, Password = userPassword };
        PlayFabClientAPI.LoginWithEmailAddress(request, OnLoginResult, OnPlayFabError); 
    }


    public void DeleteLoginPlayerPrefs()
    {
        PlayerPrefs.DeleteKey("EMAIL");
        PlayerPrefs.DeleteKey("PASSWORD");


        Debug.Log("Login PlayerPreferences have been deleted.");
    }
    #endregion Login






    #region PlayerStats
    private GetPlayerStatisticsRequest requestStats;


    public void UpdatePlayerStats()
    {
        PlayFabClientAPI.UpdatePlayerStatistics(new UpdatePlayerStatisticsRequest
        {
            // request.Statistics is a list, so multiple StatisticUpdate objects can be defined if required.
            Statistics = new List<StatisticUpdate>
            {
                new StatisticUpdate { StatisticName = "PlayerLevel", Value = playerLevel },
                new StatisticUpdate { StatisticName = "AttackDamage", Value = attackDamage },
                new StatisticUpdate { StatisticName = "PlayerHealth", Value = playerHealth },
                new StatisticUpdate { StatisticName = "SpeedLevel", Value = speedLevel },
            }
        },
        result =>
        {
            Debug.Log("User statistics updated");
        },
        error =>
        {
            Debug.LogError(error.GenerateErrorReport());
        });
    }


    public void GetStatistics()
    {
        PlayFabClientAPI.GetPlayerStatistics(new GetPlayerStatisticsRequest(), result => {


            PlayFabClientAPI.GetPlayerCombinedInfo(new GetPlayerCombinedInfoRequest
            {
                InfoRequestParameters = new GetPlayerCombinedInfoRequestParams
                {
                    GetPlayerStatistics = true
                }
            }, equals =>
            {


            }, failure => {
                //CustomAccountManagement.customAccountManagement.OnPlayFabError(error);
                Debug.LogError(failure.GenerateErrorReport());
            });


            OnGetStatistics(result);


        }, error =>
        {
            Debug.LogError(error.GenerateErrorReport());
        });
    }


    private void OnGetStatistics(GetPlayerStatisticsResult result)
    {
        //Debug.Log(result.Statistics.Count);
        if (result.Statistics == null || result.Statistics.Count == 0)
        {
            UpdatePlayerStats();
        }
        else
        {
            foreach (var eachStat in result.Statistics)
            {
                Debug.Log("Statistic (" + eachStat.StatisticName + "): " + eachStat.Value);


                switch (eachStat.StatisticName)
                {
                    case "PlayerLevel":
                        playerLevel = eachStat.Value;
                        break;
                    case "AttackDamage":
                        attackDamage = eachStat.Value;
                        break;
                    case "PlayerHealth":
                        playerHealth = eachStat.Value;
                        break;
                    case "SpeedLevel":
                        speedLevel = eachStat.Value;
                        break;
                    default:
                        break;
                }
            }
        }
    }
    #endregion PlayerStats



}
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1 Answer

·
Sarah Zhang avatar image
Sarah Zhang answered

According to your description, you are handling a Peer-to-Peer multiplayer game logic using PUN, is it right? If so, for your case, you can only set up the maxHealth of Player 2 according to the message sent by Player 2.

After researching your code, we found you only set the variable maxHealth as CustomAccountManagement.CSM.playerHealth. There are no other assignment statements for maxHealth in the code snippet you provided. And the variable CustomAccountManagement.CSM.playerHealth is only assigned by the statistic values of current player too, there is no assignment statements to set it as the statistic value of Player 2.

To implement your requirement, you would need to use PUN messaging methods to broadcast the maxHealth of all players, so that players can obtain their respective maxHealth values and display them. You can try to send the variable maxHealth using the PhotonView property – OnSerializePhotonView as how you sent the variable – health. For more information about how to send the network messages using PUN, please check the PUN documentation - Photon Unity Networking: General Documentation - Photon Unity Networking Documentation.

1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

hapygames avatar image hapygames commented ·

OMG, I LOVE YOU SO MUCH DEAR PlayFab-Team! ♥♥♥

Thanks a lot for all the Support and all the Time and all the Love that you guys put in all your work!

Please enjoy your time guys, stay healthy and once again, thank you for everything! ♥<3

0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.