question

mgambrell avatar image
mgambrell asked

Using Character data in lieu of inventory

I need to track everything the player wins in one session, while actually also awarding some of it at the moment it's won.

There's two ways I can think of to do this:

1a. Have distinct item instances with special custom data indicating whether it's just for counting or for real

1b. Since 1a might not work (on account of needing to stack the same item ID into two groups) have two item IDs, one for counting, and one for actual awarding

2. Since I don't like working with the inventory APIs in the first place*, don't use them! Just store everything in character data. All items, all counting, all everything. If I'm going to store the counting there, I may as well store the real inventory there too.

My real question is about option 2. I saw some questions from some months ago about limits to the number of keys in character data (for the free tier), but there's nothing listed right now in the limits--does that mean it's unlimited? That seems unlikely. To be clear, this proposal might involve 100s of character data keys -- since there IS a limit to the size of the character data keys.

Also, I'm wondering if you can think of some other reason why this is insane or abusive.

The only reason I can see why I should even use the inventory system at all is because that's the only way to buy items with real money, which I can easily workaround by buying a token which I immediately cash in for an edit to character data. I mean, if I can store everything in character data, I only need about 2 APIs which aren't much different from "DOWNLOAD ALL THE DATA" and "UPLOAD ALL THE DATA" and I manage the database myself.

*Today, it's the lack of quantity argument in GrantItemsToUsers's ItemGrant[] that's killing me. Are you going to want to receive 200 entries in the ItemGrant[] just so I can grant 100 copper kettles and 200 rubber duckies?

10 |1200

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

brendan avatar image
brendan answered

It's definitely the case that nothing is "unlimited", as there wouldn't be any way we could afford to have a free tier, in that case.

If you have a design for which you're struggling with the best way to implement it in PlayFab, feel free to open a ticket with us, detailing the gameplay so that we can work with you on this. It's best to work from a top-down approach, so that we can determine what implementation work best for you.

For the specifics of what you've described, it sounds like what you want is a combination of user data, statistics, and inventory to manage this.

It is definitely the case that very large inventories and adding large numbers of items both cause issues with response times currently. That's something we're very aware of, and we're working on some improvements to the inventory system to account for that. To be clear, the inventory system is designed to be a secure way for you to exchange real world currencies and virtual currencies for digital goods in your game. It's possible to bypass this using the grant API calls or other ways to represent those goods, though I would caution that you would need to make certain that the implementation is secure from hacked inputs by the client, and that you have a way to roll back if your operation fails halfway through completion.

For data, the limit that's currently shown in the limits tab is the number of keys that can be written per update call. The limit on the total number of keys per data type is technically the same as the number that can be written per call, but we can work with you on an upgrade to that, if needed. However, we do not provide an upgrade to the number of keys that can be written at once, as that is the one thing that could impact database performance the most. And making multiple calls to update data overlapping or back to back would definitely be considered abuse, so it's best to go with fewer, larger keys. We have an updated data system planned for a future release which will allow for more efficient use of small keys, at which point we'll be able to give developers a way to read/write many small keys at once.

But again, I'd recommend opening a ticket with the details of your title, so that we can work with you on the best overall approach.

10 |1200

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

mgambrell avatar image
mgambrell answered

So, I just lost 20 minutes of typing to the undo bug. Let's try this again down here where I don't have a 1200 character limit.

"The limit on the total number of keys per data type is technically the same as the number that can be written per call"
"making multiple calls to update data ... back to back would definitely be considered abuse"

I just added 10 keys of 900 bytes each (batched in two calls). The limit is not "technically" the # that can be written per call. "Technically" it's unlimited--but I'd get an agitated email when I exceed an unwritten limit of 1 call <per time unit>.

And that's a complete surprise. What else has an unwritten limit of one call <per time unit>? There's a limit of updating 5 inventory items <per time unit>. Is there a limit of 1 inventory update call <per time unit>? That's definitely a LOL. How could I ever guess?

I mean, I was already planning on well over 5 character data keys just with the most non-abusive, tiny stuff. I thought it would be lighter on your server and cloudscripts to store stuff with as much granularity as made sense, and assuming making 2 calls to fetch 5 keys if needed was perfectly fine (charge it against my cloudscript mem & cpu budgets--mine to spend however I need.) Guess I won't be doing that anymore.

I just did some calculations though and I realize I can store everything I need in 2x 1KByte keys if I take enough care (binary packing and base64 encoding) and I could save a bunch of computation if I need to by storing it a little more readily accessible.

I can see by adding all this up that buying a limit++ on the character data size is how you mean for me to solve this.

Also FYI: https://api.playfab.com/Documentation/Server/method/UpdateCharacterData contains a typo "chjaracter"

10 |1200

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

brendan avatar image
brendan answered

Well first, there is no limit of one call per a time limit. The most restrictive we are is on the SendAccountRecoveryEmail call, but that's because it generates a password reset email for the player, which should be pretty rare. What we have are burst limit checks to ensure that no single client exceeds a certain number of calls per a time period, but that's specifically to prevent abuse. If you're seeing a mail that states a limit of only one call to anything per minute, please forward that to us at devrel.

In general, the design goal for use of a service like ours is to minimize the number of transactions. In addition to this being important for our service, it also helps to optimize your network traffic, which is important for mobile devices, since it helps to not chew through the user's battery (which can cause abandonment - people do notice this).

