Update to latest pkmnlib, adds LearnedMove wrapper
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Deukhoofd 2023-01-03 13:57:29 +01:00
parent cc2468c1d0
commit 6c0e56ba1e
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
15 changed files with 332 additions and 61 deletions

View File

@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FFI/@EntryIndexedValue">FFI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HP/@EntryIndexedValue">HP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PP/@EntryIndexedValue">PP</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pkmn/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,72 @@
using PkmnLibSharp.StaticData;
using PkmnLibSharp.Utils;
using Interface = PkmnLibSharp.FFI.DynamicData.LearnedMove;
namespace PkmnLibSharp.DynamicData
{
public class LearnedMove : ExternPointer<LearnedMove.CacheData>
{
public class CacheData
{
public MoveData? MoveData { get; internal set; }
public MoveLearnMethod? LearnMethod { get; internal set; }
}
public LearnedMove(MoveData moveData, MoveLearnMethod learnMethod)
{
InitializePointer(Interface.learned_move_new(moveData.Ptr, learnMethod), true);
}
/// <summary>
/// The immutable move information of the move.
/// </summary>
public MoveData MoveData => Cache.MoveData ??= new MoveData(Interface.learned_move_move_data(Ptr), true);
/// <summary>
/// The maximal power points for this move.
/// </summary>
public byte MaxPP => Interface.learned_move_max_pp(Ptr);
/// <summary>
/// The amount of remaining power points. If this is 0, we can not use the move anymore.
/// </summary>
public byte RemainingPP => Interface.learned_move_remaining_pp(Ptr);
/// <summary>
/// The way the move was learned.
/// </summary>
public MoveLearnMethod LearnMethod => Cache.LearnMethod ??= Interface.learned_move_learn_method(Ptr);
/// <summary>
/// Try and reduce the PP by a certain amount. If the amount is higher than the current remaining uses,
/// return false. Otherwise, reduce the PP, and return true.
/// </summary>
public bool TryUse(byte amount) => Interface.learned_move_try_use(Ptr, amount) == 1;
/// <summary>
/// Set the remaining PP to the max amount of PP.
/// </summary>
public void RestoreAllUses() => Interface.learned_move_restore_all_uses(Ptr);
/// <summary>
/// Restore the remaining PP by a certain amount. Will prevent it from going above max PP.
/// </summary>
public void RestoreUses(byte amount) => Interface.learned_move_restore_uses(Ptr, amount);
protected override CacheData CreateCache() => new();
protected override void Destructor() => Interface.learned_move_drop(Ptr);
~LearnedMove()
{
Dispose();
}
}
public enum MoveLearnMethod : byte
{
/// We do not know the learn method.
Unknown = 0,
/// The move was learned through level up.
Level = 1,
}
}

View File

@ -0,0 +1,64 @@
using System;
using System.Runtime.InteropServices;
using PkmnLibSharp.DynamicData;
namespace PkmnLibSharp.FFI.DynamicData
{
internal static class LearnedMove
{
/// <summary>
/// Instantiate a new learned move.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer learned_move_new(IntPtr move, MoveLearnMethod learnMethod);
/// <summary>
/// Drops a learned move.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void learned_move_drop(IntPtr value);
/// <summary>
/// The immutable move information of the move.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer learned_move_move_data(IntPtr value);
/// <summary>
/// The maximal power points for this move.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte learned_move_max_pp(IntPtr value);
/// <summary>
/// The amount of remaining power points. If this is 0, we can not use the move anymore.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte learned_move_remaining_pp(IntPtr value);
/// <summary>
/// The way the move was learned.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern MoveLearnMethod learned_move_learn_method(IntPtr value);
/// <summary>
/// Try and reduce the PP by a certain amount. If the amount is higher than the current uses,
/// return 0. Otherwise, reduce the PP, and return 1.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte learned_move_try_use(IntPtr value, byte amount);
/// <summary>
/// Set the remaining PP to the max amount of PP.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void learned_move_restore_all_uses(IntPtr value);
/// <summary>
/// Restore the remaining PP by a certain amount. Will prevent it from going above max PP.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void learned_move_restore_uses(IntPtr value, byte amount);
}
}

