question

Anthony Pike avatar image
Anthony Pike asked

{"PlayFabId":["must be a hex-encoded number"]} on Giv

I am trying to add currency to users using cloudscript and I'm getting this result:

{"Result":null,"CustomData":null,"Error":{"HttpCode":400,"HttpStatus":"BadRequest","Error":1000,"ErrorMessage":"Invalid input parameters","ErrorDetails":{"PlayFabId":["must be a hex-encoded number"]},"RequestId":"Failed to Enumerate RequestId. Exception message: Enumeration has not started. Call MoveNext.","RetryAfterSeconds":null}}

It appears that the problem is that the PlayFabId "must be a hex-encoded number", however I am passing the same PlayFabId string that successfully works on an earlier "PlayFabAdminAPI.GetUserAccountInfoAsync" call, so it should have been identical.

One of these is "6CD7FFC2F611745D" and is the Master Player account, it doesn't have anything in there that would make it an invalid hex string. I have even attempted to append "0x" at the start to see if that affects it, but this makes no difference to the error response.

Parameters passed to Cloudscript:

{"currency":"CC","count":8,"classid":"CE0A7FC0D41F163A","mid":"F0891069681D6C27,43D9831D3094A7C6,7856B6CF0F7E7B73,6CD7FFC2F611745D,8A849383AE9D5DFA"}

^ the "mid" string will be comma separated into an array in the cloud script.

Cloud Script Function (Azure):

public static class ConferInventory
    {
        [FunctionName("ConferInventory")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            PlayFabSettings.staticSettings.TitleId = "FDD7C";// context.TitleAuthenticationContext.Id;
            PlayFabSettings.staticSettings.DeveloperSecretKey = Environment.GetEnvironmentVariable("PLAYFAB_DEV_SECRET_KEY", EnvironmentVariableTarget.Process);


            var getTitleEntityTokenRequest = new GetEntityTokenRequest(); //Do not need to set Entity
            var titleEntityResponse = await PlayFabAuthenticationAPI.GetEntityTokenAsync(getTitleEntityTokenRequest);
            if (titleEntityResponse.Result == null)
            {
                string errMsg = "Unable to get title token / entity.";
                log.LogError(errMsg);
                return new OkObjectResult(JsonConvert.DeserializeObject("{\"error\":\"" + errMsg + "\"}"));
            }


            //-------------------------


            string requestBody = String.Empty;
            using (StreamReader streamReader = new StreamReader(req.Body))
            {
                requestBody = await streamReader.ReadToEndAsync();
            }


            dynamic request = JsonConvert.DeserializeObject(requestBody);
            Newtonsoft.Json.Linq.JArray functionArgument = request.FunctionArgument;


            foreach(var item in functionArgument.Values<dynamic>())
            {
                string dbgStr = JsonConvert.SerializeObject(item);
                log.LogInformation(" > " + dbgStr);


                List<string> affectedStudents = new List<string>();
                List<string> affectedCharacters = new List<string>();


                string cIDs = item.cid;
                if(cIDs != null)
                {
                    log.LogInformation("cIDs: "+cIDs);


                    foreach(string cID in cIDs.Split(","))
                    {
                        if (cID != "")
                            affectedCharacters.Add(cID);
                    }
                }


                string mIDs = item.mid;
                if (mIDs != null)
                {
                    log.LogInformation("mIDs: " + mIDs);


                    foreach (string mID in mIDs.Split(","))
                    {
                        if (mID != "")
                            affectedStudents.Add(mID);
                    }
                }


                string currency = item.currency;
                int count = item.count;


                if (currency != "" && count > 0)
                {
                    log.LogInformation("Add "+count.ToString()+currency+" for " + affectedStudents.Count + " students.");


                    foreach (string s in affectedStudents)
                    {
                        var result = await PlayFabServerAPI.AddUserVirtualCurrencyAsync(
                            new PlayFab.ServerModels.AddUserVirtualCurrencyRequest
                            {
                                VirtualCurrency = currency,
                                Amount = count,
                                PlayFabId = s
                            }
                        );


                        string outcome = s+" :: "+JsonConvert.SerializeObject(result);
                        log.LogInformation(outcome);
                    }
                }
            }
	}

--- truncated ---

Code that executes the CloudScript:

private IEnumerator ConferInventory(Transform notificationDestination, AwardNotificationController notificationPrefab, object _params)
    {
        var jsonConverter = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer);
        PlayFab.CloudScriptModels.EntityKey cloudEntity = jsonConverter.DeserializeObject<PlayFab.CloudScriptModels.EntityKey>(jsonConverter.SerializeObject(sessionGroupAdminEntity));


        bool resultType = false;


        int attempts = 0;
        while (!resultType && attempts < 3)
        {
            bool resultReceived = false;
            PlayFabCloudScriptAPI.ExecuteFunction(
                new ExecuteFunctionRequest
                {
                    FunctionName = "ConferInventory",
                    FunctionParameter = _params,
                    Entity = cloudEntity
                },
                res =>
                {
                    resultType = true;
                    resultReceived = true;


                    string dbgStr = JsonConvert.SerializeObject(res.FunctionResult);
                    Debug.Log("Function Result: " + dbgStr);
                },
                err =>
                {
                    resultType = false;
                    resultReceived = true;
                    Debug.LogError("Unable to ConferInventory (attempt " + (attempts+1)+": " + err.ErrorMessage);
                }
            );


            yield return new WaitUntil(() => resultReceived);


            if (resultType)
                yield break;
            else
            {
                Debug.LogError("TODO: Better Error/Retry/Reconnect handling method.");
                attempts++;
            }
        }
        yield break;
    }
