Add logic update friend UI, friend status
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using BrewMonster.Network;
|
||||
using CSNetwork;
|
||||
using CSNetwork.Protocols.RPCData;
|
||||
|
||||
namespace BrewMonster
|
||||
{
|
||||
@@ -22,16 +25,18 @@ namespace BrewMonster
|
||||
public bool IsGameOnline() => IsGameOnline(Status);
|
||||
public bool IsGTOnline() => IsGTOnline(Status);
|
||||
|
||||
// C++ gnetdef.h: GAME_ONLINE=0x01, GT_INVISIBLE=0x80
|
||||
public static bool IsGameOnline(byte s)
|
||||
{
|
||||
// TODO: implement đúng theo logic C++
|
||||
return (s & 0x01) != 0;
|
||||
}
|
||||
|
||||
// C++: except GAME_ONLINE and GT_INVISIBLE, any other status means GT online
|
||||
public static bool IsGTOnline(byte s)
|
||||
{
|
||||
// TODO: implement đúng theo logic C++
|
||||
return (s & 0x02) != 0;
|
||||
const byte GAME_ONLINE = 0x01;
|
||||
const byte GT_INVISIBLE = 0x80;
|
||||
return (s & unchecked((byte)~GAME_ONLINE) & unchecked((byte)~GT_INVISIBLE)) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +91,68 @@ namespace BrewMonster
|
||||
|
||||
public bool CheckInit() => m_Groups.Count > 0;
|
||||
|
||||
/// <summary>Reset from server getfriends_re. C++ format: status list is pairs (friendIndex, statusByte).</summary>
|
||||
public void ResetFromServer(List<GGroupInfo> groups, List<GFriendInfo> friends, List<byte> status)
|
||||
{
|
||||
m_Groups.Clear();
|
||||
m_FriendTable.Clear();
|
||||
m_OfflineMsgs.Clear();
|
||||
m_FriendEx.Clear();
|
||||
m_SendInfo.Clear();
|
||||
|
||||
if (groups != null)
|
||||
{
|
||||
for (int i = 0; i < groups.Count; i++)
|
||||
{
|
||||
var g = groups[i];
|
||||
int gid = g?.gid ?? 0;
|
||||
string gname = DecodeOctets(g?.name);
|
||||
AddGroup(gid, string.IsNullOrEmpty(gname) ? $"Group{gid}" : gname);
|
||||
}
|
||||
}
|
||||
|
||||
int friendCount = friends?.Count ?? 0;
|
||||
for (int i = 0; i < friendCount; i++)
|
||||
{
|
||||
var f = friends[i];
|
||||
if (f == null) continue;
|
||||
|
||||
int gid = f.gid;
|
||||
if (GetGroupByID(gid) == null)
|
||||
AddGroup(gid, $"Group{gid}");
|
||||
|
||||
string name = DecodeOctets(f.name);
|
||||
AddFriend(f.rid, f.cls, gid, 0, name);
|
||||
}
|
||||
|
||||
// Apply status pairs: [friendIndex0, status0, friendIndex1, status1, ...]
|
||||
if (status != null && (status.Count % 2) == 0 && friends != null)
|
||||
{
|
||||
for (int i = 0; i < status.Count; i += 2)
|
||||
{
|
||||
int friendIndex = status[i];
|
||||
byte st = status[i + 1];
|
||||
if (friendIndex < 0 || friendIndex >= friends.Count) continue;
|
||||
var fi = friends[friendIndex];
|
||||
if (fi == null) continue;
|
||||
ChangeFriendStatus(fi.rid, st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string DecodeOctets(Octets o)
|
||||
{
|
||||
if (o == null || o.Size <= 0) return string.Empty;
|
||||
try
|
||||
{
|
||||
return Encoding.Unicode.GetString(o.ToArray(), 0, o.Size);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public Friend AddFriend(int id, int profession, int groupId, byte status, string name)
|
||||
{
|
||||
var friend = new Friend
|
||||
@@ -130,8 +197,21 @@ namespace BrewMonster
|
||||
|
||||
public void ChangeFriendStatus(int idFriend, byte status)
|
||||
{
|
||||
if (m_FriendTable.TryGetValue(idFriend, out var friend))
|
||||
friend.Status = status;
|
||||
if (!m_FriendTable.TryGetValue(idFriend, out var friend))
|
||||
return;
|
||||
|
||||
friend.Status = status;
|
||||
m_FriendTable[idFriend] = friend;
|
||||
|
||||
var group = GetGroupByID(friend.GroupId);
|
||||
if (group == null) return;
|
||||
|
||||
for (int i = 0; i < group.Friends.Count; i++)
|
||||
{
|
||||
if (group.Friends[i].Id != idFriend) continue;
|
||||
group.Friends[i] = friend;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeFriendGroup(int idFriend, int newGroupId)
|
||||
@@ -216,7 +296,7 @@ namespace BrewMonster
|
||||
|
||||
public int GetGroupNum() => m_Groups.Count;
|
||||
|
||||
public GROUP? GetGroupByIndex(int index)
|
||||
public GROUP GetGroupByIndex(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_Groups.Count)
|
||||
return null;
|
||||
@@ -224,7 +304,7 @@ namespace BrewMonster
|
||||
return m_Groups[index];
|
||||
}
|
||||
|
||||
public GROUP? GetGroupByID(int id)
|
||||
public GROUP GetGroupByID(int id)
|
||||
{
|
||||
return m_Groups.Find(g => g.GroupId == id);
|
||||
}
|
||||
@@ -235,7 +315,7 @@ namespace BrewMonster
|
||||
|
||||
public int GetOfflineMsgNum() => m_OfflineMsgs.Count;
|
||||
|
||||
public MESSAGE? GetOfflineMsg(int index)
|
||||
public MESSAGE GetOfflineMsg(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_OfflineMsgs.Count)
|
||||
return null;
|
||||
|
||||
@@ -66,6 +66,15 @@ namespace CSNetwork
|
||||
/// <summary>Raised when server sends PROTOCOL_ADDFRIEND_RE(203). Args: retcode (0=success), message.</summary>
|
||||
public event Action<byte, string> AddFriendResultReceived;
|
||||
|
||||
/// <summary>Raised when server sends PROTOCOL_GETFRIENDS_RE(207).</summary>
|
||||
public event Action<getfriends_re> FriendListReceived;
|
||||
|
||||
/// <summary>Raised when server sends PROTOCOL_FRIENDSTATUS(214). Args: roleid, status.</summary>
|
||||
public event Action<int, byte> FriendStatusChanged;
|
||||
|
||||
/// <summary>Raised when server sends PROTOCOL_FRIENDEXTLIST.</summary>
|
||||
public event Action<friendextlist> FriendExtListReceived;
|
||||
|
||||
/// <summary>Raised when the underlying network disconnects.</summary>
|
||||
public event Action Disconnected;
|
||||
|
||||
@@ -612,6 +621,18 @@ namespace CSNetwork
|
||||
OnAddFriendRe((addfriend_re)protocol);
|
||||
break;
|
||||
|
||||
case ProtocolType.PROTOCOL_GETFRIENDS_RE:
|
||||
OnGetFriendsRe((getfriends_re)protocol);
|
||||
break;
|
||||
|
||||
case ProtocolType.PROTOCOL_FRIENDEXTLIST:
|
||||
OnFriendExtList((friendextlist)protocol);
|
||||
break;
|
||||
|
||||
case ProtocolType.PROTOCOL_FRIENDSTATUS:
|
||||
OnFriendStatus((friendstatus)protocol);
|
||||
break;
|
||||
|
||||
default:
|
||||
_logger.Log(LogType.Warning, $"Received unhandled protocol type: {protocol.GetPType()}");
|
||||
break;
|
||||
@@ -635,6 +656,47 @@ namespace CSNetwork
|
||||
PostToUnityContext(() => FriendRequestReceived?.Invoke(p.Xid, p.Srcroleid, askerName));
|
||||
}
|
||||
|
||||
private void OnGetFriendsRe(getfriends_re p)
|
||||
{
|
||||
PostToUnityContext(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var host = EC_Game.GetGameRun()?.GetHostPlayer();
|
||||
host?.GetFriendMan()?.ResetFromServer(p.Groups, p.Friends, p.Status);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Log(LogType.Error, $"OnGetFriendsRe failed: {ex.Message}");
|
||||
_logger.LogException(ex);
|
||||
}
|
||||
FriendListReceived?.Invoke(p);
|
||||
});
|
||||
}
|
||||
|
||||
private void OnFriendExtList(friendextlist p)
|
||||
{
|
||||
PostToUnityContext(() => FriendExtListReceived?.Invoke(p));
|
||||
}
|
||||
|
||||
private void OnFriendStatus(friendstatus p)
|
||||
{
|
||||
PostToUnityContext(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var host = EC_Game.GetGameRun()?.GetHostPlayer();
|
||||
host?.GetFriendMan()?.ChangeFriendStatus(p.Roleid, p.Status);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Log(LogType.Error, $"OnFriendStatus failed: {ex.Message}");
|
||||
_logger.LogException(ex);
|
||||
}
|
||||
FriendStatusChanged?.Invoke(p.Roleid, p.Status);
|
||||
});
|
||||
}
|
||||
|
||||
private void OnAddFriendRe(addfriend_re p)
|
||||
{
|
||||
string friendName = "";
|
||||
@@ -2468,6 +2530,17 @@ namespace CSNetwork
|
||||
SendProtocol(p);
|
||||
}
|
||||
|
||||
/// <summary>Send PROTOCOL_DELFRIEND(212). Delete a friend by role id.</summary>
|
||||
public void Friend_Del(int friendId)
|
||||
{
|
||||
var p = new delfriend();
|
||||
p.Roleid = m_iCharID;
|
||||
p.Friendid = friendId;
|
||||
p.Localsid = (int)_localsid;
|
||||
SendProtocol(p);
|
||||
Friend_GetList();
|
||||
}
|
||||
|
||||
public void c2s_SendCmdTeamKickMember(int idMember)
|
||||
{
|
||||
var g = new gamedatasend();
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace BrewMonster
|
||||
{
|
||||
public partial class CECHostPlayer
|
||||
{
|
||||
private readonly CECFriendMan _friendMan = new CECFriendMan();
|
||||
public CECFriendMan GetFriendMan() => _friendMan;
|
||||
|
||||
// 服务器控制的额外操作限制
|
||||
public enum PLAYER_LIMIT
|
||||
@@ -369,7 +371,7 @@ namespace BrewMonster
|
||||
CECNPC pNPC = EC_Game.GetGameRun().GetWorld().GetNPCMan().GetNPC(m_pPetCorral.GetActivePetNPCID());
|
||||
if (pNPC && pNPC.GetMasterID() == GetCharacterID())
|
||||
{
|
||||
//pNPC.BubbleText(CECNPC::BUBBLE_HPWARN, 0);
|
||||
//pNPC.BubbleText(CECNPC::BUBBLE_HPWARN, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using BrewMonster.Network;
|
||||
using BrewMonster.Scripts.Pet;
|
||||
using BrewMonster.UI;
|
||||
using CSNetwork;
|
||||
using CSNetwork.Protocols;
|
||||
using CSNetwork.GPDataType;
|
||||
using ModelRenderer.Scripts.GameData;
|
||||
using System;
|
||||
@@ -14,6 +16,13 @@ namespace BrewMonster
|
||||
{
|
||||
public class CDlgFriendList : AUIDialog
|
||||
{
|
||||
private enum FriendTab
|
||||
{
|
||||
Friend = 0,
|
||||
Blacklist = 1,
|
||||
Archrival = 2
|
||||
}
|
||||
|
||||
[Header("Buttons")]
|
||||
[SerializeField] private Button m_helpBtn;
|
||||
[SerializeField] private Button m_friendBtn;
|
||||
@@ -41,6 +50,14 @@ namespace BrewMonster
|
||||
[SerializeField] private GameObject m_contextMenu;
|
||||
[SerializeField] private GameObject m_inputName;
|
||||
|
||||
private CSNetwork.GameSession _session;
|
||||
private FriendTab _currentTab = FriendTab.Friend;
|
||||
private int _selectedFriendId;
|
||||
private Image _selectedRowImage;
|
||||
private Color _selectedRowOriginalColor;
|
||||
private TMP_InputField _addNameInput;
|
||||
private static readonly Color SelectedRowColor = new Color32(255, 255, 255, 60);
|
||||
|
||||
public void OnInitDialog()
|
||||
{
|
||||
if (!IsShow())
|
||||
@@ -48,6 +65,18 @@ namespace BrewMonster
|
||||
Show(true);
|
||||
}
|
||||
|
||||
_session = UnityGameSession.Instance?.GameSession;
|
||||
if (_session != null)
|
||||
{
|
||||
_session.FriendListReceived -= OnFriendListReceived;
|
||||
_session.FriendListReceived += OnFriendListReceived;
|
||||
_session.FriendStatusChanged -= OnFriendStatusChanged;
|
||||
_session.FriendStatusChanged += OnFriendStatusChanged;
|
||||
_session.Friend_GetList();
|
||||
}
|
||||
|
||||
RefreshListFromHost();
|
||||
|
||||
if (m_helpBtn != null)
|
||||
{
|
||||
m_helpBtn.onClick.RemoveAllListeners();
|
||||
@@ -62,17 +91,18 @@ namespace BrewMonster
|
||||
m_friendBtn.onClick.RemoveAllListeners();
|
||||
m_friendBtn.onClick.AddListener(() =>
|
||||
{
|
||||
// TODO: Show friend list
|
||||
_currentTab = FriendTab.Friend;
|
||||
RefreshListFromHost();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (m_blacklistBtn != null)
|
||||
{
|
||||
m_blacklistBtn.onClick.RemoveAllListeners();
|
||||
m_blacklistBtn.onClick.AddListener(() =>
|
||||
{
|
||||
// TODO: Show blacklist
|
||||
_currentTab = FriendTab.Blacklist;
|
||||
RefreshListFromHost();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -81,7 +111,8 @@ namespace BrewMonster
|
||||
m_archrivalBtn.onClick.RemoveAllListeners();
|
||||
m_archrivalBtn.onClick.AddListener(() =>
|
||||
{
|
||||
// TODO: Show archrival list
|
||||
_currentTab = FriendTab.Archrival;
|
||||
RefreshListFromHost();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,7 +121,9 @@ namespace BrewMonster
|
||||
m_addBtn.onClick.RemoveAllListeners();
|
||||
m_addBtn.onClick.AddListener(() =>
|
||||
{
|
||||
m_inputName.SetActive(true);
|
||||
EnsureAddNameInput();
|
||||
if (m_inputName != null)
|
||||
m_inputName.SetActive(true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -99,7 +132,9 @@ namespace BrewMonster
|
||||
m_deleteBtn.onClick.RemoveAllListeners();
|
||||
m_deleteBtn.onClick.AddListener(() =>
|
||||
{
|
||||
// TODO: Delete selected friend
|
||||
if (_session == null) return;
|
||||
if (_selectedFriendId <= 0) return;
|
||||
_session.Friend_Del(_selectedFriendId);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -117,7 +152,15 @@ namespace BrewMonster
|
||||
m_confirmBtn.onClick.RemoveAllListeners();
|
||||
m_confirmBtn.onClick.AddListener(() =>
|
||||
{
|
||||
// TODO: Confirm adding friend with name from input field
|
||||
if (_session == null) return;
|
||||
EnsureAddNameInput();
|
||||
var n = _addNameInput != null ? _addNameInput.text : string.Empty;
|
||||
n = (n ?? string.Empty).Trim();
|
||||
if (n.Length <= 0) return;
|
||||
|
||||
_session.Friend_Add(0, n);
|
||||
if (m_inputName != null)
|
||||
m_inputName.SetActive(false);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -184,5 +227,113 @@ namespace BrewMonster
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
if (_session != null)
|
||||
{
|
||||
_session.FriendListReceived -= OnFriendListReceived;
|
||||
_session.FriendStatusChanged -= OnFriendStatusChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFriendListReceived(getfriends_re _)
|
||||
{
|
||||
RefreshListFromHost();
|
||||
}
|
||||
|
||||
private void OnFriendStatusChanged(int _, byte __)
|
||||
{
|
||||
RefreshListFromHost();
|
||||
}
|
||||
|
||||
private void RefreshListFromHost()
|
||||
{
|
||||
if (m_friendContainer == null || m_friendDetailPrefabs == null)
|
||||
return;
|
||||
|
||||
ClearSelection();
|
||||
|
||||
for (int i = m_friendContainer.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
var child = m_friendContainer.GetChild(i);
|
||||
if (child != null)
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
if (_currentTab != FriendTab.Friend)
|
||||
return;
|
||||
|
||||
var host = GetHostPlayer();
|
||||
var man = host?.GetFriendMan();
|
||||
if (man == null || !man.CheckInit())
|
||||
return;
|
||||
|
||||
int groupNum = man.GetGroupNum();
|
||||
for (int gi = 0; gi < groupNum; gi++)
|
||||
{
|
||||
var g = man.GetGroupByIndex(gi);
|
||||
if (g == null) continue;
|
||||
|
||||
foreach (var f in g.Friends)
|
||||
{
|
||||
var go = Instantiate(m_friendDetailPrefabs, m_friendContainer);
|
||||
WireRowSelection(go, f.Id);
|
||||
var nameTxt = go.transform.Find("text_name")?.GetComponent<TextMeshProUGUI>();
|
||||
var stateTxt = go.transform.Find("text_state")?.GetComponent<TextMeshProUGUI>();
|
||||
|
||||
if (nameTxt != null) nameTxt.text = string.IsNullOrEmpty(f.Name) ? f.Id.ToString() : f.Name;
|
||||
if (stateTxt != null)
|
||||
{
|
||||
bool online = f.IsGameOnline();
|
||||
stateTxt.text = online ? "Online" : "Offline";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WireRowSelection(GameObject rowGo, int friendId)
|
||||
{
|
||||
if (rowGo == null) return;
|
||||
|
||||
var btn = rowGo.GetComponent<Button>();
|
||||
var img = rowGo.GetComponent<Image>();
|
||||
if (btn == null) return;
|
||||
|
||||
btn.onClick.RemoveAllListeners();
|
||||
btn.onClick.AddListener(() => SelectRow(friendId, img));
|
||||
}
|
||||
|
||||
private void SelectRow(int friendId, Image rowImage)
|
||||
{
|
||||
if (_selectedRowImage != null)
|
||||
_selectedRowImage.color = _selectedRowOriginalColor;
|
||||
|
||||
_selectedFriendId = friendId;
|
||||
_selectedRowImage = rowImage;
|
||||
if (_selectedRowImage != null)
|
||||
{
|
||||
_selectedRowOriginalColor = _selectedRowImage.color;
|
||||
_selectedRowImage.color = SelectedRowColor;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearSelection()
|
||||
{
|
||||
if (_selectedRowImage != null)
|
||||
_selectedRowImage.color = _selectedRowOriginalColor;
|
||||
|
||||
_selectedFriendId = 0;
|
||||
_selectedRowImage = null;
|
||||
_selectedRowOriginalColor = default;
|
||||
}
|
||||
|
||||
private void EnsureAddNameInput()
|
||||
{
|
||||
if (_addNameInput != null) return;
|
||||
if (m_inputName == null) return;
|
||||
_addNameInput = m_inputName.GetComponentInChildren<TMP_InputField>(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@ namespace BrewMonster
|
||||
{
|
||||
public partial class CECHostPlayer
|
||||
{
|
||||
private CECFriendMan _pFriendMan;
|
||||
/*private CECFriendMan _pFriendMan;
|
||||
public CECFriendMan GetFriendMan() { return _pFriendMan; }
|
||||
public void SetFriendMan(CECFriendMan pFriendMan) { _pFriendMan = pFriendMan; }
|
||||
|
||||
*/
|
||||
|
||||
public bool IsOmitBlocking(int roleid)
|
||||
{
|
||||
CECFactionMan pFacMan = EC_Game.GetFactionMan();
|
||||
@@ -31,4 +32,4 @@ namespace BrewMonster
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user