Files
2026-07-20 22:19:25 +08:00

384 lines
12 KiB
C#

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using GameServer.Client;
#if UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_STANDALONE_OSX || STEAMWORKS_WIN || STEAMWORKS_LIN_OSX
using Steamworks;
#endif
public class friendCardPrefab : MonoBehaviour
{
[SerializeField] private Image profileBorder;
[SerializeField] private Image friendProfile;
[SerializeField] private Text friendName;
[SerializeField] private Text friendStatus;
[SerializeField] private Button friendDetails;
[SerializeField] private Button startPersonalConversation;
[SerializeField] private Toggle isStarFriend;
[SerializeField] private Image friendOffline_blackMask;
[Header("offline heibai")]
[SerializeField] private Material offline_material;
[Header("currently chatting")]
[SerializeField] private Sprite chattingSprite;
[SerializeField] private Sprite normalSprite;
private Material _profileBorderMaterial;
private Material _friendProfileMaterial;
private Coroutine _avatarLoadRoutine;
private Sprite _runtimeAvatarSprite;
private Texture2D _runtimeAvatarTexture;
private Texture2D _runtimeSteamAvatarTexture;
private Texture2D _runtimeSteamAvatarFlippedTexture;
private string _steamId;
private Action<string, bool> _starChanged;
private Action<string> _openDetails;
private Action<string> _openPrivateConversation;
private bool _bindingToggle;
private Sprite _defaultProfileBorderSprite;
private bool _subscribedToChatState;
private FriendCardViewData _boundData;
private void Awake()
{
_profileBorderMaterial = profileBorder != null ? profileBorder.material : null;
_friendProfileMaterial = friendProfile != null ? friendProfile.material : null;
_defaultProfileBorderSprite = profileBorder != null ? profileBorder.sprite : null;
}
private void OnEnable()
{
SubscribeChatState();
RefreshChattingVisual();
EnsureAvatarLoadStarted();
}
private void OnDestroy()
{
if (_avatarLoadRoutine != null)
{
StopCoroutine(_avatarLoadRoutine);
_avatarLoadRoutine = null;
}
ReleaseRuntimeAvatarResources();
UnsubscribeChatState();
}
private void OnDisable()
{
if (_avatarLoadRoutine != null)
{
StopCoroutine(_avatarLoadRoutine);
_avatarLoadRoutine = null;
}
UnsubscribeChatState();
}
public void Bind(FriendCardViewData data, Action<string, bool> onStarChanged, Action<string> onOpenDetails, Action<string> onOpenPrivateConversation)
{
_boundData = data;
_steamId = data != null ? data.SteamId : string.Empty;
_starChanged = onStarChanged;
_openDetails = onOpenDetails;
_openPrivateConversation = onOpenPrivateConversation;
if (friendName != null)
{
friendName.text = data != null ? data.DisplayName ?? string.Empty : string.Empty;
}
if (friendStatus != null)
{
friendStatus.text = data != null ? data.StatusText ?? string.Empty : string.Empty;
}
ApplyOnlineVisualState(data != null && data.IsOnline);
if (isStarFriend != null)
{
isStarFriend.onValueChanged.RemoveAllListeners();
_bindingToggle = true;
isStarFriend.isOn = data != null && data.IsStarred;
_bindingToggle = false;
isStarFriend.onValueChanged.AddListener(HandleStarToggleChanged);
}
if (friendDetails != null)
{
friendDetails.onClick.RemoveAllListeners();
friendDetails.onClick.AddListener(HandleOpenDetails);
}
if (startPersonalConversation != null)
{
startPersonalConversation.onClick.RemoveAllListeners();
startPersonalConversation.onClick.AddListener(HandleStartPrivateConversation);
}
if (_avatarLoadRoutine != null)
{
StopCoroutine(_avatarLoadRoutine);
_avatarLoadRoutine = null;
}
EnsureAvatarLoadStarted();
RefreshChattingVisual();
}
private void EnsureAvatarLoadStarted()
{
if (friendProfile == null || _boundData == null)
{
return;
}
if (_avatarLoadRoutine != null)
{
return;
}
if (isActiveAndEnabled)
{
_avatarLoadRoutine = StartCoroutine(LoadAvatarRoutine(_boundData));
}
else
{
ApplyCachedAvatarIfAvailable(_boundData);
}
}
private void HandleStarToggleChanged(bool isOn)
{
if (_bindingToggle)
{
return;
}
_starChanged?.Invoke(_steamId, isOn);
}
private void HandleOpenDetails()
{
_openDetails?.Invoke(_steamId);
}
private void HandleStartPrivateConversation()
{
_openPrivateConversation?.Invoke(_steamId);
}
private void ApplyOnlineVisualState(bool isOnline)
{
if (friendOffline_blackMask != null)
{
friendOffline_blackMask.gameObject.SetActive(!isOnline);
}
Material borderMaterial = isOnline ? _profileBorderMaterial : offline_material;
Material profileMaterial = isOnline ? _friendProfileMaterial : offline_material;
if (profileBorder != null)
{
profileBorder.material = borderMaterial;
}
if (friendProfile != null)
{
friendProfile.material = profileMaterial;
}
RefreshChattingVisual();
}
private void SubscribeChatState()
{
if (_subscribedToChatState)
{
return;
}
globalChatSystem.ActivePrivateConversationChanged += HandleActivePrivateConversationChanged;
_subscribedToChatState = true;
}
private void UnsubscribeChatState()
{
if (!_subscribedToChatState)
{
return;
}
globalChatSystem.ActivePrivateConversationChanged -= HandleActivePrivateConversationChanged;
_subscribedToChatState = false;
}
private void HandleActivePrivateConversationChanged(string _)
{
RefreshChattingVisual();
}
private void RefreshChattingVisual()
{
if (profileBorder == null)
{
return;
}
bool isCurrentPrivateTarget = globalChatSystem.IsViewingPrivateConversation(_steamId);
Sprite targetSprite = isCurrentPrivateTarget
? (chattingSprite != null ? chattingSprite : normalSprite)
: (normalSprite != null ? normalSprite : _defaultProfileBorderSprite);
if (targetSprite != null)
{
profileBorder.sprite = targetSprite;
}
}
private IEnumerator LoadAvatarRoutine(FriendCardViewData data)
{
if (friendProfile == null || data == null)
{
yield break;
}
ReleaseRuntimeAvatarResources();
string resolvedAvatarUrl = NetworkManager.ResolveAvatarUrl(data.AvatarUrl, data.SteamId);
if (playerMessagePrefab.TryGetCachedAvatarSprite(data.SteamId, resolvedAvatarUrl, out Sprite cachedSprite) && cachedSprite != null)
{
friendProfile.sprite = cachedSprite;
_avatarLoadRoutine = null;
yield break;
}
bool loaded = false;
if (NetworkManager.IsUsableAvatarUrl(resolvedAvatarUrl)
&& !resolvedAvatarUrl.StartsWith(NetworkManager.SteamAvatarUrlPrefix, StringComparison.OrdinalIgnoreCase))
{
using (UnityWebRequest request = UnityWebRequestTexture.GetTexture(resolvedAvatarUrl))
{
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
Texture2D texture = DownloadHandlerTexture.GetContent(request);
if (texture != null)
{
_runtimeAvatarTexture = texture;
_runtimeAvatarSprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
friendProfile.sprite = _runtimeAvatarSprite;
loaded = true;
}
}
}
}
if (!loaded)
{
yield return LoadSteamAvatarRoutine(data.SteamId);
}
_avatarLoadRoutine = null;
}
private void ApplyCachedAvatarIfAvailable(FriendCardViewData data)
{
if (friendProfile == null || data == null)
{
return;
}
string resolvedAvatarUrl = NetworkManager.ResolveAvatarUrl(data.AvatarUrl, data.SteamId);
if (playerMessagePrefab.TryGetCachedAvatarSprite(data.SteamId, resolvedAvatarUrl, out Sprite cachedSprite) && cachedSprite != null)
{
friendProfile.sprite = cachedSprite;
}
}
private IEnumerator LoadSteamAvatarRoutine(string steamId)
{
#if !(UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_STANDALONE_OSX || STEAMWORKS_WIN || STEAMWORKS_LIN_OSX)
yield break;
#else
if (!SteamManager.Initialized || string.IsNullOrWhiteSpace(steamId) || friendProfile == null || !ulong.TryParse(steamId, out ulong rawSteamId))
{
yield break;
}
var targetSteamId = new CSteamID(rawSteamId);
SteamFriends.RequestUserInformation(targetSteamId, false);
const float timeout = 5f;
float deadline = Time.realtimeSinceStartup + timeout;
while (Time.realtimeSinceStartup < deadline)
{
int imageId = SteamFriends.GetLargeFriendAvatar(targetSteamId);
if (imageId <= 0)
{
imageId = SteamFriends.GetMediumFriendAvatar(targetSteamId);
}
if (imageId > 0 && SteamUtils.GetImageSize(imageId, out uint width, out uint height) && width > 0 && height > 0)
{
byte[] buffer = new byte[width * height * 4];
if (SteamUtils.GetImageRGBA(imageId, buffer, buffer.Length))
{
_runtimeSteamAvatarTexture = new Texture2D((int)width, (int)height, TextureFormat.RGBA32, false);
_runtimeSteamAvatarTexture.LoadRawTextureData(buffer);
_runtimeSteamAvatarTexture.Apply();
_runtimeSteamAvatarFlippedTexture = new Texture2D((int)width, (int)height, TextureFormat.RGBA32, false);
for (int y = 0; y < height; y++)
{
Color[] pixels = _runtimeSteamAvatarTexture.GetPixels(0, (int)y, (int)width, 1);
_runtimeSteamAvatarFlippedTexture.SetPixels(0, (int)height - 1 - (int)y, (int)width, 1, pixels);
}
_runtimeSteamAvatarFlippedTexture.Apply();
_runtimeAvatarSprite = Sprite.Create(_runtimeSteamAvatarFlippedTexture, new Rect(0, 0, width, height), new Vector2(0.5f, 0.5f));
friendProfile.sprite = _runtimeAvatarSprite;
yield break;
}
}
yield return new WaitForSecondsRealtime(0.25f);
}
#endif
}
private void ReleaseRuntimeAvatarResources()
{
if (_runtimeAvatarSprite != null)
{
Destroy(_runtimeAvatarSprite);
_runtimeAvatarSprite = null;
}
if (_runtimeAvatarTexture != null)
{
Destroy(_runtimeAvatarTexture);
_runtimeAvatarTexture = null;
}
if (_runtimeSteamAvatarFlippedTexture != null)
{
Destroy(_runtimeSteamAvatarFlippedTexture);
_runtimeSteamAvatarFlippedTexture = null;
}
if (_runtimeSteamAvatarTexture != null)
{
Destroy(_runtimeSteamAvatarTexture);
_runtimeSteamAvatarTexture = null;
}
}
}