功能批量实现 优化 服务端 新浮动小游戏框架 新界面UI

This commit is contained in:
FloatGaming
2026-04-24 13:20:16 +08:00
parent e0bc0bbf08
commit 5eec879582
257 changed files with 38481 additions and 1288 deletions
+864 -1
View File
@@ -1,12 +1,31 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using Bansonic;
using GameServer.Client;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class roomDetails : MonoBehaviour
{
private sealed class RoomSystemFeedEntry
{
public string richText;
public long createdAtUnixMs;
public long sequence;
}
private sealed class RoomFeedEntry
{
public object entry;
public long timestampMs;
public int order;
public string key;
public long sequence;
}
[Header("room Info")]
public Text roomID;
public Text roomRemainTime;
@@ -14,7 +33,7 @@ public class roomDetails : MonoBehaviour
public Button quitRoom2;
public Button getReady;
public Button showRoomRankingList;
[Header("song info")]
public Text thisSongName;
public Text thisSongDifficulty;
@@ -26,11 +45,48 @@ public class roomDetails : MonoBehaviour
[Header("sprites")]
public Sprite[] btmSprites;
[Header("roomChatSystem")]
public GameObject playerMessagePrefab;
public GameObject selfMessagePrefab;
public GameObject systemMessagePrefab;
public Transform messageParent;
[SerializeField] private int maxMessageHistory = 500;
[SerializeField] private int messageDisplayWindow = 20;
[SerializeField] private Color[] messageTypeColors;
public InputField playerMessageInputField;
public Button sendMessageButton;
private ArenaRoomService _service;
private Coroutine _countdownRoutine;
private GameObject _roomRankingPrefabTemplate;
private Transform _roomRankingSpawnParent;
private GameObject _spawnedRoomRankingInstance;
private ScrollRect _messageScrollRect;
private Coroutine _chatCooldownRoutine;
private Text _chatPlaceholderText;
private string _defaultChatPlaceholder = string.Empty;
private float _nextChatSendAllowedAt;
private bool _isSendingRoomMessage;
private string _pendingRoomMessageContent = string.Empty;
private readonly List<RoomSystemFeedEntry> _systemFeedEntries = new List<RoomSystemFeedEntry>();
private readonly Dictionary<string, long> _feedSequences = new Dictionary<string, long>(StringComparer.Ordinal);
private long _nextFeedSequence;
private bool _isChatViewPinnedToBottom = true;
private bool _suppressChatScrollEvents;
private int _chatWindowStartIndex = -1;
private readonly List<string> _renderedChatKeys = new List<string>();
private readonly List<GameObject> _renderedChatObjects = new List<GameObject>();
private Coroutine _messageLayoutRefreshCoroutine;
private bool _messageLayoutRefreshDirty;
private bool _scrollChatToBottomAfterLayout;
private readonly List<RectTransform> _pendingMessageLayoutDirtyRoots = new List<RectTransform>();
private Coroutine _refocusChatInputCoroutine;
private bool _refocusChatInputRequested;
private const float ChatSendCooldownSeconds = 3f;
private const int InitialHistoryLoadLimit = 20;
private const int MaxDisplayWindowLimit = 20;
private const string CooldownPlaceholderFormat = "\u53d1\u9001\u51b7\u5374\u4e2d {0}s";
public void ConfigureRoomRanking(GameObject roomRankingPrefab, Transform roomRankingSpawnParent)
{
@@ -54,6 +110,10 @@ public class roomDetails : MonoBehaviour
_service.OnKicked += HandleKicked;
_service.OnRoomDismissed -= HandleRoomDismissed;
_service.OnRoomDismissed += HandleRoomDismissed;
_service.OnRoomChatMessagesChanged -= HandleRoomChatMessagesChanged;
_service.OnRoomChatMessagesChanged += HandleRoomChatMessagesChanged;
_service.OnRoomSystemMessageReceived -= HandleRoomSystemMessageReceived;
_service.OnRoomSystemMessageReceived += HandleRoomSystemMessageReceived;
if (quitRoom != null)
{
@@ -79,6 +139,34 @@ public class roomDetails : MonoBehaviour
showRoomRankingList.onClick.AddListener(OnShowRoomRankingClicked);
}
if (sendMessageButton != null)
{
sendMessageButton.onClick.RemoveListener(OnSendMessageClicked);
sendMessageButton.onClick.AddListener(OnSendMessageClicked);
}
if (playerMessageInputField != null)
{
playerMessageInputField.onEndEdit.RemoveListener(OnChatInputEndEdit);
playerMessageInputField.onEndEdit.AddListener(OnChatInputEndEdit);
_chatPlaceholderText = playerMessageInputField.placeholder as Text;
if (_chatPlaceholderText != null)
{
_defaultChatPlaceholder = _chatPlaceholderText.text;
}
}
_messageScrollRect = messageParent != null ? messageParent.GetComponentInParent<ScrollRect>() : null;
if (_messageScrollRect != null)
{
_messageScrollRect.onValueChanged.RemoveListener(OnChatScrollValueChanged);
_messageScrollRect.onValueChanged.AddListener(OnChatScrollValueChanged);
}
_service.SetRoomChatCacheLimit(GetEffectiveCacheLimit());
ClearDisplayedMessages();
UpdateChatSendUiState();
_ = InitializeRoomChatAsync();
Refresh(_service.CurrentRoom);
}
@@ -89,6 +177,8 @@ public class roomDetails : MonoBehaviour
_service.OnRoomSnapshotChanged -= HandleRoomSnapshotChanged;
_service.OnKicked -= HandleKicked;
_service.OnRoomDismissed -= HandleRoomDismissed;
_service.OnRoomChatMessagesChanged -= HandleRoomChatMessagesChanged;
_service.OnRoomSystemMessageReceived -= HandleRoomSystemMessageReceived;
}
if (quitRoom != null)
@@ -111,12 +201,47 @@ public class roomDetails : MonoBehaviour
showRoomRankingList.onClick.RemoveListener(OnShowRoomRankingClicked);
}
if (sendMessageButton != null)
{
sendMessageButton.onClick.RemoveListener(OnSendMessageClicked);
}
if (playerMessageInputField != null)
{
playerMessageInputField.onEndEdit.RemoveListener(OnChatInputEndEdit);
}
if (_countdownRoutine != null)
{
StopCoroutine(_countdownRoutine);
_countdownRoutine = null;
}
if (_messageScrollRect != null)
{
_messageScrollRect.onValueChanged.RemoveListener(OnChatScrollValueChanged);
}
if (_chatCooldownRoutine != null)
{
StopCoroutine(_chatCooldownRoutine);
_chatCooldownRoutine = null;
}
if (_messageLayoutRefreshCoroutine != null)
{
StopCoroutine(_messageLayoutRefreshCoroutine);
_messageLayoutRefreshCoroutine = null;
}
if (_refocusChatInputCoroutine != null)
{
StopCoroutine(_refocusChatInputCoroutine);
_refocusChatInputCoroutine = null;
}
RestoreDefaultChatPlaceholder();
if (_spawnedRoomRankingInstance != null)
{
Destroy(_spawnedRoomRankingInstance);
@@ -145,6 +270,48 @@ public class roomDetails : MonoBehaviour
Destroy(gameObject);
}
private void HandleRoomChatMessagesChanged(IReadOnlyList<ArenaRoomChatMessage> messages)
{
RenderChatMessages(messages, true);
}
private void HandleRoomSystemMessageReceived(string richText)
{
if (string.IsNullOrWhiteSpace(richText))
{
return;
}
long createdAtUnixMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
string key = $"system:{createdAtUnixMs}:{richText}";
_systemFeedEntries.Add(new RoomSystemFeedEntry
{
richText = richText,
createdAtUnixMs = createdAtUnixMs,
sequence = GetOrAssignFeedSequence(key)
});
TrimSystemFeedCache();
RenderChatMessages(_service != null ? _service.GetRoomChatMessages() : null, true);
}
private async System.Threading.Tasks.Task InitializeRoomChatAsync()
{
if (_service == null)
{
return;
}
try
{
await _service.EnsureRoomChatSubscribed();
RenderChatMessages(_service.GetRoomChatMessages(), false);
}
catch (Exception ex)
{
Debug.LogWarning($"[roomDetails] Init room chat failed: {ex.Message}");
}
}
private async void OnQuitClicked()
{
if (_service == null)
@@ -319,6 +486,686 @@ public class roomDetails : MonoBehaviour
}
}
private async void OnSendMessageClicked()
{
if (_service == null || playerMessageInputField == null)
{
return;
}
if (Time.unscaledTime < _nextChatSendAllowedAt)
{
RefocusChatInputNextFrame();
UpdateChatSendUiState();
return;
}
string content = playerMessageInputField.text != null ? playerMessageInputField.text.Trim() : string.Empty;
if (string.IsNullOrWhiteSpace(content))
{
RefocusChatInputNextFrame();
return;
}
if (_isSendingRoomMessage && string.Equals(content, _pendingRoomMessageContent, StringComparison.Ordinal))
{
RefocusChatInputNextFrame();
return;
}
BeginChatCooldown();
_isSendingRoomMessage = true;
_pendingRoomMessageContent = content;
try
{
playerMessageInputField.text = string.Empty;
RefocusChatInputNextFrame();
await _service.SendRoomMessage(content);
}
catch (Exception ex)
{
if (playerMessageInputField != null && string.IsNullOrEmpty(playerMessageInputField.text))
{
playerMessageInputField.text = content;
RefocusChatInputNextFrame();
}
Debug.LogWarning($"[roomDetails] Send room message failed: {ex.Message}");
}
finally
{
_isSendingRoomMessage = false;
_pendingRoomMessageContent = string.Empty;
}
}
private void OnChatInputEndEdit(string value)
{
if (!isActiveAndEnabled || playerMessageInputField == null)
{
return;
}
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter))
{
OnSendMessageClicked();
}
}
private void BeginChatCooldown()
{
_nextChatSendAllowedAt = Time.unscaledTime + ChatSendCooldownSeconds;
if (_chatCooldownRoutine != null)
{
StopCoroutine(_chatCooldownRoutine);
}
_chatCooldownRoutine = StartCoroutine(ChatCooldownCoroutine());
UpdateChatSendUiState();
}
private IEnumerator ChatCooldownCoroutine()
{
while (Time.unscaledTime < _nextChatSendAllowedAt)
{
UpdateChatSendUiState();
yield return null;
}
_chatCooldownRoutine = null;
UpdateChatSendUiState();
}
private void UpdateChatSendUiState()
{
bool coolingDown = Time.unscaledTime < _nextChatSendAllowedAt;
if (sendMessageButton != null)
{
sendMessageButton.interactable = !coolingDown;
}
if (_chatPlaceholderText != null)
{
if (coolingDown)
{
float remain = Mathf.Max(0f, _nextChatSendAllowedAt - Time.unscaledTime);
_chatPlaceholderText.text = string.Format(CooldownPlaceholderFormat, Mathf.CeilToInt(remain));
}
else
{
_chatPlaceholderText.text = _defaultChatPlaceholder;
}
}
}
private void RestoreDefaultChatPlaceholder()
{
if (_chatPlaceholderText != null)
{
_chatPlaceholderText.text = _defaultChatPlaceholder;
}
}
private void RenderChatMessages(IReadOnlyList<ArenaRoomChatMessage> messages, bool preserveWindow)
{
if (messageParent == null || messages == null || playerMessagePrefab == null)
{
ClearDisplayedMessages();
return;
}
List<RoomFeedEntry> feed = BuildRoomFeed(messages);
UpdateChatWindowState(feed.Count, preserveWindow);
int startIndex = Mathf.Clamp(_chatWindowStartIndex, 0, Mathf.Max(0, feed.Count - 1));
int endIndex = Mathf.Min(feed.Count, startIndex + GetRenderedChatWindowCapacity());
var visibleEntries = new List<RoomFeedEntry>(Mathf.Max(0, endIndex - startIndex));
for (int i = startIndex; i < endIndex; i++)
{
visibleEntries.Add(feed[i]);
}
bool changed = ApplyRenderedChatEntries(visibleEntries);
if (changed)
{
ScheduleMessageLayoutRefresh(_isChatViewPinnedToBottom);
}
}
private bool ApplyRenderedChatEntries(List<RoomFeedEntry> visibleEntries)
{
var desiredKeys = new List<string>(visibleEntries.Count);
for (int i = 0; i < visibleEntries.Count; i++)
{
desiredKeys.Add(visibleEntries[i].key);
}
if (desiredKeys.Count == _renderedChatKeys.Count)
{
bool identical = true;
for (int i = 0; i < desiredKeys.Count; i++)
{
if (!string.Equals(desiredKeys[i], _renderedChatKeys[i], StringComparison.Ordinal))
{
identical = false;
break;
}
}
if (identical)
{
return false;
}
}
int prefix = 0;
int sharedCount = Mathf.Min(_renderedChatKeys.Count, desiredKeys.Count);
while (prefix < sharedCount && string.Equals(_renderedChatKeys[prefix], desiredKeys[prefix], StringComparison.Ordinal))
{
prefix++;
}
int suffix = 0;
while (suffix < (_renderedChatKeys.Count - prefix)
&& suffix < (desiredKeys.Count - prefix)
&& string.Equals(
_renderedChatKeys[_renderedChatKeys.Count - 1 - suffix],
desiredKeys[desiredKeys.Count - 1 - suffix],
StringComparison.Ordinal))
{
suffix++;
}
for (int i = _renderedChatObjects.Count - suffix - 1; i >= prefix; i--)
{
GameObject instance = _renderedChatObjects[i];
if (instance != null)
{
Destroy(instance);
}
_renderedChatObjects.RemoveAt(i);
_renderedChatKeys.RemoveAt(i);
}
for (int i = prefix; i < desiredKeys.Count - suffix; i++)
{
GameObject instance = CreateChatFeedObject(visibleEntries[i]);
_renderedChatObjects.Insert(i, instance);
_renderedChatKeys.Insert(i, desiredKeys[i]);
RegisterMessageLayoutDirtyRoot(instance);
}
for (int i = 0; i < _renderedChatObjects.Count; i++)
{
if (_renderedChatObjects[i] != null)
{
_renderedChatObjects[i].transform.SetSiblingIndex(i);
}
}
return true;
}
private GameObject CreateChatFeedObject(RoomFeedEntry feedEntry)
{
object entry = feedEntry.entry;
if (entry is RoomSystemFeedEntry systemEntry)
{
if (systemMessagePrefab == null)
{
return null;
}
GameObject systemInstance = Instantiate(systemMessagePrefab, messageParent, false);
systemMessagePrefab systemController = systemInstance.GetComponent<systemMessagePrefab>();
if (systemController != null)
{
systemController.Bind(systemEntry.richText);
}
return systemInstance;
}
ArenaRoomChatMessage message = entry as ArenaRoomChatMessage;
if (message == null)
{
return null;
}
string localSteamId = NetworkManager.Instance != null ? NetworkManager.Instance.SteamId : string.Empty;
string senderSteamId = GetMessageSenderSteamId(message);
bool isSelf = !string.IsNullOrWhiteSpace(localSteamId)
&& string.Equals(senderSteamId, localSteamId, StringComparison.Ordinal);
Color bubbleColor = ResolveMessageBubbleColor(isSelf);
string displayName = ResolveMessageDisplayName(message, isSelf);
string title = ResolveMessageTitle();
GameObject instance = Instantiate(playerMessagePrefab, messageParent, false);
playerMessagePrefab controller = instance.GetComponent<playerMessagePrefab>();
if (controller != null)
{
string avatarUrl = GameServer.Client.NetworkManager.ResolveAvatarUrl(message.avatar_url, senderSteamId);
controller.Bind(senderSteamId, avatarUrl, displayName, title, message.content, bubbleColor);
}
return instance;
}
private static string BuildRoomSystemKey(RoomSystemFeedEntry entry)
{
return $"system:{entry.createdAtUnixMs}:{entry.richText}";
}
private static string BuildRoomMessageKey(ArenaRoomChatMessage message)
{
if (message == null)
{
return "message:null";
}
if (message.id > 0)
{
return $"message:id:{message.id}";
}
string sender = GetMessageSenderSteamId(message);
return $"message:fallback:{message.room_code}:{sender}:{message.created_at}:{message.content}";
}
private void TrimSystemFeedCache()
{
int overflow = _systemFeedEntries.Count - GetEffectiveCacheLimit();
if (overflow > 0)
{
_systemFeedEntries.RemoveRange(0, overflow);
}
}
private List<RoomFeedEntry> BuildRoomFeed(IReadOnlyList<ArenaRoomChatMessage> messages)
{
List<RoomFeedEntry> feed = new List<RoomFeedEntry>();
int order = 0;
int startIndex = Mathf.Max(0, messages.Count - GetEffectiveCacheLimit());
for (int i = startIndex; i < messages.Count; i++)
{
ArenaRoomChatMessage message = messages[i];
if (message != null)
{
string key = BuildRoomMessageKey(message);
feed.Add(new RoomFeedEntry
{
entry = message,
timestampMs = ParseMessageUnixTimestamp(message.created_at),
order = order++,
key = key,
sequence = GetOrAssignFeedSequence(key)
});
}
}
for (int i = 0; i < _systemFeedEntries.Count; i++)
{
RoomSystemFeedEntry systemEntry = _systemFeedEntries[i];
if (systemEntry == null)
{
continue;
}
feed.Add(new RoomFeedEntry
{
entry = systemEntry,
timestampMs = systemEntry.createdAtUnixMs,
order = order++,
key = BuildRoomSystemKey(systemEntry),
sequence = systemEntry.sequence
});
}
feed.Sort(CompareFeedEntries);
return feed;
}
private void UpdateChatWindowState(int feedCount, bool preserveWindow)
{
int windowCapacity = GetRenderedChatWindowCapacity();
int maxStart = Mathf.Max(0, feedCount - windowCapacity);
if (!preserveWindow || _chatWindowStartIndex < 0 || _isChatViewPinnedToBottom)
{
_chatWindowStartIndex = maxStart;
_isChatViewPinnedToBottom = true;
return;
}
_chatWindowStartIndex = Mathf.Clamp(_chatWindowStartIndex, 0, maxStart);
}
private void OnChatScrollValueChanged(Vector2 normalizedPosition)
{
if (_suppressChatScrollEvents || _service == null)
{
return;
}
List<RoomFeedEntry> feed = BuildRoomFeed(_service.GetRoomChatMessages());
if (feed.Count <= GetRenderedChatWindowCapacity())
{
_isChatViewPinnedToBottom = true;
return;
}
if (normalizedPosition.y <= 0.05f)
{
int maxStart = Mathf.Max(0, feed.Count - GetRenderedChatWindowCapacity());
if (_chatWindowStartIndex < maxStart)
{
_chatWindowStartIndex = Mathf.Min(maxStart, _chatWindowStartIndex + GetEffectiveDisplayWindow());
_isChatViewPinnedToBottom = _chatWindowStartIndex >= maxStart;
RenderChatMessages(_service.GetRoomChatMessages(), true);
SetChatScrollNormalizedPosition(0.15f);
return;
}
_isChatViewPinnedToBottom = true;
}
else if (normalizedPosition.y >= 0.95f && _chatWindowStartIndex > 0)
{
_chatWindowStartIndex = Mathf.Max(0, _chatWindowStartIndex - GetEffectiveDisplayWindow());
_isChatViewPinnedToBottom = false;
RenderChatMessages(_service.GetRoomChatMessages(), true);
SetChatScrollNormalizedPosition(0.85f);
}
else
{
_isChatViewPinnedToBottom = false;
}
}
private static int CompareFeedEntries(RoomFeedEntry left, RoomFeedEntry right)
{
int compare = left.sequence.CompareTo(right.sequence);
if (compare != 0)
{
return compare;
}
compare = left.timestampMs.CompareTo(right.timestampMs);
if (compare != 0)
{
return compare;
}
return left.order.CompareTo(right.order);
}
private long GetOrAssignFeedSequence(string key)
{
if (string.IsNullOrWhiteSpace(key))
{
return _nextFeedSequence++;
}
if (_feedSequences.TryGetValue(key, out long sequence))
{
return sequence;
}
sequence = _nextFeedSequence++;
_feedSequences[key] = sequence;
return sequence;
}
private static long ParseMessageUnixTimestamp(string createdAt)
{
if (string.IsNullOrWhiteSpace(createdAt))
{
return long.MaxValue;
}
if (long.TryParse(createdAt, out long unixValue))
{
return unixValue >= 1_000_000_000_000L ? unixValue : unixValue * 1000L;
}
if (DateTimeOffset.TryParse(createdAt, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out DateTimeOffset parsed))
{
return parsed.ToUnixTimeMilliseconds();
}
return long.MaxValue;
}
private void ClearDisplayedMessages()
{
if (messageParent == null)
{
_renderedChatKeys.Clear();
_renderedChatObjects.Clear();
return;
}
for (int i = messageParent.childCount - 1; i >= 0; i--)
{
Transform child = messageParent.GetChild(i);
child.SetParent(null, false);
child.gameObject.SetActive(false);
Destroy(child.gameObject);
}
_renderedChatKeys.Clear();
_renderedChatObjects.Clear();
}
private Color ResolveMessageBubbleColor(bool isSelf)
{
if (messageTypeColors == null || messageTypeColors.Length == 0)
{
return Color.white;
}
if (isSelf && messageTypeColors.Length > 1)
{
return messageTypeColors[1];
}
return messageTypeColors[0];
}
private string ResolveMessageDisplayName(ArenaRoomChatMessage message, bool isSelf)
{
if (message != null && !string.IsNullOrWhiteSpace(message.display_name))
{
string senderSteamId = GetMessageSenderSteamId(message);
if (GameServer.Client.NetworkManager.IsUsableDisplayName(message.display_name, senderSteamId))
{
return message.display_name;
}
}
string messageSteamId = GetMessageSenderSteamId(message);
if (isSelf && NetworkManager.Instance != null && GameServer.Client.NetworkManager.IsUsableDisplayName(NetworkManager.Instance.SteamDisplayName, messageSteamId))
{
return NetworkManager.Instance.SteamDisplayName;
}
if (_service != null && _service.CurrentRoom != null && _service.CurrentRoom.participants != null && message != null)
{
foreach (ArenaRoomParticipant participant in _service.CurrentRoom.participants)
{
if (participant != null
&& string.Equals(participant.steam_id, messageSteamId, StringComparison.Ordinal)
&& GameServer.Client.NetworkManager.IsUsableDisplayName(participant.display_name, messageSteamId))
{
return participant.display_name;
}
}
}
return GameServer.Client.NetworkManager.ResolveDisplayName(message != null ? message.display_name : string.Empty, messageSteamId, false);
}
private static string ResolveMessageTitle()
{
return string.Empty;
}
private static string GetMessageSenderSteamId(ArenaRoomChatMessage message)
{
if (message == null)
{
return string.Empty;
}
if (!string.IsNullOrWhiteSpace(message.sender_id))
{
return message.sender_id;
}
return message.steam_id ?? string.Empty;
}
private void ScheduleMessageLayoutRefresh(bool scrollToBottom)
{
_messageLayoutRefreshDirty = true;
_scrollChatToBottomAfterLayout |= scrollToBottom;
if (_messageLayoutRefreshCoroutine == null)
{
_messageLayoutRefreshCoroutine = StartCoroutine(DeferredMessageLayoutRefreshCoroutine());
}
}
private IEnumerator DeferredMessageLayoutRefreshCoroutine()
{
while (true)
{
yield return null;
bool shouldRebuild = _messageLayoutRefreshDirty;
bool shouldScrollToBottom = _scrollChatToBottomAfterLayout;
_messageLayoutRefreshDirty = false;
_scrollChatToBottomAfterLayout = false;
if (shouldRebuild)
{
ForceRebuildMessageLayoutImmediate();
if (shouldScrollToBottom && _messageScrollRect != null)
{
Canvas.ForceUpdateCanvases();
_messageScrollRect.verticalNormalizedPosition = 0f;
}
}
if (!_messageLayoutRefreshDirty)
{
break;
}
}
_messageLayoutRefreshCoroutine = null;
}
private void ForceRebuildMessageLayoutImmediate()
{
if (!(messageParent is RectTransform messageParentRect))
{
return;
}
for (int i = 0; i < _pendingMessageLayoutDirtyRoots.Count; i++)
{
RectTransform childRect = _pendingMessageLayoutDirtyRoots[i];
if (childRect != null)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(childRect);
}
}
_pendingMessageLayoutDirtyRoots.Clear();
LayoutRebuilder.ForceRebuildLayoutImmediate(messageParentRect);
if (messageParentRect.parent is RectTransform parentRect)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(parentRect);
}
Canvas.ForceUpdateCanvases();
}
private void RefocusChatInputNextFrame()
{
if (playerMessageInputField == null)
{
return;
}
_refocusChatInputRequested = true;
if (_refocusChatInputCoroutine == null)
{
_refocusChatInputCoroutine = StartCoroutine(RefocusChatInputCoroutine());
}
}
private IEnumerator RefocusChatInputCoroutine()
{
while (true)
{
yield return null;
if (!_refocusChatInputRequested)
{
break;
}
_refocusChatInputRequested = false;
if (playerMessageInputField == null)
{
continue;
}
EventSystem.current?.SetSelectedGameObject(playerMessageInputField.gameObject);
playerMessageInputField.Select();
playerMessageInputField.ActivateInputField();
playerMessageInputField.MoveTextEnd(false);
}
_refocusChatInputCoroutine = null;
}
private void SetChatScrollNormalizedPosition(float value)
{
if (_messageScrollRect == null)
{
return;
}
_suppressChatScrollEvents = true;
_messageScrollRect.verticalNormalizedPosition = Mathf.Clamp01(value);
_suppressChatScrollEvents = false;
}
private void RegisterMessageLayoutDirtyRoot(GameObject instance)
{
if (instance == null)
{
return;
}
RectTransform rect = instance.transform as RectTransform;
if (rect == null)
{
return;
}
for (int i = 0; i < _pendingMessageLayoutDirtyRoots.Count; i++)
{
if (_pendingMessageLayoutDirtyRoots[i] == rect)
{
return;
}
}
_pendingMessageLayoutDirtyRoots.Add(rect);
}
private void OnShowRoomRankingClicked()
{
if (_service == null)
@@ -541,4 +1388,20 @@ public class roomDetails : MonoBehaviour
return difficulty;
}
}
private int GetEffectiveCacheLimit()
{
return Mathf.Max(InitialHistoryLoadLimit, Mathf.Max(1, maxMessageHistory));
}
private int GetEffectiveDisplayWindow()
{
return Mathf.Clamp(messageDisplayWindow, 1, MaxDisplayWindowLimit);
}
private int GetRenderedChatWindowCapacity()
{
return Mathf.Max(GetEffectiveDisplayWindow(), Mathf.Min(GetEffectiveCacheLimit(), GetEffectiveDisplayWindow() * 3));
}
}