Skip to content

Commit

Permalink
Merge pull request #110 from ethanmoffat/gameserver_support_2
Browse files Browse the repository at this point in the history
Additional support for official GameServer software. Support account creation and character create/delete.
  • Loading branch information
ethanmoffat committed Mar 2, 2022
2 parents 96d472e + fee5887 commit db100eb
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 52 deletions.
8 changes: 4 additions & 4 deletions EOBot/BotHelper.cs
Expand Up @@ -40,9 +40,9 @@ public async Task<LoginReply> LoginToAccountAsync(string name, string password)
public async Task<CharacterReply> CreateCharacterAsync(string name)
{
var characterActions = DependencyMaster.TypeRegistry[_botIndex].Resolve<ICharacterManagementActions>();
await characterActions.RequestCharacterCreation();
var createId = await characterActions.RequestCharacterCreation();
var charParams = new CharacterCreateParameters(name, 0, 1, 0, 0);
return await characterActions.CreateCharacter(charParams);
return await characterActions.CreateCharacter(charParams, createId);
}

public async Task LoginToCharacterAsync(string name)
Expand Down Expand Up @@ -106,7 +106,7 @@ public async Task<CharacterReply> DeleteCharacterAsync(string name, bool force)
}

var characterActions = DependencyMaster.TypeRegistry[_botIndex].Resolve<ICharacterManagementActions>();
await characterActions.RequestCharacterDelete();
var deleteId = await characterActions.RequestCharacterDelete();

if (!force)
{
Expand All @@ -115,7 +115,7 @@ public async Task<CharacterReply> DeleteCharacterAsync(string name, bool force)
return CharacterReply.NotApproved;
}

return await characterActions.DeleteCharacter();
return await characterActions.DeleteCharacter(deleteId);
}
}
}
27 changes: 17 additions & 10 deletions EOLib/Domain/Account/AccountActions.cs
@@ -1,11 +1,12 @@
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using AutomaticTypeMapper;
using AutomaticTypeMapper;
using EOLib.Domain.Login;
using EOLib.Localization;
using EOLib.Net;
using EOLib.Net.Communication;
using EOLib.Net.PacketProcessing;
using System.Linq;
using System.Net;
using System.Threading.Tasks;

namespace EOLib.Domain.Account
{
Expand All @@ -16,16 +17,19 @@ public class AccountActions : IAccountActions
private readonly IPacketSendService _packetSendService;
private readonly IHDSerialNumberService _hdSerialNumberService;
private readonly ISequenceRepository _sequenceRepository;
private readonly IPlayerInfoRepository _playerInfoRepository;

public AccountActions(ICreateAccountParameterValidator createAccountParameterValidator,
IPacketSendService packetSendService,
IHDSerialNumberService hdSerialNumberService,
ISequenceRepository sequenceRepository)
ISequenceRepository sequenceRepository,
IPlayerInfoRepository playerInfoRepository)
{
_createAccountParameterValidator = createAccountParameterValidator;
_packetSendService = packetSendService;
_hdSerialNumberService = hdSerialNumberService;
_sequenceRepository = sequenceRepository;
_playerInfoRepository = playerInfoRepository;
}

public CreateAccountParameterResult CheckAccountCreateParameters(ICreateAccountParameters parameters)
Expand Down Expand Up @@ -63,12 +67,15 @@ public async Task<AccountReply> CheckAccountNameWithServer(string accountName)
var response = await _packetSendService.SendEncodedPacketAndWaitAsync(nameCheckPacket);
if (IsInvalidResponse(response))
throw new EmptyPacketReceivedException();

