diff --git a/Runtime/Client/LootLockerEndPoints.cs b/Runtime/Client/LootLockerEndPoints.cs
index 6a5aee8f..c34f75b4 100644
--- a/Runtime/Client/LootLockerEndPoints.cs
+++ b/Runtime/Client/LootLockerEndPoints.cs
@@ -349,6 +349,16 @@ public class LootLockerEndPoints
// Presence (WebSocket)
[Header("Presence")]
public static EndPointClass presenceWebSocket = new EndPointClass("presence/v1", LootLockerHTTPMethod.GET);
+
+ // Items
+ [Header("Items")]
+ public static EndPointClass listItemTemplates = new EndPointClass("player/inventory/v1", LootLockerHTTPMethod.GET);
+ public static EndPointClass listPlayerItems = new EndPointClass("player/inventory/v1/my", LootLockerHTTPMethod.GET);
+ public static EndPointClass getPlayerItem = new EndPointClass("player/inventory/v1/{0}", LootLockerHTTPMethod.GET);
+ public static EndPointClass deletePlayerItem = new EndPointClass("player/inventory/v1/{0}", LootLockerHTTPMethod.DELETE);
+ public static EndPointClass consumePlayerItem = new EndPointClass("player/inventory/v1/{0}/consume", LootLockerHTTPMethod.POST);
+ public static EndPointClass splitPlayerItemStack = new EndPointClass("player/inventory/v1/{0}/split", LootLockerHTTPMethod.POST);
+ public static EndPointClass mergePlayerItemStacks = new EndPointClass("player/inventory/v1/merge", LootLockerHTTPMethod.POST);
}
[Serializable]
diff --git a/Runtime/Game/LootLockerSDKManager.cs b/Runtime/Game/LootLockerSDKManager.cs
index 2d104dac..2b685735 100644
--- a/Runtime/Game/LootLockerSDKManager.cs
+++ b/Runtime/Game/LootLockerSDKManager.cs
@@ -6626,7 +6626,142 @@ public static void DeleteAssetInstanceFromPlayerInventory(int assetInstanceID, A
LootLockerAPIManager.DeleteAssetInstanceFromPlayerInventory(forPlayerWithUlid, data, onComplete);
}
#endregion
-
+
+ #region Items
+
+ ///
+ /// Returns a paginated list of all visible item templates.
+ ///
+ /// The page of item templates to return. Defaults to 1.
+ /// The number of item templates to return per page. Defaults to 25.
+ /// Delegate for handling the server response
+ /// Optional : Execute the request for the specified player. If not supplied, the default player will be used.
+ public static void ListItemTemplates(int page, int perPage, Action onComplete, string forPlayerWithUlid = null)
+ {
+ if (!CheckInitialized(false, forPlayerWithUlid))
+ {
+ onComplete?.Invoke(LootLockerResponseFactory.SDKNotInitializedError(forPlayerWithUlid));
+ return;
+ }
+
+ LootLockerAPIManager.ListItemTemplates(forPlayerWithUlid, page, perPage, onComplete);
+ }
+
+ ///
+ /// Returns a paginated list of the current player's inventory items, including their item templates.
+ ///
+ /// The page of items to return. Defaults to 1.
+ /// The number of items to return per page. Defaults to 25.
+ /// (Optional) Return only items whose template name starts with the specified value. Set to null to not use this filter.
+ /// (Optional) Return only items of the specified type. Set to null to not use this filter.
+ /// (Optional) Return only items that are (or are not) consumable. Set to null to not use this filter.
+ /// (Optional) The field by which to sort the items. Set to null to not use this filter.
+ /// (Optional) The direction in which to sort the items. Set to null to not use this filter.
+ /// Delegate for handling the server response
+ /// Optional : Execute the request for the specified player. If not supplied, the default player will be used.
+ public static void ListPlayerItems(int page, int perPage, string name = null, LootLockerItemType? itemType = null, bool? consumable = null, LootLockerItemSortField? sort = null, LootLockerSortOrder? order = null, Action onComplete = null, string forPlayerWithUlid = null)
+ {
+ if (!CheckInitialized(false, forPlayerWithUlid))
+ {
+ onComplete?.Invoke(LootLockerResponseFactory.SDKNotInitializedError(forPlayerWithUlid));
+ return;
+ }
+
+ LootLockerAPIManager.ListPlayerItems(forPlayerWithUlid, page, perPage, name, itemType?.ToString(), consumable, sort?.ToString(), order?.ToString(), onComplete);
+ }
+
+ ///
+ /// Returns a single inventory item for the current player, including its item template.
+ ///
+ /// The id of the inventory item to fetch.
+ /// Delegate for handling the server response
+ /// Optional : Execute the request for the specified player. If not supplied, the default player will be used.
+ public static void GetPlayerItem(string inventoryId, Action onComplete, string forPlayerWithUlid = null)
+ {
+ if (!CheckInitialized(false, forPlayerWithUlid))
+ {
+ onComplete?.Invoke(LootLockerResponseFactory.SDKNotInitializedError(forPlayerWithUlid));
+ return;
+ }
+
+ LootLockerAPIManager.GetPlayerItem(forPlayerWithUlid, inventoryId, onComplete);
+ }
+
+ ///
+ /// Deletes an inventory item from the current player's inventory.
+ ///
+ /// The id of the inventory item to delete.
+ /// Delegate for handling the server response
+ /// Optional : Execute the request for the specified player. If not supplied, the default player will be used.
+ public static void DeletePlayerItem(string inventoryId, Action onComplete, string forPlayerWithUlid = null)
+ {
+ if (!CheckInitialized(false, forPlayerWithUlid))
+ {
+ onComplete?.Invoke(LootLockerResponseFactory.SDKNotInitializedError(forPlayerWithUlid));
+ return;
+ }
+
+ LootLockerAPIManager.DeletePlayerItem(forPlayerWithUlid, inventoryId, onComplete);
+ }
+
+ ///
+ /// Consumes one or more items from a stackable inventory item. If is null, the whole stack is consumed.
+ ///
+ /// The id of the stackable inventory item to consume.
+ /// (Optional) The number of items to consume. If null, the whole stack is consumed.
+ /// Delegate for handling the server response
+ /// Optional : Execute the request for the specified player. If not supplied, the default player will be used.
+ public static void ConsumePlayerItem(string inventoryId, int? count, Action onComplete, string forPlayerWithUlid = null)
+ {
+ if (!CheckInitialized(false, forPlayerWithUlid))
+ {
+ onComplete?.Invoke(LootLockerResponseFactory.SDKNotInitializedError(forPlayerWithUlid));
+ return;
+ }
+
+ LootLockerConsumeItemRequest data = new LootLockerConsumeItemRequest { count = count };
+ LootLockerAPIManager.ConsumePlayerItem(forPlayerWithUlid, inventoryId, data, onComplete);
+ }
+
+ ///
+ /// Splits a stackable inventory item into two stacks, moving items into a new stack.
+ ///
+ /// The id of the stackable inventory item to split.
+ /// The number of items to move into the new stack.
+ /// Delegate for handling the server response
+ /// Optional : Execute the request for the specified player. If not supplied, the default player will be used.
+ public static void SplitPlayerItemStack(string inventoryId, int count, Action onComplete, string forPlayerWithUlid = null)
+ {
+ if (!CheckInitialized(false, forPlayerWithUlid))
+ {
+ onComplete?.Invoke(LootLockerResponseFactory.SDKNotInitializedError(forPlayerWithUlid));
+ return;
+ }
+
+ LootLockerSplitItemStackRequest data = new LootLockerSplitItemStackRequest { count = count };
+ LootLockerAPIManager.SplitPlayerItemStack(forPlayerWithUlid, inventoryId, data, onComplete);
+ }
+
+ ///
+ /// Merges two stacks of the same item into one.
+ ///
+ /// The id of the inventory item to merge from.
+ /// The id of the inventory item to merge into.
+ /// Delegate for handling the server response
+ /// Optional : Execute the request for the specified player. If not supplied, the default player will be used.
+ public static void MergePlayerItemStacks(string sourceInventoryId, string targetInventoryId, Action onComplete, string forPlayerWithUlid = null)
+ {
+ if (!CheckInitialized(false, forPlayerWithUlid))
+ {
+ onComplete?.Invoke(LootLockerResponseFactory.SDKNotInitializedError(forPlayerWithUlid));
+ return;
+ }
+
+ LootLockerMergeItemStacksRequest data = new LootLockerMergeItemStacksRequest { source_inventory_id = sourceInventoryId, target_inventory_id = targetInventoryId };
+ LootLockerAPIManager.MergePlayerItemStacks(forPlayerWithUlid, data, onComplete);
+ }
+ #endregion
+
#region AssetInstance progressions
/// @ingroup AssetInstanceProgressions
diff --git a/Runtime/Game/Requests/ItemRequest.cs b/Runtime/Game/Requests/ItemRequest.cs
new file mode 100644
index 00000000..1ba1a024
--- /dev/null
+++ b/Runtime/Game/Requests/ItemRequest.cs
@@ -0,0 +1,359 @@
+using System;
+using LootLocker.Requests;
+using LootLocker.Utilities.HTTP;
+
+namespace LootLocker.LootLockerEnums
+{
+ ///
+ /// The type of an item, determining whether the item instances are stackable or individually tracked.
+ ///
+ public enum LootLockerItemType
+ {
+ /// Each granted item is a separate, individually tracked instance.
+ instanced,
+ /// The item is stored as a single entry with a count that can be incremented or decremented.
+ stackable
+ }
+
+ ///
+ /// The field by which to order a player item list response.
+ ///
+ public enum LootLockerItemSortField
+ {
+ /// Order by when the item was created.
+ created_at,
+ /// Order by when the item was last updated.
+ updated_at
+ }
+
+ ///
+ /// The direction in which to order a player item list response.
+ ///
+ public enum LootLockerSortOrder
+ {
+ /// Order ascending.
+ ASC,
+ /// Order descending.
+ DESC
+ }
+}
+
+namespace LootLocker.Requests
+{
+ //==================================================
+ // Item Template Definitions
+ //==================================================
+
+ ///
+ /// An item template defines a type of item that can be granted to players.
+ ///
+ public class LootLockerItemTemplate
+ {
+ /// The unique id of the item template.
+ public string id { get; set; }
+
+ /// The name of the item template.
+ public string name { get; set; }
+
+ /// The id of the game this item template belongs to.
+ public int game_id { get; set; }
+
+ /// Indicates whether this item template is limited in how many of it can exist.
+ public int limited { get; set; }
+
+ /// The type of the item (instanced or stackable).
+ public string item_type { get; set; }
+
+ /// True if the item can be consumed by the player.
+ public bool consumable { get; set; }
+
+ /// True if the item can be deleted by the player.
+ public bool deletable { get; set; }
+
+ /// The time that this item template was created.
+ public string created_at { get; set; }
+
+ /// The time that this item template was last updated.
+ public string updated_at { get; set; }
+ }
+
+ //==================================================
+ // Player Item Definitions
+ //==================================================
+
+ ///
+ /// An item instance held in a player's inventory.
+ ///
+ public class LootLockerItem
+ {
+ /// The unique id of this inventory item.
+ public string id { get; set; }
+
+ /// The id of the player that owns this inventory item.
+ public int player_id { get; set; }
+
+ /// The id of the item template this inventory item is based on.
+ public string item_template_id { get; set; }
+
+ /// The type of the item (instanced or stackable).
+ public string item_type { get; set; }
+
+ /// True if the item can be consumed by the player.
+ public bool consumable { get; set; }
+
+ /// True if the item can be deleted by the player.
+ public bool deletable { get; set; }
+
+ /// The number of items in this stack (only relevant for stackable items).
+ public int count { get; set; }
+
+ /// The name of the item template this inventory item is based on.
+ public string name { get; set; }
+
+ /// The source of this inventory item, or null if not specified.
+ public string source { get; set; }
+
+ /// The time that this inventory item was created.
+ public string created_at { get; set; }
+
+ /// The time that this inventory item was last updated.
+ public string updated_at { get; set; }
+
+ /// Arbitrary metadata attached to this inventory item.
+ public LootLockerMetadataEntry[] metadata { get; set; }
+ }
+
+ ///
+ /// An item granted to a player as the result of consuming another item (or via an on-grant behaviour).
+ /// Matches the go-backend `GrantResult` shape returned in `granted` / `behaviour_results`.
+ ///
+ public class LootLockerGrantedItem
+ {
+ /// The source id of the granted entry (inventory id, currency id, etc.).
+ public string source_id { get; set; }
+
+ /// The number of items granted.
+ public int count { get; set; }
+
+ /// The type of the granted entry ("item_template", "currency", or "publisher_currency").
+ public string type { get; set; }
+
+ /// The name of the granted entry, if applicable.
+ public string name { get; set; }
+
+ /// The code of the granted entry, if applicable.
+ public string code { get; set; }
+ }
+
+ //==================================================
+ // Request Definitions
+ //==================================================
+
+ ///
+ /// Request to consume a stackable item from the player's inventory.
+ ///
+ public class LootLockerConsumeItemRequest
+ {
+ /// The number of items to consume. If omitted, the whole stack is consumed.
+ public int? count { get; set; }
+ }
+
+ ///
+ /// Request to split a stackable item in the player's inventory into two stacks.
+ ///
+ public class LootLockerSplitItemStackRequest
+ {
+ /// The number of items to move into the new stack.
+ public int count { get; set; }
+ }
+
+ ///
+ /// Request to merge two stacks of the same item into one.
+ ///
+ public class LootLockerMergeItemStacksRequest
+ {
+ /// The id of the source inventory item to merge from.
+ public string source_inventory_id { get; set; }
+
+ /// The id of the target inventory item to merge into.
+ public string target_inventory_id { get; set; }
+ }
+
+ //==================================================
+ // Response Definitions
+ //==================================================
+
+ ///
+ /// Response containing a paginated list of visible item templates.
+ ///
+ public class LootLockerListItemTemplatesResponse : LootLockerResponse
+ {
+ /// The list of visible item templates.
+ public LootLockerItemTemplate[] items { get; set; }
+
+ /// Pagination details for the response.
+ public LootLockerExtendedPagination pagination { get; set; }
+ }
+
+ ///
+ /// Response containing a paginated list of the player's inventory items.
+ ///
+ public class LootLockerListPlayerItemsResponse : LootLockerResponse
+ {
+ /// The list of the player's inventory items.
+ public LootLockerItem[] items { get; set; }
+
+ /// Pagination details for the response.
+ public LootLockerExtendedPagination pagination { get; set; }
+ }
+
+ ///
+ /// Response containing the player's inventory item, returned at the top level with its template and metadata.
+ ///
+ public class LootLockerGetPlayerItemResponse : LootLockerResponse
+ {
+ /// The unique id of this inventory item.
+ public string id { get; set; }
+
+ /// The id of the player that owns this inventory item.
+ public int player_id { get; set; }
+
+ /// The id of the item template this inventory item is based on.
+ public string item_template_id { get; set; }
+
+ /// The type of the item (instanced or stackable).
+ public string item_type { get; set; }
+
+ /// True if the item can be consumed by the player.
+ public bool consumable { get; set; }
+
+ /// True if the item can be deleted by the player.
+ public bool deletable { get; set; }
+
+ /// The number of items in this stack (only relevant for stackable items).
+ public int count { get; set; }
+
+ /// The source of this inventory item, or null if not specified.
+ public string source { get; set; }
+
+ /// The time that this inventory item was created.
+ public string created_at { get; set; }
+
+ /// The time that this inventory item was last updated.
+ public string updated_at { get; set; }
+
+ /// The item template this inventory item is based on.
+ public LootLockerItemTemplate template { get; set; }
+
+ /// Arbitrary metadata attached to this inventory item.
+ public LootLockerMetadataEntry[] metadata { get; set; }
+ }
+
+ ///
+ /// Response containing the result of consuming an item, including any items granted as a result.
+ ///
+ public class LootLockerConsumeItemResponse : LootLockerResponse
+ {
+ /// True if the item was consumed.
+ public bool consumed { get; set; }
+
+ /// Any items granted as a result of consuming the item.
+ public LootLockerGrantedItem[] granted { get; set; }
+ }
+
+ ///
+ /// Response containing the id of the newly created stack after splitting an item.
+ ///
+ public class LootLockerSplitItemStackResponse : LootLockerResponse
+ {
+ /// The id of the newly created item stack.
+ public string id { get; set; }
+ }
+}
+
+namespace LootLocker
+{
+ //==================================================
+ // API Class Definition
+ //==================================================
+
+ public partial class LootLockerAPIManager
+ {
+ public static void ListItemTemplates(string forPlayerWithUlid, int page, int perPage, Action onComplete)
+ {
+ EndPointClass endPoint = LootLockerEndPoints.listItemTemplates;
+
+ var queryParams = new QueryParamaterBuilder();
+ queryParams.Add("page", page);
+ queryParams.Add("per_page", perPage);
+
+ LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.endPoint + queryParams.Build(), endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); });
+ }
+
+ public static void ListPlayerItems(string forPlayerWithUlid, int page, int perPage, string name, string itemType, bool? consumable, string sort, string order, Action onComplete)
+ {
+ EndPointClass endPoint = LootLockerEndPoints.listPlayerItems;
+
+ var queryParams = new QueryParamaterBuilder();
+ queryParams.Add("page", page);
+ queryParams.Add("per_page", perPage);
+ queryParams.Add("name", name);
+ queryParams.Add("item_type", itemType);
+ if (consumable.HasValue)
+ {
+ queryParams.Add("consumable", consumable.Value.ToString().ToLower());
+ }
+ queryParams.Add("sort", sort);
+ queryParams.Add("order", order);
+
+ LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.endPoint + queryParams.Build(), endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); });
+ }
+
+ public static void GetPlayerItem(string forPlayerWithUlid, string inventoryId, Action onComplete)
+ {
+ EndPointClass endPoint = LootLockerEndPoints.getPlayerItem;
+
+ string getVariable = endPoint.WithPathParameter(inventoryId);
+
+ LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); });
+ }
+
+ public static void DeletePlayerItem(string forPlayerWithUlid, string inventoryId, Action onComplete)
+ {
+ EndPointClass endPoint = LootLockerEndPoints.deletePlayerItem;
+
+ string getVariable = endPoint.WithPathParameter(inventoryId);
+
+ LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, null, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); });
+ }
+
+ public static void ConsumePlayerItem(string forPlayerWithUlid, string inventoryId, LootLockerConsumeItemRequest data, Action onComplete)
+ {
+ EndPointClass endPoint = LootLockerEndPoints.consumePlayerItem;
+
+ string getVariable = endPoint.WithPathParameter(inventoryId);
+ string json = LootLockerJson.SerializeObject(data);
+
+ LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, json, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); });
+ }
+
+ public static void SplitPlayerItemStack(string forPlayerWithUlid, string inventoryId, LootLockerSplitItemStackRequest data, Action onComplete)
+ {
+ EndPointClass endPoint = LootLockerEndPoints.splitPlayerItemStack;
+
+ string getVariable = endPoint.WithPathParameter(inventoryId);
+ string json = LootLockerJson.SerializeObject(data);
+
+ LootLockerServerRequest.CallAPI(forPlayerWithUlid, getVariable, endPoint.httpMethod, json, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); });
+ }
+
+ public static void MergePlayerItemStacks(string forPlayerWithUlid, LootLockerMergeItemStacksRequest data, Action onComplete)
+ {
+ EndPointClass endPoint = LootLockerEndPoints.mergePlayerItemStacks;
+
+ string json = LootLockerJson.SerializeObject(data);
+
+ LootLockerServerRequest.CallAPI(forPlayerWithUlid, endPoint.endPoint, endPoint.httpMethod, json, onComplete: (serverResponse) => { LootLockerResponse.Deserialize(onComplete, serverResponse); });
+ }
+ }
+}