-
Notifications
You must be signed in to change notification settings - Fork 0
Inventory Doc Review #103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: unity/v5.0
Are you sure you want to change the base?
Inventory Doc Review #103
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| - [Inventory](inventory-overview.md) | ||
| - [Federated Inventory](inventory-federated.md) | ||
| - [Virtual Currency](virtual-currency-overview.md) | ||
| - [Stores](stores-overview.md) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| # Inventory federated | ||
|
|
||
| ## Overview | ||
|
|
||
| Beamable supports custom inventory federation using managed [microservices](../../cloud-services/microservices/microservice-framework.md). You can use this service to extend the Inventory system with items that are managed externally. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe worth mentioning NFTs here? I see that you have them in the bullet list below, so maybe not needed in the prose intro, but it might clarify "why federate inventory?" to lead with it as early as possible. |
||
|
|
||
| Some use cases: | ||
|
|
||
| - Crypto assets - use NFTs as inventory items and auto-mint new items | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there public connotations on the word "Crypto" that we could dodge by saying "Blockchain" instead? I am not super tapped into the scene, but I feel like I have heard "Crypto" spoken in the tones of a not-so-nice epithet. Probably not a big deal, either way. |
||
| - Generative AI - add support for granting players AI-generated items | ||
|
|
||
| **Requirements:** | ||
|
|
||
| - Federated Inventory depends on the implementation of [Federated Identity](../identity/federated-identity.md), that means that every player first | ||
| needs to have a federated identity with the same microservice that federates inventory | ||
| - Inventory items are content-driven. To enable federation, content items must be marked as federated to a specific microservice | ||
|
|
||
| The diagrams below illustrate the flows for retrieving and granting the Inventory Items with Federation enabled | ||
|
|
||
| {: style="height:auto;width:400px"} | ||
|
|
||
|
|
||
| {: style="height:auto;width:400px"} | ||
|
|
||
| ### `IFederatedInventory<T>` interface | ||
|
|
||
| To use the Federated Inventory you should start by implementing the `IFederatedInventory<T>` interface in your microservice. | ||
| Note that this interface also implements `IFederatedLogin<T>` because federated authentication is a prerequisite. | ||
| `T` must be your implementation of the `IThirdPartyCloudIdentity` - a basic interface that | ||
| requires you to define a unique name/namespace for your federation. This enables you to have multiple federation | ||
| implementations in a single microservice. | ||
|
|
||
| ```csharp | ||
| public class MyFederationIdentity : IThirdPartyCloudIdentity | ||
| { | ||
| public string UniqueName => "my-cool-federation"; | ||
| } | ||
|
|
||
| [Microservice("MyFederation")] | ||
| public class MyFederationService : Microservice, IFederatedInventory<MyFederationIdentity> | ||
| { | ||
| public Promise<FederatedAuthenticationResponse> Authenticate(string token, string challenge, string solution) | ||
| { | ||
| throw new System.NotImplementedException(); | ||
| } | ||
|
|
||
| public Promise<FederatedInventoryProxyState> GetInventoryState(string id) | ||
| { | ||
| throw new System.NotImplementedException(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like the implementation of inventory-related stuff is the meat and potatoes of this article, so having a skeletonized version here is a bit of a distraction. Could the sections below stand on their own without this block of code? |
||
| } | ||
|
|
||
| public Promise<FederatedInventoryProxyState> StartInventoryTransaction(string id, string transaction, Dictionary<string, long> currencies, List<FederatedItemCreateRequest> newItems, List<FederatedItemDeleteRequest> deleteItems, List<FederatedItemUpdateRequest> updateItems) | ||
| { | ||
| throw new System.NotImplementedException(); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### `GetInventoryState` implementation | ||
|
|
||
| You can do any custom logic here. For example, you could AI generate some items, load items from a smart contract, use microstorage, or do anything that satisfies your specific requirements. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For tech writing, I am a big fan of "perform" in place of "do" -- makes it sound techy without being too professorial ;) |
||
| Here's a dummy example that will return some static items and currency, just to showcase the response structure: | ||
|
|
||
| ```csharp | ||
| public Promise<FederatedInventoryProxyState> GetInventoryState(string id) | ||
| { | ||
| return Promise<FederatedInventoryProxyState>.Successful( | ||
| new FederatedInventoryProxyState | ||
| { | ||
| currencies = new Dictionary<string, long> | ||
| { | ||
| { "currency.federated-gold", 1000 }, | ||
| { "currency.federated-silver", 5000 } | ||
| }, | ||
| items = new Dictionary<string, List<FederatedItemProxy>> | ||
| { | ||
| { | ||
| "items.avatar", new List<FederatedItemProxy> | ||
| { | ||
| new() | ||
| { | ||
| proxyId = "externalAvatarId1", | ||
| properties = new List<ItemProperty> | ||
| { | ||
| new() | ||
| { | ||
| name = "level", | ||
| value = "20" | ||
| }, | ||
| new() | ||
| { | ||
| name = "color", | ||
| value = "blue" | ||
| } | ||
| } | ||
| }, | ||
| new() | ||
| { | ||
| proxyId = "externalAvatarId2", | ||
| properties = new List<ItemProperty> | ||
| { | ||
| new() | ||
| { | ||
| name = "level", | ||
| value = "30" | ||
| }, | ||
| new() | ||
| { | ||
| name = "color", | ||
| value = "red" | ||
| } | ||
| } | ||
|
Comment on lines
+80
to
+112
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any way to make this take less vertical space? My eyes kinda glaze over when I see long stretches of sparse vertical code 😇 |
||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ); | ||
| } | ||
| ``` | ||
|
|
||
| The important thing to emphasize here is the `id` argument. It's the same external account id that you return from the `Authenticate` method. If you want to access the player's id in the Beamable system, you can use `this.Context.UserId` | ||
| As an example, you can use the wallet address as an external user identifier when implementing blockchain federation. | ||
|
|
||
| ### `StartInventoryTransaction` implementation | ||
|
|
||
| The Inventory service will forward all the changes against federated currency and items. This method has the same return type as the previous one. | ||
|
|
||
| ```csharp | ||
| public Promise<FederatedInventoryProxyState> StartInventoryTransaction(string id, string transaction, Dictionary<string, long> currencies, List<FederatedItemCreateRequest> newItems, List<FederatedItemDeleteRequest> deleteItems, List<FederatedItemUpdateRequest> updateItems) | ||
| { | ||
| await _myFederation.ApplyCurrency(currencies); | ||
| await _myFederation.AddItems(newItems); | ||
| await _myFederation.UpdateItems(updateItems); | ||
| await _myFederation.DeleteItems(deleteItems); | ||
| return await GetInventoryState(id); | ||
| } | ||
| ``` | ||
|
|
||
| The `transaction` argument is a unique transaction id generated in our Inventory service, and you can use it to guard against multiple submissions. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whenever possible, using "the Beamable [thing]" instead of "our [thing]" lends it a nice tech-writing air. |
||
|
|
||
| If your transaction processing is too slow to return a timely response, you can implement the async approach. | ||
| Process the transaction in the background and return the current state. Once the transaction finishes processing, | ||
| you can report back the new state like this: | ||
|
Comment on lines
+142
to
+144
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What techniques should the game developer use for this? Simply omit the |
||
|
|
||
| ```csharp | ||
| await Requester.Request<CommonResponse>(Method.PUT, $"/object/inventory/{_userContext.UserId}/proxy/state", newState); | ||
| ``` | ||
|
|
||
| The Inventory service will notify the game client to refresh the inventory content if there's a diff. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Phrasing/branding question: do we want to call this "Federated inventory" or "Inventory federation"? (in the latter case, I think "federation" reads slightly better than "federated")