Implements Form foreign interface
This commit is contained in:
parent
8bb62aa260
commit
c8be93f83f
|
@ -0,0 +1,57 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using PkmnLibSharp.StaticData;
|
||||||
|
|
||||||
|
namespace PkmnLibSharp.FFI.StaticData
|
||||||
|
{
|
||||||
|
internal static class Form
|
||||||
|
{
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern IntPtr form_new(IntPtr name, float height, float weight, uint baseExperience,
|
||||||
|
IntPtr types, ulong typesLength, IntPtr baseStats, IntPtr abilities, ulong abilitiesLength,
|
||||||
|
IntPtr hiddenAbilities, ulong hiddenAbilitiesLength, IntPtr learnableMoves, IntPtr flags,
|
||||||
|
ulong flagsLength);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern void form_drop(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern IntPtr form_name(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern float form_height(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern float form_weight(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern uint form_base_experience(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern ulong form_types_length(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern TypeIdentifier form_types_get(IntPtr ptr, ulong index);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern IntPtr form_base_stats(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern ulong form_abilities_length(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern IntPtr form_abilities_get(IntPtr ptr, ulong index);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern ulong form_hidden_abilities_length(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern IntPtr form_hidden_abilities_get(IntPtr ptr, ulong index);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern IntPtr form_moves(IntPtr ptr);
|
||||||
|
|
||||||
|
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern byte form_has_flag(IntPtr ptr, IntPtr flag);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<RootNamespace>PkmnLibSharp</RootNamespace>
|
<RootNamespace>PkmnLibSharp</RootNamespace>
|
||||||
<LangVersion>8</LangVersion>
|
<LangVersion>9</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using PkmnLibSharp.Utils;
|
||||||
|
using Interface = PkmnLibSharp.FFI.StaticData.Form;
|
||||||
|
|
||||||
|
namespace PkmnLibSharp.StaticData
|
||||||
|
{
|
||||||
|
public class Form : ExternPointer<Form.CacheData>
|
||||||
|
{
|
||||||
|
public class CacheData
|
||||||
|
{
|
||||||
|
public string? Name { get; internal set; }
|
||||||
|
public float? Height { get; internal set; }
|
||||||
|
public float? Weight { get; internal set; }
|
||||||
|
public uint? BaseExperience { get; internal set; }
|
||||||
|
public ulong? TypesLength { get; internal set; }
|
||||||
|
public CachedExternValueArray<TypeIdentifier>? Types { get; internal set; }
|
||||||
|
public StaticStatisticSet<ushort>? BaseStats { get; internal set; }
|
||||||
|
public CachedExternArray<string>? Abilities { get; internal set; }
|
||||||
|
public CachedExternArray<string>? HiddenAbilities { get; internal set; }
|
||||||
|
public LearnableMoves? LearnableMoves { get; internal set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Form(string name, float height, float weight, uint baseExperience, TypeIdentifier[] types,
|
||||||
|
StaticStatisticSet<short> baseStats, IReadOnlyCollection<string> abilities,
|
||||||
|
IReadOnlyCollection<string> hiddenAbilities, LearnableMoves learnableMoves,
|
||||||
|
IReadOnlyCollection<string> flags)
|
||||||
|
{
|
||||||
|
var typesArr = types.ArrayPtr();
|
||||||
|
|
||||||
|
var abilitiesPtrArray = abilities.Select(x => x.ToPtr()).ToArray();
|
||||||
|
var hiddenAbilitiesPtrArray = hiddenAbilities.Select(x => x.ToPtr()).ToArray();
|
||||||
|
var flagsPtrArray = flags.Select(x => x.ToPtr()).ToArray();
|
||||||
|
|
||||||
|
var ptr = Interface.form_new(name.ToPtr(), height, weight, baseExperience, typesArr, (ulong)types.Length,
|
||||||
|
baseStats.TakeOwnershipAndInvalidate(), abilitiesPtrArray.ArrayPtr(), (ulong)abilities.Count,
|
||||||
|
hiddenAbilitiesPtrArray.ArrayPtr(), (ulong)hiddenAbilities.Count,
|
||||||
|
learnableMoves.TakeOwnershipAndInvalidate(), flagsPtrArray.ArrayPtr(), (ulong)flags.Count);
|
||||||
|
InitializePointer(ptr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name => Cache.Name ??= Interface.form_name(Ptr).PtrString()!;
|
||||||
|
public float Height => Cache.Height ??= Interface.form_height(Ptr);
|
||||||
|
public float Weight => Cache.Weight ??= Interface.form_weight(Ptr);
|
||||||
|
public uint BaseExperience => Cache.BaseExperience ??= Interface.form_base_experience(Ptr);
|
||||||
|
|
||||||
|
public IReadOnlyList<TypeIdentifier> Types =>
|
||||||
|
Cache.Types ??= new CachedExternValueArray<TypeIdentifier>(Interface.form_types_length(Ptr),
|
||||||
|
arg => Interface.form_types_get(Ptr, arg));
|
||||||
|
|
||||||
|
public StaticStatisticSet<ushort> BaseStats =>
|
||||||
|
Cache.BaseStats ??= new StaticStatisticSet<ushort>(Interface.form_base_stats(Ptr), false);
|
||||||
|
|
||||||
|
public IReadOnlyList<string> Abilities =>
|
||||||
|
Cache.Abilities ??= new CachedExternArray<string>(Interface.form_abilities_length(Ptr),
|
||||||
|
arg => Interface.form_abilities_get(Ptr, arg).PtrString()!);
|
||||||
|
|
||||||
|
public IReadOnlyList<string> HiddenAbilities =>
|
||||||
|
Cache.HiddenAbilities ??= new CachedExternArray<string>(Interface.form_hidden_abilities_length(Ptr),
|
||||||
|
arg => Interface.form_hidden_abilities_get(Ptr, arg).PtrString()!);
|
||||||
|
|
||||||
|
public LearnableMoves LearnableMoves =>
|
||||||
|
Cache.LearnableMoves ??= new LearnableMoves(Interface.form_moves(Ptr), false);
|
||||||
|
|
||||||
|
|
||||||
|
protected override CacheData CreateCache() => new CacheData();
|
||||||
|
|
||||||
|
protected override void Destructor() => Interface.form_drop(Ptr);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using PkmnLibSharp.Utils;
|
using PkmnLibSharp.Utils;
|
||||||
using Interface = PkmnLibSharp.FFI.StaticData.LearnableMoves;
|
using Interface = PkmnLibSharp.FFI.StaticData.LearnableMoves;
|
||||||
using LevelInt = System.Byte;
|
using LevelInt = System.Byte;
|
||||||
|
@ -6,6 +7,10 @@ namespace PkmnLibSharp.StaticData
|
||||||
{
|
{
|
||||||
public class LearnableMoves : ExternPointer<object>
|
public class LearnableMoves : ExternPointer<object>
|
||||||
{
|
{
|
||||||
|
internal LearnableMoves(IntPtr ptr, bool isOwner) : base(ptr, isOwner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public LearnableMoves() : base(Interface.learnable_moves_new(), true)
|
public LearnableMoves() : base(Interface.learnable_moves_new(), true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,7 @@ namespace PkmnLibSharp.StaticData
|
||||||
{
|
{
|
||||||
public float? Chance { get; internal set; }
|
public float? Chance { get; internal set; }
|
||||||
public string? Name { get; internal set; }
|
public string? Name { get; internal set; }
|
||||||
public ulong? ParameterLength { get; internal set; }
|
public CachedExternArray<EffectParameter>? Parameters { get; internal set; }
|
||||||
public EffectParameter?[]? Parameters { get; internal set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal SecondaryEffect(IntPtr ptr, bool isOwner) : base(ptr, isOwner)
|
internal SecondaryEffect(IntPtr ptr, bool isOwner) : base(ptr, isOwner)
|
||||||
|
@ -32,20 +31,10 @@ namespace PkmnLibSharp.StaticData
|
||||||
public float Chance => Cache.Chance ??= Interface.secondary_effect_chance(Ptr);
|
public float Chance => Cache.Chance ??= Interface.secondary_effect_chance(Ptr);
|
||||||
public string Name => Cache.Name ?? (Cache.Name = Interface.secondary_effect_effect_name(Ptr).PtrString()!);
|
public string Name => Cache.Name ?? (Cache.Name = Interface.secondary_effect_effect_name(Ptr).PtrString()!);
|
||||||
|
|
||||||
public ulong ParameterLength =>
|
public IReadOnlyList<EffectParameter> Parameters =>
|
||||||
Cache.ParameterLength ?? (Cache.ParameterLength = Interface.secondary_effect_parameter_length(Ptr)).Value;
|
Cache.Parameters ??= new CachedExternArray<EffectParameter>(
|
||||||
|
Interface.secondary_effect_parameter_length(Ptr),
|
||||||
public EffectParameter GetParameter(int index)
|
arg => new EffectParameter(Interface.secondary_effect_parameter_get(Ptr, arg), false));
|
||||||
{
|
|
||||||
Cache.Parameters ??= new EffectParameter[ParameterLength];
|
|
||||||
if (Cache.Parameters[index] == null)
|
|
||||||
{
|
|
||||||
var ptr = Interface.secondary_effect_parameter_get(Ptr, (ulong)index);
|
|
||||||
Cache.Parameters[index] = new EffectParameter(ptr, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Cache.Parameters[index]!;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override CacheData CreateCache()
|
protected override CacheData CreateCache()
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,6 +17,10 @@ namespace PkmnLibSharp.StaticData
|
||||||
public T? Speed { get; internal set; }
|
public T? Speed { get; internal set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal StaticStatisticSet(IntPtr ptr, bool isOwner) : base(ptr, isOwner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public StaticStatisticSet(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed)
|
public StaticStatisticSet(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed)
|
||||||
{
|
{
|
||||||
var p = typeof(T) switch
|
var p = typeof(T) switch
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace PkmnLibSharp.StaticData
|
||||||
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
[FieldOffset(0)] private readonly byte _identifier;
|
[FieldOffset(0)] private readonly byte _identifier;
|
||||||
|
|
||||||
internal TypeIdentifier(byte b)
|
public TypeIdentifier(byte b)
|
||||||
{
|
{
|
||||||
_identifier = b;
|
_identifier = b;
|
||||||
}
|
}
|
||||||
|
@ -37,5 +37,10 @@ namespace PkmnLibSharp.StaticData
|
||||||
{
|
{
|
||||||
return !left.Equals(right);
|
return !left.Equals(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Type({_identifier})";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace PkmnLibSharp.Utils
|
||||||
|
{
|
||||||
|
public class CachedExternArray<T> : IReadOnlyList<T>
|
||||||
|
where T: class
|
||||||
|
{
|
||||||
|
private readonly T?[] _array;
|
||||||
|
private readonly Func<ulong, T> _getItem;
|
||||||
|
|
||||||
|
public CachedExternArray(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CachedExternValueArray<T> : IReadOnlyList<T>
|
||||||
|
where T: struct
|
||||||
|
{
|
||||||
|
private readonly T?[] _array;
|
||||||
|
private readonly Func<ulong, T> _getItem;
|
||||||
|
|
||||||
|
public CachedExternValueArray(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] => _array[index] ??= _getItem((ulong)index);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ namespace PkmnLibSharp.Utils
|
||||||
{
|
{
|
||||||
return Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
|
return Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
|
||||||
}
|
}
|
||||||
internal static IntPtr ArrayPtr<T>(this T[] a) where T : struct, IConvertible
|
internal static IntPtr ArrayPtr<T>(this T[] a) where T : struct
|
||||||
{
|
{
|
||||||
return Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
|
return Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using PkmnLibSharp.StaticData;
|
||||||
|
|
||||||
|
namespace PkmnLibRSharpTests.StaticData
|
||||||
|
{
|
||||||
|
public class FormTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void BasicTests()
|
||||||
|
{
|
||||||
|
using var form = new Form("foobar", 0.2f, 5.8f, 300, new TypeIdentifier[] { new(1), new(2) },
|
||||||
|
new StaticStatisticSet<short>(5, 10, 30, 20, 2, 0), new[] { "foo", "bar" }, new[] { "set" },
|
||||||
|
new LearnableMoves(), Array.Empty<string>());
|
||||||
|
Assert.AreEqual("foobar", form.Name);
|
||||||
|
Assert.AreEqual(0.2f, form.Height, 0.00001f);
|
||||||
|
Assert.AreEqual(5.8f, form.Weight, 0.00001f);
|
||||||
|
Assert.AreEqual(300, form.BaseExperience);
|
||||||
|
Assert.AreEqual(new TypeIdentifier(1), form.Types[0]);
|
||||||
|
Assert.AreEqual(new TypeIdentifier(2), form.Types[1]);
|
||||||
|
Assert.AreEqual(10, form.BaseStats.Attack);
|
||||||
|
Assert.AreEqual("foo", form.Abilities[0]);
|
||||||
|
Assert.AreEqual("bar", form.Abilities[1]);
|
||||||
|
Assert.AreEqual("set", form.HiddenAbilities[0]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue