Files

437 lines
18 KiB
C#

// 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<DlgArrangeTeamListItem> m_TeammateItems = new List<DlgArrangeTeamListItem>();
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<string>();
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<string>();
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);
}
/// <summary>Selected profession filter: null = show all.</summary>
private HashSet<int> 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<int> { prof };
}
/// <summary>Refresh teammate list, optional nearby list, and button states.</summary>
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<CECTeamMember>();
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<int> 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<DlgArrangeTeamListItem> 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<DlgArrangeTeamListItem>();
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);
}
/// <summary>Invite by name/ID in input field. Public so you can assign to Button.onClick in Inspector.</summary>
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;
}
/// <summary>Kick selected teammate. Public so you can assign to Button.onClick in Inspector.</summary>
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);
}
/// <summary>Leave team. Public so you can assign to Button.onClick in Inspector.</summary>
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);
}
/// <summary>Disband team (leader). Uses C2S TEAM_DISMISS_PARTY, not leave.</summary>
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);
}
/// <summary>Make selected member leader. Public so you can assign to Button.onClick in Inspector.</summary>
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);
}
/// <summary>Refresh teammate and nearby lists. Public so you can assign to Button.onClick in Inspector.</summary>
public void OnRefresh()
{
UpdateTeam(true);
}
private void OnPickupModeChanged(short mode)
{
UnityGameSession.c2s_CmdTeamSetPickupFlag(mode);
}
private int GetSelectedTeammateId()
{
return m_selectedTeammateId;
}
}
}