Skip to content

Commit

Permalink
Merge pull request #26 from ewrogers/fs-fix
Browse files Browse the repository at this point in the history
Fs fix
  • Loading branch information
ewrogers authored Jun 22, 2023
2 parents ab501cb + 3734399 commit b0ef165
Show file tree
Hide file tree
Showing 17 changed files with 246 additions and 62 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ All notable changes to this library will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [4.8.1] - 2023-06-22

### Added

- Gold display to inventory (last slot)
- `Features` tab for client-specific feature options (per-character)
- Feature flag support for client-specific functionality in `ClientVersion` definitions

### Changed

- Client version `7.41` is now renamed `USDA 7.41` for clarity

### Fixed

- Fas spiorad bugs (needlessly cast at low mana)
- Better spellbook cooldown updates

## [4.8.0] - 2023-06-21

### Added
Expand Down
6 changes: 6 additions & 0 deletions SleepHunter/IO/Process/MemoryVariableExtender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ public static long DereferencePointer(long address, BinaryReader reader)
return reference;
}

public static bool TryDeferenceValue(this MemoryVariable variable, BinaryReader reader, out long address, bool isStringType = false)
{
address = DereferenceValue(variable, reader, isStringType);
return address != 0;
}

public static long DereferenceValue(this MemoryVariable variable, BinaryReader reader, bool isStringType = false)
{
long address = variable.Address;
Expand Down
22 changes: 11 additions & 11 deletions SleepHunter/Macro/PlayerMacroState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -765,23 +765,23 @@ private bool FlowerNextAltWaitingForMana()

private bool ShouldFasSpiorad(int? manaRequirement = null)
{
client.Update(PlayerFieldFlags.Spellbook);
var useFasSpiorad = UserSettingsManager.Instance.Settings.UseFasSpiorad;
client.Update(PlayerFieldFlags.Spellbook | PlayerFieldFlags.Stats);
var autoFasSpiorad = UserSettingsManager.Instance.Settings.UseFasSpiorad;

if (!client.HasFasSpiorad)
return false;

if (useFasSpiorad || manaRequirement.HasValue)
// If auto-fas spiorad is enabled, check the threshold
if (autoFasSpiorad)
{
client.Update(PlayerFieldFlags.Stats);

if (client.Stats.HasFullMana)
return false;

if (client.Stats.CurrentMana < UserSettingsManager.Instance.Settings.FasSpioradThreshold)
return true;
}

// If the spell being cast has a mana requirement, check if fas-spiorad on demand
if (manaRequirement.HasValue)
{
if (UserSettingsManager.Instance.Settings.UseFasSpioradOnDemand && client.Stats.CurrentMana < manaRequirement.Value)
Expand Down Expand Up @@ -859,14 +859,14 @@ private SpellQueueItem GetNextSpell()
_ => null,
};

if (currentSpell == null)
return null;

// Determine if we need to fas spiorad instead
if (currentSpell != null)
{
var currentSpellData = SpellMetadataManager.Instance.GetSpell(currentSpell.Name);
var currentSpellData = SpellMetadataManager.Instance.GetSpell(currentSpell.Name);

if (currentSpellData != null && ShouldFasSpiorad(currentSpellData.ManaCost))
return GetFasSpiorad();
}
if (currentSpellData != null && ShouldFasSpiorad(currentSpellData.ManaCost))
return GetFasSpiorad();

if (currentSpell.IsOnCooldown)
return null;
Expand Down
72 changes: 65 additions & 7 deletions SleepHunter/Models/Inventory.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,46 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;

using SleepHunter.Common;
using SleepHunter.Extensions;
using SleepHunter.IO.Process;

namespace SleepHunter.Models
{
public sealed class Inventory : IEnumerable<InventoryItem>
public sealed class Inventory : ObservableObject, IEnumerable<InventoryItem>
{
private const string InventoryKey = @"Inventory";
private const string GoldKey = @"Gold";

public static readonly int InventoryCount = 60;

private readonly List<InventoryItem> inventory = new(InventoryCount);
private int gold;

public event EventHandler InventoryUpdated;
public event EventHandler GoldChanged;

public Player Owner { get; }


public int Count => inventory.Count((item) => { return !item.IsEmpty; });

public IEnumerable<InventoryItem> AllItems => inventory;
public IEnumerable<InventoryItem> ItemsAndGold => inventory;

public int Gold
{
get => gold;
set => SetProperty(ref gold, value, nameof(Gold), (_) =>
{
UpdateGoldInventoryItem();
GoldChanged?.Invoke(this, EventArgs.Empty);
RaisePropertyChanged(nameof(ItemsAndGold));
});
}

public IEnumerable<string> ItemNames =>
from i in inventory where !i.IsEmpty && !string.IsNullOrWhiteSpace(i.Name) select i.Name;
Expand All @@ -41,6 +57,8 @@ private void InitializeInventory()

for (int i = 0; i < inventory.Capacity; i++)
inventory.Add(InventoryItem.MakeEmpty(i + 1));

UpdateGoldInventoryItem();
}

public InventoryItem GetItem(string itemName)
Expand Down Expand Up @@ -76,7 +94,7 @@ public void Update(ProcessMemoryAccessor accessor)
if (accessor == null)
throw new ArgumentNullException(nameof(accessor));

var version = this.Owner.Version;
var version = Owner.Version;

if (version == null)
{
Expand All @@ -103,9 +121,9 @@ public void Update(ProcessMemoryAccessor accessor)
}

reader.BaseStream.Position = inventoryPointer;

for (int i = 0; i < inventoryVariable.Count; i++)

// Gold is the last item, skip it
for (int i = 0; i < inventoryVariable.Count - 1; i++)
{
try
{
Expand All @@ -121,6 +139,44 @@ public void Update(ProcessMemoryAccessor accessor)
}
catch { }
}

UpdateGold(accessor);
}

private void UpdateGold(ProcessMemoryAccessor accessor)
{
if (accessor == null)
throw new ArgumentNullException(nameof(accessor));

var version = Owner.Version;

if (version == null)
{
ResetDefaults();
return;
}

if (!version.TryGetVariable(GoldKey, out var goldVariable))
{
Gold = 0;
return;
}

using var stream = accessor.GetStream();
using var reader = new BinaryReader(stream, Encoding.ASCII);

if (goldVariable.TryReadUInt32(reader, out var goldValue))
Gold = (int)goldValue;
else
Gold = 0;

UpdateGoldInventoryItem();
}

private void UpdateGoldInventoryItem()
{
inventory[InventoryCount - 1].IsEmpty = false;
inventory[InventoryCount - 1].Name = $"Gold ({Gold:n0})";
}

public void ResetDefaults()
Expand All @@ -130,6 +186,8 @@ public void ResetDefaults()
inventory[i].IsEmpty = true;
inventory[i].Name = null;
}

Gold = 0;
}

