331 lines
9.4 KiB
C#
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();
|
|
}
|
|
}
|
|
} |