Skip to content

Commit

Permalink
Merge pull request #119 from ethanmoffat/proper_optional
Browse files Browse the repository at this point in the history
Remove EOLib.Optional and replace with Optional nuget package. Reference Optional nuget package and replace usages of old Optional. Use functional approach to handling optional values. Replace some usages of null with Optional.
  • Loading branch information
ethanmoffat committed Mar 18, 2022
2 parents e3af7b3 + 74cd7bf commit 0d234fe
Show file tree
Hide file tree
Showing 62 changed files with 804 additions and 788 deletions.
5 changes: 3 additions & 2 deletions EOBot/BotHelper.cs
Expand Up @@ -5,6 +5,7 @@
using EOLib.Domain.Protocol;
using EOLib.IO.Actions;
using EOLib.Net.FileTransfer;
using Optional.Collections;
using System;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -97,9 +98,9 @@ public async Task<AccountReply> ChangePasswordAsync(string name, string oldPass,
public async Task<CharacterReply> DeleteCharacterAsync(string name, bool force)
{
var characterSelectorRepository = DependencyMaster.TypeRegistry[_botIndex].Resolve<ICharacterSelectorRepository>();
characterSelectorRepository.CharacterForDelete = characterSelectorRepository.Characters.SingleOrDefault(x => x.Name == name);
characterSelectorRepository.CharacterForDelete = characterSelectorRepository.Characters.SingleOrNone(x => x.Name == name);

if (characterSelectorRepository.CharacterForDelete == null)
if (!characterSelectorRepository.CharacterForDelete.HasValue)
{
ConsoleHelper.WriteMessage(ConsoleHelper.Type.Warning, $"Character {name} could not be deleted / does not exist");
return CharacterReply.THIS_IS_WRONG;
Expand Down
5 changes: 3 additions & 2 deletions EOBot/Program.cs
Expand Up @@ -7,6 +7,7 @@
using EOLib.Domain.Notifiers;
using EOLib.Domain.NPC;
using EOLib.IO.Repositories;
using Optional;
using System;
using System.Linq;
using System.Threading.Tasks;
Expand All @@ -33,7 +34,7 @@ class NpcWalkNotifier : INPCActionNotifier
_enfFileProvider = enfFileProvider;
}

public void NPCTakeDamage(short npcIndex, int fromPlayerId, int damageToNpc, short npcPctHealth, EOLib.Optional<int> spellId)
public void NPCTakeDamage(short npcIndex, int fromPlayerId, int damageToNpc, short npcPctHealth, Option<int> spellId)
{
if (fromPlayerId != _characterProvider.MainCharacter.ID)
return;
Expand All @@ -50,7 +51,7 @@ public void NPCTakeDamage(short npcIndex, int fromPlayerId, int damageToNpc, sho
ConsoleHelper.WriteMessage(ConsoleHelper.Type.Hit, $"{damageToNpc,7} - {npcPctHealth,3}% HP - {npcIndex,2} - {npcName ?? string.Empty}", color);
}

public void RemoveNPCFromView(int npcIndex, int playerId, EOLib.Optional<short> spellId, EOLib.Optional<int> damage, bool showDeathAnimation)
public void RemoveNPCFromView(int npcIndex, int playerId, Option<short> spellId, Option<int> damage, bool showDeathAnimation)
{
}

Expand Down
3 changes: 2 additions & 1 deletion EOBot/TrainerBot.cs
Expand Up @@ -5,6 +5,7 @@
using EOLib.Domain.Item;
using EOLib.Domain.Login;
using EOLib.Domain.Map;
using EOLib.Domain.NPC;
using EOLib.IO;
using EOLib.IO.Pub;
using EOLib.IO.Repositories;
Expand Down Expand Up @@ -237,7 +238,7 @@ protected override async Task DoWorkAsync(CancellationToken ct)

private async Task Attack(IMapCellState cellState)
{
ConsoleHelper.WriteMessage(ConsoleHelper.Type.Attack, $"{cellState.NPC.Value.Index,7} - {_npcData.Single(x => x.ID == cellState.NPC.Value.ID).Name}");
cellState.NPC.MatchSome(npc => ConsoleHelper.WriteMessage(ConsoleHelper.Type.Attack, $"{npc.Index,7} - {_npcData.Single(x => x.ID == npc.ID).Name}"));
await TrySend(_characterActions.Attack);
await Task.Delay(TimeSpan.FromMilliseconds(ATTACK_BACKOFF_MS));
}
Expand Down
15 changes: 8 additions & 7 deletions EOLib/Domain/Character/AttackValidationActions.cs
Expand Up @@ -25,14 +25,15 @@ public AttackValidationError ValidateCharacterStateBeforeAttacking()
if (_characterProvider.MainCharacter.Stats[CharacterStat.SP] <= 0)
return AttackValidationError.Exhausted;

var cellState = _mapCellStateProvider.GetCellStateAt(
_characterProvider.MainCharacter.RenderProperties.GetDestinationX(),
_characterProvider.MainCharacter.RenderProperties.GetDestinationY());
if (cellState.NPC.HasValue && cellState.NPC.Value.OpponentID.HasValue &&
cellState.NPC.Value.OpponentID != _characterProvider.MainCharacter.ID)
return AttackValidationError.NotYourBattle;
var rp = _characterProvider.MainCharacter.RenderProperties;

return AttackValidationError.OK;
return _mapCellStateProvider
.GetCellStateAt(rp.GetDestinationX(), rp.GetDestinationY())
.NPC.Match(
some: npc => npc.OpponentID.Match(
some: id => id != _characterProvider.MainCharacter.ID ? AttackValidationError.NotYourBattle : AttackValidationError.OK,
none: () => AttackValidationError.OK),
none: () => AttackValidationError.OK);
}
}

Expand Down
14 changes: 7 additions & 7 deletions EOLib/Domain/Character/CharacterManagementActions.cs
Expand Up @@ -55,9 +55,9 @@ public async Task<CharacterReply> CreateCharacter(ICharacterCreateParameters par

public async Task<short> RequestCharacterDelete()
{
var packet = new PacketBuilder(PacketFamily.Character, PacketAction.Take)
.AddInt(_characterSelectorRepository.CharacterForDelete.ID)
.Build();
var packet = _characterSelectorRepository.CharacterForDelete.Match(
some: c => new PacketBuilder(PacketFamily.Character, PacketAction.Take).AddInt(c.ID).Build(),
none: () => new EmptyPacket());

var responsePacket = await _packetSendService.SendEncodedPacketAndWaitAsync(packet);
var deleteRequestId = responsePacket.ReadShort();
Expand All @@ -67,10 +67,10 @@ public async Task<short> RequestCharacterDelete()

public async Task<CharacterReply> DeleteCharacter(short deleteRequestID)
{
var packet = new PacketBuilder(PacketFamily.Character, PacketAction.Remove)
.AddShort(deleteRequestID)
.AddInt(_characterSelectorRepository.CharacterForDelete.ID)
.Build();
var packet = _characterSelectorRepository.CharacterForDelete.Match(
some: c => new PacketBuilder(PacketFamily.Character, PacketAction.Remove).AddShort(deleteRequestID).AddInt(c.ID).Build(),
none: () => new EmptyPacket());

var responsePacket = await _packetSendService.SendEncodedPacketAndWaitAsync(packet);

var translatedData = _characterCreatePacketTranslator.TranslatePacket(responsePacket);
Expand Down
25 changes: 13 additions & 12 deletions EOLib/Domain/Character/WalkValidationActions.cs
@@ -1,9 +1,10 @@
using System;
using System.Linq;
using AutomaticTypeMapper;
using AutomaticTypeMapper;
using EOLib.Domain.Extensions;
using EOLib.Domain.Map;
using EOLib.IO.Map;
using Optional;
using System;
using System.Linq;

namespace EOLib.Domain.Character
{
Expand Down Expand Up @@ -48,19 +49,19 @@ public bool CanMoveToCoordinates(int gridX, int gridY)
var cellState = _mapCellStateProvider.GetCellStateAt(gridX, gridY);
return IsCellStateWalkable(cellState);
}

public bool IsCellStateWalkable(IMapCellState cellState)
{
var mainCharacter = _characterProvider.MainCharacter;
var mc = _characterProvider.MainCharacter;

if (cellState.Character.HasValue && cellState.Character.Value != mainCharacter) //todo: walk through players after certain elapsed time
return mainCharacter.NoWall && IsTileSpecWalkable(cellState.TileSpec);
if (cellState.NPC.HasValue)
return mainCharacter.NoWall && IsTileSpecWalkable(cellState.TileSpec);
if (cellState.Warp.HasValue)
return mainCharacter.NoWall || IsWarpWalkable(cellState.Warp.Value, cellState.TileSpec);
var cellChar = cellState.Character.FlatMap(c => c.SomeWhen(cc => cc != mc));

return mainCharacter.NoWall || IsTileSpecWalkable(cellState.TileSpec);
return cellChar.Match(
some: _ => mc.NoWall && IsTileSpecWalkable(cellState.TileSpec),
none: () => cellState.NPC.Match(
some: _ => mc.NoWall && IsTileSpecWalkable(cellState.TileSpec),
none: () => cellState.Warp.Match(
some: w => mc.NoWall || IsWarpWalkable(w, cellState.TileSpec),
none: () => mc.NoWall || IsTileSpecWalkable(cellState.TileSpec))));
}

private bool IsWarpWalkable(IWarp warp, TileSpec tile)
Expand Down
40 changes: 24 additions & 16 deletions EOLib/Domain/Item/ItemPickupValidator.cs
Expand Up @@ -4,6 +4,7 @@
using EOLib.Domain.Character;
using EOLib.Domain.Map;
using EOLib.IO.Repositories;
using Optional;

namespace EOLib.Domain.Item
{
Expand All @@ -29,22 +30,29 @@ public ItemPickupResult ValidateItemPickup(ICharacter mainCharacter, IItem item)
if (xDif > 2 || yDif > 2)
return ItemPickupResult.TooFar;

if (item.OwningPlayerID.HasValue && mainCharacter.ID != item.OwningPlayerID.Value && item.DropTime.HasValue)
{
var dropTime = item.DropTime.Value;
if (item.IsNPCDrop && (now - dropTime).TotalSeconds <= _configurationProvider.NPCDropProtectTime ||
!item.IsNPCDrop && (now - dropTime).TotalSeconds <= _configurationProvider.PlayerDropProtectTime)
return ItemPickupResult.DropProtection;
}
else
{
var itemData = _eifFileProvider.EIFFile[item.ItemID];
var totalWeight = itemData.Weight * item.Amount;
if (totalWeight + mainCharacter.Stats[CharacterStat.Weight] > mainCharacter.Stats[CharacterStat.MaxWeight])
return ItemPickupResult.TooHeavy;
}

return ItemPickupResult.Ok;
return item.OwningPlayerID
.FlatMap(id => id.SomeWhen(idx => idx != mainCharacter.ID))
.Match(
some: id =>
item.DropTime.Match(
some: dropTime =>
{
if (item.IsNPCDrop && (now - dropTime).TotalSeconds <= _configurationProvider.NPCDropProtectTime ||
!item.IsNPCDrop && (now - dropTime).TotalSeconds <= _configurationProvider.PlayerDropProtectTime)
return ItemPickupResult.DropProtection;
return ItemPickupResult.Ok;
},
none: () => ItemPickupResult.Ok),
none: () =>
{
var itemData = _eifFileProvider.EIFFile[item.ItemID];
var totalWeight = itemData.Weight * item.Amount;
if (totalWeight + mainCharacter.Stats[CharacterStat.Weight] > mainCharacter.Stats[CharacterStat.MaxWeight])
return ItemPickupResult.TooHeavy;
return ItemPickupResult.Ok;
});
}
}

Expand Down
7 changes: 4 additions & 3 deletions EOLib/Domain/Login/CharacterSelectorRepository.cs
@@ -1,28 +1,29 @@
using System.Collections.Generic;
using AutomaticTypeMapper;
using EOLib.Domain.Character;
using Optional;

namespace EOLib.Domain.Login
{
public interface ICharacterSelectorRepository
{
IReadOnlyList<ICharacter> Characters { get; set; }

ICharacter CharacterForDelete { get; set; }
Option<ICharacter> CharacterForDelete { get; set; }
}

public interface ICharacterSelectorProvider
{
IReadOnlyList<ICharacter> Characters { get; }

ICharacter CharacterForDelete { get; }
Option<ICharacter> CharacterForDelete { get; }
}

[AutoMappedType(IsSingleton = true)]
public class CharacterSelectorRepository : ICharacterSelectorRepository, ICharacterSelectorProvider
{
public IReadOnlyList<ICharacter> Characters { get; set; }

public ICharacter CharacterForDelete { get; set; }
public Option<ICharacter> CharacterForDelete { get; set; }
}
}
11 changes: 6 additions & 5 deletions EOLib/Domain/Map/IMapCellState.cs
Expand Up @@ -2,6 +2,7 @@
using EOLib.Domain.Character;
using EOLib.Domain.NPC;
using EOLib.IO.Map;
using Optional;

namespace EOLib.Domain.Map
{
Expand All @@ -15,14 +16,14 @@ public interface IMapCellState

TileSpec TileSpec { get; }

Optional<INPC> NPC { get; }
Option<INPC> NPC { get; }

Optional<ICharacter> Character { get; }
Option<ICharacter> Character { get; }

Optional<IChest> Chest { get; }
Option<IChest> Chest { get; }

Optional<IWarp> Warp { get; }
Option<IWarp> Warp { get; }

Optional<ISign> Sign { get; }
Option<ISign> Sign { get; }
}
}
30 changes: 16 additions & 14 deletions EOLib/Domain/Map/Item.cs
@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using Optional;
using System;

namespace EOLib.Domain.Map
{
Expand All @@ -17,9 +17,11 @@ public class Item : IItem

public bool IsNPCDrop { get; private set; }

public Optional<int> OwningPlayerID { get; private set; }
public Option<int> OwningPlayerID { get; private set; }

public Optional<DateTime> DropTime { get; private set; }
public Option<DateTime> DropTime { get; private set; }

public static IItem None => new Item(0, 0, 0, 0);

public Item(short uid, short itemID, byte x, byte y)
{
Expand All @@ -43,17 +45,17 @@ public IItem WithIsNPCDrop(bool isNPCDrop)
return newItem;
}

public IItem WithOwningPlayerID(Optional<int> owningPlayerID)
public IItem WithOwningPlayerID(int owningPlayerID)
{
var newItem = MakeCopy(this);
newItem.OwningPlayerID = owningPlayerID;
newItem.OwningPlayerID = Option.Some(owningPlayerID);
return newItem;
}

public IItem WithDropTime(Optional<DateTime> dropTime)
public IItem WithDropTime(DateTime dropTime)
{
var newItem = MakeCopy(this);
newItem.DropTime = dropTime;
newItem.DropTime = Option.Some(dropTime);
return newItem;
}

Expand All @@ -77,8 +79,8 @@ public override bool Equals(object obj)
Y == item.Y &&
Amount == item.Amount &&
IsNPCDrop == item.IsNPCDrop &&
EqualityComparer<Optional<int>>.Default.Equals(OwningPlayerID, item.OwningPlayerID) &&
EqualityComparer<Optional<DateTime>>.Default.Equals(DropTime, item.DropTime);
OwningPlayerID.Equals(item.OwningPlayerID) &&
DropTime.Equals(item.DropTime);
}

public override int GetHashCode()
Expand Down Expand Up @@ -110,16 +112,16 @@ public interface IItem

bool IsNPCDrop { get; }

Optional<int> OwningPlayerID { get; }
Option<int> OwningPlayerID { get; }

Optional<DateTime> DropTime { get; }
Option<DateTime> DropTime { get; }

IItem WithAmount(int newAmount);

IItem WithIsNPCDrop(bool isNPCDrop);

IItem WithOwningPlayerID(Optional<int> owningPlayerID);
IItem WithOwningPlayerID(int owningPlayerID);

IItem WithDropTime(Optional<DateTime> dropTime);
IItem WithDropTime(DateTime dropTime);
}
}
21 changes: 11 additions & 10 deletions EOLib/Domain/Map/MapCellState.cs
Expand Up @@ -2,6 +2,7 @@
using EOLib.Domain.Character;
using EOLib.Domain.NPC;
using EOLib.IO.Map;
using Optional;

namespace EOLib.Domain.Map
{
Expand All @@ -15,26 +16,26 @@ public class MapCellState : IMapCellState

public TileSpec TileSpec { get; set; }

public Optional<INPC> NPC { get; set; }
public Option<INPC> NPC { get; set; }

public Optional<ICharacter> Character { get; set; }
public Option<ICharacter> Character { get; set; }

public Optional<IChest> Chest { get; set; }
public Option<IChest> Chest { get; set; }

public Optional<IWarp> Warp { get; set; }
public Option<IWarp> Warp { get; set; }

public Optional<ISign> Sign { get; set; }
public Option<ISign> Sign { get; set; }

public MapCellState()
{
Coordinate = new MapCoordinate(0, 0);
Items = new List<IItem>();
TileSpec = TileSpec.None;
NPC = new Optional<INPC>();
Character = new Optional<ICharacter>();
Chest = new Optional<IChest>();
Warp = new Optional<IWarp>();
Sign = new Optional<ISign>();
NPC = Option.None<INPC>();
Character = Option.None<ICharacter>();
Chest = Option.None<IChest>();
Warp = Option.None<IWarp>();
Sign = Option.None<ISign>();
}
}
}

0 comments on commit 0d234fe

Please sign in to comment.