893 lines
28 KiB
C#
893 lines
28 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Bansonic;
|
|
using GameServer.Client;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
#if !(UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_STANDALONE_OSX || STEAMWORKS_WIN || STEAMWORKS_LIN_OSX)
|
|
#define FRIEND_DISABLE_STEAMWORKS
|
|
#endif
|
|
|
|
#if !FRIEND_DISABLE_STEAMWORKS
|
|
using Steamworks;
|
|
#endif
|
|
|
|
public enum FriendFilterType
|
|
{
|
|
All,
|
|
Online,
|
|
Starred,
|
|
Offline,
|
|
GameFriends,
|
|
SteamFriends
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class FriendCardViewData
|
|
{
|
|
public string SteamId;
|
|
public string DisplayName;
|
|
public string AvatarUrl;
|
|
public string StatusText;
|
|
public bool IsOnline;
|
|
public bool IsStarred;
|
|
public bool IsGameFriend;
|
|
public bool IsSteamFriend;
|
|
}
|
|
|
|
public class friendSystem : MonoBehaviour
|
|
{
|
|
private static string LabelAllFriends => LocalizationService.Get("friends.filter.all", "全部好友");
|
|
private static string LabelOnlineFriends => LocalizationService.Get("friends.filter.online", "在线好友");
|
|
private static string LabelStarredFriends => LocalizationService.Get("friends.filter.starred", "星标好友");
|
|
private static string LabelOfflineFriends => LocalizationService.Get("friends.filter.offline", "离线好友");
|
|
private static string LabelGameFriends => LocalizationService.Get("friends.filter.game", "游戏好友");
|
|
private static string LabelSteamFriends => LocalizationService.Get("friends.filter.steam", "Steam好友");
|
|
private static string StatusOnline => LocalizationService.Get("friends.status.online", "在线");
|
|
private static string StatusOffline => LocalizationService.Get("friends.status.offline", "离线");
|
|
private static string StatusPlaying => LocalizationService.Get("friends.status.playing", "游戏中");
|
|
private static string StatusInRoom => LocalizationService.Get("friends.status.in_room", "房间中");
|
|
private static string NoticeFriendDetailsNotReady => LocalizationService.Get("friends.notice.details_not_ready", "好友详情面板尚未接入");
|
|
private static string NoticePrivateChatNotReady => LocalizationService.Get("friends.notice.private_chat_not_ready", "私聊面板尚未接入");
|
|
private static string DefaultStatusLoading => LocalizationService.Get("friends.default.loading", "正在拉取好友信息...");
|
|
private static string DefaultStatusEmpty => LocalizationService.Get("friends.default.empty", "你当前没有好友");
|
|
private static string DefaultStatusServiceUnavailable => LocalizationService.Get("friends.default.service_unavailable", "无法访问服务");
|
|
|
|
public GameObject friendCardPrefab;
|
|
public Transform friendsDisplayContent;
|
|
|
|
[Header("filter")]
|
|
public Dropdown friendsDisplayDropdown;
|
|
|
|
[Header("text")]
|
|
public Text defaultText;
|
|
public Text onlineFriendsCountText;
|
|
|
|
[Header("sync")]
|
|
[SerializeField] private float steamFriendResyncIntervalSeconds = 8f;
|
|
|
|
private readonly Dictionary<string, FriendCardViewData> _mergedFriends =
|
|
new Dictionary<string, FriendCardViewData>(StringComparer.Ordinal);
|
|
private readonly Dictionary<string, FriendCardViewData> _steamFriendCache =
|
|
new Dictionary<string, FriendCardViewData>(StringComparer.Ordinal);
|
|
private readonly Dictionary<string, GameObject> _spawnedCards =
|
|
new Dictionary<string, GameObject>(StringComparer.Ordinal);
|
|
private readonly List<FriendFilterType> _filters =
|
|
new List<FriendFilterType>
|
|
{
|
|
FriendFilterType.All,
|
|
FriendFilterType.Online,
|
|
FriendFilterType.Starred,
|
|
FriendFilterType.Offline,
|
|
FriendFilterType.GameFriends,
|
|
FriendFilterType.SteamFriends
|
|
};
|
|
|
|
private bool _dropdownInitialized;
|
|
private bool _isRefreshing;
|
|
private bool _lastRefreshFailed;
|
|
private bool _hasResolvedFriendCounts;
|
|
private Coroutine _resyncCoroutine;
|
|
private bool _languageSubscribed;
|
|
private bool _chatStateSubscribed;
|
|
private static List<string> _startupSteamFriendIds = new List<string>();
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
|
private static void WarmSteamFriendIdsOnStartup()
|
|
{
|
|
_startupSteamFriendIds = ReadSteamFriendIdsOnly();
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
LocalizationService.EnsureInitialized();
|
|
ClearDisplayedFriends();
|
|
_hasResolvedFriendCounts = false;
|
|
SetDefaultText(DefaultStatusLoading);
|
|
UpdateOnlineFriendsCountText();
|
|
InitializeDropdown();
|
|
SubscribeLanguageChanged();
|
|
SubscribeChatStateChanged();
|
|
|
|
if (ArenaRoomService.Instance != null)
|
|
{
|
|
ArenaRoomService.Instance.OnFriendsListChanged += HandleFriendsListChanged;
|
|
}
|
|
|
|
StartCoroutine(InitializeFriendsRoutine());
|
|
if (_resyncCoroutine != null)
|
|
{
|
|
StopCoroutine(_resyncCoroutine);
|
|
}
|
|
_resyncCoroutine = StartCoroutine(SteamFriendResyncLoop());
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
UnsubscribeLanguageChanged();
|
|
UnsubscribeChatStateChanged();
|
|
if (ArenaRoomService.Instance != null)
|
|
{
|
|
ArenaRoomService.Instance.OnFriendsListChanged -= HandleFriendsListChanged;
|
|
}
|
|
|
|
if (_resyncCoroutine != null)
|
|
{
|
|
StopCoroutine(_resyncCoroutine);
|
|
_resyncCoroutine = null;
|
|
}
|
|
|
|
if (friendsDisplayDropdown != null)
|
|
{
|
|
friendsDisplayDropdown.onValueChanged.RemoveListener(HandleFilterChanged);
|
|
}
|
|
}
|
|
|
|
private void ClearDisplayedFriends()
|
|
{
|
|
_spawnedCards.Clear();
|
|
if (friendsDisplayContent == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int index = friendsDisplayContent.childCount - 1; index >= 0; index--)
|
|
{
|
|
Transform child = friendsDisplayContent.GetChild(index);
|
|
if (child != null)
|
|
{
|
|
Destroy(child.gameObject);
|
|
}
|
|
}
|
|
}
|
|
|
|
private IEnumerator InitializeFriendsRoutine()
|
|
{
|
|
if (_isRefreshing)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
_isRefreshing = true;
|
|
_lastRefreshFailed = false;
|
|
SetDefaultText(DefaultStatusLoading);
|
|
RefreshSteamFriendCache();
|
|
|
|
float waitDeadline = Time.realtimeSinceStartup + 3f;
|
|
while (NetworkManager.Instance == null && Time.realtimeSinceStartup < waitDeadline)
|
|
{
|
|
yield return null;
|
|
}
|
|
|
|
NetworkManager network = NetworkManager.Instance;
|
|
List<string> steamFriendIds = _steamFriendCache.Keys
|
|
.Where(id => !string.IsNullOrWhiteSpace(id))
|
|
.Distinct(StringComparer.Ordinal)
|
|
.ToList();
|
|
|
|
if (network != null)
|
|
{
|
|
var friendsTask = network.GetFriendsList(steamFriendIds);
|
|
float timeoutAt = Time.realtimeSinceStartup + 20f;
|
|
while (!friendsTask.IsCompleted && Time.realtimeSinceStartup < timeoutAt)
|
|
{
|
|
yield return null;
|
|
}
|
|
|
|
if (!friendsTask.IsCompleted)
|
|
{
|
|
_lastRefreshFailed = true;
|
|
Debug.LogWarning("[friendSystem] GetFriendsList timed out.");
|
|
}
|
|
else if (friendsTask.Status == System.Threading.Tasks.TaskStatus.RanToCompletion
|
|
&& friendsTask.Result != null
|
|
&& friendsTask.Result.success)
|
|
{
|
|
_hasResolvedFriendCounts = true;
|
|
ReplaceGameFriends(friendsTask.Result.friends);
|
|
}
|
|
else
|
|
{
|
|
_lastRefreshFailed = true;
|
|
string error = friendsTask.IsFaulted ? friendsTask.Exception?.GetBaseException().Message : "friend list request failed";
|
|
Debug.LogWarning($"[friendSystem] Initialize friends failed: {error}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_lastRefreshFailed = true;
|
|
Debug.LogWarning("[friendSystem] NetworkManager is unavailable when initializing friends.");
|
|
}
|
|
|
|
Render();
|
|
_isRefreshing = false;
|
|
}
|
|
|
|
private IEnumerator SteamFriendResyncLoop()
|
|
{
|
|
float interval = Mathf.Max(3f, steamFriendResyncIntervalSeconds);
|
|
var wait = new WaitForSecondsRealtime(interval);
|
|
while (isActiveAndEnabled)
|
|
{
|
|
yield return wait;
|
|
if (_isRefreshing)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
RefreshSteamFriendCache();
|
|
if (!ShouldRetrySteamImport())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
yield return InitializeFriendsRoutine();
|
|
}
|
|
}
|
|
|
|
private void InitializeDropdown()
|
|
{
|
|
if (friendsDisplayDropdown == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
friendsDisplayDropdown.onValueChanged.RemoveListener(HandleFilterChanged);
|
|
int selectedValue = Mathf.Clamp(friendsDisplayDropdown.value, 0, Mathf.Max(0, _filters.Count - 1));
|
|
friendsDisplayDropdown.ClearOptions();
|
|
friendsDisplayDropdown.AddOptions(_filters.Select(GetFilterLabel).ToList());
|
|
friendsDisplayDropdown.value = selectedValue;
|
|
_dropdownInitialized = true;
|
|
|
|
friendsDisplayDropdown.onValueChanged.AddListener(HandleFilterChanged);
|
|
friendsDisplayDropdown.RefreshShownValue();
|
|
}
|
|
|
|
private void HandleFilterChanged(int _)
|
|
{
|
|
Render();
|
|
}
|
|
|
|
private void HandleFriendsListChanged(IReadOnlyList<SocialFriendEntry> friends)
|
|
{
|
|
_lastRefreshFailed = false;
|
|
_hasResolvedFriendCounts = true;
|
|
RefreshSteamFriendCache();
|
|
ReplaceGameFriends(friends);
|
|
Render();
|
|
}
|
|
|
|
private void RefreshSteamFriendCache()
|
|
{
|
|
CacheSteamFriends(ReadSteamFriends().Concat(BuildStartupSteamFriendCards()));
|
|
}
|
|
|
|
private bool ShouldRetrySteamImport()
|
|
{
|
|
if (_steamFriendCache.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
foreach (KeyValuePair<string, FriendCardViewData> pair in _steamFriendCache)
|
|
{
|
|
FriendCardViewData steamFriend = pair.Value;
|
|
if (steamFriend == null || string.IsNullOrWhiteSpace(steamFriend.SteamId))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (_mergedFriends.ContainsKey(steamFriend.SteamId))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (steamFriend.IsOnline || string.Equals(steamFriend.StatusText, StatusPlaying, StringComparison.Ordinal))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void CacheSteamFriends(IEnumerable<FriendCardViewData> steamFriends)
|
|
{
|
|
_steamFriendCache.Clear();
|
|
if (steamFriends == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (FriendCardViewData steamFriend in steamFriends)
|
|
{
|
|
if (steamFriend == null || string.IsNullOrWhiteSpace(steamFriend.SteamId))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
steamFriend.IsStarred = LoadStarredState(steamFriend.SteamId);
|
|
_steamFriendCache[steamFriend.SteamId] = steamFriend;
|
|
}
|
|
}
|
|
|
|
private void ReplaceGameFriends(IEnumerable<SocialFriendEntry> gameFriends)
|
|
{
|
|
_mergedFriends.Clear();
|
|
if (gameFriends == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (SocialFriendEntry gameFriend in gameFriends)
|
|
{
|
|
if (gameFriend == null || string.IsNullOrWhiteSpace(gameFriend.friend_steam_id))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string steamId = gameFriend.friend_steam_id.Trim();
|
|
_steamFriendCache.TryGetValue(steamId, out FriendCardViewData steamFriend);
|
|
bool steamSaysPlaying = steamFriend != null && string.Equals(steamFriend.StatusText, StatusPlaying, StringComparison.Ordinal);
|
|
bool mergedOnline = gameFriend.online || (steamFriend != null && steamFriend.IsOnline) || steamSaysPlaying;
|
|
string mergedStatus = MapServerPresenceToStatusText(gameFriend.status, steamFriend, mergedOnline);
|
|
|
|
FriendCardViewData merged = new FriendCardViewData
|
|
{
|
|
SteamId = steamId,
|
|
DisplayName = ResolvePreferredDisplayName(
|
|
steamFriend != null ? steamFriend.DisplayName : string.Empty,
|
|
NetworkManager.ResolveDisplayName(gameFriend.friend_name, steamId, false),
|
|
steamId),
|
|
AvatarUrl = ResolvePreferredAvatarUrl(
|
|
steamFriend != null ? steamFriend.AvatarUrl : string.Empty,
|
|
NetworkManager.ResolveAvatarUrl(gameFriend.friend_avatar, steamId),
|
|
steamId),
|
|
StatusText = mergedStatus,
|
|
IsOnline = mergedOnline,
|
|
IsStarred = LoadStarredState(steamId),
|
|
IsGameFriend = true,
|
|
IsSteamFriend = steamFriend != null
|
|
};
|
|
|
|
_mergedFriends[steamId] = merged;
|
|
}
|
|
}
|
|
|
|
private async System.Threading.Tasks.Task HydrateRegisteredSteamFriendsAsync(NetworkManager network)
|
|
{
|
|
if (network == null || _steamFriendCache.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (KeyValuePair<string, FriendCardViewData> pair in _steamFriendCache)
|
|
{
|
|
string steamId = pair.Key;
|
|
FriendCardViewData steamFriend = pair.Value;
|
|
if (string.IsNullOrWhiteSpace(steamId) || _mergedFriends.ContainsKey(steamId))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ProfileData profile;
|
|
try
|
|
{
|
|
profile = await network.GetProfile(steamId);
|
|
}
|
|
catch
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (profile == null || string.IsNullOrWhiteSpace(profile.steam_id))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bool steamSaysPlaying = steamFriend != null && string.Equals(steamFriend.StatusText, StatusPlaying, StringComparison.Ordinal);
|
|
bool mergedOnline = steamFriend != null && steamFriend.IsOnline;
|
|
string mergedStatus = steamSaysPlaying ? StatusPlaying : (mergedOnline ? StatusOnline : StatusOffline);
|
|
|
|
_mergedFriends[steamId] = new FriendCardViewData
|
|
{
|
|
SteamId = steamId,
|
|
DisplayName = ResolvePreferredDisplayName(
|
|
steamFriend != null ? steamFriend.DisplayName : string.Empty,
|
|
NetworkManager.ResolveDisplayName(profile.display_name, steamId, false),
|
|
steamId),
|
|
AvatarUrl = ResolvePreferredAvatarUrl(
|
|
steamFriend != null ? steamFriend.AvatarUrl : string.Empty,
|
|
NetworkManager.ResolveAvatarUrl(profile.avatar_url, steamId),
|
|
steamId),
|
|
StatusText = mergedStatus,
|
|
IsOnline = mergedOnline,
|
|
IsStarred = LoadStarredState(steamId),
|
|
IsGameFriend = true,
|
|
IsSteamFriend = true
|
|
};
|
|
}
|
|
}
|
|
|
|
private void Render()
|
|
{
|
|
if (friendsDisplayContent == null || friendCardPrefab == null)
|
|
{
|
|
SetDefaultText(DefaultStatusServiceUnavailable);
|
|
UpdateOnlineFriendsCountText();
|
|
return;
|
|
}
|
|
|
|
List<FriendCardViewData> target = ApplyFilter(_mergedFriends.Values)
|
|
.OrderBy(friend => GetSortBucket(friend))
|
|
.ThenBy(friend => friend.DisplayName ?? string.Empty, StringComparer.OrdinalIgnoreCase)
|
|
.ThenBy(friend => friend.SteamId ?? string.Empty, StringComparer.OrdinalIgnoreCase)
|
|
.ToList();
|
|
|
|
HashSet<string> targetIds = new HashSet<string>(target.Select(friend => friend.SteamId), StringComparer.Ordinal);
|
|
foreach (KeyValuePair<string, GameObject> pair in _spawnedCards.ToList())
|
|
{
|
|
if (targetIds.Contains(pair.Key))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Destroy(pair.Value);
|
|
_spawnedCards.Remove(pair.Key);
|
|
}
|
|
|
|
for (int index = 0; index < target.Count; index++)
|
|
{
|
|
FriendCardViewData friend = target[index];
|
|
if (!_spawnedCards.TryGetValue(friend.SteamId, out GameObject cardObject) || cardObject == null)
|
|
{
|
|
cardObject = Instantiate(friendCardPrefab, friendsDisplayContent);
|
|
_spawnedCards[friend.SteamId] = cardObject;
|
|
}
|
|
|
|
cardObject.transform.SetSiblingIndex(index);
|
|
friendCardPrefab card = cardObject.GetComponent<friendCardPrefab>();
|
|
if (card != null)
|
|
{
|
|
card.Bind(friend, HandleStarChanged, HandleOpenDetails, HandleOpenPrivateConversation);
|
|
}
|
|
}
|
|
|
|
UpdateDefaultTextState(target.Count);
|
|
UpdateOnlineFriendsCountText();
|
|
}
|
|
|
|
private void UpdateDefaultTextState(int visibleCount)
|
|
{
|
|
if (_lastRefreshFailed)
|
|
{
|
|
SetDefaultText(DefaultStatusServiceUnavailable);
|
|
return;
|
|
}
|
|
|
|
if (visibleCount > 0)
|
|
{
|
|
SetDefaultText(string.Empty);
|
|
return;
|
|
}
|
|
|
|
SetDefaultText(DefaultStatusEmpty);
|
|
}
|
|
|
|
private void SetDefaultText(string message)
|
|
{
|
|
if (defaultText == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
defaultText.text = message ?? string.Empty;
|
|
}
|
|
|
|
private void UpdateOnlineFriendsCountText()
|
|
{
|
|
if (onlineFriendsCountText == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!_hasResolvedFriendCounts)
|
|
{
|
|
onlineFriendsCountText.text = "-/-";
|
|
return;
|
|
}
|
|
|
|
int totalCount = _mergedFriends.Count;
|
|
int onlineCount = 0;
|
|
foreach (FriendCardViewData friend in _mergedFriends.Values)
|
|
{
|
|
if (friend != null && friend.IsOnline)
|
|
{
|
|
onlineCount++;
|
|
}
|
|
}
|
|
|
|
onlineFriendsCountText.text = $"{onlineCount}/{totalCount}";
|
|
}
|
|
|
|
private IEnumerable<FriendCardViewData> ApplyFilter(IEnumerable<FriendCardViewData> source)
|
|
{
|
|
FriendFilterType filter = GetSelectedFilter();
|
|
switch (filter)
|
|
{
|
|
case FriendFilterType.All:
|
|
return source;
|
|
case FriendFilterType.Online:
|
|
return source.Where(friend => friend.IsOnline);
|
|
case FriendFilterType.Starred:
|
|
return source.Where(friend => friend.IsStarred);
|
|
case FriendFilterType.Offline:
|
|
return source.Where(friend => !friend.IsOnline);
|
|
case FriendFilterType.GameFriends:
|
|
return source.Where(friend => friend.IsGameFriend);
|
|
case FriendFilterType.SteamFriends:
|
|
return source.Where(friend => friend.IsSteamFriend);
|
|
default:
|
|
return source;
|
|
}
|
|
}
|
|
|
|
private FriendFilterType GetSelectedFilter()
|
|
{
|
|
if (friendsDisplayDropdown == null || friendsDisplayDropdown.value < 0 || friendsDisplayDropdown.value >= _filters.Count)
|
|
{
|
|
return FriendFilterType.All;
|
|
}
|
|
|
|
return _filters[friendsDisplayDropdown.value];
|
|
}
|
|
|
|
private void HandleStarChanged(string steamId, bool isOn)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(steamId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
PlayerPrefs.SetInt(BuildStarKey(steamId), isOn ? 1 : 0);
|
|
PlayerPrefs.Save();
|
|
|
|
if (_mergedFriends.TryGetValue(steamId, out FriendCardViewData friend) && friend != null)
|
|
{
|
|
friend.IsStarred = isOn;
|
|
}
|
|
|
|
if (_steamFriendCache.TryGetValue(steamId, out FriendCardViewData steamFriend) && steamFriend != null)
|
|
{
|
|
steamFriend.IsStarred = isOn;
|
|
}
|
|
|
|
Render();
|
|
}
|
|
|
|
private void HandleOpenDetails(string steamId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(steamId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
gNotice.warning.display(NoticeFriendDetailsNotReady);
|
|
}
|
|
|
|
private void HandleOpenPrivateConversation(string steamId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(steamId))
|
|
{
|
|
return;
|
|
}
|
|
|
|
globalChatSystem.OpenPrivateConversation(steamId);
|
|
}
|
|
|
|
private void SubscribeChatStateChanged()
|
|
{
|
|
if (_chatStateSubscribed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
globalChatSystem.ActivePrivateConversationChanged += HandleActivePrivateConversationChanged;
|
|
_chatStateSubscribed = true;
|
|
}
|
|
|
|
private void UnsubscribeChatStateChanged()
|
|
{
|
|
if (!_chatStateSubscribed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
globalChatSystem.ActivePrivateConversationChanged -= HandleActivePrivateConversationChanged;
|
|
_chatStateSubscribed = false;
|
|
}
|
|
|
|
private void HandleActivePrivateConversationChanged(string _)
|
|
{
|
|
if (!isActiveAndEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Render();
|
|
}
|
|
|
|
private void SubscribeLanguageChanged()
|
|
{
|
|
if (_languageSubscribed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LocalizationService.LanguageChanged += HandleLanguageChanged;
|
|
_languageSubscribed = true;
|
|
}
|
|
|
|
private void UnsubscribeLanguageChanged()
|
|
{
|
|
if (!_languageSubscribed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LocalizationService.LanguageChanged -= HandleLanguageChanged;
|
|
_languageSubscribed = false;
|
|
}
|
|
|
|
private void HandleLanguageChanged(string _)
|
|
{
|
|
if (!isActiveAndEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
InitializeDropdown();
|
|
Render();
|
|
}
|
|
|
|
private static string GetFilterLabel(FriendFilterType filter)
|
|
{
|
|
switch (filter)
|
|
{
|
|
case FriendFilterType.Online:
|
|
return LabelOnlineFriends;
|
|
case FriendFilterType.Starred:
|
|
return LabelStarredFriends;
|
|
case FriendFilterType.Offline:
|
|
return LabelOfflineFriends;
|
|
case FriendFilterType.GameFriends:
|
|
return LabelGameFriends;
|
|
case FriendFilterType.SteamFriends:
|
|
return LabelSteamFriends;
|
|
default:
|
|
return LabelAllFriends;
|
|
}
|
|
}
|
|
|
|
private static int GetSortBucket(FriendCardViewData friend)
|
|
{
|
|
if (friend == null)
|
|
{
|
|
return int.MaxValue;
|
|
}
|
|
|
|
if (friend.IsStarred && friend.IsOnline)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (friend.IsStarred && !friend.IsOnline)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if (!friend.IsStarred && friend.IsOnline)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
return 3;
|
|
}
|
|
|
|
private static string ResolvePreferredDisplayName(string currentDisplayName, string newDisplayName, string steamId)
|
|
{
|
|
if (NetworkManager.IsUsableDisplayName(newDisplayName, steamId))
|
|
{
|
|
return newDisplayName;
|
|
}
|
|
|
|
if (NetworkManager.IsUsableDisplayName(currentDisplayName, steamId))
|
|
{
|
|
return currentDisplayName;
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
private static string ResolvePreferredAvatarUrl(string currentAvatarUrl, string newAvatarUrl, string steamId)
|
|
{
|
|
if (NetworkManager.IsUsableAvatarUrl(newAvatarUrl))
|
|
{
|
|
return newAvatarUrl;
|
|
}
|
|
|
|
if (NetworkManager.IsUsableAvatarUrl(currentAvatarUrl))
|
|
{
|
|
return currentAvatarUrl;
|
|
}
|
|
|
|
return NetworkManager.ResolveAvatarUrl(string.Empty, steamId);
|
|
}
|
|
|
|
private static string BuildStarKey(string steamId)
|
|
{
|
|
return $"friend_star_{steamId}";
|
|
}
|
|
|
|
private static bool LoadStarredState(string steamId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(steamId))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return PlayerPrefs.GetInt(BuildStarKey(steamId), 0) == 1;
|
|
}
|
|
|
|
private static List<FriendCardViewData> ReadSteamFriends()
|
|
{
|
|
var result = new List<FriendCardViewData>();
|
|
#if FRIEND_DISABLE_STEAMWORKS
|
|
return result;
|
|
#else
|
|
if (!SteamManager.Initialized)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
int count = SteamFriends.GetFriendCount(EFriendFlags.k_EFriendFlagImmediate);
|
|
for (int index = 0; index < count; index++)
|
|
{
|
|
CSteamID friendSteamId = SteamFriends.GetFriendByIndex(index, EFriendFlags.k_EFriendFlagImmediate);
|
|
string steamId = friendSteamId.m_SteamID.ToString();
|
|
SteamFriends.RequestUserInformation(friendSteamId, false);
|
|
|
|
string displayName = SteamFriends.GetFriendPersonaName(friendSteamId);
|
|
EPersonaState personaState = SteamFriends.GetFriendPersonaState(friendSteamId);
|
|
FriendGameInfo_t gameInfo;
|
|
bool isPlaying = SteamFriends.GetFriendGamePlayed(friendSteamId, out gameInfo);
|
|
bool isOnline = personaState != EPersonaState.k_EPersonaStateOffline;
|
|
string statusText = isPlaying ? StatusPlaying : (isOnline ? StatusOnline : StatusOffline);
|
|
|
|
result.Add(
|
|
new FriendCardViewData
|
|
{
|
|
SteamId = steamId,
|
|
DisplayName = NetworkManager.ResolveDisplayName(displayName, steamId, false),
|
|
AvatarUrl = NetworkManager.ResolveAvatarUrl(string.Empty, steamId),
|
|
StatusText = statusText,
|
|
IsOnline = isOnline,
|
|
IsSteamFriend = true,
|
|
IsGameFriend = false,
|
|
IsStarred = LoadStarredState(steamId)
|
|
}
|
|
);
|
|
}
|
|
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
private static IEnumerable<FriendCardViewData> BuildStartupSteamFriendCards()
|
|
{
|
|
if (_startupSteamFriendIds == null || _startupSteamFriendIds.Count == 0)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
foreach (string steamId in _startupSteamFriendIds)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(steamId))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
yield return new FriendCardViewData
|
|
{
|
|
SteamId = steamId,
|
|
DisplayName = NetworkManager.ResolveDisplayName(string.Empty, steamId, false),
|
|
AvatarUrl = NetworkManager.ResolveAvatarUrl(string.Empty, steamId),
|
|
StatusText = string.Empty,
|
|
IsOnline = false,
|
|
IsSteamFriend = true,
|
|
IsGameFriend = false,
|
|
IsStarred = LoadStarredState(steamId)
|
|
};
|
|
}
|
|
}
|
|
|
|
private static List<string> ReadSteamFriendIdsOnly()
|
|
{
|
|
var result = new List<string>();
|
|
#if FRIEND_DISABLE_STEAMWORKS
|
|
return result;
|
|
#else
|
|
if (!SteamManager.Initialized)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
int count = SteamFriends.GetFriendCount(EFriendFlags.k_EFriendFlagImmediate);
|
|
for (int index = 0; index < count; index++)
|
|
{
|
|
CSteamID friendSteamId = SteamFriends.GetFriendByIndex(index, EFriendFlags.k_EFriendFlagImmediate);
|
|
string steamId = friendSteamId.m_SteamID.ToString();
|
|
if (!string.IsNullOrWhiteSpace(steamId))
|
|
{
|
|
result.Add(steamId);
|
|
}
|
|
}
|
|
|
|
return result.Distinct(StringComparer.Ordinal).ToList();
|
|
#endif
|
|
}
|
|
|
|
private static string MapServerPresenceToStatusText(string status, FriendCardViewData steamFriend, bool mergedOnline)
|
|
{
|
|
if (string.Equals(status, "IN_GAME", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return StatusPlaying;
|
|
}
|
|
|
|
if (string.Equals(status, "IN_ROOM", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return StatusInRoom;
|
|
}
|
|
|
|
if (string.Equals(status, "ONLINE", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return StatusOnline;
|
|
}
|
|
|
|
if (string.Equals(status, "OFFLINE", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return StatusOffline;
|
|
}
|
|
|
|
if (steamFriend != null && string.Equals(steamFriend.StatusText, StatusPlaying, StringComparison.Ordinal))
|
|
{
|
|
return StatusPlaying;
|
|
}
|
|
|
|
return mergedOnline ? StatusOnline : StatusOffline;
|
|
}
|
|
}
|