For example, a read or write of one key of 10,000 bytes is more efficient than a single call to read 5 keys of 2,000 bytes. In terms of database usage, this gets to be more noticeable with small data, since anything less than 1,000 bytes is effectively as costly as a 1,000 byte data read/write. Again, we'll be providing an alternate data system in a future update, but what it will effectively do is aggregate small keys into fewer, larger keys on our side. We try to be as transparent as possible on this, but we will do adjust the rate limits over time to ensure a high quality of service for all titles (though we're careful not to break any live titles in the process).

To simply this: In general, the way to think about it is, if you're making more than a few calls to any given API (other than event generation) per minute, you should really be optimizing. A game which requires a high update rate and server authority, like an MMO, a casino simulation, or other fast-action game, should really be using a custom game server for the state information, and periodically update the backend data to "save" the state.

And thanks for calling out the typo - we'll get that updated shortly!

10 |1200

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

mgambrell avatar image
mgambrell answered

OK, it seems clear now that you define as abuse of calls to be any series of calls designed to circumvent limits and it should be obvious to me because the limit of 5 keys in the call is what implements this limit. (It isn't obvious to me until you've explained it). Calls should be related to user agent actions only, and not other factors (multipliers to get around limits). And these user actions should be no more than one every several seconds.

According to my best understanding of your engineering and intentions, it should not constitute abuse to have more than 5 character data keys. If the game could be designed to use only roughly 5 data keys per user action (from an assortment of 15 or so) then it would not be abusive. From your point of view, as long as I'm just doing one call, it doesn't matter how many keys (within reason) are stored in your DB, or really even how big they are (we pay more for bigger ones). Can I assume it would be OK to have on the order of 15 character data keys?

But thanks for clarifying that the transaction count is the critical factor. It's making more and more sense to me to cram everything into one character data key, if I can't have more than 5 keys (however I still don't see why there's any difference to you technically between 1 request for 5 keys or 1 request for 1 larger key)

By the way, our game requires server authority. In fact I've never considered doing any of these calls anywhere but cloudscript. Traffic to the client isn't an issue.

7 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.

brendan avatar image brendan commented ·

Correct - coming up with ways to bypass limits would almost certainly mean doing something that would be considered abusive. The reason 1 request for 5 key/value pairs holding 100 bytes each isn't the same as 1 request for 1 key/value that has 500 bytes is because each key is a row in the data table, and so a separate lookup.

As to the question of 15 keys, the answer is that it really depends upon the usage. The limits are there to prevent a title from creating an excessive load on a data table (and to be clear, what we're concerned about are the per-user call rate - we can scale to any number of users). So if you mean that you'd be sending 1 call to read/write that data, with the standard limit per call of up to 5 keys, and that's maybe a couple of times a minute, no problem. If it's that you want to make 3 back-to-back calls of 5 keys each to be able to get 15 total keys in an update, that wouldn't be. But if it's something in between, it'd be best to just talk through the specifics so that we can give feedback on best practices and recommended implementations.

0 Likes 0 ·
mgambrell avatar image mgambrell brendan commented ·

I just replied, and it vanished, and this web app doesnt tell me it's pending moderation. Please tell me if you didn't receive it.

0 Likes 0 ·
brendan avatar image brendan mgambrell commented ·

If you reply as a Comment on an Answer, there's no moderation. It's Questions and Answers that are moderated (though once your reputation score increases, that'll stop, too).

0 Likes 0 ·
mgambrell avatar image mgambrell commented ·

A couple of times a minute doesn't sound good to me. Several times per minute is what I need. For example, we have a crafting system which needs to update the player's inventory as fast as they can work the UI. They gain XP for crafting, too, so they may want to craft and trash stuff at a rate of 10 per minute (until they run out of inventory)

I'm already thinking about having a queue of cloudscript calls.This was intended for the rapid fire stuff so they don't arrive at playfab out-of-order, but I could throttle it also. However, at some point we'll have to stall and wait for the queue to empty before we can read something from cloudscript (which loot was awarded, for instance) and that won't be great.

This is why I used the language of, let's say, per-user-action-rate. You're interested in per-user-call-rate, but if actions and calls can't be directly related, we have a problem.

0 Likes 0 ·
brendan avatar image brendan mgambrell commented ·

And that's why I always encourage folks to work with us on the details of their design. "Several" times a minute can mean very different things to different people. In your design, for example, you say you need "to update the player's inventory as fast as they can work the UI". For most games, that could mean dozens of update requests per minute, which could work, but we'd want to get info the details with you, and it would definitely require an enterprise contract, since there's no way it could be affordable for us to operate that for a title that's in the free tier (again, just being realistic).

As to the per-user rate, I would say that "actions" is more what I'm referring to as well, since a call could perform 1 "action" or many.

But I can provide more general advice for what you're describing: If you have a need to update something at a high frequency, your best plan is usually to do one of two things:

1. Update the client at that rate, but only update the backend with the delta periodically, when major things occur (or after a couple of minutes). Many clicker games use this model.

2. Use a custom game server that maintains state and updates to the backend periodically (as above).

0 Likes 0 ·
mgambrell avatar image mgambrell brendan commented ·

Let's say several means seven. I still can't determine whether this is in your danger zone. We're not playing whack-a-mole here, we're just playing a typical menu driven game where the menu operations are processed in cloudscript. For instance, navigating through the menus is processed on the client, but activating an item is done on cloudscript, for validation. I didn't expect you to go straight to dozens. And I didn't expect you to go straight to a couple, either. Now I have no idea of what to expect.

The average user will be doing somewhere between zero and seven actions per minute, I think. Someone may rarely spike above that, but the design isn't asking them to. They would not even appreciably alter the average.

0 Likes 0 ·
Show more comments

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.