Now able to enter the lobby

This commit is contained in:
AeonLucid
2021-11-04 06:29:58 +01:00
parent 667d19e9f2
commit e0010e1d31
19 changed files with 593 additions and 10 deletions
@@ -19,7 +19,6 @@ namespace Prospect.Server.Api.Controllers
{
[ApiController]
[Route("Client")]
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
public class ClientController : Controller
{
private readonly PlayFabSettings _settings;
@@ -127,17 +126,20 @@ namespace Prospect.Server.Api.Controllers
[HttpPost("AddGenericID")]
[Produces("application/json")]
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
public IActionResult AddGenericId(FAddGenericIDRequest request)
{
return Ok(new ClientResponse
return Ok(new ClientResponse<object>
{
Code = 200,
Status = "OK"
Status = "OK",
Data = new object()
});
}
[HttpPost("UpdateUserTitleDisplayName")]
[Produces("application/json")]
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
public IActionResult UpdateUserTitleDisplayName(FUpdateUserTitleDisplayNameRequest request)
{
return Ok(new ClientResponse<FUpdateUserTitleDisplayNameResult>
@@ -151,8 +153,28 @@ namespace Prospect.Server.Api.Controllers
});
}
[HttpPost("UpdateUserData")]
[Produces("application/json")]
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
public async Task<IActionResult> UpdateUserData(FUpdateUserDataRequest request)
{
var userId = User.FindAuthUserId();
await _userDataService.UpdateAsync(userId, request.PlayFabId, request.Data);
return Ok(new ClientResponse<FUpdateUserDataResult>
{
Code = 200,
Status = "OK",
Data = new FUpdateUserDataResult
{
DataVersion = 0
}
});
}
[HttpPost("GetUserData")]
[Produces("application/json")]
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
public async Task<IActionResult> GetUserData(FGetUserDataRequest request)
{
var userId = User.FindAuthUserId();
@@ -172,6 +194,7 @@ namespace Prospect.Server.Api.Controllers
[HttpPost("GetUserReadOnlyData")]
[Produces("application/json")]
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
public IActionResult GetUserReadOnlyData(FGetUserDataRequest request)
{
return Ok(new ClientResponse<FGetUserDataResult>
@@ -188,6 +211,7 @@ namespace Prospect.Server.Api.Controllers
[HttpPost("GetUserInventory")]
[Produces("application/json")]
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
public IActionResult GetUserReadOnlyData(FGetUserInventoryRequest request)
{
return Ok(new ClientResponse<FGetUserInventoryResult>
@@ -229,6 +253,7 @@ namespace Prospect.Server.Api.Controllers
[HttpPost("GetTitleData")]
[Produces("application/json")]
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
public IActionResult GetTitleData(FGetTitleDataRequest request)
{
return Ok(new ClientResponse<FGetTitleDataResult>
@@ -1,7 +1,13 @@
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Prospect.Server.Api.Models.Client;
using Prospect.Server.Api.Models.CloudScript;
using Prospect.Server.Api.Models.CloudScript.Data;
using Prospect.Server.Api.Services.Auth.Entity;
using Prospect.Server.Api.Services.Auth.Extensions;
namespace Prospect.Server.Api.Controllers
{
@@ -10,10 +16,280 @@ namespace Prospect.Server.Api.Controllers
[Authorize(AuthenticationSchemes = EntityAuthenticationOptions.DefaultScheme)]
public class CloudScriptController : Controller
{
private readonly ILogger<CloudScriptController> _logger;
public CloudScriptController(ILogger<CloudScriptController> logger)
{
_logger = logger;
}
[HttpPost("ExecuteFunction")]
[Produces("application/json")]
public IActionResult ExecuteFunction(FExecuteFunctionRequest request)
{
_logger.LogInformation("Executing function {Function}", request.FunctionName);
object result = null;
switch (request.FunctionName)
{
case "RequestMaintenanceModeState":
result = new
{
enabled = false
};
break;
case "GetCharacterVanity":
result = new
{
userId = User.FindAuthUserId(),
error = (object) null,
returnVanity = new
{
userId = User.FindAuthUserId(),
head_item = new
{
id = "Black02M_Head1",
materialIndex = 0,
},
boots_item = new
{
id = "StarterOutfit01_Boots_M",
materialIndex = 0,
},
chest_item = new
{
id = "StarterOutfit01_Chest_M",
materialIndex = 0,
},
glove_item = new
{
id = "StarterOutfit01_Gloves_M",
materialIndex = 0,
},
base_suit_item = new
{
id = "StarterOutfit01M_BaseSuit",
materialIndex = 0,
},
melee_weapon_item = new
{
id = "Melee_Omega",
materialIndex = 0,
},
body_type = 1,
archetype_id = "TheProspector",
slot_index = 0
}
};
break;
case "SetMatchAllowJoin":
result = new
{
sessionId = (object)null,
success = false
};
break;
case "GetFriendList":
// TODO: ?
result = new
{
};
break;
case "GetPlayerSets":
result = new
{
success = true,
entries = new []
{
new
{
setData = new
{
id = "",
userId = User.FindAuthUserId(),
kit = "",
shield = "",
helmet = "",
weaponOne = "",
weaponTwo = "",
bag = "",
bagItemsAsJsonStr = "",
safeItemsAsJsonStr = ""
},
items = Array.Empty<object>()
}
}
};
break;
case "RequestFactionProgression":
result = new
{
factions = new []
{
new
{
factionId = "ICA",
currentProgression = 0
},
new
{
factionId = "Korolev",
currentProgression = 0
},
new
{
factionId = "Osiris",
currentProgression = 0
},
},
userId = User.FindAuthUserId(),
error = ""
};
break;
case "GetPlayersInventoriesLimits":
result = new
{
success = true,
entries = new []
{
new {
userId = User.FindAuthUserId(),
inventoryStashLimit = 75,
inventoryBagLimit = 300,
inventorySafeLimit = 5
}
}
};
break;
case "UpdateRetentionBonus":
result = new
{
playerData = new
{
daysClaimed = 0,
lastClaimTime = new
{
seconds = 1635033600
}
},
userId = User.FindAuthUserId(),
error = (object)null
};
break;
case "GetCraftingInProgressData":
result = new FYGetCraftingInProgressDataResult
{
UserId = User.FindAuthUserId(),
Error = null,
ItemCurrentlyBeingCrafted = new FYItemCurrentlyBeingCrafted
{
ItemId = null,
ItemRarity = -1,
PurchaseAmount = -1,
UtcTimestampWhenCraftingStarted = new FYTimestamp
{
Seconds = 0
}
}
};
break;
case "RequestPlayerContracts":
result = new FYGetPlayerContractsResult
{
UserId = User.FindAuthUserId(),
Error = null,
ActiveContracts = new List<FYActiveContractPlayerData>(),
FactionsContracts = new FYFactionsContractsData
{
Boards = new List<FYFactionContractsData>
{
new FYFactionContractsData
{
FactionId = "ICA",
Contracts = new List<FYFactionContractData>
{
new FYFactionContractData
{
ContractId = "NEW-Easy-ICA-Gather-1",
ContractIsLockedDueToLowFactionReputation = false
},
new FYFactionContractData
{
ContractId = "NEW-Medium-ICA-Uplink-1",
ContractIsLockedDueToLowFactionReputation = false
},
new FYFactionContractData
{
ContractId = "NEW-Hard-ICA-Uplink-1",
ContractIsLockedDueToLowFactionReputation = false
}
}
},
new FYFactionContractsData
{
FactionId = "Korolev",
Contracts = new List<FYFactionContractData>
{
new FYFactionContractData
{
ContractId = "NEW-Easy-KOR-Mine-4",
ContractIsLockedDueToLowFactionReputation = false
},
new FYFactionContractData
{
ContractId = "NEW-Medium-KOR-Mine-1",
ContractIsLockedDueToLowFactionReputation = false
},
new FYFactionContractData
{
ContractId = "NEW-Hard-KOR-PvP-6",
ContractIsLockedDueToLowFactionReputation = false
}
}
},
new FYFactionContractsData
{
FactionId = "Osiris",
Contracts = new List<FYFactionContractData>
{
new FYFactionContractData
{
ContractId = "NEW-Easy-Osiris-Brightcaps-1",
ContractIsLockedDueToLowFactionReputation = false
},
new FYFactionContractData
{
ContractId = "NEW-Medium-Osiris-Gather-1",
ContractIsLockedDueToLowFactionReputation = false
},
new FYFactionContractData
{
ContractId = "NEW-Hard-Osiris-Gather-7",
ContractIsLockedDueToLowFactionReputation = false
}
}
}
},
LastBoardRefreshTimeUtc = new FYTimestamp
{
Seconds = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds()
}
},
RefreshHours24UtcFromBackend = 12
};
break;
default:
_logger.LogWarning("Missing function {Function}", request.FunctionName);
result = new
{
};
break;
}
return Ok(new ClientResponse<FExecuteFunctionResult>
{
Code = 200,
@@ -21,7 +297,8 @@ namespace Prospect.Server.Api.Controllers
Data = new FExecuteFunctionResult
{
ExecutionTimeMilliseconds = 12,
FunctionName = request.FunctionName
FunctionName = request.FunctionName,
FunctionResult = result
}
});
}
@@ -0,0 +1,24 @@
using System;
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Prospect.Server.Api.Converters
{
// By default System.Text.Json outputs and we want:
// Output: 2021-11-04T04:58:20.4232184Z
// Want : 2021-10-24T02:54:56.652Z
public class DateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(typeToConvert == typeof(DateTime));
return DateTime.Parse(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK"));
}
}
}
@@ -25,7 +25,14 @@ namespace Prospect.Server.Api.Middleware
if (context.Request.Method == "POST")
{
_logger.LogDebug("URL {Url} Body {Body}", context.Request.GetDisplayUrl(), body);
var requestId = "NULL";
if (context.Request.Headers.TryGetValue("X-RequestID", out var requestIdValues))
{
requestId = requestIdValues.ToString();
}
_logger.LogDebug("URL {Url} RequestId {RequestId} Body {Body}", context.Request.GetDisplayUrl(), requestId, body);
}
await _next(context);
@@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Prospect.Server.Api.Models.Client.Data;
namespace Prospect.Server.Api.Models.Client
{
public class FUpdateUserDataRequest
{
/// <summary>
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
/// </summary>
[JsonPropertyName("CustomTags")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public Dictionary<string, string> CustomTags { get; set; }
/// <summary>
/// [optional] Key-value pairs to be written to the custom data. Note that keys are trimmed of whitespace, are limited in size, and may
/// not begin with a '!' character or be null.
/// </summary>
public Dictionary<string, string> Data { get; set; }
/// <summary>
/// [optional] Optional list of Data-keys to remove from UserData. Some SDKs cannot insert null-values into Data due to language
/// constraints. Use this to delete the keys directly.
/// </summary>
public List<string> KeysToRemove { get; set; }
/// <summary>
/// [optional] Permission to be applied to all user data keys written in this request. Defaults to "private" if not set.
/// </summary>
public UserDataPermission? Permission { get; set; }
/// <summary>
/// Unique PlayFab assigned ID of the user on whom the operation will be performed.
/// </summary>
public string PlayFabId { get; set; }
}
}
@@ -0,0 +1,11 @@
namespace Prospect.Server.Api.Models.Client
{
public class FUpdateUserDataResult
{
/// <summary>
/// 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.
/// </summary>
public uint DataVersion { get; set; }
}
}
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Prospect.Server.Api.Models.CloudScript.Data
{
public class FYActiveContractPlayerData
{
[JsonPropertyName("contractId")]
public string ContractId { get; set; }
[JsonPropertyName("progress")]
public List<int> Progress { get; set; }
}
}
@@ -0,0 +1,13 @@
using System.Text.Json.Serialization;
namespace Prospect.Server.Api.Models.CloudScript.Data
{
public class FYFactionContractData
{
[JsonPropertyName("contractId")]
public string ContractId { get; set; }
[JsonPropertyName("contractIsLockedDueToLowFactionReputation")]
public bool ContractIsLockedDueToLowFactionReputation { get; set; }
}
}
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Prospect.Server.Api.Models.CloudScript.Data
{
public class FYFactionContractsData
{
[JsonPropertyName("factionId")]
public string FactionId { get; set; }
[JsonPropertyName("contracts")]
public List<FYFactionContractData> Contracts { get; set; }
}
}
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Prospect.Server.Api.Models.CloudScript.Data
{
public class FYFactionsContractsData
{
[JsonPropertyName("boards")]
public List<FYFactionContractsData> Boards { get; set; }
[JsonPropertyName("lastBoardRefreshTimeUtc")]
public FYTimestamp LastBoardRefreshTimeUtc { get; set; }
}
}
@@ -0,0 +1,19 @@
using System.Text.Json.Serialization;
namespace Prospect.Server.Api.Models.CloudScript.Data
{
public class FYItemCurrentlyBeingCrafted
{
[JsonPropertyName("")]
public string ItemId { get; set; }
[JsonPropertyName("")]
public int ItemRarity { get; set; }
[JsonPropertyName("")]
public int PurchaseAmount { get; set; }
[JsonPropertyName("")]
public FYTimestamp UtcTimestampWhenCraftingStarted { get; set; }
}
}
@@ -0,0 +1,10 @@
using System.Text.Json.Serialization;
namespace Prospect.Server.Api.Models.CloudScript.Data
{
public class FYTimestamp
{
[JsonPropertyName("seconds")]
public int Seconds { get; set; }
}
}
@@ -0,0 +1,17 @@
using System.Text.Json.Serialization;
using Prospect.Server.Api.Models.CloudScript.Data;
namespace Prospect.Server.Api.Models.CloudScript
{
public class FYGetCraftingInProgressDataResult
{
[JsonPropertyName("userId")]
public string UserId { get; set; }
[JsonPropertyName("error")]
public string Error { get; set; }
[JsonPropertyName("itemCurrentlyBeingCrafted")]
public FYItemCurrentlyBeingCrafted ItemCurrentlyBeingCrafted { get; set; }
}
}
@@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Prospect.Server.Api.Models.CloudScript.Data;
namespace Prospect.Server.Api.Models.CloudScript
{
public class FYGetPlayerContractsResult
{
[JsonPropertyName("userId")]
public string UserId { get; set; }
[JsonPropertyName("error")]
public string Error { get; set; }
[JsonPropertyName("activeContracts")]
public List<FYActiveContractPlayerData> ActiveContracts { get; set; }
[JsonPropertyName("factionsContracts")]
public FYFactionsContractsData FactionsContracts { get; set; }
[JsonPropertyName("refreshHours24UtcFromBackend")]
public int RefreshHours24UtcFromBackend { get; set; }
}
}
@@ -38,12 +38,12 @@ namespace Prospect.Server.Api.Services.Auth
return _tokenHandler.WriteToken(token);
}
public string GenerateUser(PlayFabEntity user)
public string GenerateUser(PlayFabEntity entity)
{
return CreateToken(new[]
{
new Claim(AuthClaimTypes.UserId, user.UserId),
new Claim(AuthClaimTypes.EntityId, user.Id),
new Claim(AuthClaimTypes.UserId, entity.UserId),
new Claim(AuthClaimTypes.EntityId, entity.Id),
new Claim(AuthClaimTypes.Type, AuthType.User),
});
}
@@ -52,6 +52,7 @@ namespace Prospect.Server.Api.Services.Auth
{
return CreateToken(new[]
{
new Claim(AuthClaimTypes.UserId, entity.UserId),
new Claim(AuthClaimTypes.EntityId, entity.Id),
new Claim(AuthClaimTypes.Type, AuthType.Entity),
});
@@ -47,5 +47,14 @@ namespace Prospect.Server.Api.Services.Database
return await query.ToCursorAsync();
}
public async Task UpdateValueAsync(string dataId, string value)
{
var update = Builders<PlayFabUserData>.Update
.Set(data => data.Value, value)
.Set(data => data.LastUpdated, DateTime.UtcNow);
await Collection.UpdateOneAsync(data => data.Id == dataId, update);
}
}
}
@@ -117,5 +117,66 @@ namespace Prospect.Server.Api.Services.UserData
return result;
}
/// <summary>
///
/// </summary>
/// <param name="currentUserId">
/// The authenticated user id.
/// </param>
/// <param name="requestUserId">
/// The requested user id.
/// </param>
/// <param name="changes"></param>
/// <returns></returns>
public async Task UpdateAsync(
string currentUserId,
string requestUserId,
Dictionary<string, string> changes)
{
if (changes.Count == 0)
{
return;
}
if (string.IsNullOrEmpty(currentUserId))
{
throw new ArgumentNullException(nameof(currentUserId));
}
if (requestUserId == null)
{
requestUserId = currentUserId;
}
// Whether we are updating someone else.
var other = currentUserId != requestUserId;
foreach (var (key, value) in changes)
{
var data = await _dbUserDataService.FindAsync(currentUserId, key);
if (data == null)
{
if (other)
{
_logger.LogWarning("User {PlayFabId} attempted to update non-existing key {Key} of another user {PlayFabIdOther}", currentUserId, key, requestUserId);
}
else
{
await _dbUserDataService.InsertAsync(currentUserId, key, value, false);
}
continue;
}
if (!data.Public && other)
{
_logger.LogWarning("User {PlayFabId} attempted to update non-public key {Key} of another user {PlayFabIdOther}", currentUserId, key, data.PlayFabId);
continue;
}
await _dbUserDataService.UpdateValueAsync(data.Id, value);
}
}
}
}
+5 -1
View File
@@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Prospect.Server.Api.Config;
using Prospect.Server.Api.Converters;
using Prospect.Server.Api.Middleware;
using Prospect.Server.Api.Services.Auth;
using Prospect.Server.Api.Services.Auth.User;
@@ -44,7 +45,10 @@ namespace Prospect.Server.Api
.AddUserAuthentication(_ => {})
.AddEntityAuthentication(_ => {});
services.AddControllers();
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+1
View File
@@ -4,4 +4,5 @@
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Classes_0020and_0020structs/@EntryIndexedValue">&lt;NamingElement Priority="1"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="__interface" /&gt;&lt;type Name="class" /&gt;&lt;type Name="struct" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Class_0020and_0020struct_0020methods/@EntryIndexedValue">&lt;NamingElement Priority="10"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="member function" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Namespaces/@EntryIndexedValue">&lt;NamingElement Priority="17"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="namespace" /&gt;&lt;type Name="namespace alias" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FY/@EntryIndexedValue">FY</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PF/@EntryIndexedValue">PF</s:String></wpf:ResourceDictionary>