Skip to content

Commit

Permalink
Update EOBot to work with new client architecture. Add TrainerBot.
Browse files Browse the repository at this point in the history
TrainerBot that attacks anything in front of it, picks up items, and heals if needed. Bot also walks to prevent the max attacks counter from being reached.
  • Loading branch information
ethanmoffat committed May 9, 2021
1 parent e83711c commit 7ded0ec
Show file tree
Hide file tree
Showing 15 changed files with 466 additions and 304 deletions.
21 changes: 17 additions & 4 deletions EOBot/ArgumentsParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace EOBot
{
enum ArgsError
public enum ArgsError
{
NoError,
BadFormat,
Expand All @@ -15,12 +15,12 @@ enum ArgsError
InvalidWaitFlag,
InvalidInitDelay
}
class ArgumentsParser

public class ArgumentsParser
{
public ArgsError Error { get; private set; }

public string Host { get; private set; }

public ushort Port { get; private set; }

public int NumBots { get; private set; }
Expand All @@ -29,13 +29,17 @@ class ArgumentsParser
public bool WaitForTermination { get; private set; }
public int InitDelay { get; private set; }

public string Account { get; private set; }
public string Password { get; private set; }
public string Character { get; private set; }

public ArgumentsParser(string[] args)
{
InitDelay = 1100;

Error = ArgsError.NoError;

if (args.Length != 5)
if (args.Length < 5)
{
Error = ArgsError.WrongNumberOfArgs;
return;
Expand Down Expand Up @@ -72,6 +76,15 @@ public ArgumentsParser(string[] args)
if (!ParseInitDelay(pair[1]))
return;
break;
case "account":
Account = pair[1];
break;
case "password":
Password = pair[1];
break;
case "character":
Character = pair[1];
break;
default:
Error = ArgsError.BadFormat;
return;
Expand Down
133 changes: 57 additions & 76 deletions EOBot/BotBase.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using EOLib.Config;
using EOLib.IO.Services;
using EOLib.Logger;
using EOLib.Net;
using EOLib.Net.API;
using EOLib.Domain.Protocol;
using EOLib.Net.Communication;
using EOLib.Net.Connection;
using EOLib.Net.PacketProcessing;

namespace EOBot
Expand All @@ -17,55 +17,64 @@ internal abstract class BotBase : IBot
private CancellationTokenSource _cancelTokenSource;
private bool _initialized;

//derived classes can modify this part
protected readonly int _index;
private readonly string _host;
private readonly int _port;
private EOClient _client;
protected PacketAPI _api;
protected bool TerminationRequested => _cancelTokenSource != null && _cancelTokenSource.IsCancellationRequested;

//unneeded for now
///// <summary>
///// Get whether or not the worker thread was requested to terminate via a call to Terminate()
///// </summary>
//public bool TerminationRequested { get { return _cancelTokenSource != null && _cancelTokenSource.IsCancellationRequested; } }

/// <summary>
/// Invoked once work has completed executing.
/// </summary>
public event Action WorkCompleted;

protected BotBase(int botIndex, string host, int port)
protected BotBase(int botIndex)
{
_index = botIndex;
_host = host;
_port = port;

_terminationEvent = new AutoResetEvent(false);
_cancelTokenSource = new CancellationTokenSource();
}

//all bots are going to want to do the init handshake with the server
public virtual void Initialize()
public virtual async Task InitializeAsync(string host, int port)
{
_client = new EOClient(CreatePacketProcessorActions());
if (!_client.ConnectToServer(_host, _port))
throw new ArgumentException($"Bot {_index}: Unable to connect to server! Host={_host} Port={_port}");
_api = new PacketAPI(_client);
var c = DependencyMaster.TypeRegistry[_index];

var networkClientRepository = c.Resolve<INetworkClientRepository>();
var networkClientFactory = c.Resolve<INetworkClientFactory>();
networkClientRepository.NetworkClient = networkClientFactory.CreateNetworkClient();

var configRepo = c.Resolve<IConfigurationRepository>();
configRepo.Host = host;
configRepo.Port = port;

configRepo.VersionMajor = 0;
configRepo.VersionMinor = 0;
configRepo.VersionBuild = 29;

var connectionActions = c.Resolve<INetworkConnectionActions>();
var connectResult = await connectionActions.ConnectToServer();
if (connectResult != ConnectResult.Success)
throw new ArgumentException($"Bot {_index}: Unable to connect to server! Host={host} Port={port}");

var backgroundReceiveActions = c.Resolve<IBackgroundReceiveActions>();
backgroundReceiveActions.RunBackgroundReceiveLoop();
WorkCompleted += () =>
{
backgroundReceiveActions.CancelBackgroundReceiveLoop();
connectionActions.DisconnectFromServer();
};

var handshakeResult = await connectionActions.BeginHandshake();

//todo: adapt to new networking architecture
//InitData data;
//if (!_api.Initialize(0, 0, 28, new HDSerialNumberService().GetHDSerialNumber(), out data))
// throw new TimeoutException(string.Format("Bot {0}: Failed initialization handshake with server!", _index));
//_client.SetInitData(data);
if (handshakeResult.Response != InitReply.Success)
throw new InvalidOperationException(string.Format("Bot {0}: Invalid response from server or connection failed! Must receive an OK reply.", _index));

//if (!_api.ConfirmInit(data.emulti_e, data.emulti_d, data.clientID))
// throw new TimeoutException(string.Format("Bot {0}: Failed initialization handshake with server!", _index));
var packetProcessActions = c.Resolve<IPacketProcessActions>();

//if (!_api.Initialized || !_client.ConnectedAndInitialized || data.ServerResponse != InitReply.INIT_OK)
// throw new InvalidOperationException(string.Format("Bot {0}: Invalid response from server or connection failed! Must receive an OK reply.", _index));
packetProcessActions.SetInitialSequenceNumber(handshakeResult[InitializationDataKey.SequenceByte1],
handshakeResult[InitializationDataKey.SequenceByte2]);
packetProcessActions.SetEncodeMultiples((byte)handshakeResult[InitializationDataKey.ReceiveMultiple],
(byte)handshakeResult[InitializationDataKey.SendMultiple]);

//_initialized = true;
connectionActions.CompleteHandshake(handshakeResult);

_initialized = true;
}

/// <summary>
Expand All @@ -88,17 +97,17 @@ public void Run(bool waitForTermination)
/// Abstract worker method. Override with custom work logic for the bot to execute
/// </summary>
/// <param name="ct">A cancellation token that will be signalled when Terminate() is called</param>
protected abstract void DoWork(CancellationToken ct);
protected abstract Task DoWorkAsync(CancellationToken ct);

private void DoWorkOnly()
private async void DoWorkOnly()
{
DoWork(_cancelTokenSource.Token);
await DoWorkAsync(_cancelTokenSource.Token);
FireWorkCompleted();
}

private void DoWorkAndWaitForTermination()
private async void DoWorkAndWaitForTermination()
{
DoWork(_cancelTokenSource.Token);
await DoWorkAsync(_cancelTokenSource.Token);
_terminationEvent.WaitOne();
FireWorkCompleted();
}
Expand Down Expand Up @@ -135,42 +144,14 @@ protected virtual void Dispose(bool disposing)
{
Terminate();

if (_workerThread != null)
_workerThread.Join();

if (_client != null)
{
_client.Dispose();
_client = null;
}

if (_api != null)
{
_api.Dispose();
_api = null;
}

if (_terminationEvent != null)
{
_terminationEvent.Dispose();
_terminationEvent = null;
}

if (_cancelTokenSource != null)
{
_cancelTokenSource.Dispose();
_cancelTokenSource = null;
}
}
}
_workerThread?.Join();

private static PacketProcessActions CreatePacketProcessorActions()
{
return new PacketProcessActions(new SequenceRepository(),
new PacketEncoderRepository(),
new PacketEncoderService(new NumberEncoderService()),
new PacketSequenceService(),
new LoggerProvider(new LoggerFactory(new ConfigurationRepository())));
_terminationEvent?.Dispose();
_terminationEvent = null;

_cancelTokenSource?.Dispose();
_cancelTokenSource = null;
}
}
}
}
11 changes: 6 additions & 5 deletions EOBot/BotFramework.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using EOLib.Net.Handlers;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace EOBot
{
Expand Down Expand Up @@ -44,7 +46,7 @@ public BotFramework(IBotFrameworkOutputHandler outputHandler, ArgumentsParser pa
_doneSignal = new Semaphore(simultaneousBots, simultaneousBots);
}

public void Initialize(IBotFactory botFactory, int delayBetweenInitsMS = 1100)
public async Task InitializeAsync(IBotFactory botFactory, int delayBetweenInitsMS = 1100)
{
if (_initialized)
throw new InvalidOperationException("Unable to initialize bot framework a second time.");
Expand All @@ -57,9 +59,9 @@ public void Initialize(IBotFactory botFactory, int delayBetweenInitsMS = 1100)

try
{
var bot = botFactory.CreateBot(i, _host, _port);
var bot = botFactory.CreateBot(i);
bot.WorkCompleted += () => _doneSignal.Release();
bot.Initialize();
await bot.InitializeAsync(_host, _port);
_botsList.Add(bot);
}
catch(Exception ex)
Expand Down Expand Up @@ -91,7 +93,6 @@ public void Run(bool waitForTermination)
if(!_initialized)
throw new InvalidOperationException("Must call Initialize() before running!");


_outputHandler.OutputAllBotsAreRunning(waitForTermination);
for (int i = 0; i < _numBots; ++i)
{
Expand Down

0 comments on commit 7ded0ec

Please sign in to comment.