Skip to content

Commit

Permalink
Merge pull request #120 from ethanmoffat/whoisonline
Browse files Browse the repository at this point in the history
Implement online players panel
  • Loading branch information
ethanmoffat committed Mar 19, 2022
2 parents 0d234fe + 146ef78 commit 0010791
Show file tree
Hide file tree
Showing 17 changed files with 424 additions and 306 deletions.
13 changes: 13 additions & 0 deletions EOLib/Domain/Online/OnlineIcon.cs
@@ -0,0 +1,13 @@
namespace EOLib.Domain.Online
{
public enum OnlineIcon
{
Normal = 0,
GM = 4,
HGM = 5,
Party = 6,
GMParty = 9,
HGMParty = 10,
SLNBot = 20
}
}
20 changes: 20 additions & 0 deletions EOLib/Domain/Online/OnlineListData.cs
@@ -0,0 +1,20 @@
using EOLib.Net.Translators;
using System.Collections.Generic;

namespace EOLib.Domain.Online
{
public class OnlineListData : IOnlineListData
{
public IReadOnlyList<OnlinePlayerInfo> OnlineList { get; }

public OnlineListData(IReadOnlyList<OnlinePlayerInfo> onlineList)
{
OnlineList = onlineList;
}
}

public interface IOnlineListData : ITranslatedData
{
IReadOnlyList<OnlinePlayerInfo> OnlineList { get; }
}
}
36 changes: 36 additions & 0 deletions EOLib/Domain/Online/OnlinePlayerActions.cs
@@ -0,0 +1,36 @@
using AutomaticTypeMapper;
using EOLib.Net;
using EOLib.Net.Communication;
using EOLib.Net.Translators;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace EOLib.Domain.Online
{
[AutoMappedType]
public class OnlinePlayerActions : IOnlinePlayerActions
{
private readonly IPacketSendService _packetSendService;
private readonly IPacketTranslator<IOnlineListData> _onlineListPacketTranslator;

public OnlinePlayerActions(IPacketSendService packetSendService,
IPacketTranslator<IOnlineListData> onlineListPacketTranslator)
{
_packetSendService = packetSendService;
_onlineListPacketTranslator = onlineListPacketTranslator;
}

public async Task<IReadOnlyList<OnlinePlayerInfo>> GetOnlinePlayersAsync(bool fullList)
{
var packet = new PacketBuilder(PacketFamily.Players, fullList ? PacketAction.Request : PacketAction.List).Build();
var response = await _packetSendService.SendEncodedPacketAndWaitAsync(packet);

return _onlineListPacketTranslator.TranslatePacket(response).OnlineList;
}
}

public interface IOnlinePlayerActions
{
Task<IReadOnlyList<OnlinePlayerInfo>> GetOnlinePlayersAsync(bool fullList);
}
}
29 changes: 29 additions & 0 deletions EOLib/Domain/Online/OnlinePlayerInfo.cs
@@ -0,0 +1,29 @@
namespace EOLib.Domain.Online
{
public class OnlinePlayerInfo
{
public string Name { get; }

public string Title { get; }

public string Guild { get; }

public string Class { get; }

public OnlineIcon Icon { get; }

public OnlinePlayerInfo(string name)
: this(name, string.Empty, string.Empty, string.Empty, OnlineIcon.Normal)
{
}

public OnlinePlayerInfo(string name, string title, string guild, string @class, OnlineIcon icon)
{
Name = name;
Title = title;
Guild = guild;
Class = @class;
Icon = icon;
}
}
}
13 changes: 13 additions & 0 deletions EOLib/Extensions/ChatIconExtensions.cs
@@ -0,0 +1,13 @@
using EOLib.Domain.Chat;
using Optional;

namespace EOLib.Extensions
{
public static class ChatIconExtensions
{
public static Option<(int X, int Y, int Width, int Height)> GetChatIconRectangleBounds(this ChatIcon icon)
{
return icon == ChatIcon.None ? Option.None<(int, int, int, int)>() : Option.Some((0, (int)icon * 13, 13, 13));
}
}
}
24 changes: 24 additions & 0 deletions EOLib/Extensions/OnlineIconExtensions.cs
@@ -0,0 +1,24 @@
using EOLib.Domain.Chat;
using EOLib.Domain.Online;
using System;