unity3dCloudScriptIn-Game Economy
5 comments
10 |1200

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

Gosen Gao avatar image Gosen Gao commented ·

Would you please print the parameter s(at line 90) of code snippet Cloud Script Function (Azure)?

1 Like 1 ·
Anthony Pike avatar image Anthony Pike Gosen Gao commented ·

item.mid comes from the JSON sent via ExecuteScript.

{"currency":"CC","count":8,"classid":"CE0A7FC0D41F163A","mid":"F0891069681D6C27,43D9831D3094A7C6,7856B6CF0F7E7B73,6CD7FFC2F611745D,8A849383AE9D5DFA"}


Lines 82-92:

                string mIDs = item.mid;
                if (mIDs != null)
                {
                    log.LogInformation("mIDs: " + mIDs);
                    foreach (string mID in mIDs.Split(","))
                    {
                        if (mID != "")
                            affectedStudents.Add(mID);
                    }
                }
0 Likes 0 ·
Anthony Pike avatar image Anthony Pike Gosen Gao commented ·

Then this happens in Lines 100-112:

		foreach (string s in affectedStudents)
                    {
                        var result = await PlayFabServerAPI.AddUserVirtualCurrencyAsync(
                            new PlayFab.ServerModels.AddUserVirtualCurrencyRequest
                            {
                                VirtualCurrency = currency,
                                Amount = count,
                                PlayFabId = s
                            }
                        );
                        string outcome = s+" :: "+JsonConvert.SerializeObject(result);
                        log.LogInformation(outcome);
		}
0 Likes 0 ·
Gosen Gao avatar image Gosen Gao Anthony Pike commented ·

Since the error message says that the issue is related to PlayFabId, printing the PlayFabId you are using to the console may help us figure out what is the cause. Would you please change your code to the code below,

foreach (string s in affectedStudents)
{
    log.LogInformation(s);
    var result = await PlayFabServerAPI.AddUserVirtualCurrencyAsync(
        new PlayFab.ServerModels.AddUserVirtualCurrencyRequest
        {
            VirtualCurrency = currency,
            Amount = count,
            PlayFabId = s
        }
    );
    string outcome = s+" :: "+JsonConvert.SerializeObject(result);
    log.LogInformation(outcome);
}

and share the logs to us?

0 Likes 0 ·
Anthony Pike avatar image Anthony Pike commented ·

My question title was supposed to read:

{"PlayFabId":["must be a hex-encoded number"]} on AddUserVirtualCurrencyAsync

0 Likes 0 ·

1 Answer

·
Anthony Pike avatar image
Anthony Pike answered

I'm am not sure what happened, I don't believe I changed anything on my end while I was waiting for responses to this problem but now the currency is successfully being added.

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.

Anthony Pike avatar image Anthony Pike commented ·

Reflecting on this, I believe that at one point my array had quotation marks and\or trailing commas that had not been removed.

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.