Initial work

This commit is contained in:
2022-09-18 18:02:27 +02:00
commit 097b2111aa
33 changed files with 1629 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
namespace PkmnLibSharp.FFI
{
internal static class Data
{
internal const string DllName = "pkmn_lib.so";
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Runtime.InteropServices;
namespace PkmnLibSharp.FFI.StaticData
{
internal static class Ability
{
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr ability_new(IntPtr name, IntPtr effect, IntPtr parameters, ulong size);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void ability_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern string ability_name(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern string ability_effect(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern ulong ability_parameter_length(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr ability_parameter_get(IntPtr value, ulong index);
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Runtime.InteropServices;
namespace PkmnLibSharp.FFI.StaticData
{
internal static class EffectParameter
{
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr effect_parameter_new_bool(byte value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr effect_parameter_new_int(long value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr effect_parameter_new_float(float value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr effect_parameter_new_string(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void effect_parameter_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern byte effect_parameter_get_type(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern byte effect_parameter_get_as_bool(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern long effect_parameter_get_as_int(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern float effect_parameter_get_as_float(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr effect_parameter_get_as_string(IntPtr value);
}
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Runtime.InteropServices;
using PkmnLibSharp.StaticData;
namespace PkmnLibSharp.FFI.StaticData
{
internal static class MoveData
{
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr move_data_new(IntPtr name, TypeIdentifier moveType, MoveCategory category,
byte basePower, byte accuracy, byte baseUsages, MoveTarget target, sbyte priority, IntPtr secondaryEffect,
IntPtr flags, ulong flagsLength);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void move_data_drop(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr move_data_name(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern TypeIdentifier move_data_move_type(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern MoveCategory move_data_category(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern byte move_data_base_power(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern byte move_data_accuracy(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern byte move_data_base_usages(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern MoveTarget move_data_target(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern sbyte move_data_priority(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr move_data_secondary_effect(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern byte move_data_has_flag(IntPtr p, IntPtr flag);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr secondary_effect_new(float chance, IntPtr effectName, IntPtr parameters,
ulong parametersLength);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void secondary_effect_drop(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern float secondary_effect_chance(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr secondary_effect_effect_name(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern ulong secondary_effect_parameter_length(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr secondary_effect_parameter_get(IntPtr p, ulong index);
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Runtime.InteropServices;
using PkmnLibSharp.StaticData;
namespace PkmnLibSharp.FFI.StaticData
{
internal static class Nature
{
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr nature_new(Statistic increaseStat, Statistic decreaseStat, float increaseModifier,
float decreaseModifier);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void nature_drop(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern Statistic nature_increased_stat(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern Statistic nature_decreased_stat(IntPtr p);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern float nature_get_stat_modifier(IntPtr p, Statistic statistic);
}
}

View File

@@ -0,0 +1,69 @@
using System;
using System.Runtime.InteropServices;
using PkmnLibSharp.StaticData;
namespace PkmnLibSharp.FFI.StaticData
{
internal static class StaticStatisticSet
{
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr static_statistic_set_u8_new(byte hp, byte attack, byte defense,
byte specialAttack, byte specialDefense, byte speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr static_statistic_set_u16_new(ushort hp, ushort attack, ushort defense,
ushort specialAttack, ushort specialDefense, ushort speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr static_statistic_set_u32_new(uint hp, uint attack, uint defense,
uint specialAttack, uint specialDefense, uint speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr static_statistic_set_i8_new(sbyte hp, sbyte attack, sbyte defense,
sbyte specialAttack, sbyte specialDefense, sbyte speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr static_statistic_set_i16_new(short hp, short attack, short defense,
short specialAttack, short specialDefense, short speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr static_statistic_set_i32_new(int hp, int attack, int defense, int specialAttack,
int specialDefense, int speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void static_statistic_set_u8_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void static_statistic_set_u16_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void static_statistic_set_u32_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void static_statistic_set_i8_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void static_statistic_set_i16_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void static_statistic_set_i32_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte static_statistic_set_u8_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern ushort static_statistic_set_u16_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern uint static_statistic_set_u32_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern sbyte static_statistic_set_i8_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern short static_statistic_set_i16_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern int static_statistic_set_i32_get_stat(IntPtr value, Statistic statistic);
}
}

View File

@@ -0,0 +1,125 @@
using System;
using System.Runtime.InteropServices;
using PkmnLibSharp.StaticData;
namespace PkmnLibSharp.FFI.StaticData
{
internal static class StatisticSet
{
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr statistic_set_u8_new(byte hp, byte attack, byte defense, byte specialAttack,
byte specialDefense, byte speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr statistic_set_u16_new(ushort hp, ushort attack, ushort defense,
ushort specialAttack, ushort specialDefense, ushort speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr statistic_set_u32_new(uint hp, uint attack, uint defense, uint specialAttack,
uint specialDefense, uint speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr statistic_set_i8_new(sbyte hp, sbyte attack, sbyte defense, sbyte specialAttack,
sbyte specialDefense, sbyte speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr statistic_set_i16_new(short hp, short attack, short defense, short specialAttack,
short specialDefense, short speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr statistic_set_i32_new(int hp, int attack, int defense, int specialAttack,
int specialDefense, int speed);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u8_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u16_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u32_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i8_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i16_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i32_drop(IntPtr value);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte statistic_set_u8_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern ushort statistic_set_u16_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern uint statistic_set_u32_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern sbyte statistic_set_i8_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern short statistic_set_i16_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern int statistic_set_i32_get_stat(IntPtr value, Statistic statistic);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u8_set_stat(IntPtr value, Statistic statistic, byte v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u16_set_stat(IntPtr value, Statistic statistic, ushort v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u32_set_stat(IntPtr value, Statistic statistic, uint v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i8_set_stat(IntPtr value, Statistic statistic, sbyte v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i16_set_stat(IntPtr value, Statistic statistic, short v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i32_set_stat(IntPtr value, Statistic statistic, int v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u8_increase_stat(IntPtr value, Statistic statistic, byte v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u16_increase_stat(IntPtr value, Statistic statistic, ushort v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u32_increase_stat(IntPtr value, Statistic statistic, uint v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i8_increase_stat(IntPtr value, Statistic statistic, sbyte v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i16_increase_stat(IntPtr value, Statistic statistic, short v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i32_increase_stat(IntPtr value, Statistic statistic, int v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u8_decrease_stat(IntPtr value, Statistic statistic, byte v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u16_decrease_stat(IntPtr value, Statistic statistic, ushort v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_u32_decrease_stat(IntPtr value, Statistic statistic, uint v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i8_decrease_stat(IntPtr value, Statistic statistic, sbyte v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i16_decrease_stat(IntPtr value, Statistic statistic, short v);
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void statistic_set_i32_decrease_stat(IntPtr value, Statistic statistic, int v);
}
}

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<RootNamespace>PkmnLibSharp</RootNamespace>
<LangVersion>8</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Update="libpkmn_lib.so">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,59 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using PkmnLibSharp.Utils;
using Interface = PkmnLibSharp.FFI.StaticData.Ability;
namespace PkmnLibSharp.StaticData
{
public class Ability : ExternPointer<Ability.CacheData>
{
[UsedImplicitly]
public class CacheData
{
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 Ability(string name, string effect, IReadOnlyCollection<EffectParameter> parameters)
{
// Passing effect parameters to Rust gives Rust full control over them, and means it can move it. As such
// we remove ownership and invalidate the passed parameters.
var parameterArray = parameters.Select(x => x.TakeOwnershipAndInvalidate()).ToArray();
var arrayPtr = parameterArray.ArrayPtr();
InitializePointer(Interface.ability_new(name.ToPtr(), effect.ToPtr(), arrayPtr, (ulong)parameters.Count),
true);
}
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]!;
}
protected override CacheData CreateCache()
{
return new CacheData();
}
protected override void Destructor()
{
Interface.ability_drop(Ptr);
}
}
}

View File

@@ -0,0 +1,93 @@
using System;
using JetBrains.Annotations;
using PkmnLibSharp.Utils;
using Interface = PkmnLibSharp.FFI.StaticData.EffectParameter;
namespace PkmnLibSharp.StaticData
{
public class EffectParameter : ExternPointer<EffectParameter.CacheData>
{
[UsedImplicitly]
public class CacheData
{
public ParameterType? Type { get; internal set; }
public object? Data { get; internal set; }
}
internal EffectParameter(IntPtr ptr, bool isOwner) : base(ptr, isOwner)
{
}
public EffectParameter(bool b) : base(Interface.effect_parameter_new_bool(b.ForeignBool()), true)
{
}
public EffectParameter(long l) : base(Interface.effect_parameter_new_int(l), true)
{
}
public EffectParameter(float f) : base(Interface.effect_parameter_new_float(f), true)
{
}
public EffectParameter(string s) : base(Interface.effect_parameter_new_string(s.ToPtr()), true)
{
}
public enum ParameterType : byte
{
Bool = 0,
Int = 1,
Float = 2,
String = 3
}
public ParameterType Type
{
get
{
var cache = Cache.Type;
if (cache.HasValue)
return cache.Value;
Cache.Type = (ParameterType)Interface.effect_parameter_get_type(Ptr);
return Cache.Type.Value;
}
}
public object Data
{
get
{
var cache = Cache.Data;
if (cache != null)
return cache;
var type = Type;
Cache.Data = type switch
{
ParameterType.Bool => Interface.effect_parameter_get_as_bool(Ptr) == 1,
ParameterType.Int => Interface.effect_parameter_get_as_int(Ptr),
ParameterType.Float => Interface.effect_parameter_get_as_float(Ptr),
ParameterType.String => Interface.effect_parameter_get_as_string(Ptr).PtrString(),
_ => throw new ArgumentOutOfRangeException()
};
return Cache.Data!;
}
}
protected override CacheData CreateCache()
{
return new CacheData();
}
protected override void Destructor()
{
Interface.effect_parameter_drop(Ptr);
}
public override string ToString()
{
var data = Data;
return data is string ? $"{Type}(\"{data}\")" : $"{Type}({data})";
}
}
}

View File

@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PkmnLibSharp.Utils;
using Interface = PkmnLibSharp.FFI.StaticData.MoveData;
namespace PkmnLibSharp.StaticData
{
public enum MoveCategory : byte
{
/// A physical move uses the physical attack stats and physical defense stats to calculate damage.
Physical = 0,
/// A special move uses the special attack stats and special defense stats to calculate damage.
Special = 1,
/// A status move does not do damage, and only runs a secondary effect.
Status = 2,
}
public enum MoveTarget : byte
{
/// Adjacent allows a move to target any Pokemon that is either directly to the left or right of
/// the user, opposed to the user, or left or right of the slot that is opposing the user.
Adjacent = 0,
/// AdjacentAlly allows a move to target any Pokemon that is directly to the left or right of
/// the user.
AdjacentAlly,
/// AdjacentAllySelf allows a move to target any Pokemon that is either directly to the left or
/// right of the user, or the user itself.
AdjacentAllySelf,
/// AdjacentOpponent allows a move to target any Pokemon that is either the opponent, or directly
/// to the left or right of it.
AdjacentOpponent,
/// All makes the move target everything on the field.
All,
/// AllAdjacent makes the move target everything adjacent on the field.
AllAdjacent,
/// AllAdjacentOpponent makes the move target everything adjacent to the opponent, and the opponent.
AllAdjacentOpponent,
/// AllAlly targets all Pokemon on the same side as the user.
AllAlly,
/// AllOpponent targets all Pokemon on an opposing side from the user.
AllOpponent,
/// Any allows a move to target a single Pokemon, in any position.
Any,
/// RandomOpponent allows a move to target a single Pokemon, in a random position.
RandomOpponent,
/// SelfUse makes the move target the user itself.
SelfUse,
}
public class MoveData : ExternPointer<MoveData.CacheData>
{
public class CacheData
{
public string? Name { get; internal set; }
public TypeIdentifier? Type { get; internal set; }
public MoveCategory? Category { get; internal set; }
public byte? BasePower { get; internal set; }
public byte? Accuracy { get; internal set; }
public byte? BaseUsages { get; internal set; }
public MoveTarget? Target { get; internal set; }
public sbyte? Priority { get; internal set; }
public SecondaryEffect? SecondaryEffect { get; internal set; }
}
public MoveData(string name, TypeIdentifier moveType, MoveCategory category, byte basePower, byte accuracy,
byte baseUsages, MoveTarget target, sbyte priority, SecondaryEffect? secondaryEffect,
IEnumerable<string> flags)
{
var ptrArray = flags.Select(x => x.ToPtr()).ToArray();
var ptrToPtrArray = ptrArray.ArrayPtr();
var ptr = Interface.move_data_new(name.ToPtr(), moveType, category, basePower, accuracy, baseUsages, target,
priority, secondaryEffect?.TakeOwnershipAndInvalidate() ?? IntPtr.Zero, ptrToPtrArray,
(ulong)ptrArray.Length);
InitializePointer(ptr, true);
}
public string Name => Cache.Name ??= Interface.move_data_name(Ptr).PtrString()!;
public TypeIdentifier Type => Cache.Type ??= Interface.move_data_move_type(Ptr);
public byte BasePower => Cache.BasePower ??= Interface.move_data_base_power(Ptr);
public MoveCategory Category => Cache.Category ??= Interface.move_data_category(Ptr);
public byte Accuracy => Cache.Accuracy ??= Interface.move_data_accuracy(Ptr);
public byte BaseUsages => Cache.BaseUsages ??= Interface.move_data_base_usages(Ptr);
public MoveTarget Target => Cache.Target ??= Interface.move_data_target(Ptr);
public sbyte Priority => Cache.Priority ??= Interface.move_data_priority(Ptr);
public SecondaryEffect? SecondaryEffect
{
get
{
if (Cache.SecondaryEffect != null)
return Cache.SecondaryEffect;
var effect = Interface.move_data_secondary_effect(Ptr);
if (effect == IntPtr.Zero)
return null;
Cache.SecondaryEffect = new SecondaryEffect(effect, false);
return Cache.SecondaryEffect;
}
}
public bool HasFlag(string flag)
{
return Interface.move_data_has_flag(Ptr, flag.ToPtr()) == 1;
}
protected override CacheData CreateCache()
{
return new CacheData();
}
protected override void Destructor()
{
Interface.move_data_drop(Ptr);
}
}
}

View File

@@ -0,0 +1,51 @@
using PkmnLibSharp.Utils;
using Interface = PkmnLibSharp.FFI.StaticData.Nature;
namespace PkmnLibSharp.StaticData
{
public class Nature : ExternPointer<Nature.CacheData>
{
public class CacheData
{
public Statistic? IncreasedStat { get; internal set; }
public Statistic? DecreasedStat { get; internal set; }
}
public Nature(Statistic increasedStat, Statistic decreasedStat, float increaseModifier = 1.1f,
float decreaseModifier = 0.9f) : base(
Interface.nature_new(increasedStat, decreasedStat, increaseModifier, decreaseModifier), true)
{
}
public static Nature NeutralNature()
{
return new Nature(Statistic.HP, Statistic.HP, 1f, 1f);
}
public Statistic IncreasedStat
{
get { return Cache.IncreasedStat ??= Interface.nature_increased_stat(Ptr); }
}
public Statistic DecreasedStat
{
get { return Cache.DecreasedStat ??= Interface.nature_decreased_stat(Ptr); }
}
public float GetStatModifier(Statistic statistic)
{
return Interface.nature_get_stat_modifier(Ptr, statistic);
}
protected override CacheData CreateCache()
{
return new CacheData();
}
protected override void Destructor()
{
Interface.nature_drop(Ptr);
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PkmnLibSharp.Utils;
using Interface = PkmnLibSharp.FFI.StaticData.MoveData;
namespace PkmnLibSharp.StaticData
{
public class SecondaryEffect : ExternPointer<SecondaryEffect.CacheData>
{
public class CacheData
{
public float? Chance { get; internal set; }
public string? Name { get; internal set; }
public ulong? ParameterLength { get; internal set; }
public EffectParameter?[]? Parameters { get; internal set; }
}
internal SecondaryEffect(IntPtr ptr, bool isOwner) : base(ptr, isOwner)
{
}
public SecondaryEffect(float chance, string effectName, IReadOnlyCollection<EffectParameter> parameters)
{
var parameterPtrs = parameters.Select(x => x.TakeOwnershipAndInvalidate()).ToArray();
var parameterArrayPtr = parameterPtrs.ArrayPtr();
InitializePointer(
Interface.secondary_effect_new(chance, effectName.ToPtr(), parameterArrayPtr, (ulong)parameters.Count),
true);
}
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 ulong ParameterLength =>
Cache.ParameterLength ?? (Cache.ParameterLength = Interface.secondary_effect_parameter_length(Ptr)).Value;
public EffectParameter GetParameter(int index)
{
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()
{
return new CacheData();
}
protected override void Destructor()
{
Interface.secondary_effect_drop(Ptr);
}
}
}

View File

@@ -0,0 +1,129 @@
using System;
using JetBrains.Annotations;
using PkmnLibSharp.Utils;
using Interface = PkmnLibSharp.FFI.StaticData.StaticStatisticSet;
namespace PkmnLibSharp.StaticData
{
public class StaticStatisticSet<T> : ExternPointer<StaticStatisticSet<T>.CacheData> where T : struct, IConvertible
{
public class CacheData
{
public T? HP { get; internal set; }
public T? Attack { get; internal set; }
public T? Defense { get; internal set; }
public T? SpecialAttack { get; internal set; }
public T? SpecialDefense { get; internal set; }
public T? Speed { get; internal set; }
}
public StaticStatisticSet(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed)
{
var p = typeof(T) switch
{
{ } t when t == typeof(byte) => Interface.static_statistic_set_u8_new(Convert.ToByte(hp),
Convert.ToByte(attack), Convert.ToByte(defense), Convert.ToByte(specialAttack),
Convert.ToByte(specialDefense), Convert.ToByte(speed)),
{ } t when t == typeof(ushort) => Interface.static_statistic_set_u16_new(Convert.ToUInt16(hp),
Convert.ToUInt16(attack), Convert.ToUInt16(defense), Convert.ToUInt16(specialAttack),
Convert.ToUInt16(specialDefense), Convert.ToUInt16(speed)),
{ } t when t == typeof(uint) => Interface.static_statistic_set_u32_new(Convert.ToUInt32(hp),
Convert.ToUInt32(attack), Convert.ToUInt32(defense), Convert.ToUInt32(specialAttack),
Convert.ToUInt32(specialDefense), Convert.ToUInt32(speed)),
{ } t when t == typeof(sbyte) => Interface.static_statistic_set_i8_new(Convert.ToSByte(hp),
Convert.ToSByte(attack), Convert.ToSByte(defense), Convert.ToSByte(specialAttack),
Convert.ToSByte(specialDefense), Convert.ToSByte(speed)),
{ } t when t == typeof(short) => Interface.static_statistic_set_i16_new(Convert.ToInt16(hp),
Convert.ToInt16(attack), Convert.ToInt16(defense), Convert.ToInt16(specialAttack),
Convert.ToInt16(specialDefense), Convert.ToInt16(speed)),
{ } t when t == typeof(int) => Interface.static_statistic_set_i32_new(Convert.ToInt32(hp),
Convert.ToInt32(attack), Convert.ToInt32(defense), Convert.ToInt32(specialAttack),
Convert.ToInt32(specialDefense), Convert.ToInt32(speed)),
_ => throw new ArgumentOutOfRangeException()
};
InitializePointer(p, true);
}
[PublicAPI]
public T GetStatistic(Statistic statistic)
{
switch (statistic)
{
case Statistic.HP when Cache.HP.HasValue:
return Cache.HP.Value;
case Statistic.Attack when Cache.Attack.HasValue:
return Cache.Attack.Value;
case Statistic.Defense when Cache.Defense.HasValue:
return Cache.Defense.Value;
case Statistic.SpecialAttack when Cache.SpecialAttack.HasValue:
return Cache.SpecialAttack.Value;
case Statistic.SpecialDefense when Cache.SpecialDefense.HasValue:
return Cache.SpecialDefense.Value;
case Statistic.Speed when Cache.Speed.HasValue:
return Cache.Speed.Value;
}
object p = typeof(T) switch
{
{ } t when t == typeof(byte) => Interface.static_statistic_set_u8_get_stat(Ptr, statistic),
{ } t when t == typeof(ushort) => Interface.static_statistic_set_u16_get_stat(Ptr, statistic),
{ } t when t == typeof(uint) => Interface.static_statistic_set_u32_get_stat(Ptr, statistic),
{ } t when t == typeof(sbyte) => Interface.static_statistic_set_i8_get_stat(Ptr, statistic),
{ } t when t == typeof(short) => Interface.static_statistic_set_i16_get_stat(Ptr, statistic),
{ } t when t == typeof(int) => Interface.static_statistic_set_i32_get_stat(Ptr, statistic),
_ => throw new ArgumentOutOfRangeException()
};
switch (statistic)
{
case Statistic.HP:
Cache.HP = (T)p;
break;
case Statistic.Attack:
Cache.Attack = (T)p;
break;
case Statistic.Defense:
Cache.Defense = (T)p;
break;
case Statistic.SpecialAttack:
Cache.SpecialAttack = (T)p;
break;
case Statistic.SpecialDefense:
Cache.SpecialDefense = (T)p;
break;
case Statistic.Speed:
Cache.Speed = (T)p;
break;
}
return (T)p;
}
public T HP => GetStatistic(Statistic.HP);
public T Attack => GetStatistic(Statistic.Attack);
public T Defense => GetStatistic(Statistic.Defense);
public T SpecialAttack => GetStatistic(Statistic.SpecialAttack);
public T SpecialDefense => GetStatistic(Statistic.SpecialDefense);
public T Speed => GetStatistic(Statistic.Speed);
protected override CacheData CreateCache()
{
return new CacheData();
}
protected override void Destructor()
{
if (typeof(T) == typeof(byte)) Interface.static_statistic_set_u8_drop(Ptr);
else if (typeof(T) == typeof(ushort)) Interface.static_statistic_set_u16_drop(Ptr);
else if (typeof(T) == typeof(uint)) Interface.static_statistic_set_u32_drop(Ptr);
else if (typeof(T) == typeof(sbyte)) Interface.static_statistic_set_i8_drop(Ptr);
else if (typeof(T) == typeof(short)) Interface.static_statistic_set_i16_drop(Ptr);
else if (typeof(T) == typeof(int)) Interface.static_statistic_set_i32_drop(Ptr);
}
}
}

View File

@@ -0,0 +1,12 @@
namespace PkmnLibSharp.StaticData
{
public enum Statistic : byte
{
HP = 0,
Attack = 1,
Defense = 2,
SpecialAttack = 3,
SpecialDefense = 4,
Speed = 5
}
}

View File

@@ -0,0 +1,127 @@
using System;
using JetBrains.Annotations;
using PkmnLibSharp.Utils;
using Interface = PkmnLibSharp.FFI.StaticData.StatisticSet;
namespace PkmnLibSharp.StaticData
{
public class StatisticSet<T> : ExternPointer<StatisticSet<T>.CacheData> where T : struct, IConvertible
{
public class CacheData
{
// While we require cache types for all pointer data, we can't make caching assumptions for this type.
// As such, this is empty (and never instantiated).
}
public StatisticSet(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed)
{
var p = typeof(T) switch
{
{ } t when t == typeof(byte) => Interface.statistic_set_u8_new(Convert.ToByte(hp),
Convert.ToByte(attack), Convert.ToByte(defense), Convert.ToByte(specialAttack),
Convert.ToByte(specialDefense), Convert.ToByte(speed)),
{ } t when t == typeof(ushort) => Interface.statistic_set_u16_new(Convert.ToUInt16(hp),
Convert.ToUInt16(attack), Convert.ToUInt16(defense), Convert.ToUInt16(specialAttack),
Convert.ToUInt16(specialDefense), Convert.ToUInt16(speed)),
{ } t when t == typeof(uint) => Interface.statistic_set_u32_new(Convert.ToUInt32(hp),
Convert.ToUInt32(attack), Convert.ToUInt32(defense), Convert.ToUInt32(specialAttack),
Convert.ToUInt32(specialDefense), Convert.ToUInt32(speed)),
{ } t when t == typeof(sbyte) => Interface.statistic_set_i8_new(Convert.ToSByte(hp),
Convert.ToSByte(attack), Convert.ToSByte(defense), Convert.ToSByte(specialAttack),
Convert.ToSByte(specialDefense), Convert.ToSByte(speed)),
{ } t when t == typeof(short) => Interface.statistic_set_i16_new(Convert.ToInt16(hp),
Convert.ToInt16(attack), Convert.ToInt16(defense), Convert.ToInt16(specialAttack),
Convert.ToInt16(specialDefense), Convert.ToInt16(speed)),
{ } t when t == typeof(int) => Interface.statistic_set_i32_new(Convert.ToInt32(hp),
Convert.ToInt32(attack), Convert.ToInt32(defense), Convert.ToInt32(specialAttack),
Convert.ToInt32(specialDefense), Convert.ToInt32(speed)),
_ => throw new ArgumentOutOfRangeException()
};
InitializePointer(p, true);
}
[PublicAPI]
public T GetStatistic(Statistic statistic)
{
object p = typeof(T) switch
{
{ } t when t == typeof(byte) => Interface.statistic_set_u8_get_stat(Ptr, statistic),
{ } t when t == typeof(ushort) => Interface.statistic_set_u16_get_stat(Ptr, statistic),
{ } t when t == typeof(uint) => Interface.statistic_set_u32_get_stat(Ptr, statistic),
{ } t when t == typeof(sbyte) => Interface.statistic_set_i8_get_stat(Ptr, statistic),
{ } t when t == typeof(short) => Interface.statistic_set_i16_get_stat(Ptr, statistic),
{ } t when t == typeof(int) => Interface.statistic_set_i32_get_stat(Ptr, statistic),
_ => throw new ArgumentOutOfRangeException()
};
return (T)p;
}
[PublicAPI]
public void SetStatistic(Statistic statistic, T value)
{
if (typeof(T) == typeof(byte)) Interface.statistic_set_u8_set_stat(Ptr, statistic, Convert.ToByte(value));
else if (typeof(T) == typeof(ushort))
Interface.statistic_set_u16_set_stat(Ptr, statistic, Convert.ToUInt16(value));
else if (typeof(T) == typeof(uint))
Interface.statistic_set_u32_set_stat(Ptr, statistic, Convert.ToUInt32(value));
else if (typeof(T) == typeof(sbyte))
Interface.statistic_set_i8_set_stat(Ptr, statistic, Convert.ToSByte(value));
else if (typeof(T) == typeof(short))
Interface.statistic_set_i16_set_stat(Ptr, statistic, Convert.ToInt16(value));
else if (typeof(T) == typeof(int))
Interface.statistic_set_i32_set_stat(Ptr, statistic, Convert.ToInt32(value));
}
public T HP
{
get => GetStatistic(Statistic.HP);
set => SetStatistic(Statistic.HP, value);
}
public T Attack
{
get => GetStatistic(Statistic.Attack);
set => SetStatistic(Statistic.Attack, value);
}
public T Defense
{
get => GetStatistic(Statistic.Defense);
set => SetStatistic(Statistic.Defense, value);
}
public T SpecialAttack
{
get => GetStatistic(Statistic.SpecialAttack);
set => SetStatistic(Statistic.SpecialAttack, value);
}
public T SpecialDefense
{
get => GetStatistic(Statistic.SpecialDefense);
set => SetStatistic(Statistic.SpecialDefense, value);
}
public T Speed
{
get => GetStatistic(Statistic.Speed);
set => SetStatistic(Statistic.Speed, value);
}
protected override CacheData CreateCache()
{
return new CacheData();
}
protected override void Destructor()
{
if (typeof(T) == typeof(byte)) Interface.statistic_set_u8_drop(Ptr);
else if (typeof(T) == typeof(ushort)) Interface.statistic_set_u16_drop(Ptr);
else if (typeof(T) == typeof(uint)) Interface.statistic_set_u32_drop(Ptr);
else if (typeof(T) == typeof(sbyte)) Interface.statistic_set_i8_drop(Ptr);
else if (typeof(T) == typeof(short)) Interface.statistic_set_i16_drop(Ptr);
else if (typeof(T) == typeof(int)) Interface.statistic_set_i32_drop(Ptr);
}
}
}

View File

@@ -0,0 +1,41 @@
using System.Runtime.InteropServices;
namespace PkmnLibSharp.StaticData
{
[StructLayout(LayoutKind.Explicit)]
public readonly struct TypeIdentifier
{
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
[FieldOffset(0)] private readonly byte _identifier;
internal TypeIdentifier(byte b)
{
_identifier = b;
}
public bool Equals(TypeIdentifier other)
{
return _identifier == other._identifier;
}
public override bool Equals(object? obj)
{
return obj is TypeIdentifier other && Equals(other);
}
public override int GetHashCode()
{
return _identifier.GetHashCode();
}
public static bool operator ==(TypeIdentifier left, TypeIdentifier right)
{
return left.Equals(right);
}
public static bool operator !=(TypeIdentifier left, TypeIdentifier right)
{
return !left.Equals(right);
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Concurrent;
namespace PkmnLibSharp.Utils
{
internal static class CacheHandler
{
private static readonly ConcurrentDictionary<IntPtr, object> Caches = new ConcurrentDictionary<IntPtr, object>();
internal static T GetCache<T>(IntPtr ptr, Func<object> ctor)
{
if (!Caches.TryGetValue(ptr, out var cache))
{
cache = ctor();
Caches.TryAdd(ptr, cache);
}
return (T)cache;
}
internal static void RemoveCache(IntPtr ptr)
{
Caches.TryRemove(ptr, out _);
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("PkmnLibRSharp")]
namespace PkmnLibSharp.Utils
{
public abstract class ExternPointer<TCache> : IDisposable
where TCache : class
{
private IntPtr _ptr;
private bool _isOwner;
private bool _isInvalidated;
private bool _isDisposed;
private TCache? _cache;
protected abstract TCache CreateCache();
internal TCache Cache
{
get { return _cache ??= CacheHandler.GetCache<TCache>(_ptr, CreateCache); }
}
protected ExternPointer()
{
}
protected ExternPointer(IntPtr ptr, bool isOwner)
{
InitializePointer(ptr, isOwner);
}
protected void InitializePointer(IntPtr ptr, bool isOwner)
{
_ptr = ptr;
_isOwner = isOwner;
}
protected abstract void Destructor();
internal IntPtr Ptr
{
get
{
if (_isInvalidated)
{
throw new Exception("Pointer was used after invalidate");
}
return _ptr;
}
}
internal IntPtr TakeOwnership()
{
if (!_isOwner)
{
throw new Exception("Tried to take ownership of a non-owned object");
}
_isOwner = false;
return Ptr;
}
internal IntPtr TakeOwnershipAndInvalidate()
{
var ptr = TakeOwnership();
Invalidate();
return ptr;
}
internal void Invalidate()
{
_isInvalidated = true;
CacheHandler.RemoveCache(_ptr);
}
~ExternPointer()
{
Dispose();
}
public void Dispose()
{
if (_isDisposed)
return;
if (_isOwner)
{
if (!_isInvalidated)
Destructor();
_isOwner = false;
CacheHandler.RemoveCache(_ptr);
}
_isDisposed = true;
_isInvalidated = true;
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Runtime.InteropServices;
namespace PkmnLibSharp.Utils
{
internal static class FFIExtensions
{
internal static byte ForeignBool(this bool b)
{
return b ? (byte)1 : (byte)0;
}
internal static IntPtr ToPtr(this string? s)
{
if (s == null) return IntPtr.Zero;
return Marshal.StringToHGlobalAnsi(s);
}
internal static string? PtrString(this IntPtr i)
{
return i == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(i);
}
internal static IntPtr ArrayPtr(this IntPtr[] a)
{
return Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
}
internal static IntPtr ArrayPtr<T>(this T[] a) where T : struct, IConvertible
{
return Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
}
}
}

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

Binary file not shown.