/** * Copyright 1998-2013 Epic Games, Inc. All Rights Reserved. * * This is the concrete implementation */ class McpManagedValueManager extends McpManagedValueManagerBase; /** The URL to use when making save slot */ var config String CreateSaveSlotUrl; /** The URL to use when reading save slot */ var config String ReadSaveSlotUrl; /** The URL to use when updating a value */ var config String UpdateValueUrl; /** The URL to use when deleting a value */ var config String DeleteValueUrl; /** The list of all save slots that are being managed */ var array SaveSlots; /** Holds the state information for an outstanding save slot request */ struct SaveSlotRequestState { /** The MCP id that was returned by the backend */ var string McpId; /** The save slot involved */ var string SaveSlot; /** The request object for this request */ var HttpRequestInterface Request; }; /** Holds the state information used by requests that act on a value id */ struct ValueRequestState extends SaveSlotRequestState { var Name ValueId; }; /** The set of create save slot requests that are pending */ var array CreateSaveSlotRequests; /** The set of read save slot requests that are pending */ var array ReadSaveSlotRequests; /** The set of update value requests that are pending */ var array UpdateValueRequests; /** The set of update value requests that are pending */ var array DeleteValueRequests; /** * Creates the user's specified save slot * * @param McpId the id of the user that requested the create * @param SaveSlot the save slot that is being create */ function CreateSaveSlot(String McpId, String SaveSlot) { local String Url; local HttpRequestInterface Request; local int AddAt; Request = class'HttpFactory'.static.CreateRequest(); if (Request != none) { Url = GetBaseURL() $ CreateSaveSlotUrl $ GetAppAccessURL() $ "&uniqueUserId=" $ McpId $ "&saveSlotId=" $ SaveSlot; // Build our web request with the above URL Request.SetURL(Url); Request.SetVerb("POST"); Request.OnProcessRequestComplete = OnCreateSaveSlotRequestComplete; // Store off the data for reporting later AddAt = CreateSaveSlotRequests.Length; CreateSaveSlotRequests.Length = AddAt + 1; CreateSaveSlotRequests[AddAt].McpId = McpId; CreateSaveSlotRequests[AddAt].SaveSlot = SaveSlot; CreateSaveSlotRequests[AddAt].Request = Request; // Now kick off the request if (!Request.ProcessRequest()) { `Log("Failed to start CreateSaveSlot web request for URL(" $ Url $ ")"); } `Log("Create save slot URL is " $ Url); } } /** * Called once the request/response has completed. Used to process the create save slot result * and notify any registered delegate * * @param Request the request object that was used * @param Response the response object that was generated * @param bWasSuccessful whether or not the request completed successfully */ function OnCreateSaveSlotRequestComplete(HttpRequestInterface Request, HttpResponseInterface Response, bool bWasSuccessful) { local int Index; local int ResponseCode; local string ResponseString; // Search for the corresponding entry in the array Index = CreateSaveSlotRequests.Find('Request', Request); if (Index != INDEX_NONE) { ResponseCode = 500; if (Response != none) { ResponseCode = Response.GetResponseCode(); } // Both of these need to be true for the request to be a success bWasSuccessful = bWasSuccessful && ResponseCode == 200; if (bWasSuccessful) { ResponseString = Response.GetContentAsString(); // Parse the JSON payload of default values for this save slot ParseValuesForSaveSlot(CreateSaveSlotRequests[Index].McpId, CreateSaveSlotRequests[Index].SaveSlot, ResponseString); } // Notify anyone waiting on this OnCreateSaveSlotComplete(CreateSaveSlotRequests[Index].McpId, CreateSaveSlotRequests[Index].SaveSlot, bWasSuccessful, Response.GetContentAsString()); `Log("Create save slot McpId(" $ CreateSaveSlotRequests[Index].McpId $ "), SaveSlot(" $ CreateSaveSlotRequests[Index].SaveSlot $ ") was successful " $ bWasSuccessful $ " with ResponseCode(" $ ResponseCode $ ")"); CreateSaveSlotRequests.Remove(Index,1); } } /** * Searches the stored save slots for the ones for this user * * @param McpId the user being searched for * @param SaveSlot the save slot being searched for * * @return the index of the save slot if found */ function int FindSaveSlotIndex(String McpId, String SaveSlot) { local int SaveSlotIndex; // Search all of the save slots for one that matches the user and slot id for (SaveSlotIndex = 0; SaveSlotIndex < SaveSlots.Length; SaveSlotIndex++) { if (SaveSlots[SaveSlotIndex].OwningMcpId == McpId && SaveSlots[SaveSlotIndex].SaveSlot == SaveSlot) { return SaveSlotIndex; } } return INDEX_NONE; } /** * Parses the json of managed values for a user's save slot * * @param McpId the user that owns the data * @param SaveSlot the save slot where the data is stored * @param JsonPayload the json data to parse */ function ParseValuesForSaveSlot(String McpId, String SaveSlot, String JsonPayload) { local JsonObject ParsedJson; local int JsonIndex; local int SaveSlotIndex; local int ManagedValueIndex; local name ValueId; local int Value; // Find the save slot for the user SaveSlotIndex = FindSaveSlotIndex(McpId, SaveSlot); if (SaveSlotIndex == INDEX_NONE) { // Add the save slot since it is missing SaveSlotIndex = SaveSlots.Length; SaveSlots.Length = SaveSlotIndex + 1; SaveSlots[SaveSlotIndex].OwningMcpId = McpId; SaveSlots[SaveSlotIndex].SaveSlot = SaveSlot; } // @todo joeg - Replace with Wes' ImportJson() once it's implemented with proper variable naming support ParsedJson = class'JsonObject'.static.DecodeJson(JsonPayload); // Add/update each managed value to the user's save slot for (JsonIndex = 0; JsonIndex < ParsedJson.ObjectArray.Length; JsonIndex++) { // Grab the value and id we need to store ValueId = name(ParsedJson.ObjectArray[JsonIndex].GetStringValue("value_id")); Value = ParsedJson.ObjectArray[JsonIndex].GetIntValue("value"); // Find the existing managed value ManagedValueIndex = SaveSlots[SaveSlotIndex].Values.Find('ValueId', ValueId); if (ManagedValueIndex == INDEX_NONE) { // Not stored yet, so add one ManagedValueIndex = SaveSlots[SaveSlotIndex].Values.Length; SaveSlots[SaveSlotIndex].Values.Length = ManagedValueIndex + 1; SaveSlots[SaveSlotIndex].Values[ManagedValueIndex].ValueId = ValueId; } // Store the updated value SaveSlots[SaveSlotIndex].Values[ManagedValueIndex].Value = Value; } } /** * Reads all of the values in the user's specified save slot * * @param McpId the id of the user that requested the read * @param SaveSlot the save slot that is being read */ function ReadSaveSlot(String McpId, String SaveSlot) { local String Url; local HttpRequestInterface Request; local int AddAt; Request = class'HttpFactory'.static.CreateRequest(); if (Request != none) { Url = GetBaseURL() $ ReadSaveSlotUrl $ GetAppAccessURL() $ "&uniqueUserId=" $ McpId $ "&saveSlotId=" $ SaveSlot; // Build our web request with the above URL Request.SetURL(Url); Request.SetVerb("GET"); Request.OnProcessRequestComplete = OnReadSaveSlotRequestComplete; // Store off the data for reporting later AddAt = ReadSaveSlotRequests.Length; ReadSaveSlotRequests.Length = AddAt + 1; ReadSaveSlotRequests[AddAt].McpId = McpId; ReadSaveSlotRequests[AddAt].SaveSlot = SaveSlot; ReadSaveSlotRequests[AddAt].Request = Request; // Now kick off the request if (!Request.ProcessRequest()) { `Log("Failed to start ReadSaveSlot web request for URL(" $ Url $ ")"); } `Log("Read save slot URL is " $ Url); } } /** * Called once the request/response has completed. Used to process the read save slot result * and notify any registered delegate * * @param Request the request object that was used * @param Response the response object that was generated * @param bWasSuccessful whether or not the request completed successfully */ function OnReadSaveSlotRequestComplete(HttpRequestInterface Request, HttpResponseInterface Response, bool bWasSuccessful) { local int Index; local int ResponseCode; local string ResponseString; // Search for the corresponding entry in the array Index = ReadSaveSlotRequests.Find('Request', Request); if (Index != INDEX_NONE) { ResponseCode = 500; if (Response != none) { ResponseCode = Response.GetResponseCode(); } // Both of these need to be true for the request to be a success bWasSuccessful = bWasSuccessful && ResponseCode == 200; if (bWasSuccessful) { ResponseString = Response.GetContentAsString(); // Parse the JSON payload of default values for this save slot ParseValuesForSaveSlot(ReadSaveSlotRequests[Index].McpId, ReadSaveSlotRequests[Index].SaveSlot, ResponseString); } // Notify anyone waiting on this OnReadSaveSlotComplete(ReadSaveSlotRequests[Index].McpId, ReadSaveSlotRequests[Index].SaveSlot, bWasSuccessful, Response.GetContentAsString()); `Log("Read save slot McpId(" $ ReadSaveSlotRequests[Index].McpId $ "), SaveSlot(" $ ReadSaveSlotRequests[Index].SaveSlot $ ") was successful " $ bWasSuccessful $ " with ResponseCode(" $ ResponseCode $ ")"); ReadSaveSlotRequests.Remove(Index,1); } } /** * @return The list of values for the requested user's specified save slot */ function array GetValues(String McpId, String SaveSlot) { local int SaveSlotIndex; local array EmptyArray; // Find the slot and then return the array of values stored there SaveSlotIndex = FindSaveSlotIndex(McpId, SaveSlot); if (SaveSlotIndex != INDEX_NONE) { return SaveSlots[SaveSlotIndex].Values; } // To avoid the script warning EmptyArray.Length = 0; return EmptyArray; } /** * @return The value the server returned for the requested value id from the user's specific save slot */ function int GetValue(String McpId, String SaveSlot, Name ValueId) { local int SaveSlotIndex; local int ValueIndex; local int Value; // Find the slot first SaveSlotIndex = FindSaveSlotIndex(McpId, SaveSlot); if (SaveSlotIndex != INDEX_NONE) { // Find the requested value ValueIndex = SaveSlots[SaveSlotIndex].Values.Find('ValueId', ValueId); if (ValueIndex != INDEX_NONE) { Value = SaveSlots[SaveSlotIndex].Values[ValueIndex].Value; } } return Value; } /** * Updates a specific value in the user's specified save slot * * @param McpId the id of the user that requested the update * @param SaveSlot the save slot that was being updated * @param ValueId the value that the server should update * @param Value the value to apply as the update (delta or absolute determined by the server) */ function UpdateValue(String McpId, String SaveSlot, Name ValueId, int Value) { local String Url; local HttpRequestInterface Request; local int AddAt; Request = class'HttpFactory'.static.CreateRequest(); if (Request != none) { Url = GetBaseURL() $ UpdateValueUrl $ GetAppAccessURL() $ "&uniqueUserId=" $ McpId $ "&saveSlotId=" $ SaveSlot $ "&valueId=" $ ValueId $ "&value=" $ Value; // Build our web request with the above URL Request.SetURL(Url); Request.SetVerb("POST"); Request.OnProcessRequestComplete = OnUpdateValueRequestComplete; // Store off the data for reporting later AddAt = UpdateValueRequests.Length; UpdateValueRequests.Length = AddAt + 1; UpdateValueRequests[AddAt].McpId = McpId; UpdateValueRequests[AddAt].SaveSlot = SaveSlot; UpdateValueRequests[AddAt].ValueId = ValueId; UpdateValueRequests[AddAt].Request = Request; // Now kick off the request if (!Request.ProcessRequest()) { `Log("Failed to start UpdateValue web request for URL(" $ Url $ ")"); } `Log("Update value URL is " $ Url); } } /** * Called once the request/response has completed. Used to process the update value result * and notify any registered delegate * * @param Request the request object that was used * @param Response the response object that was generated * @param bWasSuccessful whether or not the request completed successfully */ function OnUpdateValueRequestComplete(HttpRequestInterface Request, HttpResponseInterface Response, bool bWasSuccessful) { local int Index; local int ResponseCode; local string ResponseString; local int UpdatedValue; // Search for the corresponding entry in the array Index = UpdateValueRequests.Find('Request', Request); if (Index != INDEX_NONE) { ResponseCode = 500; if (Response != none) { ResponseCode = Response.GetResponseCode(); } // Both of these need to be true for the request to be a success bWasSuccessful = bWasSuccessful && ResponseCode == 200; if (bWasSuccessful) { ResponseString = "[" $ Response.GetContentAsString() $ "]"; // Parse the JSON payload of default values for this save slot ParseValuesForSaveSlot(UpdateValueRequests[Index].McpId, UpdateValueRequests[Index].SaveSlot, ResponseString); } UpdatedValue = GetValue(UpdateValueRequests[Index].McpId, UpdateValueRequests[Index].SaveSlot, UpdateValueRequests[Index].ValueId); // Notify anyone waiting on this OnUpdateValueComplete(UpdateValueRequests[Index].McpId, UpdateValueRequests[Index].SaveSlot, UpdateValueRequests[Index].ValueId, UpdatedValue, bWasSuccessful, Response.GetContentAsString()); `Log("Update value McpId(" $ UpdateValueRequests[Index].McpId $ "), SaveSlot(" $ UpdateValueRequests[Index].SaveSlot $ "), ValueId(" $ UpdateValueRequests[Index].ValueId $ "), Value(" $ UpdatedValue $ ") was successful " $ bWasSuccessful $ " with ResponseCode(" $ ResponseCode $ ")"); UpdateValueRequests.Remove(Index,1); } } /** * Deletes a value from the user's specified save slot * * @param McpId the id of the user that requested the delete * @param SaveSlot the save slot that is having the value deleted from * @param ValueId the value id for the server to delete */ function DeleteValue(String McpId, String SaveSlot, Name ValueId) { local String Url; local HttpRequestInterface Request; local int AddAt; Request = class'HttpFactory'.static.CreateRequest(); if (Request != none) { Url = GetBaseURL() $ DeleteValueUrl $ GetAppAccessURL() $ "&uniqueUserId=" $ McpId $ "&saveSlotId=" $ SaveSlot $ "&valueId=" $ ValueId; // Build our web request with the above URL Request.SetURL(Url); Request.SetVerb("DELETE"); Request.OnProcessRequestComplete = OnDeleteValueRequestComplete; // Store off the data for reporting later AddAt = DeleteValueRequests.Length; DeleteValueRequests.Length = AddAt + 1; DeleteValueRequests[AddAt].McpId = McpId; DeleteValueRequests[AddAt].SaveSlot = SaveSlot; DeleteValueRequests[AddAt].ValueId = ValueId; DeleteValueRequests[AddAt].Request = Request; // Now kick off the request if (!Request.ProcessRequest()) { `Log("Failed to start DeleteValue web request for URL(" $ Url $ ")"); } `Log("Delete value URL is " $ Url); } } /** * Called once the request/response has completed. Used to process the delete value result * and notify any registered delegate * * @param Request the request object that was used * @param Response the response object that was generated * @param bWasSuccessful whether or not the request completed successfully */ function OnDeleteValueRequestComplete(HttpRequestInterface Request, HttpResponseInterface Response, bool bWasSuccessful) { local int Index; local int ResponseCode; local int SaveSlotIndex; local int ValueIndex; // Search for the corresponding entry in the array Index = DeleteValueRequests.Find('Request', Request); if (Index != INDEX_NONE) { ResponseCode = 500; if (Response != none) { ResponseCode = Response.GetResponseCode(); } // Both of these need to be true for the request to be a success bWasSuccessful = bWasSuccessful && ResponseCode == 200; if (bWasSuccessful) { // Find the slot first SaveSlotIndex = FindSaveSlotIndex(DeleteValueRequests[Index].McpId, DeleteValueRequests[Index].SaveSlot); if (SaveSlotIndex != INDEX_NONE) { // Find the requested value ValueIndex = SaveSlots[SaveSlotIndex].Values.Find('ValueId', DeleteValueRequests[Index].ValueId); if (ValueIndex != INDEX_NONE) { // Remove it from the array SaveSlots[SaveSlotIndex].Values.Remove(ValueIndex, 1); } } } // Notify anyone waiting on this OnDeleteValueComplete(DeleteValueRequests[Index].McpId, DeleteValueRequests[Index].SaveSlot, DeleteValueRequests[Index].ValueId, bWasSuccessful, Response.GetContentAsString()); `Log("Delete value McpId(" $ DeleteValueRequests[Index].McpId $ "), SaveSlot(" $ DeleteValueRequests[Index].SaveSlot $ "), ValueId(" $ DeleteValueRequests[Index].ValueId $ ") was successful " $ bWasSuccessful $ " with ResponseCode(" $ ResponseCode $ ")"); DeleteValueRequests.Remove(Index,1); } }