Files
test/Assets/PerfectWorld/Scripts/Managers/EC_Friend.cs
2026-03-18 11:39:26 +07:00

331 lines
9.4 KiB
C#

using System.Collections.Generic;
using System.Text;
using BrewMonster.Network;
using CSNetwork;
using CSNetwork.Protocols.RPCData;
namespace BrewMonster
{
public class CECFriendMan
{
// =========================
// Nested Types
// =========================
public struct Friend
{
public int Id;
public int Profession;
public int GroupId;
public byte Status;
public int Level;
public int AreaId;
public string Name;
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)
{
return (s & 0x01) != 0;
}
// C++: except GAME_ONLINE and GT_INVISIBLE, any other status means GT online
public static bool IsGTOnline(byte s)
{
const byte GAME_ONLINE = 0x01;
const byte GT_INVISIBLE = 0x80;
return (s & unchecked((byte)~GAME_ONLINE) & unchecked((byte)~GT_INVISIBLE)) != 0;
}
}
public class FRIEND_EX
{
public bool NewFriendPlaceHolder;
public int Uid;
public int Rid;
public int Level;
public long LastLoginTime;
public long UpdateTime;
public int ReincarnationCount;
public string Remarks = string.Empty;
}
public class SEND_INFO
{
public int Rid;
public long SendMailTime;
}
public class GROUP
{
public string Name = string.Empty;
public int GroupId;
public uint Color; // nếu dùng Unity thì có thể đổi sang Color
public List<Friend> Friends = new();
}
public class MESSAGE
{
public string SenderName = string.Empty;
public int SenderId;
public string MessageText = string.Empty;
public byte Flag;
}
// =========================
// Fields
// =========================
private List<GROUP> m_Groups = new();
private Dictionary<int, Friend> m_FriendTable = new();
private List<MESSAGE> m_OfflineMsgs = new();
private List<FRIEND_EX> m_FriendEx = new();
private List<SEND_INFO> m_SendInfo = new();
// =========================
// Operations
// =========================
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
{
Id = id,
Profession = profession,
GroupId = groupId,
Status = status,
Name = name
};
m_FriendTable[id] = friend;
var group = GetGroupByID(groupId);
group?.Friends.Add(friend);
if (friend.IsGameOnline())
{
// Todo: Check again
EC_Game.GetGameRun().AddPlayerName(id, name);
}
return friend;
}
public void RemoveFriend(int idFriend)
{
if (!m_FriendTable.TryGetValue(idFriend, out var friend))
return;
m_FriendTable.Remove(idFriend);
var group = GetGroupByID(friend.GroupId);
group?.Friends.Remove(friend);
}
public void RemoveAllFriends()
{
m_FriendTable.Clear();
foreach (var group in m_Groups)
group.Friends.Clear();
}
public void ChangeFriendStatus(int idFriend, byte 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)
{
if (!m_FriendTable.TryGetValue(idFriend, out var friend))
return;
var oldGroup = GetGroupByID(friend.GroupId);
oldGroup?.Friends.Remove(friend);
friend.GroupId = newGroupId;
var newGroup = GetGroupByID(newGroupId);
newGroup?.Friends.Add(friend);
}
public Friend? GetFriendByID(int idFriend)
{
m_FriendTable.TryGetValue(idFriend, out var friend);
return friend;
}
public Friend? GetFriendByName(string name)
{
foreach (var friend in m_FriendTable.Values)
{
if (friend.Name == name)
return friend;
}
return null;
}
public void SetFriendLevel(int idFriend, int level)
{
if (m_FriendTable.TryGetValue(idFriend, out var friend))
friend.Level = level;
}
public void SetFriendArea(int idFriend, int areaId)
{
if (m_FriendTable.TryGetValue(idFriend, out var friend))
friend.AreaId = areaId;
}
// =========================
// Group Operations
// =========================
public bool AddGroup(int idGroup, string name)
{
if (GetGroupByID(idGroup) != null)
return false;
m_Groups.Add(new GROUP
{
GroupId = idGroup,
Name = name
});
return true;
}
public void RemoveGroup(int idGroup)
{
m_Groups.RemoveAll(g => g.GroupId == idGroup);
}
public void ChangeGroupName(int idGroup, string name)
{
var group = GetGroupByID(idGroup);
if (group != null)
group.Name = name;
}
public void SetGroupColor(int idGroup, uint color)
{
var group = GetGroupByID(idGroup);
if (group != null)
group.Color = color;
}
public int GetGroupNum() => m_Groups.Count;
public GROUP GetGroupByIndex(int index)
{
if (index < 0 || index >= m_Groups.Count)
return null;
return m_Groups[index];
}
public GROUP GetGroupByID(int id)
{
return m_Groups.Find(g => g.GroupId == id);
}
// =========================
// Offline Messages
// =========================
public int GetOfflineMsgNum() => m_OfflineMsgs.Count;
public MESSAGE GetOfflineMsg(int index)
{
if (index < 0 || index >= m_OfflineMsgs.Count)
return null;
return m_OfflineMsgs[index];
}
public void RemoveAllOfflineMsgs()
{
m_OfflineMsgs.Clear();
}
}
}