Hello, I am using playfab and photon plugin in my game. I can login with Playfab without any problem. In the main menu of my game, there is a user-specific panel with the user picture and username in the upper right corner. I can show the username on the panel and map it to the photon without a problem. Additionally, with a plugin, I allow users to select a profile photo from the phone gallery at login. I can show this user-selected photo on the panel in the main menu. But I want this photo to be specific to the user who is logged in with playfab, I want to show this photo next to the usernames in the rooms where the photon and usernames are listed. Is it possible? Can you guide me, what should I do? I am sharing the link of the plugin I mentioned and the code file I used.
The second code file is the code file of the prefab converted game object containing the username of the users joining the room.
https://github.com/yasirkula/UnityNativeGallery
using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.UI; using PlayFab; using PlayFab.ClientModels; using System; using System.IO; public class PlayFabManager : MonoBehaviour { [Header("UI")] public Text messageText,isim ; public InputField usernameInput; public InputField emailInput; public InputField passwordInput; public GameObject Panel public Image profilepicture; private string Email; private string Username; private string Password; private PlayFabAuthService _AuthService = PlayFabAuthService.Instance; public void profılepıcture() { GaleridenResimCek( 1024 ); } private void GaleridenResimCek( int maksimumBuyukluk ) { NativeGallery.Permission izin = NativeGallery.GetImageFromGallery( ( konum ) => { Debug.Log( "Seçilen resmin konumu: " + konum ); if( konum != null ) { Texture2D texture = NativeGallery.LoadImageAtPath( konum, maksimumBuyukluk ); System.IO.File.Copy(konum, Application.persistentDataPath + "/SavedImage.png", true); if ( texture == null ) { Debug.Log( konum + " konumundaki resimden bir texture oluşturulamadı." ); return; } profilepicture.sprite = Sprite.Create(texture, new Rect(0f, 0f, texture.width, texture.height), new Vector2(0.5f, 0.5f), 100.0f); } }, "Bir resim seçin", "image/png" ); Debug.Log( "İzin durumu: " + izin ); } public void RegisterButton() { if (passwordInput.text.Length < 6) { messageText.text = "Şifreniz en az 6 karakter içermelidir!"; return; } if (usernameInput.text.Length < 6) { messageText.text = "Kullanıcı Adı 3-20 Karakter Arası Olmalıdır!"; return; } var request = new RegisterPlayFabUserRequest { Email = emailInput.text, Password = passwordInput.text, Username = usernameInput.text, RequireBothUsernameAndEmail = true }; PlayFabClientAPI.RegisterPlayFabUser(request, OnRegisterSuccess, OnError); } void OnRegisterSuccess(RegisterPlayFabUserResult result) { messageText.text = "Kayıt Yapıldı, Giriş Yapabilirsiniz"; Username = PlayerPrefs.GetString("Username"); Password = PlayerPrefs.GetString("Password"); PlayerPrefs.Save(); } void OnError(PlayFabError error) { switch (error.Error) { case PlayFabErrorCode.InvalidEmailAddress: case PlayFabErrorCode.InvalidPassword: case PlayFabErrorCode.InvalidEmailOrPassword: messageText.text = "Geçersiz Şifre/Kullanıcı Adı/Email"; break; case PlayFabErrorCode.UnknownError: messageText.text = "İnternet Bağlantınızı Kontrol Edin Ve Uygulamayı Yeniden Başlatın"; break; case PlayFabErrorCode.InvalidAccount: case PlayFabErrorCode.InvalidUsername: messageText.text = "Geçersiz"; break; } messageText.text = error.ErrorMessage; Debug.Log(error.GenerateErrorReport()); } public void LoginButton() { PlayFabClientAPI.LoginWithPlayFab(new LoginWithPlayFabRequest { Username = "xxx", Password = "123456", InfoRequestParameters = new GetPlayerCombinedInfoRequestParams { GetUserAccountInfo = true } }, result => { isim.text = result.InfoResultPayload.AccountInfo.Username; }, error => { Debug.LogError(error.GenerateErrorReport()); }); var request = new LoginWithPlayFabRequest { Password = passwordInput.text, Username = usernameInput.text }; PlayFabClientAPI.LoginWithPlayFab(request, OnLoginSuccess, OnError); PlayerPrefs.SetString("Username", usernameInput.text); PlayerPrefs.SetString("Password", passwordInput.text); PlayerPrefs.Save(); } public void ResetPasswordButton() { var request = new SendAccountRecoveryEmailRequest { Email = emailInput.text, TitleId = "xxxx" }; PlayFabClientAPI.SendAccountRecoveryEmail(request, OnPasswordReset, OnError); } private void OnPasswordReset(SendAccountRecoveryEmailResult result) { messageText.text = "Şifre Sıfırlama Bağlantısı Mail Adresinize Gönderildi"; } void OnLoginSuccess(LoginResult result) { Debug.LogFormat("Logged In as: {0}", result.PlayFabId); messageText.text = "Giriş Yapıldı"; Debug.Log("Giriş Başarılı"); isim.text = Username; Panel.SetActive(false); } void Login() { if (Username ==string.Empty && Password == string.Empty) { Debug.Log("Kutucuklar Boş"); } else { Debug.Log("Zaten Giriş Yapıldı"); var request = new LoginWithPlayFabRequest { Password = Password, Username = Username }; PlayFabClientAPI.LoginWithPlayFab(request, OnLoginSuccess, OnError); } } void Start() { if (File.Exists(Application.persistentDataPath + "/SavedImage.png")) { Texture2D texture = NativeGallery.LoadImageAtPath(Application.persistentDataPath + "/SavedImage.png", 1024); profilepicture.sprite = Sprite.Create(texture, new Rect(0f, 0f, texture.width, texture.height), new Vector2(0.5f, 0.5f), 100.0f); ; } _AuthService.InfoRequestParams = InfoRequestParams; Username = PlayerPrefs.GetString("Username"); Password = PlayerPrefs.GetString("Password"); Login(); } }
using Photon.Pun; using Photon.Realtime; using System.Collections; using System.Collections.Generic; using System; using UnityEngine; using UnityEngine.UI; public class playerlistprefab : MonoBehaviourPunCallbacks { [SerializeField] private Text _text; [SerializeField] private string nickName; public Player Player { get; private set; } public void SetPlayerInfo(Player player) { Player = player; _text.text = player.NickName; } private void Awake() { nickName = PlayerPrefs.GetString("Username"); } }
Answer by Made Wang · Feb 24 at 08:44 AM
You can upload the chosen avatar to some external avatar hosting service and then call UpdateAvatarUrl to add the returned URL to the player's profile. You can call GetPlayerProfile when needed or get it directly at login as written in your code. After getting the URL, you can use some http download methods to get the avatar.
Thank you very much for your comment. I did some research and saw that external avatar hosting services are also paid. I wonder if I can fix the problem without using this service. I save the image that the user chooses during registration into application.persistentDataPath. Then, with the File.Exists method, I can display this image in the list of players joining the room in the lobby panel if there is a photo in Application.persistentDataPath. But the same image is shown for each user. How do I set this image to be specific to each user. After all i can get the location of the image and load the image from this patht. I also think that it can be displayed privately for each user. I'm just thinking, I wanted to ask if my thought would be possible. Thank you so much again
As far as I know, application.persistentDataPath is the path where the local file is stored, if you want to get the player's avatar in the local path, then you need to pre-store the player's avatar and distinguish all the avatars by name.
For multiplayer online games, each user's avatar should be downloaded through the network, we still recommend using an external avatar hosting service to store the image and store the url in PlayFab.
Other than that, you can try to store the avatar in the entity file. But it should be noted that if your title is in live mode then this will incur some charges, refer to Pricing Meters - PlayFab | Microsoft Docs for billing methods.
Answer by omerdruu · Apr 15 at 11:25 PM
I did some research and as you said, I decided to store the profile picture of the users in the entity file.
https://docs.microsoft.com/en-us/gaming/playfab/features/data/entities/quickstart
I followed this link, but now there are errors for me.
public class resimplayfab : MonoBehaviour { public Image profilep; public string entityId; // Id representing the logged in player public string entityType; // entityType representing the logged in player private readonly Dictionary<string, string> _entityFileJson = new Dictionary<string, string>(); private readonly Dictionary<string, string> _tempUpdates = new Dictionary<string, string>(); public string ActiveUploadFileName; public string NewFileName; public int GlobalFileLock = 0; // Kind of cheap and simple way to handle this kind of lock public void tıkla() { GaleridenResimCek(1024); } void OnLogin(PlayFab.ClientModels.LoginResult result) { entityId = result.EntityToken.Entity.Id; // The expected entity type is title_player_account. entityType = result.EntityToken.Entity.Type; } private void GaleridenResimCek(int maksimumBuyukluk) { NativeGallery.Permission izin = NativeGallery.GetImageFromGallery((konum) => { Debug.Log("Seçilen resmin konumu: " + konum); if (konum != null) { // Seçilen resmi bir Texture2D'ye çevir Texture2D texture = NativeGallery.LoadImageAtPath(konum, maksimumBuyukluk); if (texture == null) { Debug.Log(konum + " konumundaki resimden bir texture oluşturulamadı."); return; } profilep.sprite = Sprite.Create(texture, new Rect(0f, 0f, texture.width, texture.height), new Vector2(0.5f, 0.5f), 100.0f); } }, "Bir resim seçin", "image/png"); Debug.Log("İzin durumu: " + izin); } void OnPlayFabError(PlayFabError error) { Debug.Log(error.GenerateErrorReport()); } void OnSharedFailure(PlayFabError error) { Debug.LogError(error.GenerateErrorReport()); GlobalFileLock -= 1; } void UploadFile(string fileName) { if (GlobalFileLock != 0) throw new Exception("This example overly restricts file operations for safety. Careful consideration must be made when doing multiple file operations in parallel to avoid conflict."); ActiveUploadFileName = fileName; GlobalFileLock += 1; // Start InitiateFileUploads var request = new PlayFab.DataModels.InitiateFileUploadsRequest { Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType }, FileNames = new List<string> { ActiveUploadFileName }, }; PlayFabDataAPI.InitiateFileUploads(request, OnInitFileUpload, OnInitFailed); } void OnInitFailed(PlayFabError error) { if (error.Error == PlayFabErrorCode.EntityFileOperationPending) { // This is an error you should handle when calling InitiateFileUploads, but your resolution path may vary GlobalFileLock += 1; // Start AbortFileUploads var request = new PlayFab.DataModels.AbortFileUploadsRequest { Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType }, FileNames = new List<string> { ActiveUploadFileName }, }; PlayFabDataAPI.AbortFileUploads(request, (result) => { GlobalFileLock -= 1; UploadFile(ActiveUploadFileName); }, OnSharedFailure); GlobalFileLock -= 1; // Finish AbortFileUploads GlobalFileLock -= 1; // Failed InitiateFileUploads } else OnSharedFailure(error); } void OnInitFileUpload(PlayFab.DataModels.InitiateFileUploadsResponse response) { Texture2D tex = (Texture2D)profilep.mainTexture; tex.ReadPixels(new Rect(0, 0, profilep.mainTexture.width, profilep.mainTexture.height), 0, 0); tex.Apply(); byte[] bytes = tex.EncodeToPNG(); GlobalFileLock += 1; // Start SimplePutCall PlayFabHttp.SimplePutCall(response.UploadDetails[0].UploadUrl, bytes, FinalizeUpload, error => { Debug.Log(error); } ); GlobalFileLock -= 1; // Finish InitiateFileUploads } void FinalizeUpload(byte[] obj) { GlobalFileLock += 1; // Start FinalizeFileUploads var request = new PlayFab.DataModels.FinalizeFileUploadsRequest { Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType }, FileNames = new List<string> { ActiveUploadFileName }, }; PlayFabDataAPI.FinalizeFileUploads(request, OnUploadSuccess, OnSharedFailure); GlobalFileLock -= 1; // Finish SimplePutCall } void OnUploadSuccess(PlayFab.DataModels.FinalizeFileUploadsResponse result) { Debug.Log("File upload success: " + ActiveUploadFileName); GlobalFileLock -= 1; // Finish FinalizeFileUploads } }
result: i get this error: /File/InitiateFileUploads: Invalid input parameters EntityKey: Type or TypeString is required. EntityKey: Id is required. EntityKey: is not an allowed value of Type.
I shared the code I used for playfab user login in my question. I'm using LoginWithPlayFab for this. And I think the error I got is that I do not access the id and type in the entity key at the beginning. I guess I can't get this part to work properly:
void Login() { var request = new PlayFab.ClientModels.LoginWithCustomIDRequest { CustomId = SystemInfo.deviceUniqueIdentifier, CreateAccount = true, }; PlayFabClientAPI.LoginWithCustomID(request, OnLogin, OnSharedFailure); }
Are my findings so far correct? If so, can you help me how to solve this problem by using LoginWithPlayFab instead of using LoginWithCustomIDRequest? @Made Wang
Lightweight mmo possible in Unity + Photon Bolt + Playfab? 1 Answer
How to log into original account on reinstall or new device? 1 Answer
understanding the authentication flow better, few questions 1 Answer
Unable to Connect to Photon Chat, Error Code: 32755 3 Answers
Where should I enable Steam authentication when using Photon & Playfab? 1 Answer