diff --git a/src/Prospect.Server.Api/Controllers/ClientController.cs b/src/Prospect.Server.Api/Controllers/ClientController.cs new file mode 100644 index 0000000..c807999 --- /dev/null +++ b/src/Prospect.Server.Api/Controllers/ClientController.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; +using Prospect.Server.Api.Models.Client; +using Prospect.Server.Api.Models.Client.Data; + +namespace Prospect.Server.Api.Controllers +{ + [Route("Client")] + [ApiController] + public class ClientController : Controller + { + [HttpPost("LoginWithSteam")] + [Produces("application/json")] + public IActionResult LoginWithSteam(ClientLoginWithSteamRequest request) + { + var playerIdOne = "AAAABBBBCCCCDDDD"; // PlayFabId + var playerIdTwo = "0000111122223333"; // EntityId + var playerName = "AeonLucid"; + + var titleId = "A22AB"; + var publisherId = "850902E5B40508ED"; + + if (!string.IsNullOrEmpty(request.SteamTicket)) + { + return Ok(new ClientResponse + { + Code = 200, + Status = "OK", + Data = new FServerLoginResult + { + EntityToken = new FEntityTokenResponse + { + Entity = new FEntityKey + { + Id = playerIdTwo, + Type = "title_player_account", + TypeString = "title_player_account" + }, + EntityToken = "RW50aXR5VG9rZW4=", + TokenExpiration = DateTime.UtcNow.AddDays(1), + }, + InfoResultPayload = new FGetPlayerCombinedInfoResultPayload + { + CharacterInventories = new List(), + PlayerProfile = new FPlayerProfileModel + { + DisplayName = playerName, + PlayerId = playerIdOne, + PublisherId = publisherId, + TitleId = titleId + }, + UserDataVersion = 0, + UserInventory = new List(), + UserReadOnlyDataVersion = 0 + }, + LastLoginTime = DateTime.UtcNow, + NewlyCreated = false, + PlayFabId = playerIdOne, + SessionTicket = "SOME", + SettingsForUser = new FUserSettings + { + GatherDeviceInfo = true, + GatherFocusInfo = true, + NeedsAttribution = false, + }, + TreatmentAssignment = new FTreatmentAssignment + { + Variables = new List(), + Variants = new List() + } + } + }); + } + + return BadRequest(new ClientResponse + { + Code = 400, + Status = "BadRequest", + Error = "InvalidSteamTicket", + ErrorCode = 1010, + ErrorMessage = "Steam API AuthenticateUserTicket error response .." + }); + } + + [HttpPost("AddGenericID")] + [Produces("application/json")] + public IActionResult AddGenericId(FAddGenericIDRequest request) + { + return Ok(new ClientResponse + { + Code = 200, + Status = "OK" + }); + } + + [HttpPost("UpdateUserTitleDisplayName")] + [Produces("application/json")] + public IActionResult AddGenericId(FUpdateUserTitleDisplayNameRequest request) + { + return Ok(new ClientResponse + { + Code = 200, + Status = "OK", + Data = new FUpdateUserTitleDisplayNameResult + { + DisplayName = request.DisplayName + } + }); + } + + [HttpPost("GetUserData")] + [Produces("application/json")] + public IActionResult GetUserData(FGetUserDataRequest request) + { + return Ok(new ClientResponse + { + Code = 200, + Status = "OK", + Data = new FGetUserDataResult + { + Data = new Dictionary(), + DataVersion = 0 + } + }); + } + + [HttpPost("GetUserReadOnlyData")] + [Produces("application/json")] + public IActionResult GetUserReadOnlyData(FGetUserDataRequest request) + { + return Ok(new ClientResponse + { + Code = 200, + Status = "OK", + Data = new FGetUserDataResult + { + Data = new Dictionary(), + DataVersion = 0 + } + }); + } + + [HttpPost("GetUserInventory")] + [Produces("application/json")] + public IActionResult GetUserReadOnlyData(FGetUserInventoryRequest request) + { + return Ok(new ClientResponse + { + Code = 200, + Status = "OK", + Data = new FGetUserInventoryResult + { + Inventory = new List + { + new FItemInstance + { + ItemId = "Helmet_03", + ItemInstanceId = "0102030405060708", + ItemClass = "Helmet", + PurchaseDate = DateTime.Now.AddDays(-1), + CatalogVersion = "StaticItems", + DisplayName = "Helmet", + UnitPrice = 0, + CustomData = new Dictionary + { + ["insurance"] = "None", + ["mods"] = "{\"m\":[]}", + ["vanity_misc_data"] = "{\"v\":\"\",\"s\":\"\",\"l\":3,\"a\":1,\"d\":300}" + } + } + }, + VirtualCurrency = new Dictionary + { + ["AE"] = 0, + ["AS"] = 0, + ["AU"] = 0, + ["SC"] = 12345 + }, + VirtualCurrencyRechargeTimes = new Dictionary() + } + }); + } + + [HttpPost("GetTitleData")] + [Produces("application/json")] + public IActionResult GetTitleData(FGetTitleDataRequest request) + { + return Ok(new ClientResponse + { + Code = 200, + Status = "OK", + Data = new FGetTitleDataResult() + { + Data = new Dictionary() + } + }); + } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Middleware/RequestLoggerMiddleware.cs b/src/Prospect.Server.Api/Middleware/RequestLoggerMiddleware.cs new file mode 100644 index 0000000..fd91bca --- /dev/null +++ b/src/Prospect.Server.Api/Middleware/RequestLoggerMiddleware.cs @@ -0,0 +1,57 @@ +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace Prospect.Server.Api.Middleware +{ + public class RequestLoggerMiddleware + { + private readonly ILogger _logger; + private readonly RequestDelegate _next; + + public RequestLoggerMiddleware(ILogger logger, RequestDelegate next) + { + _logger = logger; + _next = next; + } + + public async Task Invoke(HttpContext context) + { + var body = await RequestAsync(context.Request); + + if (context.Request.Method == "POST") + { + _logger.LogDebug("URL {Url} Body {Body}", context.Request.GetDisplayUrl(), body); + } + + await _next(context); + } + + private static async Task RequestAsync(HttpRequest request) + { + request.EnableBuffering(); + + try + { + using (var reader = new StreamReader(request.Body, Encoding.UTF8, false, 4096, true)) + { + var body = await reader.ReadToEndAsync(); + if (body.StartsWith("{")) + { + return JsonConvert.SerializeObject(JsonConvert.DeserializeObject(body), Formatting.Indented); + } + + return body; + } + } + finally + { + request.Body.Position = 0; + } + } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/ClientLoginWithSteamRequest.cs b/src/Prospect.Server.Api/Models/Client/ClientLoginWithSteamRequest.cs new file mode 100644 index 0000000..31e0480 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/ClientLoginWithSteamRequest.cs @@ -0,0 +1,59 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client +{ + public class ClientLoginWithSteamRequest + { + [JsonPropertyName("CreateAccount")] + public bool CreateAccount { get; set; } + + [JsonPropertyName("CustomTags")] + public JsonDocument CustomTags { get; set; } + + [JsonPropertyName("EncryptedRequest")] + public string EncryptedRequest { get; set; } + + [JsonPropertyName("InfoRequestParameters")] + public InfoParameters InfoRequestParameters { get; set; } + + [JsonPropertyName("PlayerSecret")] + public string PlayerSecret { get; set; } + + [JsonPropertyName("SteamTicket")] + public string SteamTicket { get; set; } + } + + public class InfoParameters + { + [JsonPropertyName("GetCharacterInventories")] + public bool GetCharacterInventories { get; set; } + + [JsonPropertyName("GetCharacterList")] + public bool GetCharacterList { get; set; } + + [JsonPropertyName("GetPlayerProfile")] + public bool GetPlayerProfile { get; set; } + + [JsonPropertyName("GetPlayerStatistics")] + public bool GetPlayerStatistics { get; set; } + + [JsonPropertyName("GetTitleData")] + public bool GetTitleData { get; set; } + + [JsonPropertyName("GetUserAccountInfo")] + public bool GetUserAccountInfo { get; set; } + + [JsonPropertyName("GetUserData")] + public bool GetUserData { get; set; } + + [JsonPropertyName("GetUserInventory")] + public bool GetUserInventory { get; set; } + + [JsonPropertyName("GetUserReadOnlyData")] + public bool GetUserReadOnlyData { get; set; } + + [JsonPropertyName("GetUserVirtualCurrency")] + public bool GetUserVirtualCurrency { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/ClientResponse.cs b/src/Prospect.Server.Api/Models/Client/ClientResponse.cs new file mode 100644 index 0000000..ed483fb --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/ClientResponse.cs @@ -0,0 +1,32 @@ +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client +{ + public class ClientResponse + { + [JsonPropertyName("code")] + public int Code { get; set; } + + [JsonPropertyName("status")] + public string Status { get; set; } + + [JsonPropertyName("error")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Error { get; set; } + + [JsonPropertyName("errorCode")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public int ErrorCode { get; set; } + + [JsonPropertyName("errorMessage")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string ErrorMessage { get; set; } + } + + public class ClientResponse : ClientResponse + { + [JsonPropertyName("data")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public T Data { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FEntityKey.cs b/src/Prospect.Server.Api/Models/Client/Data/FEntityKey.cs new file mode 100644 index 0000000..26f4adf --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FEntityKey.cs @@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FEntityKey + { + /// + /// Unique ID of the entity. + /// + [JsonPropertyName("Id")] + public string Id { get; set; } + + /// + /// [optional] Entity type. See https://docs.microsoft.com/gaming/playfab/features/data/entities/available-built-in-entity-types + /// + [JsonPropertyName("Type")] + public string Type { get; set; } + + // Not in PlayFab SDK + [JsonPropertyName("TypeString")] + public string TypeString { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FEntityTokenResponse.cs b/src/Prospect.Server.Api/Models/Client/Data/FEntityTokenResponse.cs new file mode 100644 index 0000000..8c18309 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FEntityTokenResponse.cs @@ -0,0 +1,29 @@ +using System; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FEntityTokenResponse + { + /// + /// [optional] The entity id and type. + /// + [JsonPropertyName("Entity")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public FEntityKey Entity { get; set; } + + /// + /// [optional] The token used to set X-EntityToken for all entity based API calls. + /// + [JsonPropertyName("EntityToken")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string EntityToken { get; set; } + + /// + /// [optional] The time the token will expire, if it is an expiring token, in UTC. + /// + [JsonPropertyName("TokenExpiration")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public DateTime? TokenExpiration { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FGenericServiceId.cs b/src/Prospect.Server.Api/Models/Client/Data/FGenericServiceId.cs new file mode 100644 index 0000000..31d00f3 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FGenericServiceId.cs @@ -0,0 +1,19 @@ +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FGenericServiceId + { + /// + /// Name of the service for which the player has a unique identifier. + /// + [JsonPropertyName("ServiceName")] + public string ServiceName { get; set; } + + /// + /// Unique identifier of the player in that service. + /// + [JsonPropertyName("UserId")] + public string UserId { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FGetPlayerCombinedInfoResultPayload.cs b/src/Prospect.Server.Api/Models/Client/Data/FGetPlayerCombinedInfoResultPayload.cs new file mode 100644 index 0000000..d496608 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FGetPlayerCombinedInfoResultPayload.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FGetPlayerCombinedInfoResultPayload + { + // TSharedPtr AccountInfo; + + /// + /// [optional] Inventories for each character for the user. + /// + [JsonPropertyName("CharacterInventories")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public List CharacterInventories { get; set; } + + // TArray CharacterList; + + /// + /// [optional] The profile of the players. This profile is not guaranteed to be up-to-date. For a new player, this profile will not + /// exist. + /// + [JsonPropertyName("PlayerProfile")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public FPlayerProfileModel PlayerProfile { get; set; } + + // TArray PlayerStatistics; + + // TMap TitleData; + + // TMap UserData; + + /// + /// The version of the UserData that was returned. + /// + [JsonPropertyName("UserDataVersion")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public uint? UserDataVersion { get; set; } + + /// + /// [optional] Array of inventory items in the user's current inventory. + /// + [JsonPropertyName("UserInventory")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public List UserInventory { get; set; } + + // TMap UserReadOnlyData; + + /// + /// The version of the Read-Only UserData that was returned. + /// + [JsonPropertyName("UserReadOnlyDataVersion")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public uint? UserReadOnlyDataVersion { get; set; } + + // TMap UserVirtualCurrency; + + // TMap UserVirtualCurrencyRechargeTimes; + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FItemInstance.cs b/src/Prospect.Server.Api/Models/Client/Data/FItemInstance.cs new file mode 100644 index 0000000..36f46b1 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FItemInstance.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FItemInstance + { + /// + /// [optional] Game specific comment associated with this instance when it was added to the user inventory. + /// + [JsonPropertyName("Annotation")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Annotation { get; set; } + + /// + /// [optional] Array of unique items that were awarded when this catalog item was purchased. + /// + [JsonPropertyName("BundleContents")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public List BundleContents { get; set; } + + /// + /// [optional] Unique identifier for the parent inventory item, as defined in the catalog, for object which were added from a bundle or + /// container. + /// + [JsonPropertyName("BundleParent")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string BundleParent { get; set; } + + /// + /// [optional] Catalog version for the inventory item, when this instance was created. + /// + [JsonPropertyName("CatalogVersion")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string CatalogVersion { get; set; } + + /// + /// [optional] A set of custom key-value pairs on the instance of the inventory item, which is not to be confused with the catalog + /// item's custom data. + /// + [JsonPropertyName("CustomData")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Dictionary CustomData { get; set; } + + /// + /// [optional] CatalogItem.DisplayName at the time this item was purchased. + /// + [JsonPropertyName("DisplayName")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string DisplayName { get; set; } + + /// + /// [optional] Timestamp for when this instance will expire. + /// + [JsonPropertyName("Expiration")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public DateTime? Expiration { get; set; } + + /// + /// [optional] Class name for the inventory item, as defined in the catalog. + /// + [JsonPropertyName("ItemClass")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string ItemClass { get; set; } + + /// + /// [optional] Unique identifier for the inventory item, as defined in the catalog. + /// + [JsonPropertyName("ItemId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string ItemId { get; set; } + + /// + /// [optional] Unique item identifier for this specific instance of the item. + /// + [JsonPropertyName("ItemInstanceId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string ItemInstanceId { get; set; } + + /// + /// [optional] Timestamp for when this instance was purchased. + /// + [JsonPropertyName("PurchaseDate")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public DateTime? PurchaseDate { get; set; } + + /// + /// [optional] Total number of remaining uses, if this is a consumable item. + /// + [JsonPropertyName("RemainingUses")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public int? RemainingUses { get; set; } + + /// + /// [optional] Currency type for the cost of the catalog item. Not available when granting items. + /// + [JsonPropertyName("UnitCurrency")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string UnitCurrency { get; set; } + + /// + /// Cost of the catalog item in the given currency. Not available when granting items. + /// + [JsonPropertyName("UnitPrice")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public uint? UnitPrice { get; set; } + + /// + /// [optional] The number of uses that were added or removed to this item in this call. + /// + [JsonPropertyName("UsesIncrementedBy")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public int? UsesIncrementedBy { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FPlayerProfileModel.cs b/src/Prospect.Server.Api/Models/Client/Data/FPlayerProfileModel.cs new file mode 100644 index 0000000..e11a50d --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FPlayerProfileModel.cs @@ -0,0 +1,35 @@ +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FPlayerProfileModel + { + /// + /// [optional] Player display name + /// + [JsonPropertyName("DisplayName")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string DisplayName { get; set; } + + /// + /// [optional] PlayFab player account unique identifier + /// + [JsonPropertyName("PlayerId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string PlayerId { get; set; } + + /// + /// [optional] Publisher this player belongs to + /// + [JsonPropertyName("PublisherId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string PublisherId { get; set; } + + /// + /// [optional] Title ID this player profile applies to + /// + [JsonPropertyName("TitleId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string TitleId { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FTreatmentAssignment.cs b/src/Prospect.Server.Api/Models/Client/Data/FTreatmentAssignment.cs new file mode 100644 index 0000000..0cfeb15 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FTreatmentAssignment.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FTreatmentAssignment + { + /// + /// [optional] List of the experiment variables. + /// + [JsonPropertyName("Variables")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public List Variables { get; set; } + + /// + /// [optional] List of the experiment variants. + /// + [JsonPropertyName("Variants")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public List Variants { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FUserDataRecord.cs b/src/Prospect.Server.Api/Models/Client/Data/FUserDataRecord.cs new file mode 100644 index 0000000..2c4eb74 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FUserDataRecord.cs @@ -0,0 +1,30 @@ +using System; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FUserDataRecord + { + /// + /// Timestamp for when this data was last updated. + /// + [JsonPropertyName("LastUpdated")] + public DateTime LastUpdated { get; set; } + + /// + /// [optional] Indicates whether this data can be read by all users (public) or only the user (private). This is used for GetUserData + /// requests being made by one player about another player. + /// + [JsonPropertyName("Permission")] + [JsonConverter(typeof(JsonStringEnumConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public UserDataPermission Permission { get; set; } + + /// + /// [optional] Data stored for the specified user data key. + /// + [JsonPropertyName("Value")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FUserSettings.cs b/src/Prospect.Server.Api/Models/Client/Data/FUserSettings.cs new file mode 100644 index 0000000..509a816 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FUserSettings.cs @@ -0,0 +1,25 @@ +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FUserSettings + { + /// + /// Boolean for whether this player is eligible for gathering device info. + /// + [JsonPropertyName("GatherDeviceInfo")] + public bool GatherDeviceInfo { get; set; } + + /// + /// Boolean for whether this player should report OnFocus play-time tracking. + /// + [JsonPropertyName("GatherFocusInfo")] + public bool GatherFocusInfo { get; set; } + + /// + /// Boolean for whether this player is eligible for ad tracking. + /// + [JsonPropertyName("NeedsAttribution")] + public bool NeedsAttribution { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FVariable.cs b/src/Prospect.Server.Api/Models/Client/Data/FVariable.cs new file mode 100644 index 0000000..718c2cf --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FVariable.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FVariable + { + /// + /// Name of the variable. + /// + [JsonPropertyName("Name")] + public string Name { get; set; } + + /// + /// [optional] Value of the variable. + /// + [JsonPropertyName("Value")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/FVirtualCurrencyRechargeTime.cs b/src/Prospect.Server.Api/Models/Client/Data/FVirtualCurrencyRechargeTime.cs new file mode 100644 index 0000000..f17edc3 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/FVirtualCurrencyRechargeTime.cs @@ -0,0 +1,28 @@ +using System; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client.Data +{ + public class FVirtualCurrencyRechargeTime + { + /// + /// Maximum value to which the regenerating currency will automatically increment. Note that it can exceed this value + /// through use of the AddUserVirtualCurrency API call. However, it will not regenerate automatically until it has fallen + /// below this value. + /// + [JsonPropertyName("RechargeMax")] + public int RechargeMax { get; set; } + + /// + /// Server timestamp in UTC indicating the next time the virtual currency will be incremented. + /// + [JsonPropertyName("RechargeTime")] + public DateTime RechargeTime { get; set; } + + /// + /// Time remaining (in seconds) before the next recharge increment of the virtual currency. + /// + [JsonPropertyName("SecondsToRecharge")] + public int SecondsToRecharge { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/Data/UserDataPermission.cs b/src/Prospect.Server.Api/Models/Client/Data/UserDataPermission.cs new file mode 100644 index 0000000..4ab44ab --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/Data/UserDataPermission.cs @@ -0,0 +1,8 @@ +namespace Prospect.Server.Api.Models.Client.Data +{ + public enum UserDataPermission + { + Public, + Private + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/FAddGenericIDRequest.cs b/src/Prospect.Server.Api/Models/Client/FAddGenericIDRequest.cs new file mode 100644 index 0000000..fa44472 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/FAddGenericIDRequest.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; +using Prospect.Server.Api.Models.Client.Data; + +namespace Prospect.Server.Api.Models.Client +{ + public class FAddGenericIDRequest + { + [JsonPropertyName("GenericId")] + public FGenericServiceId GenericId { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/FGetTitleDataRequest.cs b/src/Prospect.Server.Api/Models/Client/FGetTitleDataRequest.cs new file mode 100644 index 0000000..01c5280 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/FGetTitleDataRequest.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client +{ + public class FGetTitleDataRequest + { + /// + /// [optional] Specific keys to search for in the title data (leave null to get all keys) + /// + [JsonPropertyName("Keys")] + public List Keys { get; set; } + + /// + /// [optional] Name of the override. This value is ignored when used by the game client; otherwise, the overrides are applied + /// automatically to the title data. + /// + [JsonPropertyName("OverrideLabel")] + public string OverrideLabel { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/FGetTitleDataResult.cs b/src/Prospect.Server.Api/Models/Client/FGetTitleDataResult.cs new file mode 100644 index 0000000..0ae60d6 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/FGetTitleDataResult.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client +{ + public class FGetTitleDataResult + { + /// + /// [optional] a dictionary object of key / value pairs + /// + [JsonPropertyName("Data")] + public Dictionary Data { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/FGetUserDataRequest.cs b/src/Prospect.Server.Api/Models/Client/FGetUserDataRequest.cs new file mode 100644 index 0000000..aa91c67 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/FGetUserDataRequest.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client +{ + public class FGetUserDataRequest + { + /// + /// [optional] The version that currently exists according to the caller. The call will return the data for all of the keys if the + /// version in the system is greater than this. + /// + [JsonPropertyName("IfChangedFromDataVersion")] + public List IfChangedFromDataVersion { get; set; } + + /// + /// [optional] List of unique keys to load from. + /// + [JsonPropertyName("Keys")] + public List Keys { get; set; } + + /// + /// [optional] Unique PlayFab identifier of the user to load data for. Optional, defaults to yourself if not set. When specified to a + /// PlayFab id of another player, then this will only return public keys for that account. + /// + [JsonPropertyName("PlayFabId")] + public string PlayFabId { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/FGetUserDataResult.cs b/src/Prospect.Server.Api/Models/Client/FGetUserDataResult.cs new file mode 100644 index 0000000..cd00e9e --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/FGetUserDataResult.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Prospect.Server.Api.Models.Client.Data; + +namespace Prospect.Server.Api.Models.Client +{ + public class FGetUserDataResult + { + /// + /// [optional] User specific data for this title. + /// + [JsonPropertyName("Data")] + public Dictionary Data { get; set; } + + /// + /// [optional] Indicates the current version of the data that has been set. This is incremented with every set call for that type of + /// data (read-only, internal, etc). This version can be provided in Get calls to find updated data. + /// + [JsonPropertyName("DataVersion")] + public uint DataVersion { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/FGetUserInventoryRequest.cs b/src/Prospect.Server.Api/Models/Client/FGetUserInventoryRequest.cs new file mode 100644 index 0000000..de6ea89 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/FGetUserInventoryRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client +{ + public class FGetUserInventoryRequest + { + /// + /// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.). + /// + [JsonPropertyName("CustomTags")] + public Dictionary CustomTags { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/FGetUserInventoryResult.cs b/src/Prospect.Server.Api/Models/Client/FGetUserInventoryResult.cs new file mode 100644 index 0000000..d2cec94 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/FGetUserInventoryResult.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Prospect.Server.Api.Models.Client.Data; + +namespace Prospect.Server.Api.Models.Client +{ + public class FGetUserInventoryResult + { + /// + /// [optional] Array of inventory items belonging to the user. + /// + [JsonPropertyName("Inventory")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public List Inventory { get; set; } + + /// + /// [optional] Array of virtual currency balance(s) belonging to the user. + /// + [JsonPropertyName("VirtualCurrency")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Dictionary VirtualCurrency { get; set; } + + /// + /// [optional] Array of virtual currency balance(s) belonging to the user. + /// + [JsonPropertyName("VirtualCurrencyRechargeTimes")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Dictionary VirtualCurrencyRechargeTimes { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/FServerLoginResult.cs b/src/Prospect.Server.Api/Models/Client/FServerLoginResult.cs new file mode 100644 index 0000000..416bafa --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/FServerLoginResult.cs @@ -0,0 +1,64 @@ +using System; +using System.Text.Json.Serialization; +using Prospect.Server.Api.Models.Client.Data; + +namespace Prospect.Server.Api.Models.Client +{ + public class FServerLoginResult + { + /// + /// [optional] If LoginTitlePlayerAccountEntity flag is set on the login request the title_player_account will also be logged in and + /// returned. + /// + [JsonPropertyName("EntityToken")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public FEntityTokenResponse EntityToken { get; set; } + + /// + /// [optional] Results for requested info. + /// + [JsonPropertyName("InfoResultPayload")] + public FGetPlayerCombinedInfoResultPayload InfoResultPayload { get; set; } + + /// + /// [optional] The time of this user's previous login. If there was no previous login, then it's DateTime.MinValue + /// + [JsonPropertyName("LastLoginTime")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public DateTime? LastLoginTime { get; set; } + + /// + /// True if the account was newly created on this login. + /// + [JsonPropertyName("NewlyCreated")] + public bool NewlyCreated { get; set; } + + /// + /// [optional] Player's unique PlayFabId. + /// + [JsonPropertyName("PlayFabId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string PlayFabId { get; set; } + + /// + /// [optional] Unique token authorizing the user and game at the server level, for the current session. + /// + [JsonPropertyName("SessionTicket")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string SessionTicket { get; set; } + + /// + /// [optional] Settings specific to this user. + /// + [JsonPropertyName("SettingsForUser")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public FUserSettings SettingsForUser { get; set; } + + /// + /// [optional] The experimentation treatments for this user at the time of login. + /// + [JsonPropertyName("TreatmentAssignment")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public FTreatmentAssignment TreatmentAssignment { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/FUpdateUserTitleDisplayNameRequest.cs b/src/Prospect.Server.Api/Models/Client/FUpdateUserTitleDisplayNameRequest.cs new file mode 100644 index 0000000..8fa99f3 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/FUpdateUserTitleDisplayNameRequest.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Prospect.Server.Api.Models.Client +{ + public class FUpdateUserTitleDisplayNameRequest + { + /// + /// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.). + /// + [JsonPropertyName("CustomTags")] + public Dictionary CustomTags { get; set; } + + /// + /// New title display name for the user - must be between 3 and 25 characters. + /// + [JsonPropertyName("DisplayName")] + public string DisplayName { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Models/Client/FUpdateUserTitleDisplayNameResult.cs b/src/Prospect.Server.Api/Models/Client/FUpdateUserTitleDisplayNameResult.cs new file mode 100644 index 0000000..3d0f130 --- /dev/null +++ b/src/Prospect.Server.Api/Models/Client/FUpdateUserTitleDisplayNameResult.cs @@ -0,0 +1,10 @@ +namespace Prospect.Server.Api.Models.Client +{ + public class FUpdateUserTitleDisplayNameResult + { + /// + /// [optional] Current title display name for the user (this will be the original display name if the rename attempt failed). + /// + public string DisplayName { get; set; } + } +} \ No newline at end of file diff --git a/src/Prospect.Server.Api/Program.cs b/src/Prospect.Server.Api/Program.cs index ce0723e..b542c8a 100644 --- a/src/Prospect.Server.Api/Program.cs +++ b/src/Prospect.Server.Api/Program.cs @@ -11,6 +11,7 @@ namespace Prospect.Server.Api public static int Main(string[] args) { Log.Logger = new LoggerConfiguration() + .MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Information) .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) .Enrich.FromLogContext() diff --git a/src/Prospect.Server.Api/Properties/launchSettings.json b/src/Prospect.Server.Api/Properties/launchSettings.json index e4c9f57..3a338b1 100644 --- a/src/Prospect.Server.Api/Properties/launchSettings.json +++ b/src/Prospect.Server.Api/Properties/launchSettings.json @@ -4,7 +4,7 @@ "commandName": "Project", "dotnetRunMessages": "true", "launchBrowser": false, - "applicationUrl": "http://localhost:8888", + "applicationUrl": "http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/src/Prospect.Server.Api/Startup.cs b/src/Prospect.Server.Api/Startup.cs index de03832..7cee2ae 100644 --- a/src/Prospect.Server.Api/Startup.cs +++ b/src/Prospect.Server.Api/Startup.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Prospect.Server.Api.Middleware; using Serilog; namespace Prospect.Server.Api @@ -21,9 +22,8 @@ namespace Prospect.Server.Api } app.UseSerilogRequestLogging(); - + app.UseMiddleware(); app.UseRouting(); - app.UseEndpoints(endpoints => { endpoints.MapControllers();