namespace EOLib.Extensions
{
public static class OnlineIconExtensions
{
public static ChatIcon ToChatIcon(this OnlineIcon icon)
{
switch (icon)
{
case OnlineIcon.Normal: return ChatIcon.Player;
case OnlineIcon.GM: return ChatIcon.GM;
case OnlineIcon.HGM: return ChatIcon.HGM;
case OnlineIcon.Party: return ChatIcon.PlayerParty;
case OnlineIcon.GMParty: return ChatIcon.GMParty;
case OnlineIcon.HGMParty: return ChatIcon.HGMParty;
case OnlineIcon.SLNBot: return ChatIcon.PlayerPartyDark;
default: throw new ArgumentOutOfRangeException(nameof(icon), "Invalid Icon type specified.");
}
}
}
}
108 changes: 2 additions & 106 deletions EOLib/Net/API/Init.cs
@@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using EOLib.Net.Handlers;
using System;
using System.IO;
using System.Threading;
using EOLib.Net.Handlers;

namespace EOLib.Net.API
{
Expand Down Expand Up @@ -33,39 +32,12 @@ public enum PaperdollIconType
SLNBot = 20
}

public class OnlineEntry
{
private readonly string m_name, m_title, m_guild;
private readonly int m_class;
private readonly PaperdollIconType m_iconType;

public string Name => m_name;

public string Title => m_title;

public string Guild => m_guild;

public int ClassID => m_class;

public PaperdollIconType Icon => m_iconType;

public OnlineEntry(string name, string title, string guild, int clss, PaperdollIconType icon)
{
m_name = name;
m_title = title;
m_guild = guild;
m_class = clss;
m_iconType = icon;
}
}

public partial class PacketAPI
{
private AutoResetEvent m_init_responseEvent;

//shared between API calls and response handler
private int m_init_requestedMap;
private List<OnlineEntry> m_init_onlinePlayerList;

public event Action OnMapMutation;

Expand All @@ -74,7 +46,6 @@ private void _createInitMembers()
m_init_responseEvent = new AutoResetEvent(false);

m_init_requestedMap = 0;
m_init_onlinePlayerList = null;

m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Init, PacketAction.Init), _handleInitInit, false);
}
Expand All @@ -88,46 +59,11 @@ private void _disposeInitMembers()
}
}

/// <summary>
/// Performas a synchronous request for the list of online players
/// </summary>
/// <param name="includeFullInfo">True if requesting the full information including Name, Title, Class, Guild, and Icon. False if requesting names only</param>
/// <param name="list">The list of players represented by OnlineEntry objects</param>
/// <returns>True if operation was successful, false otherwise.</returns>
public bool RequestOnlinePlayers(bool includeFullInfo, out List<OnlineEntry> list)
{
list = null;
if (!m_client.ConnectedAndInitialized || !Initialized)
return false;

//wait for file if it is in process
if (m_client.ExpectingFile && !m_init_responseEvent.WaitOne(Constants.ResponseFileTimeout))
return false;

m_client.ExpectingPlayerList = true;
OldPacket pkt = new OldPacket(PacketFamily.Players, includeFullInfo ? PacketAction.Request : PacketAction.List);
if (!m_client.SendPacket(pkt))
return false;

if (!m_init_responseEvent.WaitOne(Constants.ResponseTimeout))
return false;

list = m_init_onlinePlayerList;

return true;
}

private void _handleInitInit(OldPacket pkt)
{
InitReply response = (InitReply)pkt.GetByte();
switch (response)
{
case InitReply.INIT_FRIEND_LIST_PLAYERS:
case InitReply.INIT_PLAYERS:
if (!m_client.ExpectingPlayerList)
break;
_handlePlayerList(pkt, response == InitReply.INIT_FRIEND_LIST_PLAYERS);
break;
case InitReply.INIT_MAP_MUTATION:
{
string localDir = response == InitReply.INIT_FILE_MAP || response == InitReply.INIT_MAP_MUTATION ? "maps" : "pub";
Expand Down Expand Up @@ -167,47 +103,7 @@ private void _handleInitInit(OldPacket pkt)
}

m_client.ExpectingFile = false;
m_client.ExpectingPlayerList = false;
m_init_responseEvent.Set(); //packet was handled
}

private void _handlePlayerList(OldPacket pkt, bool isFriendList)
{
short numTotal = pkt.GetShort();
if (pkt.GetByte() != 255)
return;

m_init_onlinePlayerList = new List<OnlineEntry>();
for (int i = 0; i < numTotal; ++i)
{
string name = pkt.GetBreakString();

if (!isFriendList)
{
string title = pkt.GetBreakString();
if (string.IsNullOrWhiteSpace(title))
title = "-";
if (pkt.GetChar() != 0)
return;

PaperdollIconType iconType = (PaperdollIconType)pkt.GetChar();

int clsId = pkt.GetChar();

string guild = pkt.GetBreakString();
if (string.IsNullOrWhiteSpace(guild))
guild = "-";

name = char.ToUpper(name[0]) + name.Substring(1);
title = char.ToUpper(title[0]) + title.Substring(1);

m_init_onlinePlayerList.Add(new OnlineEntry(name, title, guild, clsId, iconType));
}
else
{
m_init_onlinePlayerList.Add(new OnlineEntry(name, "", "", 0, PaperdollIconType.Normal));
}
}
}
}
}
4 changes: 0 additions & 4 deletions EOLib/Net/EOClient.cs
Expand Up @@ -114,10 +114,6 @@ public class EOClient : ClientBase
/// Set to 'true' when a file is requested. Changes handling for received data
/// </summary>
internal bool ExpectingFile { get; set; }
/// <summary>
/// Set to 'true' when online player list is requested. Changes handling for received data
/// </summary>
internal bool ExpectingPlayerList { get; set; }