public IEnumerator<InventoryItem> GetEnumerator()
Expand Down
2 changes: 1 addition & 1 deletion SleepHunter/Models/InventoryItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public string Name
set => SetProperty(ref name, value, nameof(Name), (_) => RaisePropertyChanged(nameof(DisplayName)));
}

public string DisplayName => ColorTextRegex.Replace(Name, string.Empty);
public string DisplayName => ColorTextRegex.Replace(Name ?? string.Empty, string.Empty);

public int Quantity
{
Expand Down
2 changes: 1 addition & 1 deletion SleepHunter/Models/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace SleepHunter.Models
public sealed class Player : ObservableObject, IDisposable
{
private const string CharacterNameKey = @"CharacterName";

private bool isDisposed;
private ClientVersion version;
private readonly ProcessMemoryAccessor accessor;
Expand Down
42 changes: 31 additions & 11 deletions SleepHunter/Models/Spellbook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ public void Update(ProcessMemoryAccessor accessor)
if (version == null)
{
ResetDefaults();
UpdateCooldowns();
return;
}

Expand All @@ -135,6 +136,7 @@ public void Update(ProcessMemoryAccessor accessor)
if (spellbookVariable == null)
{
ResetDefaults();
UpdateCooldowns();
return;
}

Expand All @@ -146,6 +148,7 @@ public void Update(ProcessMemoryAccessor accessor)
if (spellbookPointer == 0)
{
ResetDefaults();
UpdateCooldowns();
return;
}

Expand Down Expand Up @@ -206,24 +209,15 @@ public void Update(ProcessMemoryAccessor accessor)
spells[i].Cooldown = TimeSpan.Zero;
spells[i].CanImprove = true;
}

spells[i].IsOnCooldown = false;

// NOTE: Spell cooldowns are not read from the client, instead they are internal timers
// Probably not ideal, but haven't taken the time to see if memory laid out the same as skills
DateTime timestamp = DateTime.MinValue;
if (spells[i].Cooldown > TimeSpan.Zero && spellCooldownTimestamps.TryGetValue(name, out timestamp))
{
var elapsed = DateTime.Now - timestamp;
spells[i].IsOnCooldown = elapsed < (spells[i].Cooldown + TimeSpan.FromMilliseconds(500));
}
}
catch { }
}