View File

@ -6,7 +6,9 @@ namespace PkmnLibSharp.FFI.StaticData.Libraries
internal static class StaticData
{
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer static_data_new(IntPtr settings);
internal static extern IdentifiablePointer static_data_new(IntPtr settings, IntPtr speciesLibrary,
IntPtr moveLibrary, IntPtr itemLibrary, IntPtr growthRateLibrary, IntPtr typeLibrary, IntPtr natureLibrary,
IntPtr abilityLibrary);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void static_data_drop(IntPtr ptr);

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<RootNamespace>PkmnLibSharp</RootNamespace>
<LangVersion>9</LangVersion>
<LangVersion>11</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>

View File

@ -15,8 +15,7 @@ namespace PkmnLibSharp.StaticData
{
public string? Name { get; internal set; }
public string? Effect { get; internal set; }
public ulong? ParameterLength { get; internal set; }
public EffectParameter?[]? Parameters { get; internal set; }
public DisposableCachedExternArray<EffectParameter>? Parameters { get; internal set; }
}
public Ability(string name, string effect, IReadOnlyCollection<EffectParameter> parameters)
@ -36,20 +35,12 @@ namespace PkmnLibSharp.StaticData
public string Name => Cache.Name ?? (Cache.Name = Interface.ability_name(Ptr));
public string Effect => Cache.Effect ?? (Cache.Effect = Interface.ability_effect(Ptr));
public ulong ParameterLength =>
Cache.ParameterLength ?? (Cache.ParameterLength = Interface.ability_parameter_length(Ptr)).Value;
public EffectParameter GetParameter(int index)
{
Cache.Parameters ??= new EffectParameter[ParameterLength];
if (Cache.Parameters[index] == null)
{
var ptr = Interface.ability_parameter_get(Ptr, (ulong)index);
Cache.Parameters[index] = new EffectParameter(ptr, false);
}
return Cache.Parameters[index]!;
}
public IReadOnlyList<EffectParameter> Parameters =>
Cache.Parameters ??= new DisposableCachedExternArray<EffectParameter>(
Interface.ability_parameter_length(Ptr),
#pragma warning disable IDISP012
arg => new EffectParameter(Interface.ability_parameter_get(Ptr, arg), false));
#pragma warning restore IDISP012
protected override CacheData CreateCache()
@ -65,12 +56,13 @@ namespace PkmnLibSharp.StaticData
public override void InvalidateChildren()
{
if (Cache.Parameters == null) return;
foreach (var cacheParameter in Cache.Parameters)
for (var index = 0; index < Cache.Parameters.Count; index++)
{
cacheParameter?.Invalidate();
Cache.Parameters.GetCachedValue(index)?.Invalidate();
}
Cache.Parameters.Dispose();
}
~Ability()
{
Dispose();

View File

@ -1,13 +1,13 @@
using System;
using PkmnLibSharp.FFI;
using PkmnLibSharp.Utils;
using Interface = PkmnLibSharp.FFI.StaticData.Libraries.ItemLibrary;
using Interface = PkmnLibSharp.FFI.StaticData.Libraries.AbilityLibrary;
namespace PkmnLibSharp.StaticData.Libraries
{
public class AbilityLibrary : DataLibrary<Ability>
{
public AbilityLibrary(ulong capacity) : base(Interface.item_library_new(capacity), true)
public AbilityLibrary(ulong capacity) : base(Interface.ability_library_new(capacity), true)
{
}
@ -15,21 +15,21 @@ namespace PkmnLibSharp.StaticData.Libraries
{
}
protected override void Destructor() => Interface.item_library_drop(Ptr);
protected override void Destructor() => Interface.ability_library_drop(Ptr);
public override void Add(string key, Ability value) =>
Interface.item_library_add(Ptr, key.ToPtr(), value.TakeOwnershipAndInvalidate());
Interface.ability_library_add(Ptr, key.ToPtr(), value.TakeOwnershipAndInvalidate());
public override int Count => (int)Interface.item_library_len(Ptr);
public override int Count => (int)Interface.ability_library_len(Ptr);
protected override Ability? GetValueByKey(string key)
{
var ptr = Interface.item_library_get(Ptr, key.ToPtr());
var ptr = Interface.ability_library_get(Ptr, key.ToPtr());
return ptr.Ptr == IntPtr.Zero ? null : new Ability(ptr, false);
}
public override string? GetKeyByIndex(ulong index) =>
Interface.item_library_get_key_by_index(Ptr, index).PtrString();
Interface.ability_library_get_key_by_index(Ptr, index).PtrString();
public override void InvalidateChildren()
{

View File

@ -18,8 +18,14 @@ namespace PkmnLibSharp.StaticData.Libraries
public AbilityLibrary? AbilityLibrary { get; internal set; }
}
public StaticData(LibrarySettings settings) : base(
Interface.static_data_new(settings.TakeOwnershipAndInvalidate()), true)
public StaticData(LibrarySettings settings, SpeciesLibrary speciesLibrary, MoveLibrary moveLibrary,
ItemLibrary itemLibrary, GrowthRateLibrary growthRateLibrary, TypeLibrary typeLibrary,
NatureLibrary natureLibrary, AbilityLibrary abilityLibrary) : base(
Interface.static_data_new(settings.TakeOwnershipAndInvalidate(),
speciesLibrary.TakeOwnershipAndInvalidate(), moveLibrary.TakeOwnershipAndInvalidate(),
itemLibrary.TakeOwnershipAndInvalidate(), growthRateLibrary.TakeOwnershipAndInvalidate(),
typeLibrary.TakeOwnershipAndInvalidate(), natureLibrary.TakeOwnershipAndInvalidate(),
abilityLibrary.TakeOwnershipAndInvalidate()), true)
{
}
@ -64,7 +70,7 @@ namespace PkmnLibSharp.StaticData.Libraries
Cache.NatureLibrary?.Invalidate();
Cache.AbilityLibrary?.Invalidate();
}
~StaticData()
{
Dispose();

View File

@ -13,7 +13,7 @@ namespace PkmnLibSharp.StaticData
{
public float? Chance { get; internal set; }
public string? Name { get; internal set; }
public CachedExternArray<EffectParameter>? Parameters { get; internal set; }
public DisposableCachedExternArray<EffectParameter>? Parameters { get; internal set; }
}
internal SecondaryEffect(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner)
@ -34,7 +34,8 @@ namespace PkmnLibSharp.StaticData
public IReadOnlyList<EffectParameter> GetParameters()
{
return Cache.Parameters ??= new CachedExternArray<EffectParameter>(Interface.secondary_effect_parameter_length(Ptr),
return Cache.Parameters ??= new DisposableCachedExternArray<EffectParameter>(
Interface.secondary_effect_parameter_length(Ptr),
arg => new EffectParameter(Interface.secondary_effect_parameter_get(Ptr, arg), false));
}
@ -57,9 +58,10 @@ namespace PkmnLibSharp.StaticData
{
Cache.Parameters.GetCachedValue(index)?.Invalidate();
}
Cache.Parameters.Dispose();
}
}
~SecondaryEffect()
{
Dispose();

View File

@ -5,7 +5,59 @@ using System.Runtime.CompilerServices;
namespace PkmnLibSharp.Utils
{
public class CachedExternArray<T> : IReadOnlyList<T>
public sealed class DisposableCachedExternArray<T> : IReadOnlyList<T>, IDisposable
where T: class, IDisposable
{
private readonly T?[] _array;
private readonly Func<ulong, T> _getItem;
public DisposableCachedExternArray(ulong size, Func<ulong, T> getItem)
{
_array = new T?[(int)size];
_getItem = getItem;
}
public IEnumerator<T> GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
yield return this[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count => _array.Length;
public T this[int index]
{
get
{
if (index >= _array.Length)
throw new ArgumentOutOfRangeException(
$"Index {index} was outside of the bounds of the external array with length {Count}");
return _array[index] ??= _getItem((ulong)index);
}
}
internal T? GetCachedValue(int i)
{
return _array[i];
}
public void Dispose()
{
foreach (var item in _array)
{
item?.Dispose();
}
}
}
public sealed class CachedExternArray<T> : IReadOnlyList<T>
where T: class
{
private readonly T?[] _array;
@ -48,6 +100,7 @@ namespace PkmnLibSharp.Utils
return _array[i];
}
}
public class CachedExternValueArray<T> : IReadOnlyList<T>
where T: struct

BIN
PkmnLibRSharp/libpkmn_lib.so (Stored with Git LFS)

Binary file not shown.

View File

@ -0,0 +1,72 @@
using System;
using NUnit.Framework;
using PkmnLibSharp.DynamicData;
using PkmnLibSharp.StaticData;
namespace PkmnLibRSharpTests.DynamicData
{
public class LearnedMoveTests
{
[Test]
public void LearnedMoveMoveData()
{
using var moveData = new MoveData("foo", new TypeIdentifier(0), MoveCategory.Physical, 100, 20, 30,
MoveTarget.All, 0, null, Array.Empty<string>());
using var learnedMove = new LearnedMove(moveData, MoveLearnMethod.Level);
Assert.AreEqual("foo", learnedMove.MoveData.Name);
}
[Test]
public void LearnedMoveMaxPP()
{
using var moveData = new MoveData("foo", new TypeIdentifier(0), MoveCategory.Physical, 100, 20, 30,
MoveTarget.All, 0, null, Array.Empty<string>());
using var learnedMove = new LearnedMove(moveData, MoveLearnMethod.Level);
Assert.AreEqual(30, learnedMove.MaxPP);
}
[Test]
public void LearnedMoveRemainingPP()
{
using var moveData = new MoveData("foo", new TypeIdentifier(0), MoveCategory.Physical, 100, 20, 30,
MoveTarget.All, 0, null, Array.Empty<string>());
using var learnedMove = new LearnedMove(moveData, MoveLearnMethod.Level);
Assert.IsTrue(learnedMove.TryUse(1));
Assert.AreEqual(29, learnedMove.RemainingPP);
}
[Test]
public void LearnedMoveLearnMethod()
{
using var moveData = new MoveData("foo", new TypeIdentifier(0), MoveCategory.Physical, 100, 20, 30,
MoveTarget.All, 0, null, Array.Empty<string>());
using var learnedMove = new LearnedMove(moveData, MoveLearnMethod.Level);
Assert.AreEqual(MoveLearnMethod.Level, learnedMove.LearnMethod);
}
[Test]
public void LearnedMoveRestoreAllUses()
{
using var moveData = new MoveData("foo", new TypeIdentifier(0), MoveCategory.Physical, 100, 20, 30,
MoveTarget.All, 0, null, Array.Empty<string>());
using var learnedMove = new LearnedMove(moveData, MoveLearnMethod.Level);
Assert.IsTrue(learnedMove.TryUse(15));
Assert.AreEqual(15, learnedMove.RemainingPP);
learnedMove.RestoreAllUses();
Assert.AreEqual(30, learnedMove.RemainingPP);
}
[Test]
public void LearnedMoveRestoreUses()
{
using var moveData = new MoveData("foo", new TypeIdentifier(0), MoveCategory.Physical, 100, 20, 30,
MoveTarget.All, 0, null, Array.Empty<string>());
using var learnedMove = new LearnedMove(moveData, MoveLearnMethod.Level);
Assert.IsTrue(learnedMove.TryUse(15));
Assert.AreEqual(15, learnedMove.RemainingPP);
learnedMove.RestoreUses(5);
Assert.AreEqual(20, learnedMove.RemainingPP);
}
}
}

View File

@ -1,10 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<LangVersion>11</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

View File

@ -25,14 +25,14 @@ namespace PkmnLibRSharpTests.StaticData
{
using var ability = new Ability("", "",
new EffectParameter[] { new(100), new(false), new("foobar"), new(true) });
Assert.AreEqual(4, ability.ParameterLength);
using var p1 = ability.GetParameter(0);
Assert.AreEqual(4, ability.Parameters.Count);
var p1 = ability.Parameters[0];
Assert.AreEqual(100, p1.Data);
using var p2 = ability.GetParameter(1);
var p2 = ability.Parameters[1];
Assert.AreEqual(false, p2.Data);
using var p3 = ability.GetParameter(2);
var p3 = ability.Parameters[2];
Assert.AreEqual("foobar", p3.Data);
using var p4 = ability.GetParameter(3);
var p4 = ability.Parameters[3];
Assert.AreEqual(true, p4.Data);
}
}

View File

@ -5,74 +5,79 @@ namespace PkmnLibRSharpTests.StaticData.Libraries
{
public class StaticDataTests
{
private PkmnLibSharp.StaticData.Libraries.StaticData Build()
{
using var settings = new LibrarySettings(100);
using var species = new SpeciesLibrary(0);
using var moves = new MoveLibrary(0);
using var items = new ItemLibrary(0);
using var growthRates = new GrowthRateLibrary(0);
using var types = new TypeLibrary(0);
using var natures = new NatureLibrary(0);
using var abilities = new AbilityLibrary(0);
return new PkmnLibSharp.StaticData.Libraries.StaticData(settings, species, moves, items,
growthRates, types, natures, abilities);
}
[Test]
public void CreateNewStaticData()
{
using var settings = new LibrarySettings(100);
using var library = new PkmnLibSharp.StaticData.Libraries.StaticData(settings);
using var _ = Build();
}
[Test]
public void GetSettings()
{
using var settings = new LibrarySettings(100);
using var library = new PkmnLibSharp.StaticData.Libraries.StaticData(settings);
using var library = Build();
var _ = library.LibrarySettings;
}
[Test]
public void GetSpecies()
{
using var settings = new LibrarySettings(100);
using var library = new PkmnLibSharp.StaticData.Libraries.StaticData(settings);
using var library = Build();
var _ = library.SpeciesLibrary;
}
[Test]
public void GetMoves()
{
using var settings = new LibrarySettings(100);
using var library = new PkmnLibSharp.StaticData.Libraries.StaticData(settings);
using var library = Build();
var _ = library.MoveLibrary;
}
[Test]
public void GetItems()
{
using var settings = new LibrarySettings(100);
using var library = new PkmnLibSharp.StaticData.Libraries.StaticData(settings);
using var library = Build();
var _ = library.ItemLibrary;
}
[Test]
public void GetGrowthRates()
{
using var settings = new LibrarySettings(100);
using var library = new PkmnLibSharp.StaticData.Libraries.StaticData(settings);
using var library = Build();
var _ = library.GrowthRateLibrary;
}
[Test]
public void GetTypeLibrary()
{
using var settings = new LibrarySettings(100);
using var library = new PkmnLibSharp.StaticData.Libraries.StaticData(settings);
using var library = Build();
var _ = library.TypeLibrary;
}
[Test]
public void GetNatureLibrary()
{
using var settings = new LibrarySettings(100);
using var library = new PkmnLibSharp.StaticData.Libraries.StaticData(settings);
using var library = Build();
var _ = library.NatureLibrary;
}
[Test]
public void GetAbilityLibrary()
{
using var settings = new LibrarySettings(100);
using var library = new PkmnLibSharp.StaticData.Libraries.StaticData(settings);
using var library = Build();
var _ = library.AbilityLibrary;
}
}