功能批量实现 优化 服务端 新浮动小游戏框架 新界面UI
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
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)
|
||||
#define FRIEND_DISABLE_STEAMWORKS
|
||||
#endif
|
||||
|
||||
#if !FRIEND_DISABLE_STEAMWORKS
|
||||
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;
|
||||
|
||||
private Material _profileBorderMaterial;
|
||||
private Material _friendProfileMaterial;
|
||||
private Coroutine _avatarLoadRoutine;
|
||||
private string _steamId;
|
||||
private Action<string, bool> _starChanged;
|
||||
private Action<string> _openDetails;
|
||||
private Action<string> _openPrivateConversation;
|
||||
private bool _bindingToggle;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_profileBorderMaterial = profileBorder != null ? profileBorder.material : null;
|
||||
_friendProfileMaterial = friendProfile != null ? friendProfile.material : null;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_avatarLoadRoutine != null)
|
||||
{
|
||||
StopCoroutine(_avatarLoadRoutine);
|
||||
_avatarLoadRoutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind(FriendCardViewData data, Action<string, bool> onStarChanged, Action<string> onOpenDetails, Action<string> onOpenPrivateConversation)
|
||||
{
|
||||
_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 = StartCoroutine(LoadAvatarRoutine(data));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator LoadAvatarRoutine(FriendCardViewData data)
|
||||
{
|
||||
if (friendProfile == null || data == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
string resolvedAvatarUrl = NetworkManager.ResolveAvatarUrl(data.AvatarUrl, data.SteamId);
|
||||
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)
|
||||
{
|
||||
friendProfile.sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loaded)
|
||||
{
|
||||
yield return LoadSteamAvatarRoutine(data.SteamId);
|
||||
}
|
||||
|
||||
_avatarLoadRoutine = null;
|
||||
}
|
||||
|
||||
private IEnumerator LoadSteamAvatarRoutine(string steamId)
|
||||
{
|
||||
#if FRIEND_DISABLE_STEAMWORKS
|
||||
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))
|
||||
{
|
||||
friendProfile.sprite = CreateFlippedSteamAvatarSprite(buffer, (int)width, (int)height);
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
yield return new WaitForSecondsRealtime(0.25f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static Sprite CreateFlippedSteamAvatarSprite(byte[] rgbaBuffer, int width, int height)
|
||||
{
|
||||
Texture2D texture = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||
texture.LoadRawTextureData(rgbaBuffer);
|
||||
texture.Apply();
|
||||
|
||||
Texture2D flipped = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
Color[] pixels = texture.GetPixels(0, y, width, 1);
|
||||
flipped.SetPixels(0, height - 1 - y, width, 1, pixels);
|
||||
}
|
||||
flipped.Apply();
|
||||
return Sprite.Create(flipped, new Rect(0, 0, width, height), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 281d6e71d4aa56440a980d4d95af38e4
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4114343157163b04da9c9640daa57742
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,216 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Threading.Tasks;
|
||||
using GameServer.Client;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
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 class friendRequestPrefab : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Image profileImage;
|
||||
[SerializeField] private Text friendName;
|
||||
[SerializeField] private Text friendSourceInfomation;
|
||||
[SerializeField] private Button acceptButton;
|
||||
[SerializeField] private Button rejectButton;
|
||||
|
||||
private Coroutine _avatarLoadRoutine;
|
||||
private Coroutine _buttonCooldownRoutine;
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_avatarLoadRoutine != null)
|
||||
{
|
||||
StopCoroutine(_avatarLoadRoutine);
|
||||
_avatarLoadRoutine = null;
|
||||
}
|
||||
|
||||
if (_buttonCooldownRoutine != null)
|
||||
{
|
||||
StopCoroutine(_buttonCooldownRoutine);
|
||||
_buttonCooldownRoutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind(SocialFriendRequestEntry request, Func<Task> onAccept, Func<Task> onReject, float cooldownSeconds)
|
||||
{
|
||||
string steamId = request != null ? request.from_steam_id : string.Empty;
|
||||
if (friendName != null)
|
||||
{
|
||||
friendName.text = request != null
|
||||
? NetworkManager.ResolveDisplayName(request.from_name, steamId, false)
|
||||
: string.Empty;
|
||||
}
|
||||
|
||||
if (acceptButton != null)
|
||||
{
|
||||
acceptButton.onClick.RemoveAllListeners();
|
||||
if (onAccept != null)
|
||||
{
|
||||
acceptButton.onClick.AddListener(() =>
|
||||
{
|
||||
if (_buttonCooldownRoutine != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ = HandleDecisionClickedAsync(onAccept, cooldownSeconds);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (rejectButton != null)
|
||||
{
|
||||
rejectButton.onClick.RemoveAllListeners();
|
||||
if (onReject != null)
|
||||
{
|
||||
rejectButton.onClick.AddListener(() =>
|
||||
{
|
||||
if (_buttonCooldownRoutine != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ = HandleDecisionClickedAsync(onReject, cooldownSeconds);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (_avatarLoadRoutine != null)
|
||||
{
|
||||
StopCoroutine(_avatarLoadRoutine);
|
||||
}
|
||||
|
||||
if (profileImage != null && request != null)
|
||||
{
|
||||
profileImage.sprite = null;
|
||||
string avatarUrl = NetworkManager.ResolveAvatarUrl(request.from_avatar, steamId);
|
||||
_avatarLoadRoutine = StartCoroutine(LoadAvatarRoutine(steamId, avatarUrl));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleDecisionClickedAsync(Func<Task> action, float cooldownSeconds)
|
||||
{
|
||||
SetDecisionButtonsInteractable(false);
|
||||
_buttonCooldownRoutine = StartCoroutine(ButtonCooldownRoutine(cooldownSeconds));
|
||||
await action();
|
||||
}
|
||||
|
||||
private IEnumerator ButtonCooldownRoutine(float cooldownSeconds)
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(cooldownSeconds);
|
||||
SetDecisionButtonsInteractable(true);
|
||||
_buttonCooldownRoutine = null;
|
||||
}
|
||||
|
||||
private void SetDecisionButtonsInteractable(bool interactable)
|
||||
{
|
||||
if (acceptButton != null)
|
||||
{
|
||||
acceptButton.interactable = interactable;
|
||||
}
|
||||
|
||||
if (rejectButton != null)
|
||||
{
|
||||
rejectButton.interactable = interactable;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator LoadAvatarRoutine(string steamId, string avatarUrl)
|
||||
{
|
||||
if (profileImage == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
bool loaded = false;
|
||||
if (NetworkManager.IsUsableAvatarUrl(avatarUrl)
|
||||
&& !avatarUrl.StartsWith(NetworkManager.SteamAvatarUrlPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
using (UnityWebRequest request = UnityWebRequestTexture.GetTexture(avatarUrl))
|
||||
{
|
||||
yield return request.SendWebRequest();
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
Texture2D texture = DownloadHandlerTexture.GetContent(request);
|
||||
if (texture != null)
|
||||
{
|
||||
profileImage.sprite = Sprite.Create(
|
||||
texture,
|
||||
new Rect(0f, 0f, texture.width, texture.height),
|
||||
new Vector2(0.5f, 0.5f));
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loaded)
|
||||
{
|
||||
yield return LoadSteamAvatarRoutine(steamId);
|
||||
}
|
||||
|
||||
_avatarLoadRoutine = null;
|
||||
}
|
||||
|
||||
private IEnumerator LoadSteamAvatarRoutine(string steamId)
|
||||
{
|
||||
#if FRIEND_DISABLE_STEAMWORKS
|
||||
yield break;
|
||||
#else
|
||||
if (!SteamManager.Initialized || string.IsNullOrWhiteSpace(steamId) || profileImage == null || !ulong.TryParse(steamId, out ulong rawSteamId))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
CSteamID targetSteamId = new CSteamID(rawSteamId);
|
||||
SteamFriends.RequestUserInformation(targetSteamId, false);
|
||||
|
||||
float deadline = Time.realtimeSinceStartup + 5f;
|
||||
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))
|
||||
{
|
||||
profileImage.sprite = CreateFlippedSteamAvatarSprite(buffer, (int)width, (int)height);
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
yield return new WaitForSecondsRealtime(0.25f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static Sprite CreateFlippedSteamAvatarSprite(byte[] rgbaBuffer, int width, int height)
|
||||
{
|
||||
Texture2D texture = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||
texture.LoadRawTextureData(rgbaBuffer);
|
||||
texture.Apply();
|
||||
|
||||
Texture2D flipped = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
Color[] pixels = texture.GetPixels(0, y, width, 1);
|
||||
flipped.SetPixels(0, height - 1 - y, width, 1, pixels);
|
||||
}
|
||||
flipped.Apply();
|
||||
return Sprite.Create(flipped, new Rect(0, 0, width, height), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 801af46c3c30ecc44ad9befbb892dc33
|
||||
@@ -0,0 +1,769 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &167812896000688069
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 171703084932209816}
|
||||
- component: {fileID: 7766852143305575412}
|
||||
- component: {fileID: 2512442011294951853}
|
||||
m_Layer: 0
|
||||
m_Name: source
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &171703084932209816
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 167812896000688069}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1887113380917164164}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 30.39, y: -4}
|
||||
m_SizeDelta: {x: 143.18, y: 12.573}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7766852143305575412
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 167812896000688069}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &2512442011294951853
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 167812896000688069}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: bd4be44636ad6c24a9b117a7108a75e9, type: 3}
|
||||
m_FontSize: 10
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 1
|
||||
m_MaxSize: 18
|
||||
m_Alignment: 3
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: "\u96C5\u8389\u68A6\u7483\u9AD8\u65B0\u4EA7\u4E1A\u56ED Steam2\u533A"
|
||||
--- !u!1 &171027573892652408
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5899234148902931492}
|
||||
- component: {fileID: 752898224887842841}
|
||||
- component: {fileID: 7879641519199484437}
|
||||
- component: {fileID: 3532086592632966835}
|
||||
m_Layer: 0
|
||||
m_Name: acceptRequest
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &5899234148902931492
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 171027573892652408}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 2373904671374910531}
|
||||
m_Father: {fileID: 1887113380917164164}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -9.2046, y: -17.465}
|
||||
m_SizeDelta: {x: 63.9929, y: 17.071}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &752898224887842841
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 171027573892652408}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &7879641519199484437
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 171027573892652408}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.4198113, g: 1, b: 0.5353115, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: 7f3b1220317607e44bbb8f0e1998044a, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 5
|
||||
--- !u!114 &3532086592632966835
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 171027573892652408}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 7879641519199484437}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &696844997186230125
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1887113380917164164}
|
||||
- component: {fileID: 8398379083156494532}
|
||||
- component: {fileID: 885345931350300794}
|
||||
m_Layer: 0
|
||||
m_Name: btm
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1887113380917164164
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 696844997186230125}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 3062756356687769231}
|
||||
- {fileID: 3192042035776563592}
|
||||
- {fileID: 171703084932209816}
|
||||
- {fileID: 5899234148902931492}
|
||||
- {fileID: 9058676790248205063}
|
||||
m_Father: {fileID: 7715568052211693546}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 220, y: 70}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &8398379083156494532
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 696844997186230125}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &885345931350300794
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 696844997186230125}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: 537c5cf3bf53c2f4a9404248acd2d336, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &1234883103932309115
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3062756356687769231}
|
||||
- component: {fileID: 7577265852821514236}
|
||||
- component: {fileID: 322438256967861300}
|
||||
m_Layer: 0
|
||||
m_Name: profile
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3062756356687769231
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1234883103932309115}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1887113380917164164}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -74.39, y: 1.5}
|
||||
m_SizeDelta: {x: 55, y: 55}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7577265852821514236
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1234883103932309115}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &322438256967861300
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1234883103932309115}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &1752572000902273007
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8230912162764402355}
|
||||
- component: {fileID: 4345137299206345491}
|
||||
- component: {fileID: 107565700018763461}
|
||||
m_Layer: 0
|
||||
m_Name: Text (Legacy)
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8230912162764402355
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1752572000902273007}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 9058676790248205063}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &4345137299206345491
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1752572000902273007}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &107565700018763461
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1752572000902273007}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: bd4be44636ad6c24a9b117a7108a75e9, type: 3}
|
||||
m_FontSize: 10
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 1
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: "\u62D2\u7EDD\u7533\u8BF7"
|
||||
--- !u!1 &4212541439505938081
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7715568052211693546}
|
||||
- component: {fileID: 2770649873537820046}
|
||||
m_Layer: 0
|
||||
m_Name: friendRequestPrefab
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7715568052211693546
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4212541439505938081}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1887113380917164164}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 100, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &2770649873537820046
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4212541439505938081}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 801af46c3c30ecc44ad9befbb892dc33, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
profileImage: {fileID: 322438256967861300}
|
||||
friendName: {fileID: 946637269750711889}
|
||||
friendSourceInfomation: {fileID: 2512442011294951853}
|
||||
acceptButton: {fileID: 3532086592632966835}
|
||||
rejectButton: {fileID: 1318607288835086267}
|
||||
--- !u!1 &4555906629148779692
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3192042035776563592}
|
||||
- component: {fileID: 3709975975265226361}
|
||||
- component: {fileID: 946637269750711889}
|
||||
m_Layer: 0
|
||||
m_Name: username
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3192042035776563592
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4555906629148779692}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1887113380917164164}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 30.39, y: 14}
|
||||
m_SizeDelta: {x: 143.18, y: 26}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &3709975975265226361
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4555906629148779692}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &946637269750711889
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4555906629148779692}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: dfa10de3e2846524089b5073175cd151, type: 3}
|
||||
m_FontSize: 24
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 1
|
||||
m_MinSize: 12
|
||||
m_MaxSize: 24
|
||||
m_Alignment: 3
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: "\u73A9\u5BB6\u540D\u5B57\u653E\u5728\u8FD9\u91CC\u5982\u679C\u5B57\u6570\u5B9E\u5728\u662F\u592A\u591A"
|
||||
--- !u!1 &7108017819273845759
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 9058676790248205063}
|
||||
- component: {fileID: 9058361928411038020}
|
||||
- component: {fileID: 8625764165904734956}
|
||||
- component: {fileID: 1318607288835086267}
|
||||
m_Layer: 0
|
||||
m_Name: rejectRequest
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &9058676790248205063
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7108017819273845759}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 8230912162764402355}
|
||||
m_Father: {fileID: 1887113380917164164}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 63.383705, y: -17.465}
|
||||
m_SizeDelta: {x: 62.1074, y: 17.071}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &9058361928411038020
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7108017819273845759}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &8625764165904734956
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7108017819273845759}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 0.7684825, b: 0.759434, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: 7f3b1220317607e44bbb8f0e1998044a, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 5
|
||||
--- !u!114 &1318607288835086267
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7108017819273845759}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 8625764165904734956}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &8090928456119292382
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2373904671374910531}
|
||||
- component: {fileID: 3245753848347248243}
|
||||
- component: {fileID: 660554859512802687}
|
||||
m_Layer: 0
|
||||
m_Name: Text (Legacy)
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &2373904671374910531
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8090928456119292382}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 5899234148902931492}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &3245753848347248243
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8090928456119292382}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &660554859512802687
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8090928456119292382}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: bd4be44636ad6c24a9b117a7108a75e9, type: 3}
|
||||
m_FontSize: 10
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 1
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: "\u63A5\u53D7\u7533\u8BF7"
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8ca0ff1de25bed438ccb59d4be1154b
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Threading.Tasks;
|
||||
using GameServer.Client;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
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 class friendSearchPrefab : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Image profileImage;
|
||||
[SerializeField] private Text friendName;
|
||||
[SerializeField] private Text friendSourceInfomation;
|
||||
[SerializeField] private Button addFriendButton;
|
||||
[SerializeField] private Text addFriendButtonText;
|
||||
|
||||
private Coroutine _avatarLoadRoutine;
|
||||
private Coroutine _buttonCooldownRoutine;
|
||||
private string _defaultAddButtonText;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Text buttonText = ResolveAddButtonText();
|
||||
_defaultAddButtonText = buttonText != null ? buttonText.text : string.Empty;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_avatarLoadRoutine != null)
|
||||
{
|
||||
StopCoroutine(_avatarLoadRoutine);
|
||||
_avatarLoadRoutine = null;
|
||||
}
|
||||
|
||||
if (_buttonCooldownRoutine != null)
|
||||
{
|
||||
StopCoroutine(_buttonCooldownRoutine);
|
||||
_buttonCooldownRoutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind(ProfileData profile, bool canAdd, string disabledButtonText, Func<Task> onAddClicked, float cooldownSeconds)
|
||||
{
|
||||
if (friendName != null)
|
||||
{
|
||||
friendName.text = profile != null
|
||||
? NetworkManager.ResolveDisplayName(profile.display_name, profile.steam_id, false)
|
||||
: string.Empty;
|
||||
}
|
||||
|
||||
if (addFriendButton != null)
|
||||
{
|
||||
addFriendButton.onClick.RemoveAllListeners();
|
||||
addFriendButton.interactable = canAdd;
|
||||
Text buttonText = ResolveAddButtonText();
|
||||
if (buttonText != null)
|
||||
{
|
||||
buttonText.text = !canAdd && !string.IsNullOrWhiteSpace(disabledButtonText)
|
||||
? disabledButtonText
|
||||
: _defaultAddButtonText;
|
||||
}
|
||||
if (canAdd && onAddClicked != null)
|
||||
{
|
||||
addFriendButton.onClick.AddListener(() =>
|
||||
{
|
||||
if (_buttonCooldownRoutine != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ = HandleAddClickedAsync(onAddClicked, cooldownSeconds);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (_avatarLoadRoutine != null)
|
||||
{
|
||||
StopCoroutine(_avatarLoadRoutine);
|
||||
}
|
||||
|
||||
if (profileImage != null && profile != null)
|
||||
{
|
||||
profileImage.sprite = null;
|
||||
string avatarUrl = NetworkManager.ResolveAvatarUrl(profile.avatar_url, profile.steam_id);
|
||||
_avatarLoadRoutine = StartCoroutine(LoadAvatarRoutine(profile.steam_id, avatarUrl));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleAddClickedAsync(Func<Task> onAddClicked, float cooldownSeconds)
|
||||
{
|
||||
if (addFriendButton != null)
|
||||
{
|
||||
addFriendButton.interactable = false;
|
||||
}
|
||||
|
||||
_buttonCooldownRoutine = StartCoroutine(ButtonCooldownRoutine(cooldownSeconds));
|
||||
await onAddClicked();
|
||||
}
|
||||
|
||||
private IEnumerator ButtonCooldownRoutine(float cooldownSeconds)
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(cooldownSeconds);
|
||||
if (addFriendButton != null)
|
||||
{
|
||||
addFriendButton.interactable = true;
|
||||
}
|
||||
|
||||
_buttonCooldownRoutine = null;
|
||||
}
|
||||
|
||||
private IEnumerator LoadAvatarRoutine(string steamId, string avatarUrl)
|
||||
{
|
||||
if (profileImage == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
bool loaded = false;
|
||||
if (NetworkManager.IsUsableAvatarUrl(avatarUrl)
|
||||
&& !avatarUrl.StartsWith(NetworkManager.SteamAvatarUrlPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
using (UnityWebRequest request = UnityWebRequestTexture.GetTexture(avatarUrl))
|
||||
{
|
||||
yield return request.SendWebRequest();
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
Texture2D texture = DownloadHandlerTexture.GetContent(request);
|
||||
if (texture != null)
|
||||
{
|
||||
profileImage.sprite = Sprite.Create(
|
||||
texture,
|
||||
new Rect(0f, 0f, texture.width, texture.height),
|
||||
new Vector2(0.5f, 0.5f));
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loaded)
|
||||
{
|
||||
yield return LoadSteamAvatarRoutine(steamId);
|
||||
}
|
||||
|
||||
_avatarLoadRoutine = null;
|
||||
}
|
||||
|
||||
private IEnumerator LoadSteamAvatarRoutine(string steamId)
|
||||
{
|
||||
#if FRIEND_DISABLE_STEAMWORKS
|
||||
yield break;
|
||||
#else
|
||||
if (!SteamManager.Initialized || string.IsNullOrWhiteSpace(steamId) || profileImage == null || !ulong.TryParse(steamId, out ulong rawSteamId))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
CSteamID targetSteamId = new CSteamID(rawSteamId);
|
||||
SteamFriends.RequestUserInformation(targetSteamId, false);
|
||||
|
||||
float deadline = Time.realtimeSinceStartup + 5f;
|
||||
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))
|
||||
{
|
||||
profileImage.sprite = CreateFlippedSteamAvatarSprite(buffer, (int)width, (int)height);
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
yield return new WaitForSecondsRealtime(0.25f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private Text ResolveAddButtonText()
|
||||
{
|
||||
if (addFriendButtonText != null)
|
||||
{
|
||||
return addFriendButtonText;
|
||||
}
|
||||
|
||||
return addFriendButton != null ? addFriendButton.GetComponentInChildren<Text>(true) : null;
|
||||
}
|
||||
|
||||
private static Sprite CreateFlippedSteamAvatarSprite(byte[] rgbaBuffer, int width, int height)
|
||||
{
|
||||
Texture2D texture = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||
texture.LoadRawTextureData(rgbaBuffer);
|
||||
texture.Apply();
|
||||
|
||||
Texture2D flipped = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
Color[] pixels = texture.GetPixels(0, y, width, 1);
|
||||
flipped.SetPixels(0, height - 1 - y, width, 1, pixels);
|
||||
}
|
||||
flipped.Apply();
|
||||
return Sprite.Create(flipped, new Rect(0, 0, width, height), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6960d1bacccebf45bc74ca08eab154b
|
||||
@@ -0,0 +1,567 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &167812896000688069
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 171703084932209816}
|
||||
- component: {fileID: 7766852143305575412}
|
||||
- component: {fileID: 2512442011294951853}
|
||||
m_Layer: 0
|
||||
m_Name: source
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &171703084932209816
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 167812896000688069}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1887113380917164164}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 30.39, y: -4}
|
||||
m_SizeDelta: {x: 143.18, y: 12.573}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7766852143305575412
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 167812896000688069}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &2512442011294951853
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 167812896000688069}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: bd4be44636ad6c24a9b117a7108a75e9, type: 3}
|
||||
m_FontSize: 10
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 1
|
||||
m_MaxSize: 18
|
||||
m_Alignment: 3
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: "\u96C5\u8389\u68A6\u7483\u9AD8\u65B0\u4EA7\u4E1A\u56ED Steam2\u533A"
|
||||
--- !u!1 &171027573892652408
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5899234148902931492}
|
||||
- component: {fileID: 752898224887842841}
|
||||
- component: {fileID: 7879641519199484437}
|
||||
- component: {fileID: 3532086592632966835}
|
||||
m_Layer: 0
|
||||
m_Name: sendRequest
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &5899234148902931492
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 171027573892652408}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 2373904671374910531}
|
||||
m_Father: {fileID: 1887113380917164164}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 30.389, y: -17.465}
|
||||
m_SizeDelta: {x: 143.18, y: 17.071}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &752898224887842841
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 171027573892652408}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &7879641519199484437
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 171027573892652408}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.6367924, g: 1, b: 0.9797205, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: 7f3b1220317607e44bbb8f0e1998044a, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 5
|
||||
--- !u!114 &3532086592632966835
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 171027573892652408}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 7879641519199484437}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &696844997186230125
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1887113380917164164}
|
||||
- component: {fileID: 8398379083156494532}
|
||||
- component: {fileID: 885345931350300794}
|
||||
m_Layer: 0
|
||||
m_Name: btm
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1887113380917164164
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 696844997186230125}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 3062756356687769231}
|
||||
- {fileID: 3192042035776563592}
|
||||
- {fileID: 171703084932209816}
|
||||
- {fileID: 5899234148902931492}
|
||||
m_Father: {fileID: 7715568052211693546}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 220, y: 70}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &8398379083156494532
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 696844997186230125}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &885345931350300794
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 696844997186230125}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: 537c5cf3bf53c2f4a9404248acd2d336, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &1234883103932309115
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3062756356687769231}
|
||||
- component: {fileID: 7577265852821514236}
|
||||
- component: {fileID: 322438256967861300}
|
||||
m_Layer: 0
|
||||
m_Name: profile
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3062756356687769231
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1234883103932309115}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1887113380917164164}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -74.39, y: 1.5}
|
||||
m_SizeDelta: {x: 55, y: 55}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7577265852821514236
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1234883103932309115}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &322438256967861300
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1234883103932309115}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &4212541439505938081
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7715568052211693546}
|
||||
- component: {fileID: 6174152505969619671}
|
||||
m_Layer: 0
|
||||
m_Name: friendSearchPrefab
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7715568052211693546
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4212541439505938081}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1887113380917164164}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 100, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &6174152505969619671
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4212541439505938081}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e6960d1bacccebf45bc74ca08eab154b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
profileImage: {fileID: 322438256967861300}
|
||||
friendName: {fileID: 946637269750711889}
|
||||
friendSourceInfomation: {fileID: 2512442011294951853}
|
||||
addFriendButton: {fileID: 3532086592632966835}
|
||||
--- !u!1 &4555906629148779692
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3192042035776563592}
|
||||
- component: {fileID: 3709975975265226361}
|
||||
- component: {fileID: 946637269750711889}
|
||||
m_Layer: 0
|
||||
m_Name: username
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3192042035776563592
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4555906629148779692}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1887113380917164164}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 30.39, y: 14}
|
||||
m_SizeDelta: {x: 143.18, y: 26}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &3709975975265226361
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4555906629148779692}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &946637269750711889
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4555906629148779692}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: dfa10de3e2846524089b5073175cd151, type: 3}
|
||||
m_FontSize: 24
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 1
|
||||
m_MinSize: 12
|
||||
m_MaxSize: 24
|
||||
m_Alignment: 3
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: "\u73A9\u5BB6\u540D\u5B57\u653E\u5728\u8FD9\u91CC\u5982\u679C\u5B57\u6570\u5B9E\u5728\u662F\u592A\u591A"
|
||||
--- !u!1 &8090928456119292382
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2373904671374910531}
|
||||
- component: {fileID: 3245753848347248243}
|
||||
- component: {fileID: 660554859512802687}
|
||||
m_Layer: 0
|
||||
m_Name: Text (Legacy)
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &2373904671374910531
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8090928456119292382}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 5899234148902931492}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &3245753848347248243
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8090928456119292382}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &660554859512802687
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8090928456119292382}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 12800000, guid: bd4be44636ad6c24a9b117a7108a75e9, type: 3}
|
||||
m_FontSize: 10
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 1
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: "\u70B9\u51FB\u5411\u5176\u53D1\u9001\u597D\u53CB\u7533\u8BF7"
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 473497bd46c599a47a629dd5455a04cd
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,769 @@
|
||||
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 const string LabelAllFriends = "全部好友";
|
||||
private const string LabelOnlineFriends = "在线好友";
|
||||
private const string LabelStarredFriends = "星标好友";
|
||||
private const string LabelOfflineFriends = "离线好友";
|
||||
private const string LabelGameFriends = "游戏好友";
|
||||
private const string LabelSteamFriends = "Steam好友";
|
||||
private const string StatusOnline = "在线";
|
||||
private const string StatusOffline = "离线";
|
||||
private const string StatusPlaying = "游戏中";
|
||||
private const string StatusInRoom = "房间中";
|
||||
private const string NoticeFriendDetailsNotReady = "好友详情面板尚未接入";
|
||||
private const string NoticePrivateChatNotReady = "私聊面板尚未接入";
|
||||
private const string DefaultStatusLoading = "正在拉取好友信息...";
|
||||
private const string DefaultStatusEmpty = "你当前没有好友";
|
||||
private const string DefaultStatusServiceUnavailable = "无法访问服务";
|
||||
|
||||
public GameObject friendCardPrefab;
|
||||
public Transform friendsDisplayContent;
|
||||
|
||||
[Header("filter")]
|
||||
public Dropdown friendsDisplayDropdown;
|
||||
|
||||
[Header("text")]
|
||||
public Text defaultText;
|
||||
|
||||
[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 filter, string label)> _filters =
|
||||
new List<(FriendFilterType filter, string label)>
|
||||
{
|
||||
(FriendFilterType.All, LabelAllFriends),
|
||||
(FriendFilterType.Online, LabelOnlineFriends),
|
||||
(FriendFilterType.Starred, LabelStarredFriends),
|
||||
(FriendFilterType.Offline, LabelOfflineFriends),
|
||||
(FriendFilterType.GameFriends, LabelGameFriends),
|
||||
(FriendFilterType.SteamFriends, LabelSteamFriends)
|
||||
};
|
||||
|
||||
private bool _dropdownInitialized;
|
||||
private bool _isRefreshing;
|
||||
private bool _lastRefreshFailed;
|
||||
private Coroutine _resyncCoroutine;
|
||||
private static List<string> _startupSteamFriendIds = new List<string>();
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void WarmSteamFriendIdsOnStartup()
|
||||
{
|
||||
_startupSteamFriendIds = ReadSteamFriendIdsOnly();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
ClearDisplayedFriends();
|
||||
SetDefaultText(DefaultStatusLoading);
|
||||
InitializeDropdown();
|
||||
|
||||
if (ArenaRoomService.Instance != null)
|
||||
{
|
||||
ArenaRoomService.Instance.OnFriendsListChanged += HandleFriendsListChanged;
|
||||
}
|
||||
|
||||
StartCoroutine(InitializeFriendsRoutine());
|
||||
if (_resyncCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_resyncCoroutine);
|
||||
}
|
||||
_resyncCoroutine = StartCoroutine(SteamFriendResyncLoop());
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
if (!_dropdownInitialized)
|
||||
{
|
||||
friendsDisplayDropdown.ClearOptions();
|
||||
friendsDisplayDropdown.AddOptions(_filters.Select(item => item.label).ToList());
|
||||
friendsDisplayDropdown.value = 0;
|
||||
_dropdownInitialized = true;
|
||||
}
|
||||
|
||||
friendsDisplayDropdown.onValueChanged.AddListener(HandleFilterChanged);
|
||||
friendsDisplayDropdown.RefreshShownValue();
|
||||
}
|
||||
|
||||
private void HandleFilterChanged(int _)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
|
||||
private void HandleFriendsListChanged(IReadOnlyList<SocialFriendEntry> friends)
|
||||
{
|
||||
_lastRefreshFailed = false;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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 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].filter;
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e90a1965bd8aeff459ac3039e97c3df3
|
||||
@@ -0,0 +1,668 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bansonic;
|
||||
using GameServer.Client;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class friendsManager : MonoBehaviour
|
||||
{
|
||||
private const float RequestCooldownSeconds = 3f;
|
||||
|
||||
public InputField searchFriend_iptfd;
|
||||
public Button searchButton;
|
||||
|
||||
[Header("FriendSearchObjects")]
|
||||
public GameObject friendSearchPrefab;
|
||||
public Transform friendSearchParent;
|
||||
|
||||
[Header("FriendRequestObjects")]
|
||||
public GameObject friendRequestPrefab;
|
||||
public GameObject friendRequestParent;
|
||||
public Button quickAcceptAll;
|
||||
public Button quickRejectAll;
|
||||
|
||||
[Header("Default Texts")]
|
||||
public Text defaultFriendSearchText;
|
||||
public Text defaultFriendRequestText;
|
||||
|
||||
private readonly Dictionary<long, GameObject> _spawnedRequestCards = new Dictionary<long, GameObject>();
|
||||
private readonly Dictionary<string, float> _actionCooldownUntil = new Dictionary<string, float>();
|
||||
private readonly HashSet<string> _pendingActions = new HashSet<string>();
|
||||
private GameObject _spawnedSearchCard;
|
||||
private bool _isSearching;
|
||||
private bool _isBatchProcessing;
|
||||
|
||||
private Transform RequestParentTransform => friendRequestParent != null ? friendRequestParent.transform : null;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
ClearSearchParentChildren();
|
||||
ClearRequestParentChildren();
|
||||
SetSearchDefaultVisible(false);
|
||||
SetRequestDefaultVisible(true);
|
||||
BindUiEvents();
|
||||
|
||||
if (ArenaRoomService.Instance != null)
|
||||
{
|
||||
ArenaRoomService.Instance.OnFriendRequestsChanged += HandleFriendRequestsChanged;
|
||||
}
|
||||
|
||||
_ = InitializeAsync();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (ArenaRoomService.Instance != null)
|
||||
{
|
||||
ArenaRoomService.Instance.OnFriendRequestsChanged -= HandleFriendRequestsChanged;
|
||||
}
|
||||
|
||||
UnbindUiEvents();
|
||||
}
|
||||
|
||||
private async Task InitializeAsync()
|
||||
{
|
||||
ArenaRoomService arena = ArenaRoomService.Instance;
|
||||
if (arena == null)
|
||||
{
|
||||
SetRequestDefaultVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IReadOnlyList<SocialFriendRequestEntry> requests = await arena.GetFriendRequestsAsync(true);
|
||||
RenderFriendRequests(requests);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
gNotice.error.display(ex.Message);
|
||||
SetRequestDefaultVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void BindUiEvents()
|
||||
{
|
||||
if (searchButton != null)
|
||||
{
|
||||
searchButton.onClick.RemoveListener(HandleSearchClicked);
|
||||
searchButton.onClick.AddListener(HandleSearchClicked);
|
||||
}
|
||||
|
||||
if (searchFriend_iptfd != null)
|
||||
{
|
||||
searchFriend_iptfd.onEndEdit.RemoveListener(HandleSearchEndEdit);
|
||||
searchFriend_iptfd.onEndEdit.AddListener(HandleSearchEndEdit);
|
||||
}
|
||||
|
||||
if (quickAcceptAll != null)
|
||||
{
|
||||
quickAcceptAll.onClick.RemoveListener(HandleQuickAcceptAll);
|
||||
quickAcceptAll.onClick.AddListener(HandleQuickAcceptAll);
|
||||
}
|
||||
|
||||
if (quickRejectAll != null)
|
||||
{
|
||||
quickRejectAll.onClick.RemoveListener(HandleQuickRejectAll);
|
||||
quickRejectAll.onClick.AddListener(HandleQuickRejectAll);
|
||||
}
|
||||
}
|
||||
|
||||
private void UnbindUiEvents()
|
||||
{
|
||||
if (searchButton != null)
|
||||
{
|
||||
searchButton.onClick.RemoveListener(HandleSearchClicked);
|
||||
}
|
||||
|
||||
if (searchFriend_iptfd != null)
|
||||
{
|
||||
searchFriend_iptfd.onEndEdit.RemoveListener(HandleSearchEndEdit);
|
||||
}
|
||||
|
||||
if (quickAcceptAll != null)
|
||||
{
|
||||
quickAcceptAll.onClick.RemoveListener(HandleQuickAcceptAll);
|
||||
}
|
||||
|
||||
if (quickRejectAll != null)
|
||||
{
|
||||
quickRejectAll.onClick.RemoveListener(HandleQuickRejectAll);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleFriendRequestsChanged(IReadOnlyList<SocialFriendRequestEntry> requests)
|
||||
{
|
||||
RenderFriendRequests(requests);
|
||||
}
|
||||
|
||||
private void HandleSearchClicked()
|
||||
{
|
||||
string actionSignature = BuildSearchSignature();
|
||||
if (!TryBeginAction(actionSignature))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BeginButtonCooldown(searchButton);
|
||||
_ = SearchExactPlayerAsync(actionSignature);
|
||||
}
|
||||
|
||||
private void HandleSearchEndEdit(string value)
|
||||
{
|
||||
if (!isActiveAndEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter))
|
||||
{
|
||||
string actionSignature = BuildSearchSignature();
|
||||
if (!TryBeginAction(actionSignature))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BeginButtonCooldown(searchButton);
|
||||
_ = SearchExactPlayerAsync(actionSignature);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SearchExactPlayerAsync(string actionSignature)
|
||||
{
|
||||
if (_isSearching || string.IsNullOrWhiteSpace(actionSignature))
|
||||
{
|
||||
EndAction(actionSignature);
|
||||
return;
|
||||
}
|
||||
|
||||
_isSearching = true;
|
||||
SetSearchDefaultVisible(false);
|
||||
ClearSearchParentChildren();
|
||||
|
||||
try
|
||||
{
|
||||
string query = searchFriend_iptfd != null ? searchFriend_iptfd.text?.Trim() : string.Empty;
|
||||
ProfileData profile = await LookupProfileExactAsync(query);
|
||||
if (!IsValidProfile(profile))
|
||||
{
|
||||
SetSearchDefaultVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (friendSearchPrefab == null || friendSearchParent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_spawnedSearchCard = Instantiate(friendSearchPrefab, friendSearchParent, false);
|
||||
friendSearchPrefab prefab = _spawnedSearchCard.GetComponent<friendSearchPrefab>();
|
||||
if (prefab != null)
|
||||
{
|
||||
bool alreadyFriend = IsAlreadyFriend(profile.steam_id);
|
||||
bool canSendRequest = CanSendFriendRequest(profile.steam_id);
|
||||
prefab.Bind(
|
||||
profile,
|
||||
canSendRequest,
|
||||
alreadyFriend ? "你们已经是好友" : string.Empty,
|
||||
() => SendFriendRequestAsync(profile.steam_id),
|
||||
RequestCooldownSeconds);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
gNotice.error.display(ex.Message);
|
||||
SetSearchDefaultVisible(true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSearching = false;
|
||||
EndAction(actionSignature);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ProfileData> LookupProfileExactAsync(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
NetworkManager network = NetworkManager.Instance;
|
||||
if (network == null)
|
||||
{
|
||||
throw new Exception("NetworkManager is not initialized");
|
||||
}
|
||||
|
||||
string trimmed = query.Trim();
|
||||
if (trimmed.All(char.IsDigit))
|
||||
{
|
||||
if (trimmed.Length >= 16)
|
||||
{
|
||||
return await SafeGetProfileBySteamId(network, trimmed);
|
||||
}
|
||||
|
||||
if (int.TryParse(trimmed, out int uid) && uid > 0)
|
||||
{
|
||||
return await SafeGetProfileByUid(network, uid);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static async Task<ProfileData> SafeGetProfileBySteamId(NetworkManager network, string steamId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await network.GetProfile(steamId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<ProfileData> SafeGetProfileByUid(NetworkManager network, int uid)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await network.GetPlayerByUid(uid);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsValidProfile(ProfileData profile)
|
||||
{
|
||||
return profile != null && !string.IsNullOrWhiteSpace(profile.steam_id);
|
||||
}
|
||||
|
||||
private bool CanSendFriendRequest(string targetSteamId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(targetSteamId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NetworkManager network = NetworkManager.Instance;
|
||||
if (network != null && string.Equals(network.SteamId, targetSteamId, StringComparison.Ordinal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !IsAlreadyFriend(targetSteamId);
|
||||
}
|
||||
|
||||
private bool IsAlreadyFriend(string targetSteamId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(targetSteamId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ArenaRoomService arena = ArenaRoomService.Instance;
|
||||
return arena != null && arena.GetFriendsSnapshot().Any(friend =>
|
||||
friend != null && string.Equals(friend.friend_steam_id, targetSteamId, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private async Task SendFriendRequestAsync(string targetSteamId)
|
||||
{
|
||||
string actionSignature = $"send:{targetSteamId}";
|
||||
if (!TryBeginAction(actionSignature))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArenaRoomService arena = ArenaRoomService.Instance;
|
||||
if (arena == null)
|
||||
{
|
||||
gNotice.error.display("好友服务未初始化");
|
||||
EndAction(actionSignature);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await arena.SendFriendRequestAsync(targetSteamId);
|
||||
ClearSearchParentChildren();
|
||||
SetSearchDefaultVisible(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
gNotice.error.display(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndAction(actionSignature);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderFriendRequests(IReadOnlyList<SocialFriendRequestEntry> requests)
|
||||
{
|
||||
Transform parent = RequestParentTransform;
|
||||
if (parent == null || friendRequestPrefab == null)
|
||||
{
|
||||
SetRequestDefaultVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
ClearRequestParentChildren();
|
||||
|
||||
List<SocialFriendRequestEntry> normalized = (requests ?? Array.Empty<SocialFriendRequestEntry>())
|
||||
.Where(request => request != null && request.id > 0 && !string.IsNullOrWhiteSpace(request.from_steam_id))
|
||||
.OrderByDescending(request => request.created_at ?? string.Empty, StringComparer.Ordinal)
|
||||
.ThenByDescending(request => request.id)
|
||||
.ToList();
|
||||
|
||||
for (int index = 0; index < normalized.Count; index++)
|
||||
{
|
||||
SocialFriendRequestEntry request = normalized[index];
|
||||
GameObject cardObject = Instantiate(friendRequestPrefab, parent, false);
|
||||
_spawnedRequestCards[request.id] = cardObject;
|
||||
cardObject.transform.SetSiblingIndex(index);
|
||||
friendRequestPrefab prefab = cardObject.GetComponent<friendRequestPrefab>();
|
||||
if (prefab != null)
|
||||
{
|
||||
prefab.Bind(
|
||||
request,
|
||||
() => AcceptRequestAsync(request.id),
|
||||
() => RejectRequestAsync(request.id),
|
||||
RequestCooldownSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
SetRequestDefaultVisible(normalized.Count == 0);
|
||||
}
|
||||
|
||||
private async Task AcceptRequestAsync(long requestId)
|
||||
{
|
||||
string actionSignature = $"accept:{requestId}";
|
||||
if (!TryBeginAction(actionSignature))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArenaRoomService arena = ArenaRoomService.Instance;
|
||||
if (arena == null)
|
||||
{
|
||||
gNotice.error.display("好友服务未初始化");
|
||||
EndAction(actionSignature);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await arena.AcceptFriendRequestAsync(requestId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
gNotice.error.display(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndAction(actionSignature);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RejectRequestAsync(long requestId)
|
||||
{
|
||||
string actionSignature = $"reject:{requestId}";
|
||||
if (!TryBeginAction(actionSignature))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArenaRoomService arena = ArenaRoomService.Instance;
|
||||
if (arena == null)
|
||||
{
|
||||
gNotice.error.display("好友服务未初始化");
|
||||
EndAction(actionSignature);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await arena.RejectFriendRequestAsync(requestId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
gNotice.error.display(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndAction(actionSignature);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleQuickAcceptAll()
|
||||
{
|
||||
const string actionSignature = "batch:accept";
|
||||
if (_isBatchProcessing || !TryBeginAction(actionSignature))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BeginButtonCooldown(quickAcceptAll);
|
||||
_ = ProcessAllRequestsAsync(accept: true, actionSignature);
|
||||
}
|
||||
|
||||
private void HandleQuickRejectAll()
|
||||
{
|
||||
const string actionSignature = "batch:reject";
|
||||
if (_isBatchProcessing || !TryBeginAction(actionSignature))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BeginButtonCooldown(quickRejectAll);
|
||||
_ = ProcessAllRequestsAsync(accept: false, actionSignature);
|
||||
}
|
||||
|
||||
private async Task ProcessAllRequestsAsync(bool accept, string actionSignature)
|
||||
{
|
||||
ArenaRoomService arena = ArenaRoomService.Instance;
|
||||
if (arena == null)
|
||||
{
|
||||
gNotice.error.display("好友服务未初始化");
|
||||
EndAction(actionSignature);
|
||||
return;
|
||||
}
|
||||
|
||||
_isBatchProcessing = true;
|
||||
SetBatchButtonsInteractable(false);
|
||||
try
|
||||
{
|
||||
List<long> requestIds = arena.GetFriendRequestsSnapshot()
|
||||
.Where(request => request != null && request.id > 0)
|
||||
.Select(request => request.id)
|
||||
.ToList();
|
||||
|
||||
foreach (long requestId in requestIds)
|
||||
{
|
||||
if (accept)
|
||||
{
|
||||
await arena.AcceptFriendRequestAsync(requestId);
|
||||
}
|
||||
else
|
||||
{
|
||||
await arena.RejectFriendRequestAsync(requestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
gNotice.error.display(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isBatchProcessing = false;
|
||||
EndAction(actionSignature);
|
||||
StartCoroutine(ReenableBatchButtonsAfterCooldown());
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildSearchSignature()
|
||||
{
|
||||
string query = searchFriend_iptfd != null ? searchFriend_iptfd.text?.Trim() : string.Empty;
|
||||
return string.IsNullOrWhiteSpace(query) ? string.Empty : $"search:{query}";
|
||||
}
|
||||
|
||||
private bool TryBeginAction(string actionSignature)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(actionSignature))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float now = Time.unscaledTime;
|
||||
CleanupExpiredActions(now);
|
||||
if (_pendingActions.Contains(actionSignature))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_actionCooldownUntil.TryGetValue(actionSignature, out float cooldownUntil) && cooldownUntil > now)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_pendingActions.Add(actionSignature);
|
||||
_actionCooldownUntil[actionSignature] = now + RequestCooldownSeconds;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void EndAction(string actionSignature)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(actionSignature))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_pendingActions.Remove(actionSignature);
|
||||
}
|
||||
|
||||
private void CleanupExpiredActions(float now)
|
||||
{
|
||||
List<string> expiredKeys = null;
|
||||
foreach (KeyValuePair<string, float> entry in _actionCooldownUntil)
|
||||
{
|
||||
if (_pendingActions.Contains(entry.Key) || entry.Value > now)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
expiredKeys ??= new List<string>();
|
||||
expiredKeys.Add(entry.Key);
|
||||
}
|
||||
|
||||
if (expiredKeys == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string key in expiredKeys)
|
||||
{
|
||||
_actionCooldownUntil.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginButtonCooldown(Button button)
|
||||
{
|
||||
if (button == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StartCoroutine(ButtonCooldownRoutine(button));
|
||||
}
|
||||
|
||||
private IEnumerator ButtonCooldownRoutine(Button button)
|
||||
{
|
||||
button.interactable = false;
|
||||
yield return new WaitForSecondsRealtime(RequestCooldownSeconds);
|
||||
if (button != null)
|
||||
{
|
||||
button.interactable = true;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator ReenableBatchButtonsAfterCooldown()
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(RequestCooldownSeconds);
|
||||
SetBatchButtonsInteractable(true);
|
||||
}
|
||||
|
||||
private void SetBatchButtonsInteractable(bool interactable)
|
||||
{
|
||||
if (quickAcceptAll != null)
|
||||
{
|
||||
quickAcceptAll.interactable = interactable;
|
||||
}
|
||||
|
||||
if (quickRejectAll != null)
|
||||
{
|
||||
quickRejectAll.interactable = interactable;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearSearchParentChildren()
|
||||
{
|
||||
Transform parent = friendSearchParent;
|
||||
if (parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int index = parent.childCount - 1; index >= 0; index--)
|
||||
{
|
||||
Transform child = parent.GetChild(index);
|
||||
if (child != null)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
_spawnedSearchCard = null;
|
||||
}
|
||||
|
||||
private void ClearRequestParentChildren()
|
||||
{
|
||||
Transform parent = RequestParentTransform;
|
||||
if (parent != null)
|
||||
{
|
||||
for (int index = parent.childCount - 1; index >= 0; index--)
|
||||
{
|
||||
Transform child = parent.GetChild(index);
|
||||
if (child != null)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_spawnedRequestCards.Clear();
|
||||
}
|
||||
|
||||
private void SetSearchDefaultVisible(bool visible)
|
||||
{
|
||||
if (defaultFriendSearchText != null)
|
||||
{
|
||||
defaultFriendSearchText.gameObject.SetActive(visible);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetRequestDefaultVisible(bool visible)
|
||||
{
|
||||
if (defaultFriendRequestText != null)
|
||||
{
|
||||
defaultFriendRequestText.gameObject.SetActive(visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfee62e88f648294aa2f71387a1e58b5
|
||||
Reference in New Issue
Block a user