Bind online session browser to canvas, drop IMGUI
- OnlineSessionManager: remove OnGUI/IMGUI state; now a logic-only layer exposing Host/Refresh/Join/Disconnect plus Status/IsBusy/IsConnected/ InSession/Sessions and Changed/SessionsChanged events - OnlineSessionBrowserUI (new): drives the Servers canvas — 4 buttons, session list from Entry Template clones (name + players), row selection, state-driven interactability, status footer - Main scene: attach binder, add status footer line, wire 8 refs; dev bootstrap panel disabled - Online Session Manager.prefab (new) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
286473930a
commit
d27ee16004
6 files changed
+3135
-85
No files matched your search
@@ -0,0 +1,168 @@
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/// <summary>
|
||||
/// uGUI binding for <see cref="OnlineSessionManager"/>. Drives the server-browser canvas - Host / Refresh /
|
||||
/// pick a row / Join / Disconnect plus a status line - and mirrors the manager's state through its
|
||||
/// <see cref="OnlineSessionManager.Changed"/> / <see cref="OnlineSessionManager.SessionsChanged"/> events.
|
||||
/// Replaces the old IMGUI browser. Lives on the browser canvas; the session logic stays on the
|
||||
/// NetworkManager's <see cref="OnlineSessionManager"/>.
|
||||
///
|
||||
/// Selection model: Refresh fills the list with clones of <see cref="entryTemplate"/> (each a clickable row
|
||||
/// showing name + player count). Clicking a row selects it; Join connects to the selected session. While
|
||||
/// connected, only Disconnect is interactable.
|
||||
/// </summary>
|
||||
public class OnlineSessionBrowserUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private OnlineSessionManager manager;
|
||||
|
||||
[Header("Buttons")]
|
||||
[SerializeField] private Button hostButton;
|
||||
[SerializeField] private Button refreshButton;
|
||||
[SerializeField] private Button joinButton;
|
||||
[SerializeField] private Button disconnectButton;
|
||||
|
||||
[Header("List")]
|
||||
[Tooltip("Content RectTransform of the session ScrollRect (rows are added here).")]
|
||||
[SerializeField] private RectTransform listContent;
|
||||
[Tooltip("A row prototype kept disabled; cloned once per session. Children named 'Name' and 'Players' carry the text.")]
|
||||
[SerializeField] private GameObject entryTemplate;
|
||||
|
||||
[Header("Status")]
|
||||
[SerializeField] private TMP_Text statusLabel;
|
||||
|
||||
[Tooltip("Background tint of the selected row.")]
|
||||
[SerializeField] private Color selectedTint = new Color(0.26f, 0.52f, 0.96f, 1f);
|
||||
[Tooltip("Background tint of an unselected row.")]
|
||||
[SerializeField] private Color normalTint = new Color(1f, 1f, 1f, 0.05f);
|
||||
|
||||
private struct Row { public string id; public Image image; public GameObject go; }
|
||||
private readonly List<Row> _rows = new List<Row>();
|
||||
private string _selectedId;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// The template is the prototype, never shown itself - layout ignores it while disabled.
|
||||
if (entryTemplate) entryTemplate.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (hostButton) hostButton.onClick.AddListener(OnHost);
|
||||
if (refreshButton) refreshButton.onClick.AddListener(OnRefresh);
|
||||
if (joinButton) joinButton.onClick.AddListener(OnJoin);
|
||||
if (disconnectButton) disconnectButton.onClick.AddListener(OnDisconnect);
|
||||
|
||||
if (manager)
|
||||
{
|
||||
manager.Changed += OnManagerChanged;
|
||||
manager.SessionsChanged += RebuildList;
|
||||
}
|
||||
|
||||
RebuildList();
|
||||
OnManagerChanged();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (hostButton) hostButton.onClick.RemoveListener(OnHost);
|
||||
if (refreshButton) refreshButton.onClick.RemoveListener(OnRefresh);
|
||||
if (joinButton) joinButton.onClick.RemoveListener(OnJoin);
|
||||
if (disconnectButton) disconnectButton.onClick.RemoveListener(OnDisconnect);
|
||||
|
||||
if (manager)
|
||||
{
|
||||
manager.Changed -= OnManagerChanged;
|
||||
manager.SessionsChanged -= RebuildList;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHost() { if (manager) manager.Host(); }
|
||||
private void OnRefresh() { if (manager) manager.Refresh(); }
|
||||
private void OnJoin() { if (manager && !string.IsNullOrEmpty(_selectedId)) manager.Join(_selectedId); }
|
||||
private void OnDisconnect() { if (manager) manager.Disconnect(); }
|
||||
|
||||
private void OnManagerChanged()
|
||||
{
|
||||
if (!manager) return;
|
||||
if (statusLabel) statusLabel.text = manager.Status;
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void UpdateButtons()
|
||||
{
|
||||
if (!manager) return;
|
||||
bool busy = manager.IsBusy;
|
||||
bool connected = manager.IsConnected;
|
||||
bool hasSelection = !string.IsNullOrEmpty(_selectedId);
|
||||
|
||||
if (hostButton) hostButton.interactable = !busy && !connected;
|
||||
if (refreshButton) refreshButton.interactable = !busy && !connected;
|
||||
if (joinButton) joinButton.interactable = !busy && !connected && hasSelection;
|
||||
if (disconnectButton) disconnectButton.interactable = !busy && connected;
|
||||
}
|
||||
|
||||
private void RebuildList()
|
||||
{
|
||||
for (int i = 0; i < _rows.Count; i++)
|
||||
if (_rows[i].go) Destroy(_rows[i].go);
|
||||
_rows.Clear();
|
||||
|
||||
if (manager && entryTemplate && listContent)
|
||||
{
|
||||
var sessions = manager.Sessions;
|
||||
bool selectionStillPresent = false;
|
||||
|
||||
for (int i = 0; i < sessions.Count; i++)
|
||||
{
|
||||
var s = sessions[i];
|
||||
var go = Instantiate(entryTemplate, listContent);
|
||||
go.SetActive(true);
|
||||
|
||||
var nameText = FindText(go.transform, "Name");
|
||||
if (nameText) nameText.text = s.Name;
|
||||
|
||||
var playersText = FindText(go.transform, "Players");
|
||||
if (playersText)
|
||||
{
|
||||
int taken = Mathf.Max(0, s.MaxPlayers - s.AvailableSlots);
|
||||
playersText.text = $"{taken}/{s.MaxPlayers}";
|
||||
}
|
||||
|
||||
string id = s.Id; // capture per-row for the click closure
|
||||
var button = go.GetComponent<Button>();
|
||||
if (button) button.onClick.AddListener(() => Select(id));
|
||||
|
||||
_rows.Add(new Row { id = id, image = go.GetComponent<Image>(), go = go });
|
||||
if (id == _selectedId) selectionStillPresent = true;
|
||||
}
|
||||
|
||||
if (!selectionStillPresent) _selectedId = null;
|
||||
}
|
||||
|
||||
ApplyTints();
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void Select(string id)
|
||||
{
|
||||
_selectedId = id;
|
||||
ApplyTints();
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void ApplyTints()
|
||||
{
|
||||
for (int i = 0; i < _rows.Count; i++)
|
||||
if (_rows[i].image)
|
||||
_rows[i].image.color = _rows[i].id == _selectedId ? selectedTint : normalTint;
|
||||
}
|
||||
|
||||
private static TMP_Text FindText(Transform root, string childName)
|
||||
{
|
||||
var t = root.Find(childName);
|
||||
return t ? t.GetComponent<TMP_Text>() : null;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user