// Port of C++ DlgArrangeTeam - Arrange Team dialog (invite, kick, leave, list teammates, nearby players, pickup mode, make leader). // Uses Unity UI: content RectTransforms + item prefab with DlgArrangeTeamListItem (text component, optional Button). using System.Collections.Generic; using BrewMonster; using BrewMonster.Managers; using BrewMonster.Network; using BrewMonster.Scripts; using UnityEngine; using UnityEngine.UI; using TMPro; namespace BrewMonster.UI { public class DlgArrangeTeam : AUIDialog { #region UI References [Header("Teammates list (Unity UI)")] [SerializeField] private RectTransform Content_Teammates; [SerializeField] private GameObject TeammateItemPrefab; [Header("Nearby players list (Unity UI)")] [SerializeField] private RectTransform Content_Nearby; [SerializeField] private GameObject NearbyItemPrefab; [Header("Buttons")] [SerializeField] private Button m_pBtn_Invite; [SerializeField] private Button m_pBtn_Kick; [SerializeField] private Button m_pBtn_Leave; [SerializeField] private Button m_pBtn_Disband; [SerializeField] private Button m_pBtn_MakeLeader; [SerializeField] private Button m_pBtn_Refresh; [SerializeField] private Button m_pBtn_Close; [Header("Invite")] [SerializeField] private TMP_InputField m_pInput_Name; [Header("Pickup Mode")] [SerializeField] private Toggle m_pChk_Random; [SerializeField] private Toggle m_pChk_Free; [Header("Profession filter (dropdown: trigger opens panel with multi-select toggles)")] [SerializeField] private TMP_Dropdown m_pDropdown_Prof; #endregion private readonly List m_TeammateItems = new List(); private int m_selectedTeammateId; public override void Awake() { base.Awake(); SetName("Win_ArrangeTeam"); #if UNITY_EDITOR if (m_pBtn_Leave == null) Debug.LogWarning("[DlgArrangeTeam] m_pBtn_Leave is not assigned in Inspector. Assign the Leave button."); if (m_pBtn_Disband == null) Debug.LogWarning("[DlgArrangeTeam] m_pBtn_Disband is not assigned in Inspector. Assign the Disband button."); #endif } private new void Start() { BindButtonListeners(); } public override void OnEnable() { base.OnEnable(); BindButtonListeners(); } public override void OnDisable() { UnbindButtonListeners(); base.OnDisable(); } private void BindButtonListeners() { if (m_pBtn_Invite != null) { m_pBtn_Invite.onClick.RemoveListener(OnInvite); m_pBtn_Invite.onClick.AddListener(OnInvite); } if (m_pBtn_Kick != null) { m_pBtn_Kick.onClick.RemoveListener(OnKick); m_pBtn_Kick.onClick.AddListener(OnKick); } if (m_pBtn_Leave != null) { m_pBtn_Leave.onClick.RemoveListener(OnLeave); m_pBtn_Leave.onClick.AddListener(OnLeave); } if (m_pBtn_Disband != null) { m_pBtn_Disband.onClick.RemoveListener(OnDisband); m_pBtn_Disband.onClick.AddListener(OnDisband); } if (m_pBtn_MakeLeader != null) { m_pBtn_MakeLeader.onClick.RemoveListener(OnMakeLeader); m_pBtn_MakeLeader.onClick.AddListener(OnMakeLeader); } if (m_pBtn_Refresh != null) { m_pBtn_Refresh.onClick.RemoveListener(OnRefresh); m_pBtn_Refresh.onClick.AddListener(OnRefresh); } if (m_pChk_Random != null) m_pChk_Random.onValueChanged.AddListener(OnRandomToggled); if (m_pChk_Free != null) m_pChk_Free.onValueChanged.AddListener(OnFreeToggled); if (m_pBtn_Close != null) m_pBtn_Close.onClick.AddListener(CloseDialogue); BindProfDropdown(); } private void UnbindButtonListeners() { if (m_pBtn_Invite != null) m_pBtn_Invite.onClick.RemoveListener(OnInvite); if (m_pBtn_Kick != null) m_pBtn_Kick.onClick.RemoveListener(OnKick); if (m_pBtn_Leave != null) m_pBtn_Leave.onClick.RemoveListener(OnLeave); if (m_pBtn_Disband != null) m_pBtn_Disband.onClick.RemoveListener(OnDisband); if (m_pBtn_MakeLeader != null) m_pBtn_MakeLeader.onClick.RemoveListener(OnMakeLeader); if (m_pBtn_Refresh != null) m_pBtn_Refresh.onClick.RemoveListener(OnRefresh); if (m_pChk_Random != null) m_pChk_Random.onValueChanged.RemoveListener(OnRandomToggled); if (m_pChk_Free != null) m_pChk_Free.onValueChanged.RemoveListener(OnFreeToggled); if (m_pBtn_Close != null) m_pBtn_Close.onClick.RemoveListener(CloseDialogue); UnbindProfDropdown(); CloseProfFilterPanel(); } private void OnRandomToggled(bool on) { if (on) OnPickupModeChanged(1); } private void OnFreeToggled(bool on) { if (on) OnPickupModeChanged(0); } private void BindProfDropdown() { if (m_pDropdown_Prof == null) return; m_pDropdown_Prof.onValueChanged.RemoveListener(OnProfessionDropdownChanged); m_pDropdown_Prof.onValueChanged.AddListener(OnProfessionDropdownChanged); } private void UnbindProfDropdown() { if (m_pDropdown_Prof == null) return; m_pDropdown_Prof.onValueChanged.RemoveListener(OnProfessionDropdownChanged); } private void OnProfessionDropdownChanged(int _) { UpdateProfDropdownCaption(); UpdateTeam(true); } private void CloseProfFilterPanel() { } private void UpdateProfDropdownCaption() { if (m_pDropdown_Prof == null) return; var set = GetSelectedProfessionSet(); string caption; if (set == null) caption = "All"; else if (set.Count >= (int)Profession.NUM_PROFESSION) caption = "All"; else { var gameRun = EC_Game.GetGameRun(); var names = new List(); foreach (int i in set) { string name = gameRun?.GetProfName(i); names.Add(string.IsNullOrEmpty(name) ? $"Prof {i}" : name); } caption = string.Join(", ", names); } var label = m_pDropdown_Prof.captionText; if (label != null) label.text = caption; } public override void OnShowDialogue() { EnsureProfDropdownHasCaption(); UpdateProfDropdownCaption(); CloseProfFilterPanel(); UpdateTeam(true); } private void EnsureProfDropdownHasCaption() { if (m_pDropdown_Prof == null) return; if (m_pDropdown_Prof.options.Count != 0) return; var opts = new List(); opts.Add("All"); var gameRun = EC_Game.GetGameRun(); for (int i = 0; i < (int)Profession.NUM_PROFESSION; i++) { string name = gameRun?.GetProfName(i); opts.Add(string.IsNullOrEmpty(name) ? $"Prof {i}" : name); } m_pDropdown_Prof.AddOptions(opts); } /// Selected profession filter: null = show all. private HashSet GetSelectedProfessionSet() { if (m_pDropdown_Prof == null) return null; // Dropdown mapping: // 0 = All (no filter) // 1..NUM_PROFESSION = specific profession (value-1) int v = m_pDropdown_Prof.value; if (v <= 0) return null; int prof = v - 1; if (prof < 0 || prof >= (int)Profession.NUM_PROFESSION) return null; return new HashSet { prof }; } /// Refresh teammate list, optional nearby list, and button states. public bool UpdateTeam(bool bUpdateNear = false) { CECHostPlayer host = GetHostPlayer(); if (host == null) return true; var team = host.GetTeam(); bool hasTeam = team != null; int idHost = host.GetCharacterID(); bool isLeader = hasTeam && team.GetLeaderID() == idHost; // Teammates list: clear and rebuild from prefab. Sort by each member's single profession, then by name. ClearList(Content_Teammates, m_TeammateItems); m_selectedTeammateId = 0; if (Content_Teammates != null && TeammateItemPrefab != null && hasTeam) { var members = new List(); int n = team.GetMemberNum(); for (int i = 0; i < n; i++) { var m = team.GetMemberByIndex(i); if (m != null) members.Add(m); } members.Sort((a, b) => { int c = a.GetProfession().CompareTo(b.GetProfession()); if (c != 0) return c; return string.CompareOrdinal(a.GetName() ?? "", b.GetName() ?? ""); }); foreach (var m in members) { string mateName = m.GetName(); int cid = m.GetCharacterID(); if (!string.IsNullOrEmpty(mateName)) Debug.Log($"[DlgArrangeTeam] Teammate: {mateName} (id {cid})"); var item = CreateListItem(Content_Teammates, TeammateItemPrefab, mateName, cid, true, out var listItem); if (listItem != null) { Debug.Log($"[DlgArrangeTeam] Set teammate item detail: level {m.GetLevel()}"); listItem.SetDetail(m.GetProfession()); m_TeammateItems.Add(listItem); } } } // Nearby players list: filter by selected professions (multi-select); sort by each player's single profession, then by name if (bUpdateNear && Content_Nearby != null) { var prefab = NearbyItemPrefab != null ? NearbyItemPrefab : TeammateItemPrefab; ClearList(Content_Nearby, null); var manPlayer = EC_ManMessageMono.Instance?.GetECManPlayer; if (manPlayer != null && prefab != null) { HashSet filterSet = GetSelectedProfessionSet(); var nearby = new List<(string name, int cid, int prof)>(); var otherIds = manPlayer.GetOtherPlayerCharacterIds(); foreach (int cid in otherIds) { if (hasTeam && team.GetMemberByID(cid) != null) continue; var p = manPlayer.GetPlayer(cid, 0); string name = p != null ? (p.GetName() ?? "") : ""; if (string.IsNullOrEmpty(name) && p?.gameObject != null && !string.IsNullOrEmpty(p.gameObject.name)) name = p.gameObject.name; if (string.IsNullOrEmpty(name)) name = "Player_" + cid; int prof = (p as CECPlayer) != null ? (p as CECPlayer).GetProfession() : 0; if (filterSet != null && !filterSet.Contains(prof)) continue; nearby.Add((name, cid, prof)); } nearby.Sort((a, b) => { int c = a.prof.CompareTo(b.prof); if (c != 0) return c; return string.CompareOrdinal(a.name, b.name); }); foreach (var t in nearby) { Debug.Log($"[DlgArrangeTeam] Nearby: {t.name} (id {t.cid})"); CreateListItem(Content_Nearby, prefab, t.name, t.cid, false, out var listItem); listItem.SetDetail(t.prof); } } } // Button states if (m_pBtn_Leave != null) m_pBtn_Leave.interactable = hasTeam; if (m_pBtn_Disband != null) m_pBtn_Disband.interactable = hasTeam && isLeader; if (m_pBtn_Kick != null) m_pBtn_Kick.interactable = hasTeam && isLeader; if (m_pBtn_Invite != null) m_pBtn_Invite.interactable = isLeader; if (m_pBtn_MakeLeader != null) m_pBtn_MakeLeader.interactable = hasTeam && isLeader; if (m_pBtn_Refresh != null) m_pBtn_Refresh.interactable = true; if (m_pChk_Random != null) m_pChk_Random.interactable = hasTeam && isLeader; if (m_pChk_Free != null) m_pChk_Free.interactable = hasTeam && isLeader; if (hasTeam && isLeader) { ushort pick = team.GetPickupFlag(); if (m_pChk_Random != null) m_pChk_Random.SetIsOnWithoutNotify(pick != 0); if (m_pChk_Free != null) m_pChk_Free.SetIsOnWithoutNotify(pick == 0); } return true; } private static void ClearList(RectTransform content, List items) { if (content == null) return; if (items != null) items.Clear(); for (int i = content.childCount - 1; i >= 0; i--) { var child = content.GetChild(i); if (child != null && child.gameObject != null) Destroy(child.gameObject); } } private GameObject CreateListItem(RectTransform content, GameObject prefab, string displayName, int characterId, bool isTeammate, out DlgArrangeTeamListItem listItem) { listItem = null; var go = Instantiate(prefab, content); go.SetActive(true); var comp = go.GetComponent(); if (comp != null) { comp.Set(displayName, characterId); listItem = comp; if (isTeammate) comp.SetClickCallback(OnTeammateItemSelected); else { comp.SetClickCallback(OnNearbyItemSelected); comp.SetInviteCallback(OnNearbyItemInvite); } } return go; } private void OnTeammateItemSelected(DlgArrangeTeamListItem item) { m_selectedTeammateId = item.CharacterId; foreach (var i in m_TeammateItems) i.SetSelected(i == item); } private void OnNearbyItemSelected(DlgArrangeTeamListItem item) { if (m_pInput_Name != null) m_pInput_Name.text = !string.IsNullOrEmpty(item.DisplayName) ? item.DisplayName : item.CharacterId.ToString(); } private void OnNearbyItemInvite(DlgArrangeTeamListItem item) { if (item?.CharacterId > 0) UnityGameSession.c2s_CmdTeamInvite(item.CharacterId); } /// Invite by name/ID in input field. Public so you can assign to Button.onClick in Inspector. public void OnInvite() { CECHostPlayer host = GetHostPlayer(); if (host == null) return; int idPlayer = ResolveInviteTarget(); if (idPlayer <= 0) return; UnityGameSession.c2s_CmdTeamInvite(idPlayer); } private int ResolveInviteTarget() { if (m_pInput_Name == null || string.IsNullOrWhiteSpace(m_pInput_Name.text)) return 0; string raw = m_pInput_Name.text.Trim(); if (int.TryParse(raw, out int id) && id > 0) return id; var manPlayer = EC_ManMessageMono.Instance?.GetECManPlayer; if (manPlayer == null) return 0; var otherIds = manPlayer.GetOtherPlayerCharacterIds(); foreach (int cid in otherIds) { var p = manPlayer.GetPlayer(cid, 0); string name = p?.GetName(); if (!string.IsNullOrEmpty(name) && string.Equals(name, raw, System.StringComparison.OrdinalIgnoreCase)) return cid; } return 0; } /// Kick selected teammate. Public so you can assign to Button.onClick in Inspector. public void OnKick() { int idMember = GetSelectedTeammateId(); if (idMember <= 0) { Debug.Log("[DlgArrangeTeam] Kick: select a teammate first (click a row in the list)."); return; } Debug.Log($"[DlgArrangeTeam] Kick member id={idMember}"); UnityGameSession.c2s_CmdTeamKickMember(idMember); } /// Leave team. Public so you can assign to Button.onClick in Inspector. public void OnLeave() { if (UnityGameSession.Instance == null) { Debug.LogWarning("[DlgArrangeTeam] OnLeave: UnityGameSession.Instance is null. Cannot send leave command."); return; } Debug.Log("[DlgArrangeTeam] Leave team"); UnityGameSession.c2s_CmdTeamLeaveParty(); Show(false); } /// Disband team (leader). Uses C2S TEAM_DISMISS_PARTY, not leave. public void OnDisband() { if (UnityGameSession.Instance == null) { Debug.LogWarning("[DlgArrangeTeam] OnDisband: UnityGameSession.Instance is null. Cannot send disband command."); return; } Debug.Log("[DlgArrangeTeam] Disband team"); UnityGameSession.c2s_CmdTeamDismissParty(); Show(false); } /// Make selected member leader. Public so you can assign to Button.onClick in Inspector. public void OnMakeLeader() { int idMember = GetSelectedTeammateId(); if (idMember <= 0) { Debug.Log("[DlgArrangeTeam] Make leader: select a teammate first (click a row in the list)."); return; } Debug.Log($"[DlgArrangeTeam] Make leader id={idMember}"); UnityGameSession.c2s_CmdTeamChangeLeader(idMember); } /// Refresh teammate and nearby lists. Public so you can assign to Button.onClick in Inspector. public void OnRefresh() { UpdateTeam(true); } private void OnPickupModeChanged(short mode) { UnityGameSession.c2s_CmdTeamSetPickupFlag(mode); } private int GetSelectedTeammateId() { return m_selectedTeammateId; } } }