friends: richer GetFriendList payload (field aliases) + log returned JSON
Build & Deploy / build (push) Successful in 53s

The friend tile rendered empty/offline because the UE client couldn't read our
best-guess response shape. Expose each friend's identity/name/steam/presence under
every plausible field name (camelCase + PlayFab PascalCase, flat + nested profile)
under both friends/Friends keys, and log the JSON so we can pin the exact shape.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-16 09:06:17 +02:00
co-authored by Claude Opus 4.8
parent 81092b077e
commit d7821ebf1f
@@ -32,9 +32,8 @@ public class GetFriendList : ICloudScriptFunction<FYBaseSocialRequest, object?>
}
var userId = context.User.FindAuthUserId();
// Resolve the imported Steam friends (persisted by ClientsideFriendsImport) to the
// players that actually exist on this server. It's a private server, so only friends
// who have logged in here will show up.
// Imported Steam friends (persisted by ClientsideFriendsImport), resolved to players
// that actually exist on this private server.
var steamIds = new List<string>();
var userData = await _userDataService.FindAsync(userId, userId, new List<string> { "ImportedSteamFriends" });
if (userData.TryGetValue("ImportedSteamFriends", out var rec) && !string.IsNullOrWhiteSpace(rec.Value))
@@ -52,8 +51,10 @@ public class GetFriendList : ICloudScriptFunction<FYBaseSocialRequest, object?>
{
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 steamId = player.Auth?.FirstOrDefault(a => a.Type == PlayFabUserAuthType.Steam)?.Key ?? "";
var displayName = string.IsNullOrWhiteSpace(player.DisplayName) ? "Prospector" : player.DisplayName;
// 0 = offline, 1 = online, 2 = in match. Online if seen in the last 3 minutes.
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))
@@ -69,22 +70,50 @@ public class GetFriendList : ICloudScriptFunction<FYBaseSocialRequest, object?>
catch { /* ignore malformed presence */ }
}
// The exact model the UE client binds is not documented, so expose the identity
// under every plausible field name (camelCase + PlayFab PascalCase) and both a
// flat and nested profile — whichever the client reads, the tile gets populated.
friends.Add(new
{
profile = new
{
playerId = player.Id,
displayName = player.DisplayName,
avatarUrl = "",
},
// identity
friendPlayFabId = player.Id,
FriendPlayFabId = player.Id,
playerId = player.Id,
PlayerId = player.Id,
playFabId = player.Id,
PlayFabId = player.Id,
// name
displayName,
DisplayName = displayName,
titleDisplayName = displayName,
TitleDisplayName = displayName,
name = displayName,
username = displayName,
Username = displayName,
// steam
steamId,
SteamId = steamId,
steamInfo = new { steamId, SteamId = steamId },
SteamInfo = new { SteamId = steamId, steamId },
// presence
onlineState,
OnlineState = onlineState,
isOnline = onlineState > 0,
inMatch = onlineState == 2,
presence = new { onlineState, state = onlineState },
avatarUrl = "",
// nested profiles
profile = new { playerId = player.Id, displayName, avatarUrl = "" },
Profile = new { PlayerId = player.Id, DisplayName = displayName, PlayerProfileModel = new { DisplayName = displayName } },
tags = Array.Empty<string>(),
Tags = Array.Empty<string>(),
});
}
}
// NOTE: the exact response shape the client expects is not yet confirmed; this is a
// best-effort structure. The log lets us verify resolution while we validate in game.
_logger.LogInformation("GetFriendList for {User}: {Count} friend(s) resolved on server", userId, friends.Count);
return new { friends };
// Return the list under both the camelCase and PlayFab-cased container keys.
var result = new { friends, Friends = friends, count = friends.Count };
_logger.LogInformation("GetFriendList for {User}: {Count} friend(s); payload={Json}", userId, friends.Count, JsonSerializer.Serialize(result));
return result;
}
}