Skip to content

Commit

Permalink
Merge pull request #118 from ethanmoffat/immutable_pub
Browse files Browse the repository at this point in the history
- Make pub files/records immutable.
- Separate (de)serialization from pub files/records.
- Use generic approach to handling properties on pub files and records.
API now follows consistent approach that matches how map files are handled
  • Loading branch information
ethanmoffat committed Mar 18, 2022
2 parents d50bbb9 + 771735f commit e3af7b3
Show file tree
Hide file tree
Showing 61 changed files with 1,669 additions and 2,572 deletions.
4 changes: 2 additions & 2 deletions BatchMap/Program.cs
Expand Up @@ -194,7 +194,7 @@ private static void ProcessFiles(string src, string dst, bool singleFile)
{
var npcSpawn = mapFile.NPCSpawns[ndx];
var npcRec = _pubProvider.ENFFile[npcSpawn.ID];
if (npcSpawn.ID > _pubProvider.ENFFile.Data.Count || npcRec == null)
if (npcSpawn.ID > _pubProvider.ENFFile.Length || npcRec == null)
{
Console.WriteLine("[MAP {0}] NPC Spawn {1}x{2} uses non-existent NPC #{3}. Removing.", mapID, npcSpawn.X, npcSpawn.Y, npcSpawn.ID);
mapFile = mapFile.RemoveNPCSpawn(npcSpawn);
Expand Down Expand Up @@ -241,7 +241,7 @@ private static void ProcessFiles(string src, string dst, bool singleFile)
{
var chestSpawn = mapFile.Chests[ndx];
var rec = _pubProvider.EIFFile[chestSpawn.ItemID];
if (chestSpawn.ItemID > _pubProvider.EIFFile.Data.Count || rec == null)
if (chestSpawn.ItemID > _pubProvider.EIFFile.Length || rec == null)
{
Console.WriteLine("[MAP {0}] Chest Spawn {1}x{2} uses non-existent Item #{3}. Removing.", mapID, chestSpawn.X, chestSpawn.Y, chestSpawn.ItemID);
mapFile = mapFile.RemoveChestSpawn(chestSpawn);
Expand Down
14 changes: 7 additions & 7 deletions BatchPub/frmMain.cs
Expand Up @@ -7,6 +7,7 @@
using EOLib.IO;
using EOLib.IO.Pub;
using EOLib.IO.Services;
using EOLib.IO.Services.Serializers;

namespace BatchPub
{
Expand Down Expand Up @@ -96,7 +97,7 @@ private void btnProcess_Click(object sender, EventArgs e)
}

rtfOutput.Text += "Processing change: set " + pi.Name + "(" + pi.PropertyType.ToString() + ")=" + newValue.ToString() + " for all items...";
foreach (var rec in eif.Data)
foreach (var rec in eif)
{
System.Reflection.PropertyInfo prop = rec.GetType().GetProperty(pi.Name);
prop.SetValue(rec, Convert.ChangeType(newValue, pi.PropertyType));
Expand Down Expand Up @@ -169,7 +170,7 @@ private void btnProcess_Click(object sender, EventArgs e)
}
}

List<EIFRecord> filtered = eif.Data.Where(record =>
List<EIFRecord> filtered = eif.Where(record =>
{
EIFRecord rec = (EIFRecord)record;
if (rec == null || rec.ID == 0) return false;
Expand Down Expand Up @@ -255,13 +256,12 @@ private void btnBrowse_Click(object sender, EventArgs e)

private void btnLoad_Click(object sender, EventArgs e)
{
eif = new EIFFile();

var deserializer = new PubFileSerializer(new NumberEncoderService(), new PubRecordSerializer(new NumberEncoderService()));
_fname = "";
try
{
var fileBytes = File.ReadAllBytes(_fname = string.IsNullOrEmpty(txtFileName.Text) ? PubFileNameConstants.PathToEIFFile : txtFileName.Text);
eif.DeserializeFromByteArray(fileBytes, new NumberEncoderService());
eif = deserializer.DeserializeFromByteArray(fileBytes, () => new EIFFile());
lblFileName.Text = "Loaded file: " + _fname;
grpStepTwo.Enabled = true;
btnReset.Enabled = true;
Expand Down Expand Up @@ -417,8 +417,8 @@ private void btnSave_Click(object sender, EventArgs e)

try
{
eif.CheckSum++;//todo: recalculate checksum
var bytes = eif.SerializeToByteArray(new NumberEncoderService());
var serializer = new PubFileSerializer(new NumberEncoderService(), new PubRecordSerializer(new NumberEncoderService()));
var bytes = serializer.SerializeToByteArray(eif);
}
catch(Exception ex)
{
Expand Down
8 changes: 4 additions & 4 deletions EOBot/Interpreter/BuiltInIdentifierConfigurator.cs
Expand Up @@ -210,7 +210,7 @@ private Task LoginToCharacterAsync(string charName)
() => new ArrayVariable(
inventoryProvider.ItemInventory.Select(x =>
{
var itemName = pubProvider.EIFFile.Data.Single(d => d.ID == x.ItemID).Name;
var itemName = pubProvider.EIFFile.Single(d => d.ID == x.ItemID).Name;
var retObj = new ObjectVariable();
retObj.SymbolTable[PredefinedIdentifiers.NAME] = Readonly(new StringVariable(itemName));
Expand All @@ -222,7 +222,7 @@ private Task LoginToCharacterAsync(string charName)
() => new ArrayVariable(
inventoryProvider.SpellInventory.Select(x =>
{
var spellName = pubProvider.ESFFile.Data.Single(d => d.ID == x.ID).Name;
var spellName = pubProvider.ESFFile.Single(d => d.ID == x.ID).Name;
var retObj = new ObjectVariable();
retObj.SymbolTable[PredefinedIdentifiers.NAME] = Readonly(new StringVariable(spellName));
Expand Down Expand Up @@ -274,7 +274,7 @@ private IVariable GetMapStateNPC(INPC npc)
var npcFile = DependencyMaster.TypeRegistry[_botIndex].Resolve<IPubFileProvider>().ENFFile;

var npcObj = new ObjectVariable();
npcObj.SymbolTable[PredefinedIdentifiers.NAME] = Readonly(new StringVariable(npcFile.Data.Single(x => x.ID == npc.ID).Name));
npcObj.SymbolTable[PredefinedIdentifiers.NAME] = Readonly(new StringVariable(npcFile.Single(x => x.ID == npc.ID).Name));
npcObj.SymbolTable["x"] = Readonly(new IntVariable(npc.X));
npcObj.SymbolTable["y"] = Readonly(new IntVariable(npc.Y));
npcObj.SymbolTable["id"] = Readonly(new IntVariable(npc.ID));
Expand All @@ -287,7 +287,7 @@ private IVariable GetMapStateItem(IItem item)
var itemFile = DependencyMaster.TypeRegistry[_botIndex].Resolve<IPubFileProvider>().EIFFile;

var itemObj = new ObjectVariable();
itemObj.SymbolTable[PredefinedIdentifiers.NAME] = Readonly(new StringVariable(itemFile.Data.Single(x => x.ID == item.ItemID).Name));
itemObj.SymbolTable[PredefinedIdentifiers.NAME] = Readonly(new StringVariable(itemFile.Single(x => x.ID == item.ItemID).Name));
itemObj.SymbolTable["x"] = Readonly(new IntVariable(item.X));
itemObj.SymbolTable["y"] = Readonly(new IntVariable(item.Y));
itemObj.SymbolTable["id"] = Readonly(new IntVariable(item.ItemID));
Expand Down
2 changes: 1 addition & 1 deletion EOBot/Program.cs
Expand Up @@ -39,7 +39,7 @@ public void NPCTakeDamage(short npcIndex, int fromPlayerId, int damageToNpc, sho
return;

var npc = _currentMapStateRepository.NPCs.SingleOrDefault(x => x.Index == npcIndex);
var npcName = _enfFileProvider.ENFFile.Data.SingleOrDefault(x => npc != null && npc.ID == x.ID)?.Name;
var npcName = _enfFileProvider.ENFFile.SingleOrDefault(x => npc != null && npc.ID == x.ID)?.Name;

var color = npcPctHealth < 25
? ConsoleColor.Red
Expand Down
14 changes: 7 additions & 7 deletions EOBot/TrainerBot.cs
Expand Up @@ -182,11 +182,11 @@ protected override async Task DoWorkAsync(CancellationToken ct)
}

healItems = charInventoryRepo.ItemInventory
.Where(x => _itemData.Data.Any(y => y.ID == x.ItemID && y.Type == ItemType.Heal))
.Where(x => _itemData.Any(y => y.ID == x.ItemID && y.Type == ItemType.Heal))
.ToList();

healSpells = charInventoryRepo.SpellInventory
.Where(x => _spellData.Data.Any(y => y.ID == x.ID && y.Type == SpellType.Heal))
.Where(x => _spellData.Any(y => y.ID == x.ID && y.Type == SpellType.Heal))
.ToList();
}
else
Expand Down Expand Up @@ -237,7 +237,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.Data.Single(x => x.ID == cellState.NPC.Value.ID).Name}");
ConsoleHelper.WriteMessage(ConsoleHelper.Type.Attack, $"{cellState.NPC.Value.Index,7} - {_npcData.Single(x => x.ID == cellState.NPC.Value.ID).Name}");
await TrySend(_characterActions.Attack);
await Task.Delay(TimeSpan.FromMilliseconds(ATTACK_BACKOFF_MS));
}
Expand Down Expand Up @@ -298,7 +298,7 @@ private async Task PickUpItem(IItem item)
{
await TrySend(() =>
{
var itemName = _itemData.Data.Single(x => x.ID == item.ItemID).Name;
var itemName = _itemData.Single(x => x.ID == item.ItemID).Name;
var pickupResult = _mapActions.PickUpItem(item);
if (pickupResult == ItemPickupResult.Ok)
ConsoleHelper.WriteMessage(ConsoleHelper.Type.TakeItem, $"{item.Amount,7} - {itemName}");
Expand All @@ -310,14 +310,14 @@ private async Task PickUpItem(IItem item)

private async Task JunkItem(IItem item)
{
ConsoleHelper.WriteMessage(ConsoleHelper.Type.JunkItem, $"{item.Amount,7} - {_itemData.Data.Single(x => x.ID == item.ItemID).Name}");
ConsoleHelper.WriteMessage(ConsoleHelper.Type.JunkItem, $"{item.Amount,7} - {_itemData.Single(x => x.ID == item.ItemID).Name}");
await TrySend(() => _mapActions.JunkItem(item));
await Task.Delay(TimeSpan.FromMilliseconds(ATTACK_BACKOFF_MS));
}

private async Task CastHealSpell(IEnumerable<IInventorySpell> healSpells)
{
var spellToUse = _spellData.Data
var spellToUse = _spellData
.Where(x => healSpells.Any(y => y.ID == x.ID) && x.Target != SpellTarget.Group)
.OrderByDescending(x => x.HP)
.First();
Expand All @@ -334,7 +334,7 @@ private async Task CastHealSpell(IEnumerable<IInventorySpell> healSpells)

private async Task UseHealItem(IEnumerable<IInventoryItem> healItems)
{
var itemToUse = _itemData.Data
var itemToUse = _itemData
.Where(x => healItems.Any(y => y.ItemID == x.ID))
.OrderBy(x => x.HP)
.First();
Expand Down
131 changes: 36 additions & 95 deletions EOLib.IO.Test/EIFRecordExtensionsTest.cs
Expand Up @@ -8,100 +8,41 @@ namespace EOLib.IO.Test
[TestFixture, ExcludeFromCodeCoverage]
public class EIFRecordExtensionsTest
{
[Test]
public void GetEquipLocation_Accessory_ReturnsAccessory()
{
Assert.AreEqual(EquipLocation.Accessory, new EIFRecord {Type = ItemType.Accessory}.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Armlet_ReturnsArmlet1()
{
Assert.AreEqual(EquipLocation.Armlet1, new EIFRecord { Type = ItemType.Armlet }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Armor_ReturnsArmor()
{
Assert.AreEqual(EquipLocation.Armor, new EIFRecord { Type = ItemType.Armor }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Belt_ReturnsBelt()
{
Assert.AreEqual(EquipLocation.Belt, new EIFRecord { Type = ItemType.Belt }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Boots_ReturnsBoots()
{
Assert.AreEqual(EquipLocation.Boots, new EIFRecord { Type = ItemType.Boots }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Bracer_ReturnsBracer()
{
Assert.AreEqual(EquipLocation.Bracer1, new EIFRecord { Type = ItemType.Bracer }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Gloves_ReturnsGloves()
{
Assert.AreEqual(EquipLocation.Gloves, new EIFRecord { Type = ItemType.Gloves }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Hat_ReturnsHat()
{
Assert.AreEqual(EquipLocation.Hat, new EIFRecord { Type = ItemType.Hat }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Necklace_ReturnsNecklace()
{
Assert.AreEqual(EquipLocation.Necklace, new EIFRecord { Type = ItemType.Necklace }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Ring_ReturnsRing1()
{
Assert.AreEqual(EquipLocation.Ring1, new EIFRecord { Type = ItemType.Ring }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Shield_ReturnsShield()
{
Assert.AreEqual(EquipLocation.Shield, new EIFRecord { Type = ItemType.Shield }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Weapon_ReturnsWeapon()
{
Assert.AreEqual(EquipLocation.Weapon, new EIFRecord { Type = ItemType.Weapon }.GetEquipLocation());
}

[Test]
public void GetEquipLocation_Unsupported_ReturnsPaperdollMax()
{
var unsupported = new[]
{
ItemType.Beer,
ItemType.CureCurse,
ItemType.EXPReward,
ItemType.EffectPotion,
ItemType.HairDye,
ItemType.Heal,
ItemType.Key,
ItemType.Money,
ItemType.SkillReward,
ItemType.StatReward,
ItemType.Static,
ItemType.Teleport,
ItemType.UnknownType1
};

foreach (var type in unsupported)
Assert.AreEqual(EquipLocation.PAPERDOLL_MAX, new EIFRecord {Type = type}.GetEquipLocation());
}
[TestCase(EquipLocation.Accessory, ItemType.Accessory)]
[TestCase(EquipLocation.Armlet1, ItemType.Armlet)]
[TestCase(EquipLocation.Armor, ItemType.Armor)]
[TestCase(EquipLocation.Belt, ItemType.Belt)]
[TestCase(EquipLocation.Boots, ItemType.Boots)]
[TestCase(EquipLocation.Bracer1, ItemType.Bracer)]
[TestCase(EquipLocation.Gloves, ItemType.Gloves)]
[TestCase(EquipLocation.Hat, ItemType.Hat)]
[TestCase(EquipLocation.Necklace, ItemType.Necklace)]
[TestCase(EquipLocation.Ring1, ItemType.Ring)]
[TestCase(EquipLocation.Shield, ItemType.Shield)]
[TestCase(EquipLocation.Weapon, ItemType.Weapon)]
public void GetEquipLocation_Matches_ItemType(EquipLocation equipLocation, ItemType itemType)
{
Assert.That(WithItemType(itemType).GetEquipLocation(), Is.EqualTo(equipLocation));
}

[TestCase(ItemType.Beer)]
[TestCase(ItemType.CureCurse)]
[TestCase(ItemType.EXPReward)]
[TestCase(ItemType.EffectPotion)]
[TestCase(ItemType.HairDye)]
[TestCase(ItemType.Heal)]
[TestCase(ItemType.Key)]
[TestCase(ItemType.Money)]
[TestCase(ItemType.SkillReward)]
[TestCase(ItemType.StatReward)]
[TestCase(ItemType.Static)]
[TestCase(ItemType.Teleport)]
[TestCase(ItemType.UnknownType1)]
public void GetEquipLocation_Unsupported_ReturnsPaperdollMax(ItemType type)
{
Assert.That(WithItemType(type).GetEquipLocation(), Is.EqualTo(EquipLocation.PAPERDOLL_MAX));
}

private static EIFRecord WithItemType(ItemType type) => (EIFRecord)new EIFRecord().WithProperty(PubRecordProperty.ItemType, (int)type);
}
}

0 comments on commit e3af7b3

Please sign in to comment.