var reply = (AccountReply)response.ReadShort();
if (reply == AccountReply.Continue)
if (reply >= AccountReply.OK_CodeRange)
{
_playerInfoRepository.AccountCreateID = (ushort)reply;

// Based on patch: https://github.com/eoserv/eoserv/commit/80dde6d4e7f440a93503aeec79f4a2f5931dc13d
// Account may change sequence start depending on the eoserv build being used
// Official software always updates sequence number
var hasNewSequence = response.Length == 7;
if (hasNewSequence)
{
Expand All @@ -86,11 +93,11 @@ public async Task<AccountReply> CheckAccountNameWithServer(string accountName)
public async Task<AccountReply> CreateAccount(ICreateAccountParameters parameters)
{
var createAccountPacket = new PacketBuilder(PacketFamily.Account, PacketAction.Create)
.AddShort(1337) //eoserv doesn't
.AddByte(42) //validate these values
.AddShort((short)_playerInfoRepository.AccountCreateID)
.AddByte(255)
.AddBreakString(parameters.AccountName)
.AddBreakString(parameters.Password)
.AddBreakString(parameters.Location)
.AddBreakString(parameters.RealName)
.AddBreakString(parameters.Location)
.AddBreakString(parameters.Email)
.AddBreakString(Dns.GetHostName())
Expand Down
7 changes: 5 additions & 2 deletions EOLib/Domain/Account/AccountReply.cs
@@ -1,13 +1,16 @@
namespace EOLib.Domain.Account
{
public enum AccountReply : short
public enum AccountReply : ushort
{
THIS_IS_WRONG = 0,
Exists = 1,
NotApproved = 2,
Created = 3,
ChangeFailed = 5,
ChangeSuccess = 6,
Continue = 1000
/// <summary>
/// Anything greater or equal to this value means the account was approved
/// </summary>
OK_CodeRange = 10,
}
}
25 changes: 14 additions & 11 deletions EOLib/Domain/Character/CharacterManagementActions.cs
Expand Up @@ -27,15 +27,17 @@ public class CharacterManagementActions : ICharacterManagementActions

public async Task<short> RequestCharacterCreation()
{
var packet = new PacketBuilder(PacketFamily.Character, PacketAction.Request).Build();
var packet = new PacketBuilder(PacketFamily.Character, PacketAction.Request)
.AddBreakString("NEW")
.Build();
var responsePacket = await _packetSendService.SendEncodedPacketAndWaitAsync(packet);
return responsePacket.ReadShort();
}

public async Task<CharacterReply> CreateCharacter(ICharacterCreateParameters parameters)
public async Task<CharacterReply> CreateCharacter(ICharacterCreateParameters parameters, short createID)
{
var packet = new PacketBuilder(PacketFamily.Character, PacketAction.Create)
.AddShort(255)
.AddShort(createID)
.AddShort((short)parameters.Gender)
.AddShort((short)parameters.HairStyle)
.AddShort((short)parameters.HairColor)
Expand All @@ -51,21 +53,22 @@ public async Task<CharacterReply> CreateCharacter(ICharacterCreateParameters par
return translatedData.Response;
}

public async Task<int> RequestCharacterDelete()
public async Task<short> RequestCharacterDelete()
{
var packet = new PacketBuilder(PacketFamily.Character, PacketAction.Take)
.AddInt(_characterSelectorRepository.CharacterForDelete.ID)
.Build();

var responsePacket = await _packetSendService.SendEncodedPacketAndWaitAsync(packet);
responsePacket.Seek(2, SeekOrigin.Current);
return responsePacket.ReadInt();
var deleteRequestId = responsePacket.ReadShort();

return deleteRequestId;
}

public async Task<CharacterReply> DeleteCharacter()
public async Task<CharacterReply> DeleteCharacter(short deleteRequestID)
{
var packet = new PacketBuilder(PacketFamily.Character, PacketAction.Remove)
.AddShort(255)
.AddShort(deleteRequestID)
.AddInt(_characterSelectorRepository.CharacterForDelete.ID)
.Build();
var responsePacket = await _packetSendService.SendEncodedPacketAndWaitAsync(packet);
Expand All @@ -80,10 +83,10 @@ public interface ICharacterManagementActions
{
Task<short> RequestCharacterCreation();

Task<CharacterReply> CreateCharacter(ICharacterCreateParameters parameters);
Task<CharacterReply> CreateCharacter(ICharacterCreateParameters parameters, short createID);

Task<int> RequestCharacterDelete();
Task<short> RequestCharacterDelete();

Task<CharacterReply> DeleteCharacter();
Task<CharacterReply> DeleteCharacter(short deleteRequestID);
}
}
7 changes: 7 additions & 0 deletions EOLib/Domain/Login/PlayerInfoRepository.cs
Expand Up @@ -10,6 +10,8 @@ public interface IPlayerInfoRepository

short PlayerID { get; set; }

ushort AccountCreateID { get; set; }

bool IsFirstTimePlayer { get; set; }

bool PlayerIsInGame { get; set; }
Expand All @@ -23,6 +25,8 @@ public interface IPlayerInfoProvider

short PlayerID { get; }

ushort AccountCreateID { get; set; }

bool IsFirstTimePlayer { get; }

bool PlayerIsInGame { get; }
Expand All @@ -37,6 +41,8 @@ public sealed class PlayerInfoRepository : IPlayerInfoRepository, IPlayerInfoPro

public short PlayerID { get; set; }

public ushort AccountCreateID { get; set; }

public bool IsFirstTimePlayer { get; set; }

public bool PlayerIsInGame { get; set; }
Expand All @@ -46,6 +52,7 @@ public void ResetState()
LoggedInAccountName = "";
PlayerPassword = "";
PlayerID = 0;
AccountCreateID = 0;
IsFirstTimePlayer = false;
PlayerIsInGame = false;
}
Expand Down
2 changes: 1 addition & 1 deletion EOLib/Net/PacketBuilder.cs
Expand Up @@ -67,7 +67,7 @@ public IPacketBuilder AddChar(byte b)

public IPacketBuilder AddShort(short s)
{
return AddBytes(_encoderService.EncodeNumber(s, 2));
return AddBytes(_encoderService.EncodeNumber((ushort)s, 2));
}

public IPacketBuilder AddThree(int t)
Expand Down
10 changes: 7 additions & 3 deletions EOLib/Net/Translators/CharacterDisplayPacketTranslator.cs
Expand Up @@ -23,17 +23,21 @@ protected IEnumerable<ICharacter> GetCharacters(IPacket packet)
var characters = new List<ICharacter>();

var numberOfCharacters = (int)packet.ReadChar();
packet.Seek(1, SeekOrigin.Current);

// EOSERV sends this byte unconditionally for CHARACTER_REPLY, but GameServer appears
// to not send it on delete packets
if (packet.PeekByte() == 1)
packet.ReadByte();

for (int i = 0; i < numberOfCharacters; ++i)
{
if (packet.ReadByte() != 255)
throw new MalformedPacketException("Login packet missing character separator byte", packet);
throw new MalformedPacketException($"{packet.Family}_{packet.Action} packet missing character separator byte", packet);
characters.Add(GetNextCharacter(packet));
}

if (packet.ReadByte() != 255)
throw new MalformedPacketException("Login packet missing character separator byte", packet);
throw new MalformedPacketException($"{packet.Family}_{packet.Action} packet missing character separator byte", packet);

return characters;
}
Expand Down
5 changes: 4 additions & 1 deletion EOLib/PacketHandlers/ConnectionPlayerHandler.cs
Expand Up @@ -39,7 +39,10 @@ public override bool HandlePacket(IPacket packet)

_packetProcessActions.SetUpdatedBaseSequenceNumber(seq1, seq2);

var response = new PacketBuilder(PacketFamily.Connection, PacketAction.Ping).Build();
var response = new PacketBuilder(PacketFamily.Connection, PacketAction.Ping)
.AddString("k")
.Build();

try
{
_packetSendService.SendPacket(response);
Expand Down
2 changes: 1 addition & 1 deletion EndlessClient/Controllers/AccountController.cs
Expand Up @@ -48,7 +48,7 @@ public async Task CreateAccount(ICreateAccountParameters createAccountParameters
return;

var nameResult = checkNameOperation.Result;
if (nameResult != AccountReply.Continue)
if (nameResult < AccountReply.OK_CodeRange)
{
_accountDialogDisplayActions.ShowCreateAccountServerError(nameResult);
return;
Expand Down
21 changes: 3 additions & 18 deletions EndlessClient/Controllers/CharacterManagementController.cs
Expand Up @@ -58,15 +58,6 @@ public async Task CreateCharacter()
DisconnectAndStopReceiving();
return;
}

//todo: other server implementations might have a different value than 1000
// it is set to a constant 1000 in eoserv
if (createID != 1000)
{
SetInitialStateAndShowError();
DisconnectAndStopReceiving();
return;
}

//todo: make not approved character names cancel the dialog close
var parameters = await _characterDialogActions.ShowCreateCharacterDialog();
Expand All @@ -76,7 +67,7 @@ public async Task CreateCharacter()
CharacterReply response;
try
{
response = await _characterManagementActions.CreateCharacter(parameters.Value);
response = await _characterManagementActions.CreateCharacter(parameters.Value, createID);
}
catch (NoDataSentException)
{
Expand Down Expand Up @@ -106,7 +97,7 @@ public async Task DeleteCharacter(ICharacter characterToDelete)
return;
}

int takeID;
short takeID;
try
{
takeID = await _characterManagementActions.RequestCharacterDelete();
Expand All @@ -124,20 +115,14 @@ public async Task DeleteCharacter(ICharacter characterToDelete)
return;
}

if (takeID != characterToDelete.ID)
{
_characterDialogActions.ShowCharacterDeleteError();
return;
}

var dialogResult = await _characterDialogActions.ShowConfirmDeleteWarning(characterToDelete.Name);
if (dialogResult != XNADialogResult.OK)
return;

CharacterReply response;
try
{
response = await _characterManagementActions.DeleteCharacter();
response = await _characterManagementActions.DeleteCharacter(takeID);
}
catch (NoDataSentException)
{
Expand Down
3 changes: 2 additions & 1 deletion EndlessClient/Dialogs/ProgressDialog.cs
Expand Up @@ -79,7 +79,8 @@ protected override void OnUpdateControl(GameTime gt)
if (timeOpened == null)
timeOpened = gt.TotalGameTime;

var pbPercent = (int)((gt.TotalGameTime.TotalSeconds - timeOpened.Value.TotalSeconds) / 2.0f * 100);
const double SECONDS_FOR_CREATE = 2.0;
var pbPercent = (int)((gt.TotalGameTime.TotalSeconds - timeOpened.Value.TotalSeconds) / SECONDS_FOR_CREATE * 100);
_pbWidth = (int)Math.Round(pbPercent / 100.0f * _pbBackgroundTexture.Width);

if (pbPercent >= 100)
Expand Down

0 comments on commit db100eb

Please sign in to comment.