public EOClient(IPacketProcessActions packetProcessActions)
{
Expand Down
70 changes: 70 additions & 0 deletions EOLib/Net/Translators/OnlineListPacketTranslator.cs
@@ -0,0 +1,70 @@
using AutomaticTypeMapper;
using EOLib.Domain.Online;
using EOLib.Domain.Protocol;
using EOLib.IO.Repositories;
using System.Collections.Generic;

namespace EOLib.Net.Translators
{
[AutoMappedType]
public class OnlineListPacketTranslator : IPacketTranslator<IOnlineListData>
{
private readonly IECFFileProvider _classFileProvider;

public OnlineListPacketTranslator(IECFFileProvider classFileProvider)
{
_classFileProvider = classFileProvider;
}

public IOnlineListData TranslatePacket(IPacket packet)
{
var reply = (InitReply)packet.ReadChar();

if (reply != InitReply.AllPlayersList && reply != InitReply.FriendPlayersList)
throw new MalformedPacketException($"Expected online list or friend list init data, but was {reply}", packet);

short numTotal = packet.ReadShort();
if (packet.ReadByte() != 255)
throw new MalformedPacketException("Expected break byte after number of entries", packet);

var retList = new List<OnlinePlayerInfo>(numTotal);
for (int i = 0; i < numTotal; ++i)
{
string name = packet.ReadBreakString();

if (reply == InitReply.AllPlayersList)
{
var title = packet.ReadBreakString();
if (packet.ReadChar() != 0)
throw new MalformedPacketException("Expected 0 char after online entry title", packet);

var iconType = (OnlineIcon)packet.ReadChar();
int clsId = packet.ReadChar();
var guild = packet.ReadBreakString();

name = char.ToUpper(name[0]) + name.Substring(1);

if (string.IsNullOrWhiteSpace(title))
title = "-";
else
title = char.ToUpper(title[0]) + title.Substring(1);

var className = _classFileProvider.ECFFile.Length <= clsId
? _classFileProvider.ECFFile[clsId].Name
: "-";

if (string.IsNullOrWhiteSpace(guild))
guild = "-";

retList.Add(new OnlinePlayerInfo(name, title, guild, className, iconType));
}
else
{
retList.Add(new OnlinePlayerInfo(name));
}
}

return new OnlineListData(retList);
}
}
}
6 changes: 3 additions & 3 deletions EndlessClient/Dialogs/FriendIgnoreListDialog.cs
Expand Up @@ -100,9 +100,9 @@ public static void Show(PacketAPI apiHandle, bool isIgnoreList)

Instance = dlg;

List<OnlineEntry> onlineList;
apiHandle.RequestOnlinePlayers(false, out onlineList);
Instance.SetActiveItemList(onlineList.Select(_oe => _oe.Name).ToList());
//List<OnlineEntry> onlineList;
//apiHandle.RequestOnlinePlayers(false, out onlineList);
//Instance.SetActiveItemList(onlineList.Select(_oe => _oe.Name).ToList());

EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, isIgnoreList ? EOResourceID.STATUS_LABEL_IGNORE_LIST : EOResourceID.STATUS_LABEL_FRIEND_LIST,
OldWorld.GetString(EOResourceID.STATUS_LABEL_USE_RIGHT_MOUSE_CLICK_DELETE));
Expand Down

0 comments on commit 0010791

Please sign in to comment.