lobby tweaking
This commit is contained in:
@@ -64,9 +64,17 @@ namespace MegaKoop.UI
|
||||
private Button btnLeaveLobby;
|
||||
private Button btnBackFromLobby;
|
||||
|
||||
[Header("Player Ready Styling")]
|
||||
[SerializeField] private Color readyBorderColor = new Color(0.2f, 0.82f, 0.35f, 1f);
|
||||
[SerializeField] private Color notReadyBorderColor = new Color(0.85f, 0.25f, 0.25f, 1f);
|
||||
[SerializeField] private float avatarBorderThickness = 12f;
|
||||
|
||||
// Selection
|
||||
private string selectedPlayerSteamId = string.Empty;
|
||||
|
||||
// Cached readiness state per member
|
||||
private readonly Dictionary<string, bool> memberReadyCache = new Dictionary<string, bool>();
|
||||
|
||||
// Steam service
|
||||
private SteamLobbyService steam;
|
||||
|
||||
@@ -364,6 +372,7 @@ namespace MegaKoop.UI
|
||||
private void OnLobbyCreated()
|
||||
{
|
||||
selectedPlayerSteamId = string.Empty;
|
||||
memberReadyCache.Clear();
|
||||
UpdateUIFromSteam();
|
||||
// Auto-open invite overlay for the host
|
||||
if (steam != null && steam.IsInLobby && steam.IsHost)
|
||||
@@ -376,6 +385,7 @@ namespace MegaKoop.UI
|
||||
private void OnLobbyEntered()
|
||||
{
|
||||
selectedPlayerSteamId = string.Empty;
|
||||
memberReadyCache.Clear();
|
||||
UpdateUIFromSteam();
|
||||
// Auto-open invite overlay if we are the host entering our lobby
|
||||
if (steam != null && steam.IsInLobby && steam.IsHost)
|
||||
@@ -388,6 +398,7 @@ namespace MegaKoop.UI
|
||||
private void OnLobbyLeft()
|
||||
{
|
||||
selectedPlayerSteamId = string.Empty;
|
||||
memberReadyCache.Clear();
|
||||
UpdateUIFromSteam();
|
||||
}
|
||||
|
||||
@@ -427,9 +438,24 @@ namespace MegaKoop.UI
|
||||
if (av)
|
||||
{
|
||||
var img = av.GetComponent<Image>();
|
||||
if (img && steam.TryGetAvatarSprite(steamId, out var spr2, true))
|
||||
if (img)
|
||||
{
|
||||
img.sprite = spr2; img.color = Color.white; img.preserveAspect = true;
|
||||
if (steam.TryGetAvatarSprite(steamId, out var spr2, true))
|
||||
{
|
||||
img.sprite = spr2;
|
||||
img.color = Color.white;
|
||||
img.preserveAspect = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
img.sprite = null;
|
||||
img.color = new Color(0.3f, 0.6f, 0.3f, 1f);
|
||||
}
|
||||
|
||||
if (TryGetMemberReadyState(steamId, out var isReady))
|
||||
{
|
||||
ApplyReadyBorder(img, isReady);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -572,12 +598,19 @@ namespace MegaKoop.UI
|
||||
{
|
||||
if (IsHost || !IsInLobby || steam == null) return;
|
||||
var members = GetSteamMembers();
|
||||
CacheMemberReadyStates(members);
|
||||
var localId = steam.LocalSteamIdString;
|
||||
bool current = false;
|
||||
var me = members.FirstOrDefault(m => m.steamId == localId);
|
||||
// When tuple is default, steamId will be null; guard
|
||||
if (me.steamId == localId) current = me.isReady;
|
||||
steam.SetReady(!current);
|
||||
bool newReadyState = !current;
|
||||
steam.SetReady(newReadyState);
|
||||
if (!string.IsNullOrEmpty(localId))
|
||||
{
|
||||
memberReadyCache[localId] = newReadyState;
|
||||
UpdateAvatarUIForSteamId(localId);
|
||||
}
|
||||
UpdateUIFromSteam();
|
||||
}
|
||||
|
||||
@@ -664,7 +697,15 @@ namespace MegaKoop.UI
|
||||
|
||||
private void UpdateVisibility()
|
||||
{
|
||||
if (btnStartGame) btnStartGame.gameObject.SetActive(IsInLobby && IsHost);
|
||||
if (btnStartGame)
|
||||
{
|
||||
bool canHostStart = IsInLobby && IsHost;
|
||||
btnStartGame.gameObject.SetActive(canHostStart);
|
||||
if (btnStartGame.gameObject.activeSelf)
|
||||
{
|
||||
btnStartGame.interactable = AreAllPlayersReady();
|
||||
}
|
||||
}
|
||||
if (btnLeaveLobby) btnLeaveLobby.gameObject.SetActive(IsInLobby);
|
||||
if (btnToggleReady) btnToggleReady.gameObject.SetActive(IsInLobby && !IsHost);
|
||||
if (btnInviteFriends) btnInviteFriends.gameObject.SetActive(IsInLobby && IsHost);
|
||||
@@ -681,6 +722,137 @@ namespace MegaKoop.UI
|
||||
return steam != null ? steam.GetMembers().ToList() : new List<(string, string, bool, bool)>();
|
||||
}
|
||||
|
||||
private void CacheMemberReadyStates(IEnumerable<(string steamId, string name, bool isReady, bool isHost)> members)
|
||||
{
|
||||
memberReadyCache.Clear();
|
||||
if (members == null) return;
|
||||
foreach (var member in members)
|
||||
{
|
||||
if (string.IsNullOrEmpty(member.steamId)) continue;
|
||||
memberReadyCache[member.steamId] = member.isReady;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetMemberReadyState(string steamId, out bool isReady)
|
||||
{
|
||||
isReady = false;
|
||||
if (string.IsNullOrEmpty(steamId)) return false;
|
||||
|
||||
if (memberReadyCache.TryGetValue(steamId, out var cachedReady))
|
||||
{
|
||||
isReady = cachedReady;
|
||||
return true;
|
||||
}
|
||||
|
||||
var members = GetSteamMembers();
|
||||
CacheMemberReadyStates(members);
|
||||
foreach (var member in members)
|
||||
{
|
||||
if (member.steamId == steamId)
|
||||
{
|
||||
isReady = member.isReady;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool AreAllPlayersReady()
|
||||
{
|
||||
if (!IsInLobby) return false;
|
||||
if (memberReadyCache.Count == 0)
|
||||
{
|
||||
CacheMemberReadyStates(GetSteamMembers());
|
||||
}
|
||||
if (memberReadyCache.Count == 0) return false;
|
||||
foreach (var kvp in memberReadyCache)
|
||||
{
|
||||
if (!kvp.Value) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ApplyReadyBorder(Image avatarImage, bool isReady)
|
||||
{
|
||||
if (avatarImage == null) return;
|
||||
|
||||
var legacyOutline = avatarImage.GetComponent<Outline>();
|
||||
if (legacyOutline != null) legacyOutline.enabled = false;
|
||||
|
||||
var borderImage = EnsureAvatarBorderImage(avatarImage);
|
||||
if (borderImage == null) return;
|
||||
|
||||
if (avatarBorderThickness <= 0f)
|
||||
{
|
||||
borderImage.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
borderImage.enabled = true;
|
||||
borderImage.color = isReady ? readyBorderColor : notReadyBorderColor;
|
||||
|
||||
var avatarRect = avatarImage.rectTransform;
|
||||
var borderRect = borderImage.rectTransform;
|
||||
borderRect.anchorMin = avatarRect.anchorMin;
|
||||
borderRect.anchorMax = avatarRect.anchorMax;
|
||||
borderRect.pivot = avatarRect.pivot;
|
||||
borderRect.anchoredPosition = avatarRect.anchoredPosition;
|
||||
borderRect.localPosition = avatarRect.localPosition;
|
||||
borderRect.localRotation = avatarRect.localRotation;
|
||||
borderRect.localScale = avatarRect.localScale;
|
||||
var padding = avatarBorderThickness * 2f;
|
||||
borderRect.sizeDelta = avatarRect.sizeDelta + new Vector2(padding, padding);
|
||||
}
|
||||
|
||||
private Image EnsureAvatarBorderImage(Image avatarImage)
|
||||
{
|
||||
if (avatarImage == null) return null;
|
||||
var parent = avatarImage.transform.parent;
|
||||
if (parent == null) return null;
|
||||
|
||||
const string borderName = "Image_AvatarBorder";
|
||||
Transform borderTransform = null;
|
||||
for (int i = 0; i < parent.childCount; i++)
|
||||
{
|
||||
var child = parent.GetChild(i);
|
||||
if (child != null && child.name == borderName)
|
||||
{
|
||||
borderTransform = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (borderTransform == null)
|
||||
{
|
||||
var borderGO = new GameObject(borderName, typeof(RectTransform), typeof(Image));
|
||||
borderTransform = borderGO.transform;
|
||||
borderTransform.SetParent(parent, false);
|
||||
}
|
||||
|
||||
var borderImage = borderTransform.GetComponent<Image>();
|
||||
if (borderImage == null)
|
||||
{
|
||||
borderImage = borderTransform.gameObject.AddComponent<Image>();
|
||||
}
|
||||
|
||||
borderImage.raycastTarget = false;
|
||||
borderImage.preserveAspect = false;
|
||||
borderImage.type = Image.Type.Simple;
|
||||
|
||||
var layoutElement = borderTransform.GetComponent<LayoutElement>();
|
||||
if (layoutElement == null)
|
||||
{
|
||||
layoutElement = borderTransform.gameObject.AddComponent<LayoutElement>();
|
||||
}
|
||||
layoutElement.ignoreLayout = true;
|
||||
|
||||
var avatarIndex = avatarImage.transform.GetSiblingIndex();
|
||||
borderTransform.SetSiblingIndex(avatarIndex);
|
||||
avatarImage.transform.SetSiblingIndex(borderTransform.GetSiblingIndex() + 1);
|
||||
|
||||
return borderImage;
|
||||
}
|
||||
|
||||
private void RebuildPlayers()
|
||||
{
|
||||
if (contentPlayers == null) return;
|
||||
@@ -694,6 +866,7 @@ namespace MegaKoop.UI
|
||||
foreach (var go in toDestroy) DestroyImmediate(go);
|
||||
|
||||
var members = GetSteamMembers();
|
||||
CacheMemberReadyStates(members);
|
||||
if (textPlayerCount) textPlayerCount.text = $"{members.Count}/{(ddMaxPlayers ? int.Parse(ddMaxPlayers.options[ddMaxPlayers.value].text) : 4)}";
|
||||
|
||||
if (members.Count == 0)
|
||||
@@ -735,6 +908,14 @@ namespace MegaKoop.UI
|
||||
var goLE = go.GetComponent<LayoutElement>(); if (!goLE) goLE = go.AddComponent<LayoutElement>();
|
||||
goLE.minHeight = 100; goLE.flexibleWidth = 1f;
|
||||
|
||||
var horizontalLayout = go.GetComponent<HorizontalLayoutGroup>();
|
||||
if (horizontalLayout)
|
||||
{
|
||||
var paddingValue = Mathf.CeilToInt(avatarBorderThickness);
|
||||
if (horizontalLayout.padding.left < paddingValue) horizontalLayout.padding.left = paddingValue;
|
||||
if (horizontalLayout.padding.right < paddingValue) horizontalLayout.padding.right = paddingValue;
|
||||
}
|
||||
|
||||
// Children
|
||||
// Find avatar inside this item (not globally)
|
||||
Image avatarGO = null;
|
||||
@@ -786,7 +967,20 @@ namespace MegaKoop.UI
|
||||
avRT.anchoredPosition = Vector2.zero;
|
||||
avRT.sizeDelta = new Vector2(96, 96);
|
||||
var avLE = avatarGO.GetComponent<LayoutElement>() ?? avatarGO.gameObject.AddComponent<LayoutElement>();
|
||||
avLE.minWidth = 96; avLE.minHeight = 96;
|
||||
var avatarSize = Mathf.Max(avRT.sizeDelta.x, avRT.sizeDelta.y);
|
||||
var paddedSize = avatarSize + avatarBorderThickness * 2f;
|
||||
avLE.minWidth = paddedSize;
|
||||
avLE.minHeight = paddedSize;
|
||||
avLE.preferredWidth = paddedSize;
|
||||
avLE.preferredHeight = paddedSize;
|
||||
|
||||
if (goLE != null)
|
||||
{
|
||||
goLE.minWidth = Mathf.Max(goLE.minWidth, paddedSize);
|
||||
goLE.preferredWidth = Mathf.Max(goLE.preferredWidth, paddedSize);
|
||||
}
|
||||
|
||||
ApplyReadyBorder(avatarGO, ready);
|
||||
}
|
||||
|
||||
// Selection handler
|
||||
|
||||
Reference in New Issue
Block a user