Owner.HasFasSpiorad = foundFasSpiorad;
Owner.HasLyliacPlant = foundLyliacPlant;
Owner.HasLyliacVineyard = foundLyliacVineyard;

UpdateCooldowns();
}

public void ResetDefaults()
Expand All @@ -234,6 +228,7 @@ public void ResetDefaults()
{
spells[i].IsEmpty = true;
spells[i].Name = null;
spells[i].IsOnCooldown = false;
}
}

Expand All @@ -245,5 +240,30 @@ public IEnumerator<Spell> GetEnumerator()
}

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

private void UpdateCooldowns()
{
for (var i = 0; i < spells.Capacity; i++)
{
var spellName = spells[i].Name;

if (spells[i].IsEmpty || string.IsNullOrWhiteSpace(spellName))
{
spells[i].IsOnCooldown = false;
continue;
}

if (!spellCooldownTimestamps.TryGetValue(spells[i].Name, out var lastUsedTimestamp))
{
spells[i].IsOnCooldown = false;
continue;
}

var cooldownTicks = spells[i].Cooldown.TotalSeconds * TimeSpan.TicksPerSecond;
var readyAtTicks = lastUsedTimestamp.Ticks + cooldownTicks;

spells[i].IsOnCooldown = readyAtTicks > DateTime.Now.Ticks;
}
}
}
}
20 changes: 11 additions & 9 deletions SleepHunter/Resources/Versions.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<ClientVersions>
<Clients>
<Client Key="7.41" IsDefault="true">
<Client Key="USDA 7.41" IsDefault="true">
<Signature Address="685B08" Value="7D4E--1K" />
<ExecutableName>Darkages.exe</ExecutableName>
<WindowClassName>DarkAges</WindowClassName>
Expand Down Expand Up @@ -66,6 +66,11 @@
<Offset Value="1092" />
</Offsets>
</Dynamic>
<Dynamic Key="Gold" Address="755AA4">
<Offsets>
<Offset Value="198" />
</Offsets>
</Dynamic>
<Dynamic Key="Equipment" Address="6FC914" MaxLength="128" Size="261" Count="18">
<Offsets>
<Offset Value="1152" />
Expand Down Expand Up @@ -133,6 +138,9 @@
<WindowClassName>DarkAges</WindowClassName>
<MultipleInstanceAddress>78D559</MultipleInstanceAddress>
<IntroVideoAddress>62F455</IntroVideoAddress>
<Features>
<FeatureFlag Key="UseWaterAndBeds" Enabled="true" />
</Features>
<Variables>
<Static Key="VersionNumber" Address="972288" />
<Static Key="CharacterName" Address="95F6E0" MaxLength="13" />
Expand Down Expand Up @@ -192,15 +200,9 @@
<Offset Value="1092" />
</Offsets>
</Dynamic>
<Dynamic Key="Equipment" Address="961A48" MaxLength="128" Size="261" Count="18">
<Dynamic Key="Gold" Address="977774">
<Offsets>
<Offset Value="14" />
<Offset Value="4" />
<Offset Value="FC" />
<Offset Value="0" />
<Offset Value="2C0" />
<Offset Value="46C" />
<Offset Value="670" />
<Offset Value="198" />
</Offsets>
</Dynamic>
<Dynamic Key="Skillbook" Address="AA3AE8" MaxLength="256" Size="260" Count="90">
Expand Down
Loading

0 comments on commit b0ef165

Please sign in to comment.