diff --git a/src/Prospect.Server.Api/Controllers/AdminController.cs b/src/Prospect.Server.Api/Controllers/AdminController.cs
index 0cd6041..74f1515 100644
--- a/src/Prospect.Server.Api/Controllers/AdminController.cs
+++ b/src/Prospect.Server.Api/Controllers/AdminController.cs
@@ -4,6 +4,8 @@ using System.Text;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Prospect.Server.Api.Services.Database;
+using Prospect.Server.Api.Services.Database.Models;
+using Prospect.Server.Api.Services.Steam;
using Prospect.Server.Api.Services.UserData;
namespace Prospect.Server.Api.Controllers;
@@ -18,14 +20,16 @@ public class AdminController : ControllerBase
private readonly DbEntityService _entityService;
private readonly DbUserDataService _userDataService;
private readonly TitleDataService _titleDataService;
+ private readonly SteamWebApiService _steamWebApi;
public AdminController(DbUserService userService, DbEntityService entityService,
- DbUserDataService userDataService, TitleDataService titleDataService)
+ DbUserDataService userDataService, TitleDataService titleDataService, SteamWebApiService steamWebApi)
{
_userService = userService;
_entityService = entityService;
_userDataService = userDataService;
_titleDataService = titleDataService;
+ _steamWebApi = steamWebApi;
}
// ---------- pages ----------
@@ -82,7 +86,8 @@ public class AdminController : ControllerBase
}
var sb = new StringBuilder();
- sb.Append($"
");
+ sb.Append($"");
sb.Append($"{users.Count} joueur(s)
");
sb.Append("| DisplayName | PlayFab Id | Entity Id | Auth | |
");
foreach (var u in users.OrderBy(u => u.DisplayName))
@@ -179,6 +184,38 @@ public class AdminController : ControllerBase
return Html(Layout("TitleData · " + key, $"{Esc(key)}
" + body));
}
+ [HttpGet("backfill-names")]
+ public async Task BackfillNames()
+ {
+ if (!IsLan()) return Denied();
+ if (!_steamWebApi.Enabled)
+ return Html(Layout("Backfill", "Steam Web API non configurée (clé absente).
← Joueurs
"));
+
+ var users = await _userService.GetAllAsync();
+ int updated = 0, skipped = 0, failed = 0;
+ var rows = new StringBuilder();
+ foreach (var u in users)
+ {
+ if (!string.IsNullOrEmpty(u.DisplayName) && u.DisplayName != "Unknown") { skipped++; continue; }
+ var steam = u.Auth?.FirstOrDefault(a => a.Type == PlayFabUserAuthType.Steam)?.Key;
+ if (string.IsNullOrEmpty(steam)) { skipped++; continue; }
+
+ var persona = await _steamWebApi.GetPersonaNameAsync(steam);
+ if (!string.IsNullOrWhiteSpace(persona))
+ {
+ await _userService.UpdateDisplayNameAsync(u.Id, persona);
+ updated++;
+ rows.Append($"| {Esc(u.Id)} | {Esc(persona)} |
");
+ }
+ else { failed++; }
+ }
+
+ var body = $"Backfill des pseudos Steam
{updated} mis à jour · {skipped} ignorés · {failed} échec(s)
" +
+ (updated > 0 ? $"| PlayFabId | Nouveau nom |
{rows}
" : "") +
+ "← Joueurs
";
+ return Html(Layout("Backfill", body));
+ }
+
// ---------- helpers ----------
private bool IsLan()
diff --git a/src/Prospect.Server.Api/Controllers/ClientController.cs b/src/Prospect.Server.Api/Controllers/ClientController.cs
index e8c6b00..b31e35a 100644
--- a/src/Prospect.Server.Api/Controllers/ClientController.cs
+++ b/src/Prospect.Server.Api/Controllers/ClientController.cs
@@ -32,6 +32,7 @@ public class ClientController : Controller
private readonly DbEntityService _entityService;
private readonly UserDataService _userDataService;
private readonly TitleDataService _titleDataService;
+ private readonly Prospect.Server.Api.Services.Steam.SteamWebApiService _steamWebApi;
public ClientController(ILogger logger,
IOptions settings,
@@ -39,7 +40,8 @@ public class ClientController : Controller
DbUserService userService,
DbEntityService entityService,
UserDataService userDataService,
- TitleDataService titleDataService)
+ TitleDataService titleDataService,
+ Prospect.Server.Api.Services.Steam.SteamWebApiService steamWebApi)
{
_settings = settings.Value;
_logger = logger;
@@ -48,6 +50,7 @@ public class ClientController : Controller
_entityService = entityService;
_userDataService = userDataService;
_titleDataService = titleDataService;
+ _steamWebApi = steamWebApi;
}
[AllowAnonymous]
@@ -63,6 +66,19 @@ public class ClientController : Controller
var userSteamId = ticket.SteamId.ToString();
var user = await _userService.FindOrCreateAsync(PlayFabUserAuthType.Steam, userSteamId);
+
+ // Backfill the display name from the Steam persona when we don't have a real
+ // one yet (accounts are created as "Unknown"; the client never sends a name).
+ if (string.IsNullOrEmpty(user.DisplayName) || user.DisplayName == "Unknown")
+ {
+ var persona = await _steamWebApi.GetPersonaNameAsync(userSteamId);
+ if (!string.IsNullOrWhiteSpace(persona))
+ {
+ await _userService.UpdateDisplayNameAsync(user.Id, persona);
+ user.DisplayName = persona;
+ }
+ }
+
var entity = await _entityService.FindOrCreateAsync(user.Id);
var userTicket = _authTokenService.GenerateUser(entity);
diff --git a/src/Prospect.Server.Api/Services/Steam/SteamWebApiService.cs b/src/Prospect.Server.Api/Services/Steam/SteamWebApiService.cs
new file mode 100644
index 0000000..f6f480e
--- /dev/null
+++ b/src/Prospect.Server.Api/Services/Steam/SteamWebApiService.cs
@@ -0,0 +1,55 @@
+using System.Text.Json;
+
+namespace Prospect.Server.Api.Services.Steam;
+
+// Resolves a Steam persona (display) name from a SteamID64 via the Steam Web API.
+// PlayFab does this server-side too; our emulator only gets the SteamID from the auth
+// ticket, so the real name needs an API key. Inert (no-op) when no key is configured.
+public class SteamWebApiService
+{
+ private static readonly HttpClient Http = new() { Timeout = TimeSpan.FromSeconds(5) };
+
+ private readonly string? _apiKey;
+ private readonly ILogger _logger;
+
+ public SteamWebApiService(IConfiguration configuration, ILogger logger)
+ {
+ _apiKey = configuration["SteamWebApiKey"];
+ _logger = logger;
+ }
+
+ public bool Enabled => !string.IsNullOrWhiteSpace(_apiKey);
+
+ public async Task GetPersonaNameAsync(string steamId64)
+ {
+ if (!Enabled)
+ {
+ return null;
+ }
+
+ try
+ {
+ var url = $"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/?key={_apiKey}&steamids={steamId64}";
+ var json = await Http.GetStringAsync(url);
+ using var doc = JsonDocument.Parse(json);
+ if (doc.RootElement.TryGetProperty("response", out var response) &&
+ response.TryGetProperty("players", out var players) &&
+ players.ValueKind == JsonValueKind.Array)
+ {
+ foreach (var player in players.EnumerateArray())
+ {
+ if (player.TryGetProperty("personaname", out var name))
+ {
+ return name.GetString();
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.LogWarning(e, "Steam GetPlayerSummaries failed for {SteamId}", steamId64);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Prospect.Server.Api/Startup.cs b/src/Prospect.Server.Api/Startup.cs
index 96e42a1..fea82b1 100644
--- a/src/Prospect.Server.Api/Startup.cs
+++ b/src/Prospect.Server.Api/Startup.cs
@@ -30,6 +30,8 @@ public class Startup
services.AddSingleton();
services.AddSingleton();
+ services.AddSingleton();
+
services.AddSingleton();
services.AddSingleton();