Compare commits
2
Commits
7dbab1aab8
...
1d9cf795dd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d9cf795dd | ||
|
|
0a68a97291 |
@@ -140,8 +140,18 @@ public class ClientController : Controller
|
|||||||
[HttpPost("AddGenericID")]
|
[HttpPost("AddGenericID")]
|
||||||
[Produces(MediaTypeNames.Application.Json)]
|
[Produces(MediaTypeNames.Application.Json)]
|
||||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||||
public IActionResult AddGenericId(FAddGenericIDRequest request)
|
public async Task<IActionResult> AddGenericId(FAddGenericIDRequest request)
|
||||||
{
|
{
|
||||||
|
// Persist the linked generic service id instead of dropping it (was a no-op stub).
|
||||||
|
var userId = User.FindAuthUserId();
|
||||||
|
if (request.GenericId != null && !string.IsNullOrEmpty(request.GenericId.ServiceName))
|
||||||
|
{
|
||||||
|
await _userDataService.UpdateAsync(userId, userId, new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["GenericId_" + request.GenericId.ServiceName] = request.GenericId.UserId ?? ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(new ClientResponse<object>
|
return Ok(new ClientResponse<object>
|
||||||
{
|
{
|
||||||
Code = 200,
|
Code = 200,
|
||||||
|
|||||||
@@ -47,9 +47,28 @@ public class GetFriendList : ICloudScriptFunction<FYBaseSocialRequest, object?>
|
|||||||
if (steamIds.Count > 0)
|
if (steamIds.Count > 0)
|
||||||
{
|
{
|
||||||
var players = await _userService.FindManyAsync(PlayFabUserAuthType.Steam, steamIds);
|
var players = await _userService.FindManyAsync(PlayFabUserAuthType.Steam, steamIds);
|
||||||
|
var nowUtc = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||||
foreach (var player in players)
|
foreach (var player in players)
|
||||||
{
|
{
|
||||||
if (player.Id == userId) continue; // never list yourself
|
if (player.Id == userId) continue; // never list yourself
|
||||||
|
|
||||||
|
// Presence persisted by UpdatePlayerPresenceState: online if seen in the last
|
||||||
|
// 3 minutes. EYUserState best-effort: 0 = offline, 1 = online, 2 = in match.
|
||||||
|
var onlineState = 0;
|
||||||
|
var presenceData = await _userDataService.FindAsync(player.Id, player.Id, new List<string> { "PresenceState" });
|
||||||
|
if (presenceData.TryGetValue("PresenceState", out var presenceRec) && !string.IsNullOrWhiteSpace(presenceRec.Value))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var presence = JsonSerializer.Deserialize<PlayerPresenceState>(presenceRec.Value);
|
||||||
|
if (presence != null && nowUtc - presence.LastSeenUtc <= 180)
|
||||||
|
{
|
||||||
|
onlineState = presence.InMatch ? 2 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { /* ignore malformed presence */ }
|
||||||
|
}
|
||||||
|
|
||||||
friends.Add(new
|
friends.Add(new
|
||||||
{
|
{
|
||||||
profile = new
|
profile = new
|
||||||
@@ -58,7 +77,7 @@ public class GetFriendList : ICloudScriptFunction<FYBaseSocialRequest, object?>
|
|||||||
displayName = player.DisplayName,
|
displayName = player.DisplayName,
|
||||||
avatarUrl = "",
|
avatarUrl = "",
|
||||||
},
|
},
|
||||||
onlineState = 0, // EYUserState — real presence tracking is a later phase
|
onlineState,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-9
@@ -8,13 +8,8 @@ public class GetPlayerStatisticsRequestsClientRequest
|
|||||||
public string[] Statistics { get; set; }
|
public string[] Statistics { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GetPlayerStatisticsRequestsClientResponse
|
|
||||||
{
|
|
||||||
// TODO: Unknown structure
|
|
||||||
}
|
|
||||||
|
|
||||||
[CloudScriptFunction("GetPlayerStatisticsRequestsClient")]
|
[CloudScriptFunction("GetPlayerStatisticsRequestsClient")]
|
||||||
public class GetPlayerStatisticsRequestsClientFunction : ICloudScriptFunction<GetPlayerStatisticsRequestsClientRequest, GetPlayerStatisticsRequestsClientResponse>
|
public class GetPlayerStatisticsRequestsClientFunction : ICloudScriptFunction<GetPlayerStatisticsRequestsClientRequest, object>
|
||||||
{
|
{
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
|
||||||
@@ -23,7 +18,7 @@ public class GetPlayerStatisticsRequestsClientFunction : ICloudScriptFunction<Ge
|
|||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<GetPlayerStatisticsRequestsClientResponse> ExecuteAsync(GetPlayerStatisticsRequestsClientRequest request)
|
public Task<object> ExecuteAsync(GetPlayerStatisticsRequestsClientRequest request)
|
||||||
{
|
{
|
||||||
var context = _httpContextAccessor.HttpContext;
|
var context = _httpContextAccessor.HttpContext;
|
||||||
if (context == null)
|
if (context == null)
|
||||||
@@ -31,8 +26,15 @@ public class GetPlayerStatisticsRequestsClientFunction : ICloudScriptFunction<Ge
|
|||||||
throw new CloudScriptException("CloudScript was not called within a http request");
|
throw new CloudScriptException("CloudScript was not called within a http request");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GetPlayerStatisticsRequestsClientResponse
|
// Return each requested statistic with a value so the career screen renders instead
|
||||||
|
// of staying blank. Raid stats (kills/deaths/evacs/damage/…) come from the
|
||||||
|
// client-hosted raid and aren't tracked server-side, so they report 0 for now.
|
||||||
|
var stats = new List<object>();
|
||||||
|
foreach (var name in request.Statistics ?? Array.Empty<string>())
|
||||||
{
|
{
|
||||||
};
|
stats.Add(new { statisticName = name, value = 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult<object>(new { statistics = stats });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-3
@@ -1,12 +1,51 @@
|
|||||||
using Prospect.Server.Api.Services.CloudScript.Models;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Prospect.Server.Api.Services.Auth.Extensions;
|
||||||
|
using Prospect.Server.Api.Services.CloudScript.Models;
|
||||||
|
using Prospect.Server.Api.Services.UserData;
|
||||||
|
|
||||||
namespace Prospect.Server.Api.Services.CloudScript.Functions;
|
namespace Prospect.Server.Api.Services.CloudScript.Functions;
|
||||||
|
|
||||||
|
// Persisted presence, read back by GetFriendList to show friends' online / in-match state.
|
||||||
|
public class PlayerPresenceState
|
||||||
|
{
|
||||||
|
[JsonPropertyName("inMatch")]
|
||||||
|
public bool InMatch { get; set; }
|
||||||
|
[JsonPropertyName("lastSeenUtc")]
|
||||||
|
public long LastSeenUtc { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[CloudScriptFunction("UpdatePlayerPresenceState")]
|
[CloudScriptFunction("UpdatePlayerPresenceState")]
|
||||||
public class UpdatePlayerPresenceState : ICloudScriptFunction<FYUpdatePlayerPresenceStateRequest, object>
|
public class UpdatePlayerPresenceState : ICloudScriptFunction<FYUpdatePlayerPresenceStateRequest, object>
|
||||||
{
|
{
|
||||||
public Task<object> ExecuteAsync(FYUpdatePlayerPresenceStateRequest request)
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
private readonly UserDataService _userDataService;
|
||||||
|
|
||||||
|
public UpdatePlayerPresenceState(IHttpContextAccessor httpContextAccessor, UserDataService userDataService)
|
||||||
{
|
{
|
||||||
return Task.FromResult<object>(new { });
|
_httpContextAccessor = httpContextAccessor;
|
||||||
|
_userDataService = userDataService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<object> ExecuteAsync(FYUpdatePlayerPresenceStateRequest request)
|
||||||
|
{
|
||||||
|
var context = _httpContextAccessor.HttpContext;
|
||||||
|
if (context == null)
|
||||||
|
{
|
||||||
|
return new { };
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId = context.User.FindAuthUserId();
|
||||||
|
var state = new PlayerPresenceState
|
||||||
|
{
|
||||||
|
InMatch = request.InMatch,
|
||||||
|
LastSeenUtc = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
|
||||||
|
};
|
||||||
|
await _userDataService.UpdateAsync(
|
||||||
|
userId, userId,
|
||||||
|
new Dictionary<string, string> { ["PresenceState"] = JsonSerializer.Serialize(state) }
|
||||||
|
);
|
||||||
|
|
||||||
|
return new { };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user