From 3369696956485205c12d50aecebfff51546e8f93 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Tue, 3 Jan 2023 16:53:58 +0100 Subject: [PATCH] Initial work on DynamicLibrary up to and including the Pokemon model. --- PkmnLibRSharp/DynamicData/DamageSource.cs | 20 ++ PkmnLibRSharp/DynamicData/LearnedMove.cs | 14 +- .../Libraries/BattleStatCalculator.cs | 22 ++ .../DynamicData/Libraries/DamageLibrary.cs | 25 ++ .../DynamicData/Libraries/DynamicLibrary.cs | 25 ++ .../DynamicData/Libraries/MiscLibrary.cs | 24 ++ .../DynamicData/Libraries/ScriptResolver.cs | 30 ++ .../Libraries/WasmScriptResolver.cs | 30 ++ PkmnLibRSharp/DynamicData/Pokemon.cs | 151 +++++++++ .../Libraries/BattleStatCalculator.cs | 22 ++ .../DynamicData/Libraries/DamageLibrary.cs | 22 ++ .../DynamicData/Libraries/DynamicLibrary.cs | 22 ++ .../FFI/DynamicData/Libraries/MiscLibrary.cs | 20 ++ .../DynamicData/Libraries/ScriptResolver.cs | 43 +++ PkmnLibRSharp/FFI/DynamicData/Pokemon.cs | 306 ++++++++++++++++++ PkmnLibRSharp/FFI/IdentifiablePointer.cs | 2 + PkmnLibRSharp/PkmnLibRSharp.csproj | 3 + PkmnLibRSharp/StaticData/Ability.cs | 2 +- PkmnLibRSharp/StaticData/Form.cs | 2 +- PkmnLibRSharp/StaticData/Gender.cs | 20 ++ PkmnLibRSharp/StaticData/Item.cs | 2 +- .../StaticData/Libraries/AbilityLibrary.cs | 2 +- .../StaticData/Libraries/ItemLibrary.cs | 2 +- .../StaticData/Libraries/SpeciesLibrary.cs | 2 +- PkmnLibRSharp/StaticData/Species.cs | 7 +- PkmnLibRSharp/StaticData/StatisticSet.cs | 6 +- PkmnLibRSharp/Utils/ExternValueArray.cs | 35 ++ PkmnLibRSharp/libpkmn_lib.so | 4 +- 28 files changed, 849 insertions(+), 16 deletions(-) create mode 100644 PkmnLibRSharp/DynamicData/DamageSource.cs create mode 100644 PkmnLibRSharp/DynamicData/Libraries/BattleStatCalculator.cs create mode 100644 PkmnLibRSharp/DynamicData/Libraries/DamageLibrary.cs create mode 100644 PkmnLibRSharp/DynamicData/Libraries/DynamicLibrary.cs create mode 100644 PkmnLibRSharp/DynamicData/Libraries/MiscLibrary.cs create mode 100644 PkmnLibRSharp/DynamicData/Libraries/ScriptResolver.cs create mode 100644 PkmnLibRSharp/DynamicData/Libraries/WasmScriptResolver.cs create mode 100644 PkmnLibRSharp/DynamicData/Pokemon.cs create mode 100644 PkmnLibRSharp/FFI/DynamicData/Libraries/BattleStatCalculator.cs create mode 100644 PkmnLibRSharp/FFI/DynamicData/Libraries/DamageLibrary.cs create mode 100644 PkmnLibRSharp/FFI/DynamicData/Libraries/DynamicLibrary.cs create mode 100644 PkmnLibRSharp/FFI/DynamicData/Libraries/MiscLibrary.cs create mode 100644 PkmnLibRSharp/FFI/DynamicData/Libraries/ScriptResolver.cs create mode 100644 PkmnLibRSharp/FFI/DynamicData/Pokemon.cs create mode 100644 PkmnLibRSharp/StaticData/Gender.cs create mode 100644 PkmnLibRSharp/Utils/ExternValueArray.cs diff --git a/PkmnLibRSharp/DynamicData/DamageSource.cs b/PkmnLibRSharp/DynamicData/DamageSource.cs new file mode 100644 index 0000000..88a0f97 --- /dev/null +++ b/PkmnLibRSharp/DynamicData/DamageSource.cs @@ -0,0 +1,20 @@ +namespace PkmnLibSharp.DynamicData +{ + public enum DamageSource : byte + { + /// + /// The damage is done by a move. + /// + MoveDamage = 0, + + /// + /// The damage is done by something else. + /// + Misc = 1, + + /// + /// The damage is done because of struggling. + /// + Struggle = 2, + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/DynamicData/LearnedMove.cs b/PkmnLibRSharp/DynamicData/LearnedMove.cs index 0a2a44a..366b724 100644 --- a/PkmnLibRSharp/DynamicData/LearnedMove.cs +++ b/PkmnLibRSharp/DynamicData/LearnedMove.cs @@ -1,3 +1,4 @@ +using PkmnLibSharp.FFI; using PkmnLibSharp.StaticData; using PkmnLibSharp.Utils; using Interface = PkmnLibSharp.FFI.DynamicData.LearnedMove; @@ -12,6 +13,10 @@ namespace PkmnLibSharp.DynamicData public MoveLearnMethod? LearnMethod { get; internal set; } } + internal LearnedMove(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner) + { + } + public LearnedMove(MoveData moveData, MoveLearnMethod learnMethod) { InitializePointer(Interface.learned_move_new(moveData.Ptr, learnMethod), true); @@ -21,17 +26,17 @@ namespace PkmnLibSharp.DynamicData /// The immutable move information of the move. /// public MoveData MoveData => Cache.MoveData ??= new MoveData(Interface.learned_move_move_data(Ptr), true); - + /// /// The maximal power points for this move. /// public byte MaxPP => Interface.learned_move_max_pp(Ptr); - + /// /// The amount of remaining power points. If this is 0, we can not use the move anymore. /// public byte RemainingPP => Interface.learned_move_remaining_pp(Ptr); - + /// /// The way the move was learned. /// @@ -47,7 +52,7 @@ namespace PkmnLibSharp.DynamicData /// Set the remaining PP to the max amount of PP. /// public void RestoreAllUses() => Interface.learned_move_restore_all_uses(Ptr); - + /// /// Restore the remaining PP by a certain amount. Will prevent it from going above max PP. /// @@ -66,6 +71,7 @@ namespace PkmnLibSharp.DynamicData { /// We do not know the learn method. Unknown = 0, + /// The move was learned through level up. Level = 1, } diff --git a/PkmnLibRSharp/DynamicData/Libraries/BattleStatCalculator.cs b/PkmnLibRSharp/DynamicData/Libraries/BattleStatCalculator.cs new file mode 100644 index 0000000..b1b30d4 --- /dev/null +++ b/PkmnLibRSharp/DynamicData/Libraries/BattleStatCalculator.cs @@ -0,0 +1,22 @@ +using PkmnLibSharp.FFI; +using PkmnLibSharp.Utils; +using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.BattleStatCalculator; + +namespace PkmnLibSharp.DynamicData.Libraries +{ + public abstract class BattleStatCalculator : ExternPointer + { + public BattleStatCalculator(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner){} + + protected override object CreateCache() => new(); + + protected override void Destructor() => Interface.battle_stat_calculator_drop(Ptr); + } + + public class Gen7BattleStatCalculator : BattleStatCalculator + { + public Gen7BattleStatCalculator() : base(Interface.gen_7_battle_stat_calculator_new(), true) + { + } + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/DynamicData/Libraries/DamageLibrary.cs b/PkmnLibRSharp/DynamicData/Libraries/DamageLibrary.cs new file mode 100644 index 0000000..73ea652 --- /dev/null +++ b/PkmnLibRSharp/DynamicData/Libraries/DamageLibrary.cs @@ -0,0 +1,25 @@ +using PkmnLibSharp.FFI; +using PkmnLibSharp.Utils; +using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.DamageLibrary; + +namespace PkmnLibSharp.DynamicData.Libraries +{ + public abstract class DamageLibrary : ExternPointer + { + protected DamageLibrary(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner) + { + } + + protected override object CreateCache() => new(); + + protected override void Destructor() => Interface.damage_library_drop(Ptr); + } + + public class Gen7DamageLibrary : DamageLibrary + { + public Gen7DamageLibrary(bool hasRandomness) : base( + Interface.gen_7_damage_library_new((byte)(hasRandomness ? 1 : 0)), true) + { + } + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/DynamicData/Libraries/DynamicLibrary.cs b/PkmnLibRSharp/DynamicData/Libraries/DynamicLibrary.cs new file mode 100644 index 0000000..81585b1 --- /dev/null +++ b/PkmnLibRSharp/DynamicData/Libraries/DynamicLibrary.cs @@ -0,0 +1,25 @@ +using PkmnLibSharp.FFI; +using PkmnLibSharp.Utils; +using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.DynamicLibrary; + +namespace PkmnLibSharp.DynamicData.Libraries +{ + public class DynamicLibrary : ExternPointer + { + public class CacheData + { + } + + internal DynamicLibrary(IdentifiablePointer ptr) : base(ptr, false) {} + + public DynamicLibrary(StaticData.Libraries.StaticData staticData, BattleStatCalculator statCalculator, + DamageLibrary damageLibrary, MiscLibrary miscLibrary, ScriptResolver scriptResolver) : base( + Interface.dynamic_library_new(staticData.Ptr, statCalculator.Ptr, damageLibrary.Ptr, miscLibrary.Ptr, + scriptResolver.Ptr), true) + { + } + + protected override CacheData CreateCache() => new(); + protected override void Destructor() => Interface.dynamic_library_drop(Ptr); + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/DynamicData/Libraries/MiscLibrary.cs b/PkmnLibRSharp/DynamicData/Libraries/MiscLibrary.cs new file mode 100644 index 0000000..35a60b8 --- /dev/null +++ b/PkmnLibRSharp/DynamicData/Libraries/MiscLibrary.cs @@ -0,0 +1,24 @@ +using PkmnLibSharp.FFI; +using PkmnLibSharp.Utils; +using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.MiscLibrary; + +namespace PkmnLibSharp.DynamicData.Libraries +{ + public abstract class MiscLibrary : ExternPointer + { + protected MiscLibrary(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner) + { + } + + protected override object CreateCache() => new(); + + protected override void Destructor() => Interface.misc_library_drop(Ptr); + } + + public class Gen7MiscLibrary : MiscLibrary + { + public Gen7MiscLibrary() : base(Interface.gen_7_misc_library_new(), true) + { + } + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/DynamicData/Libraries/ScriptResolver.cs b/PkmnLibRSharp/DynamicData/Libraries/ScriptResolver.cs new file mode 100644 index 0000000..09c19c8 --- /dev/null +++ b/PkmnLibRSharp/DynamicData/Libraries/ScriptResolver.cs @@ -0,0 +1,30 @@ +using System; +using PkmnLibSharp.FFI; +using PkmnLibSharp.Utils; +using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.ScriptResolver; + +namespace PkmnLibSharp.DynamicData.Libraries +{ + public abstract class ScriptResolver : ExternPointer + { + protected ScriptResolver(IdentifiablePointer ptr) : base(ptr, true){} + protected ScriptResolver(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner){} + + public class CacheData{} + + protected override CacheData CreateCache() => new(); + + protected override void Destructor() + { + Interface.script_resolver_drop(Ptr); + } + } + + /// + /// An implementation of a script resolver that pretends there are no existing scripts. + /// + public class EmptyScriptResolver : ScriptResolver + { + public EmptyScriptResolver() : base(Interface.empty_script_resolver_new()){} + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/DynamicData/Libraries/WasmScriptResolver.cs b/PkmnLibRSharp/DynamicData/Libraries/WasmScriptResolver.cs new file mode 100644 index 0000000..011c692 --- /dev/null +++ b/PkmnLibRSharp/DynamicData/Libraries/WasmScriptResolver.cs @@ -0,0 +1,30 @@ +#if WASM +using PkmnLibSharp.Utils; +using Interface = PkmnLibSharp.FFI.DynamicData.Libraries.ScriptResolver; + +namespace PkmnLibSharp.DynamicData.Libraries +{ + public class WasmScriptResolver : ScriptResolver + { + public WasmScriptResolver() : base(Interface.webassembly_script_resolver_new(), true){} + + /// + /// Loads a compiled WASM module into the script resolver. + /// + /// The bytes of a compiled WASM module + public void LoadBytes(byte[] data) + { + Interface.webassembly_script_resolver_load_wasm_from_bytes(Ptr, data.ArrayPtr(), (ulong)data.LongLength); + } + + /// + /// Tells the script resolver we're done loading wasm modules, and to finalize the resolver. After this it is + /// ready for use. + /// + public void FinalizeResolver() + { + Interface.webassembly_script_resolver_finalize(Ptr); + } + } +} +#endif \ No newline at end of file diff --git a/PkmnLibRSharp/DynamicData/Pokemon.cs b/PkmnLibRSharp/DynamicData/Pokemon.cs new file mode 100644 index 0000000..efa4f50 --- /dev/null +++ b/PkmnLibRSharp/DynamicData/Pokemon.cs @@ -0,0 +1,151 @@ +using PkmnLibSharp.DynamicData.Libraries; +using PkmnLibSharp.StaticData; +using PkmnLibSharp.Utils; +using Form = PkmnLibSharp.StaticData.Form; +using Interface = PkmnLibSharp.FFI.DynamicData.Pokemon; +using Item = PkmnLibSharp.StaticData.Item; +using Species = PkmnLibSharp.StaticData.Species; + +namespace PkmnLibSharp.DynamicData +{ + public class Pokemon : ExternPointer + { + public Pokemon(DynamicLibrary dynamicLibrary, Species species, Form form, bool hiddenAbility, byte abilityIndex, + LevelInt level, uint uid, Gender gender, byte coloring, string nature) : base( + Interface.pokemon_new(dynamicLibrary.Ptr, species.Ptr, form.Ptr, hiddenAbility.ForeignBool(), abilityIndex, + level, uid, gender, coloring, nature.ToPtr()), true) + { + } + + /// + /// The library data the Pokemon uses. + /// + public DynamicLibrary Library => Cache.DynamicLibrary ??= new DynamicLibrary(Interface.pokemon_library(Ptr)); + + /// + /// The species of the Pokemon. + /// + public Species Species => new(Interface.pokemon_species(Ptr)); + + /// + /// The form of the Pokemon. + /// + public Form Form => new(Interface.pokemon_form(Ptr)); + + /// + /// The species that should be displayed to the user. This handles stuff like the Illusion ability. + /// + public Species DisplaySpecies => new(Interface.pokemon_display_species(Ptr)); + + /// + /// The form that should be displayed to the user. This handles stuff like the Illusion ability. + /// + public Form DisplayForm => new(Interface.pokemon_display_form(Ptr)); + + public LevelInt Level => Interface.pokemon_level(Ptr); + public uint Experience => Interface.pokemon_experience(Ptr); + public uint UniqueIdentifier => Interface.pokemon_unique_identifier(Ptr); + public Gender Gender => Interface.pokemon_gender(Ptr); + public byte Coloring => Interface.pokemon_coloring(Ptr); + public bool IsShiny => Coloring == 1; + + public Item? HeldItem + { + get + { + var ptr = Interface.pokemon_held_item(Ptr); + return ptr.IsNull ? null : new Item(ptr); + } + } + + public bool HasHeldItem(string name) => Interface.pokemon_has_held_item(Ptr, name.ToPtr()) == 1; + + public void SetHeldItem(Item? item) + { + if (item == null) + RemoveHeldItem(); + else + Interface.pokemon_set_held_item(Ptr, item.Ptr); + } + + public void RemoveHeldItem() => Interface.pokemon_remove_held_item(Ptr); + + public bool ConsumeHeldItem() => Interface.pokemon_consume_held_item(Ptr) == 1; + + public uint CurrentHealth => Interface.pokemon_current_health(Ptr); + public uint MaxHealth => Interface.pokemon_max_health(Ptr); + public float Weight => Interface.pokemon_weight(Ptr); + public float Height => Interface.pokemon_height(Ptr); + + public string? Nickname => Interface.pokemon_nickname(Ptr).PtrString(); + public bool HasHiddenAbility => Interface.pokemon_real_ability_is_hidden(Ptr) == 1; + public byte AbilityIndex => Interface.pokemon_real_ability_index(Ptr); + + public ExternValueArray Types => + Cache.Types ??= new ExternValueArray(() => Interface.pokemon_types_length(Ptr), + arg => Interface.pokemon_types_get(Ptr, arg)); + + public LearnedMove? LearnedMove(ulong index) + { + var ptr = Interface.pokemon_learned_move_get(Ptr, index); + return ptr.IsNull ? null : new LearnedMove(ptr, false); + } + + public StatisticSet FlatStats => + Cache.FlatStats ??= new StatisticSet(Interface.pokemon_flat_stats(Ptr), false); + + public StatisticSet BoostedStats => + Cache.BoostedStats ??= new StatisticSet(Interface.pokemon_boosted_stats(Ptr), false); + + public sbyte GetStatBoost(Statistic statistic) => Interface.pokemon_get_stat_boost(Ptr, statistic); + public byte GetIndividualValue(Statistic statistic) => Interface.pokemon_get_individual_value(Ptr, statistic); + public byte GetEffortValue(Statistic statistic) => Interface.pokemon_get_effort_value(Ptr, statistic); + + public void SetIndividualValue(Statistic statistic, byte value) => + Interface.pokemon_set_individual_value(Ptr, statistic, value); + + public void SetEffortValue(Statistic statistic, byte value) => + Interface.pokemon_set_effort_value(Ptr, statistic, value); + + // TODO: Battle getter + public byte BattleSideIndex => Interface.pokemon_get_battle_side_index(Ptr); + public byte BattleIndex => Interface.pokemon_get_battle_index(Ptr); + public bool IsAbilityOverriden => Interface.pokemon_is_ability_overriden(Ptr) == 1; + public Ability ActiveAbility => new(Interface.pokemon_active_ability(Ptr)); + public bool AllowedExperienceGain => Interface.pokemon_allowed_experience_gain(Ptr) == 1; + public Nature Nature => new(Interface.pokemon_nature(Ptr)); + + public void RecalculateFlatStats() => Interface.pokemon_recalculate_flat_stats(Ptr); + public void RecalculateBoostedStats() => Interface.pokemon_recalculate_boosted_stats(Ptr); + + public void ChangeSpecies(Species species, Form form) => + Interface.pokemon_change_species(Ptr, species.Ptr, form.Ptr); + + public void ChangeForm(Form form) => Interface.pokemon_change_form(Ptr, form.Ptr); + + public bool IsUsable => Interface.pokemon_is_usable(Ptr) == 1; + public bool IsFainted => Interface.pokemon_is_fainted(Ptr) == 1; + public bool IsOnBattleField => Interface.pokemon_is_on_battlefield(Ptr) == 1; + + public void Damage(uint amount, DamageSource source) => Interface.pokemon_damage(Ptr, amount, source); + + public bool Heal(uint amount, bool allowRevive) => + Interface.pokemon_heal(Ptr, amount, allowRevive.ForeignBool()) == 1; + + public void LearnMove(string moveName, MoveLearnMethod learnMethod) => + Interface.pokemon_learn_move(Ptr, moveName.ToPtr(), learnMethod); + + public void ClearStatus() => Interface.pokemon_clear_status(Ptr); + + public class CacheData + { + public DynamicLibrary? DynamicLibrary { get; set; } + public ExternValueArray? Types { get; set; } + public StatisticSet? FlatStats { get; set; } + public StatisticSet? BoostedStats { get; set; } + } + + protected override CacheData CreateCache() => new(); + protected override void Destructor() => Interface.pokemon_drop(Ptr); + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/FFI/DynamicData/Libraries/BattleStatCalculator.cs b/PkmnLibRSharp/FFI/DynamicData/Libraries/BattleStatCalculator.cs new file mode 100644 index 0000000..0e9ae6e --- /dev/null +++ b/PkmnLibRSharp/FFI/DynamicData/Libraries/BattleStatCalculator.cs @@ -0,0 +1,22 @@ +using System; +using System.Runtime.InteropServices; +using PkmnLibSharp.DynamicData; + +namespace PkmnLibSharp.FFI.DynamicData.Libraries +{ + internal static class BattleStatCalculator + { + /// + /// Creates a new Gen 7 battle stat calculator + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer gen_7_battle_stat_calculator_new(); + + /// + /// Creates a new Gen 7 battle stat calculator + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void battle_stat_calculator_drop(IntPtr ptr); + + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/FFI/DynamicData/Libraries/DamageLibrary.cs b/PkmnLibRSharp/FFI/DynamicData/Libraries/DamageLibrary.cs new file mode 100644 index 0000000..900455e --- /dev/null +++ b/PkmnLibRSharp/FFI/DynamicData/Libraries/DamageLibrary.cs @@ -0,0 +1,22 @@ +using System; +using System.Runtime.InteropServices; + +namespace PkmnLibSharp.FFI.DynamicData.Libraries +{ + internal static class DamageLibrary + { + /// + /// Creates a new generation 7 damage library. + /// + /// whether or not a random damage modifier (0.85x - 1.00x) is applied to the + /// calculated damage. 0 for not, 1 for true + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer gen_7_damage_library_new(byte hasRandomness); + + /// + /// Drops a DamageLibrary. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void damage_library_drop(IntPtr ptr); + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/FFI/DynamicData/Libraries/DynamicLibrary.cs b/PkmnLibRSharp/FFI/DynamicData/Libraries/DynamicLibrary.cs new file mode 100644 index 0000000..c1783c9 --- /dev/null +++ b/PkmnLibRSharp/FFI/DynamicData/Libraries/DynamicLibrary.cs @@ -0,0 +1,22 @@ +using System; +using System.Runtime.InteropServices; + +namespace PkmnLibSharp.FFI.DynamicData.Libraries +{ + internal static class DynamicLibrary + { + /// + /// Instantiates a new DynamicLibrary with given parameters. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer dynamic_library_new(IntPtr staticData, IntPtr statCalculator, + IntPtr damageLibrary, IntPtr miscLibrary, IntPtr scriptResolver); + + /// + /// Drops a dynamic library. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void dynamic_library_drop(IntPtr dynamicLibrary); + + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/FFI/DynamicData/Libraries/MiscLibrary.cs b/PkmnLibRSharp/FFI/DynamicData/Libraries/MiscLibrary.cs new file mode 100644 index 0000000..9448093 --- /dev/null +++ b/PkmnLibRSharp/FFI/DynamicData/Libraries/MiscLibrary.cs @@ -0,0 +1,20 @@ +using System; +using System.Runtime.InteropServices; + +namespace PkmnLibSharp.FFI.DynamicData.Libraries +{ + internal static class MiscLibrary + { + /// + /// Instantiates a new MiscLibrary. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer gen_7_misc_library_new(); + + /// + /// Drops a MiscLibrary. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void misc_library_drop(IntPtr ptr); + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/FFI/DynamicData/Libraries/ScriptResolver.cs b/PkmnLibRSharp/FFI/DynamicData/Libraries/ScriptResolver.cs new file mode 100644 index 0000000..830eab8 --- /dev/null +++ b/PkmnLibRSharp/FFI/DynamicData/Libraries/ScriptResolver.cs @@ -0,0 +1,43 @@ +using System; +using System.Runtime.InteropServices; + +namespace PkmnLibSharp.FFI.DynamicData.Libraries +{ + internal static class ScriptResolver + { + /// + /// Instantiates a basic empty script resolver, that always returns None. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer empty_script_resolver_new(); + + /// + /// Drops a script resolver. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void script_resolver_drop(IntPtr ptr); + + // WASM is a feature flag in the crate, and can be disabled. If disabled, these entry points do not exist. In + // this case it's recommended to remove the WASM compile flag from the csproj as well. +#if WASM + /// + /// Instantiates a new WebAssemblyScriptResolver. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer webassembly_script_resolver_new(); + + /// + /// Load a compiled WASM module. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void webassembly_script_resolver_load_wasm_from_bytes(IntPtr resolver, IntPtr byteArray, + ulong arrayLength); + + /// + /// Tells the script resolver we're done loading wasm modules, and to finalize the resolver. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void webassembly_script_resolver_finalize(IntPtr resolver); +#endif + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/FFI/DynamicData/Pokemon.cs b/PkmnLibRSharp/FFI/DynamicData/Pokemon.cs new file mode 100644 index 0000000..9bdf24c --- /dev/null +++ b/PkmnLibRSharp/FFI/DynamicData/Pokemon.cs @@ -0,0 +1,306 @@ +using System; +using System.Runtime.InteropServices; +using PkmnLibSharp.DynamicData; +using PkmnLibSharp.FFI.StaticData; +using PkmnLibSharp.StaticData; + +namespace PkmnLibSharp.FFI.DynamicData +{ + internal static class Pokemon + { + /// + /// Instantiates a new Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_new(IntPtr dynamicLibrary, IntPtr species, IntPtr form, + byte hiddenAbility, byte abilityIndex, LevelInt level, uint uniqueIdentifier, Gender gender, byte coloring, + IntPtr natureName); + + /// + /// Drops an Arc reference held by the FFI. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void pokemon_drop(IntPtr pokemon); + + /// + /// The library data of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_library(IntPtr pokemon); + + /// + /// The species of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_species(IntPtr pokemon); + + /// + /// The form of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_form(IntPtr pokemon); + + /// + /// The species that should be displayed to the user. This handles stuff like the Illusion ability. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_display_species(IntPtr pokemon); + + /// + /// The form that should be displayed to the user. This handles stuff like the Illusion ability. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_display_form(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern LevelInt pokemon_level(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern uint pokemon_experience(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern uint pokemon_unique_identifier(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern Gender pokemon_gender(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_coloring(IntPtr pokemon); + + /// + /// Gets the held item of a Pokemon + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_held_item(IntPtr pokemon); + + /// + /// Checks whether the Pokemon is holding a specific item. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_has_held_item(IntPtr pokemon, IntPtr itemName); + + /// + /// Changes the held item of the Pokemon. Returns the previously held item. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_set_held_item(IntPtr pokemon, IntPtr item); + + /// + /// Removes the held item from the Pokemon. Returns the previously held item. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_remove_held_item(IntPtr pokemon); + + /// + /// Makes the Pokemon uses its held item. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_consume_held_item(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern uint pokemon_current_health(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern uint pokemon_max_health(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern float pokemon_weight(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern float pokemon_height(IntPtr pokemon); + + /// + /// An optional nickname of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IntPtr pokemon_nickname(IntPtr pokemon); + + /// + /// Whether the actual ability on the form is a hidden ability. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_real_ability_is_hidden(IntPtr pokemon); + + /// + /// The index of the actual ability on the form. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_real_ability_index(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern ulong pokemon_types_length(IntPtr pokemon); + + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern TypeIdentifier pokemon_types_get(IntPtr pokemon, ulong index); + + /// + /// Gets a learned move of the Pokemon. Index should generally be below [`MAX_MOVES`], you will get + /// a null pointer otherwise. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_learned_move_get(IntPtr pokemon, ulong index); + + /// + /// The stats of the Pokemon when disregarding any stat boosts. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_flat_stats(IntPtr pokemon); + + /// + /// The stats of the Pokemon including the stat boosts. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_boosted_stats(IntPtr pokemon); + + /// + /// Get the stat boosts for a specific stat. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern sbyte pokemon_get_stat_boost(IntPtr pokemon, Statistic statistic); + + /// + /// Change a boosted stat by a certain amount. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern sbyte pokemon_change_stat_boost(IntPtr pokemon, Statistic statistic, sbyte diffAmount, + byte selfInflicted); + + /// + /// Gets a individual value of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_get_individual_value(IntPtr pokemon, Statistic statistic); + + /// + /// Modifies a individual value of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void pokemon_set_individual_value(IntPtr pokemon, Statistic statistic, byte value); + + /// + /// Gets a effort value of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_get_effort_value(IntPtr pokemon, Statistic statistic); + + /// + /// Modifies a effort value of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void pokemon_set_effort_value(IntPtr pokemon, Statistic statistic, byte value); + + /// + /// Gets the data for the battle the Pokemon is currently in. If the Pokemon is not in a battle, this + /// returns null. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_get_battle(IntPtr pokemon); + + /// + /// Get the index of the side of the battle the Pokemon is in. If the Pokemon + /// is not on the battlefield, this always returns 0. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_get_battle_side_index(IntPtr pokemon); + + /// + /// Get the index of the slot on the side of the battle the Pokemon is in. If the Pokemon + /// is not on the battlefield, this always returns 0. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_get_battle_index(IntPtr pokemon); + + /// + /// Returns whether something overrides the ability. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_is_ability_overriden(IntPtr pokemon); + + /// + /// Returns the currently active ability. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_active_ability(IntPtr pokemon); + + /// + /// Whether or not the Pokemon is allowed to gain experience. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_allowed_experience_gain(IntPtr pokemon); + + /// + /// The nature of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IdentifiablePointer pokemon_nature(IntPtr pokemon); + + /// + /// Calculates the flat stats on the Pokemon. This should be called when for example the base + /// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted + /// stats, as those depend on the flat stats. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void pokemon_recalculate_flat_stats(IntPtr pokemon); + + /// + /// Calculates the boosted stats on the Pokemon. This should be called when a stat boost changes. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void pokemon_recalculate_boosted_stats(IntPtr pokemon); + + /// + /// Change the species of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void pokemon_change_species(IntPtr pokemon, IntPtr species, IntPtr form); + + /// + /// Change the form of the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void pokemon_change_form(IntPtr pokemon, IntPtr form); + + /// + /// Whether or not the Pokemon is usable in a battle. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_is_usable(IntPtr pokemon); + + /// + /// Returns whether the Pokemon is fainted. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_is_fainted(IntPtr pokemon); + + /// + /// Whether or not the Pokemon is on the battlefield. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_is_on_battlefield(IntPtr pokemon); + + /// + /// Damages the Pokemon by a certain amount of damage, from a damage source. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void pokemon_damage(IntPtr pokemon, uint damage, DamageSource damageSource); + + /// + /// Heals the Pokemon by a specific amount. Unless allowRevive is set to 1, this will not + /// heal if the Pokemon has 0 health. If the amount healed is 0, this will return false. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern byte pokemon_heal(IntPtr pokemon, uint damage, byte allowRevive); + + /// + /// Learn a move. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void pokemon_learn_move(IntPtr pokemon, IntPtr moveName, MoveLearnMethod learnMethod); + + /// + /// Removes the current non-volatile status from the Pokemon. + /// + [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void pokemon_clear_status(IntPtr pokemon); + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/FFI/IdentifiablePointer.cs b/PkmnLibRSharp/FFI/IdentifiablePointer.cs index 416067a..bfe2182 100644 --- a/PkmnLibRSharp/FFI/IdentifiablePointer.cs +++ b/PkmnLibRSharp/FFI/IdentifiablePointer.cs @@ -8,5 +8,7 @@ namespace PkmnLibSharp.FFI { public readonly IntPtr Ptr; public readonly nuint Identifier; + + public bool IsNull => Ptr == IntPtr.Zero; } } \ No newline at end of file diff --git a/PkmnLibRSharp/PkmnLibRSharp.csproj b/PkmnLibRSharp/PkmnLibRSharp.csproj index ecd94bd..7634494 100644 --- a/PkmnLibRSharp/PkmnLibRSharp.csproj +++ b/PkmnLibRSharp/PkmnLibRSharp.csproj @@ -11,11 +11,14 @@ 6 true ;NU1605;CA2000 + IDISP012 true + TRACE;WASM; true + TRACE;WASM; diff --git a/PkmnLibRSharp/StaticData/Ability.cs b/PkmnLibRSharp/StaticData/Ability.cs index cf46bf4..918e795 100644 --- a/PkmnLibRSharp/StaticData/Ability.cs +++ b/PkmnLibRSharp/StaticData/Ability.cs @@ -28,7 +28,7 @@ namespace PkmnLibSharp.StaticData true); } - internal Ability(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner) + internal Ability(IdentifiablePointer ptr) : base(ptr, true) { } diff --git a/PkmnLibRSharp/StaticData/Form.cs b/PkmnLibRSharp/StaticData/Form.cs index c6efa6b..f6cc9e4 100644 --- a/PkmnLibRSharp/StaticData/Form.cs +++ b/PkmnLibRSharp/StaticData/Form.cs @@ -23,7 +23,7 @@ namespace PkmnLibSharp.StaticData public LearnableMoves? LearnableMoves { get; internal set; } } - internal Form(IdentifiablePointer formPtr, bool isOwner) : base(formPtr, isOwner) + internal Form(IdentifiablePointer formPtr) : base(formPtr, true) { } diff --git a/PkmnLibRSharp/StaticData/Gender.cs b/PkmnLibRSharp/StaticData/Gender.cs new file mode 100644 index 0000000..1efafa4 --- /dev/null +++ b/PkmnLibRSharp/StaticData/Gender.cs @@ -0,0 +1,20 @@ +namespace PkmnLibSharp.StaticData +{ + public enum Gender : byte + { + /// + /// The Pokemon has no gender. + /// + Genderless = 0, + + /// + /// The Pokemon is male. + /// + Male = 1, + + /// + /// The Pokemon is female. + /// + Female = 2, + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/StaticData/Item.cs b/PkmnLibRSharp/StaticData/Item.cs index 6c99432..629c81d 100644 --- a/PkmnLibRSharp/StaticData/Item.cs +++ b/PkmnLibRSharp/StaticData/Item.cs @@ -104,7 +104,7 @@ namespace PkmnLibSharp.StaticData InitializePointer(ptr, true); } - internal Item(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner) + internal Item(IdentifiablePointer ptr) : base(ptr, true) { } diff --git a/PkmnLibRSharp/StaticData/Libraries/AbilityLibrary.cs b/PkmnLibRSharp/StaticData/Libraries/AbilityLibrary.cs index 58aa733..5fcf0a4 100644 --- a/PkmnLibRSharp/StaticData/Libraries/AbilityLibrary.cs +++ b/PkmnLibRSharp/StaticData/Libraries/AbilityLibrary.cs @@ -25,7 +25,7 @@ namespace PkmnLibSharp.StaticData.Libraries protected override Ability? GetValueByKey(string key) { var ptr = Interface.ability_library_get(Ptr, key.ToPtr()); - return ptr.Ptr == IntPtr.Zero ? null : new Ability(ptr, false); + return ptr.Ptr == IntPtr.Zero ? null : new Ability(ptr); } public override string? GetKeyByIndex(ulong index) => diff --git a/PkmnLibRSharp/StaticData/Libraries/ItemLibrary.cs b/PkmnLibRSharp/StaticData/Libraries/ItemLibrary.cs index 45c9037..a142123 100644 --- a/PkmnLibRSharp/StaticData/Libraries/ItemLibrary.cs +++ b/PkmnLibRSharp/StaticData/Libraries/ItemLibrary.cs @@ -25,7 +25,7 @@ namespace PkmnLibSharp.StaticData.Libraries protected override Item? GetValueByKey(string key) { var ptr = Interface.item_library_get(Ptr, key.ToPtr()); - return ptr.Ptr == IntPtr.Zero ? null : new Item(ptr, false); + return ptr.Ptr == IntPtr.Zero ? null : new Item(ptr); } public override string? GetKeyByIndex(ulong index) => diff --git a/PkmnLibRSharp/StaticData/Libraries/SpeciesLibrary.cs b/PkmnLibRSharp/StaticData/Libraries/SpeciesLibrary.cs index 928cc2d..d322261 100644 --- a/PkmnLibRSharp/StaticData/Libraries/SpeciesLibrary.cs +++ b/PkmnLibRSharp/StaticData/Libraries/SpeciesLibrary.cs @@ -25,7 +25,7 @@ namespace PkmnLibSharp.StaticData.Libraries protected override Species? GetValueByKey(string key) { var ptr = Interface.species_library_get(Ptr, key.ToPtr()); - return ptr.Ptr == IntPtr.Zero ? null : new Species(ptr, false); + return ptr.Ptr == IntPtr.Zero ? null : new Species(ptr); } public override string? GetKeyByIndex(ulong index) => diff --git a/PkmnLibRSharp/StaticData/Species.cs b/PkmnLibRSharp/StaticData/Species.cs index 904fe37..8c5f7ae 100644 --- a/PkmnLibRSharp/StaticData/Species.cs +++ b/PkmnLibRSharp/StaticData/Species.cs @@ -19,7 +19,7 @@ namespace PkmnLibSharp.StaticData public Dictionary Forms { get; } = new(); } - internal Species(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner) + internal Species(IdentifiablePointer ptr) : base(ptr, true) { } @@ -48,7 +48,8 @@ namespace PkmnLibSharp.StaticData form = null; return false; } - form = new Form(formPtr, false); + + form = new Form(formPtr); Cache.Forms.Add(formName, form); return true; } @@ -67,7 +68,7 @@ namespace PkmnLibSharp.StaticData form.Value.Invalidate(); } } - + ~Species() { Dispose(); diff --git a/PkmnLibRSharp/StaticData/StatisticSet.cs b/PkmnLibRSharp/StaticData/StatisticSet.cs index 8c88210..d726915 100644 --- a/PkmnLibRSharp/StaticData/StatisticSet.cs +++ b/PkmnLibRSharp/StaticData/StatisticSet.cs @@ -1,5 +1,6 @@ using System; using JetBrains.Annotations; +using PkmnLibSharp.FFI; using PkmnLibSharp.Utils; using Interface = PkmnLibSharp.FFI.StaticData.StatisticSet; @@ -7,6 +8,9 @@ namespace PkmnLibSharp.StaticData { public class StatisticSet : ExternPointer where T : struct, IConvertible { + internal StatisticSet(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner) + { + } public StatisticSet(T hp, T attack, T defense, T specialAttack, T specialDefense, T speed) { @@ -115,7 +119,7 @@ namespace PkmnLibSharp.StaticData else if (typeof(T) == typeof(short)) Interface.statistic_set_i16_drop(Ptr); else if (typeof(T) == typeof(int)) Interface.statistic_set_i32_drop(Ptr); } - + ~StatisticSet() { Dispose(); diff --git a/PkmnLibRSharp/Utils/ExternValueArray.cs b/PkmnLibRSharp/Utils/ExternValueArray.cs new file mode 100644 index 0000000..d64a0a8 --- /dev/null +++ b/PkmnLibRSharp/Utils/ExternValueArray.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace PkmnLibSharp.Utils +{ + public class ExternValueArray : IReadOnlyList where T : struct + { + private readonly Func _getLength; + private readonly Func _getItem; + + public ExternValueArray(Func getSize, Func getItem) + { + _getLength = getSize; + _getItem = getItem; + } + + public IEnumerator GetEnumerator() + { + for (var i = 0; i < Count; i++) + { + yield return this[i]; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public int Count => (int)_getLength(); + + public T this[int index] => _getItem((ulong)index); + } +} \ No newline at end of file diff --git a/PkmnLibRSharp/libpkmn_lib.so b/PkmnLibRSharp/libpkmn_lib.so index 1454a0f..8361eca 100755 --- a/PkmnLibRSharp/libpkmn_lib.so +++ b/PkmnLibRSharp/libpkmn_lib.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac83a8f9c15b0073673967d1a9be39bc8df15d9ae235458237e9cd5c1c956a2b -size 118173856 +oid sha256:39cf9d7a787d19ba082f2a6fd036ef384292c76f0018077951e504e0f2738d6a +size 118266520