Initial work on DynamicLibrary up to and including the Pokemon model.
continuous-integration/drone/push Build is failing Details
continuous-integration/drone Build is passing Details

This commit is contained in:
Deukhoofd 2023-01-03 16:53:58 +01:00
parent 6c0e56ba1e
commit 3369696956
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
28 changed files with 849 additions and 16 deletions

View File

@ -0,0 +1,20 @@
namespace PkmnLibSharp.DynamicData
{
public enum DamageSource : byte
{
/// <summary>
/// The damage is done by a move.
/// </summary>
MoveDamage = 0,
/// <summary>
/// The damage is done by something else.
/// </summary>
Misc = 1,
/// <summary>
/// The damage is done because of struggling.
/// </summary>
Struggle = 2,
}
}

View File

@ -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.
/// </summary>
public MoveData MoveData => Cache.MoveData ??= new MoveData(Interface.learned_move_move_data(Ptr), true);
/// <summary>
/// The maximal power points for this move.
/// </summary>
public byte MaxPP => Interface.learned_move_max_pp(Ptr);
/// <summary>
/// The amount of remaining power points. If this is 0, we can not use the move anymore.
/// </summary>
public byte RemainingPP => Interface.learned_move_remaining_pp(Ptr);
/// <summary>
/// The way the move was learned.
/// </summary>
@ -47,7 +52,7 @@ namespace PkmnLibSharp.DynamicData
/// Set the remaining PP to the max amount of PP.
/// </summary>
public void RestoreAllUses() => Interface.learned_move_restore_all_uses(Ptr);
/// <summary>
/// Restore the remaining PP by a certain amount. Will prevent it from going above max PP.
/// </summary>
@ -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,
}

View File

@ -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<object>
{
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)
{
}
}
}

View File

@ -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<object>
{
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)
{
}
}
}

View File

@ -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<DynamicLibrary.CacheData>
{
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);
}
}

View File

@ -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<object>
{
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)
{
}
}
}

View File

@ -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<ScriptResolver.CacheData>
{
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);
}
}
/// <summary>
/// An implementation of a script resolver that pretends there are no existing scripts.
/// </summary>
public class EmptyScriptResolver : ScriptResolver
{
public EmptyScriptResolver() : base(Interface.empty_script_resolver_new()){}
}
}

View File

@ -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){}
/// <summary>
/// Loads a compiled WASM module into the script resolver.
/// </summary>
/// <param name="data">The bytes of a compiled WASM module</param>
public void LoadBytes(byte[] data)
{
Interface.webassembly_script_resolver_load_wasm_from_bytes(Ptr, data.ArrayPtr(), (ulong)data.LongLength);
}
/// <summary>
/// Tells the script resolver we're done loading wasm modules, and to finalize the resolver. After this it is
/// ready for use.
/// </summary>
public void FinalizeResolver()
{
Interface.webassembly_script_resolver_finalize(Ptr);
}
}
}
#endif

View File

@ -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<Pokemon.CacheData>
{
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)
{
}
/// <summary>
/// The library data the Pokemon uses.
/// </summary>
public DynamicLibrary Library => Cache.DynamicLibrary ??= new DynamicLibrary(Interface.pokemon_library(Ptr));
/// <summary>
/// The species of the Pokemon.
/// </summary>
public Species Species => new(Interface.pokemon_species(Ptr));
/// <summary>
/// The form of the Pokemon.
/// </summary>
public Form Form => new(Interface.pokemon_form(Ptr));
/// <summary>
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
/// </summary>
public Species DisplaySpecies => new(Interface.pokemon_display_species(Ptr));
/// <summary>
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
/// </summary>
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<TypeIdentifier> Types =>
Cache.Types ??= new ExternValueArray<TypeIdentifier>(() => 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<uint> FlatStats =>
Cache.FlatStats ??= new StatisticSet<uint>(Interface.pokemon_flat_stats(Ptr), false);
public StatisticSet<uint> BoostedStats =>
Cache.BoostedStats ??= new StatisticSet<uint>(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<TypeIdentifier>? Types { get; set; }
public StatisticSet<uint>? FlatStats { get; set; }
public StatisticSet<uint>? BoostedStats { get; set; }
}
protected override CacheData CreateCache() => new();
protected override void Destructor() => Interface.pokemon_drop(Ptr);
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Runtime.InteropServices;
using PkmnLibSharp.DynamicData;
namespace PkmnLibSharp.FFI.DynamicData.Libraries
{
internal static class BattleStatCalculator
{
/// <summary>
/// Creates a new Gen 7 battle stat calculator
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer gen_7_battle_stat_calculator_new();
/// <summary>
/// Creates a new Gen 7 battle stat calculator
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void battle_stat_calculator_drop(IntPtr ptr);
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Runtime.InteropServices;
namespace PkmnLibSharp.FFI.DynamicData.Libraries
{
internal static class DamageLibrary
{
/// <summary>
/// Creates a new generation 7 damage library.
/// </summary>
/// <param name="hasRandomness">whether or not a random damage modifier (0.85x - 1.00x) is applied to the
/// calculated damage. 0 for not, 1 for true</param>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer gen_7_damage_library_new(byte hasRandomness);
/// <summary>
/// Drops a DamageLibrary.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void damage_library_drop(IntPtr ptr);
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Runtime.InteropServices;
namespace PkmnLibSharp.FFI.DynamicData.Libraries
{
internal static class DynamicLibrary
{
/// <summary>
/// Instantiates a new DynamicLibrary with given parameters.
/// </summary>
[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);
/// <summary>
/// Drops a dynamic library.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void dynamic_library_drop(IntPtr dynamicLibrary);
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Runtime.InteropServices;
namespace PkmnLibSharp.FFI.DynamicData.Libraries
{
internal static class MiscLibrary
{
/// <summary>
/// Instantiates a new MiscLibrary.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer gen_7_misc_library_new();
/// <summary>
/// Drops a MiscLibrary.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void misc_library_drop(IntPtr ptr);
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Runtime.InteropServices;
namespace PkmnLibSharp.FFI.DynamicData.Libraries
{
internal static class ScriptResolver
{
/// <summary>
/// Instantiates a basic empty script resolver, that always returns None.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer empty_script_resolver_new();
/// <summary>
/// Drops a script resolver.
/// </summary>
[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
/// <summary>
/// Instantiates a new WebAssemblyScriptResolver.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer webassembly_script_resolver_new();
/// <summary>
/// Load a compiled WASM module.
/// </summary>
[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);
/// <summary>
/// Tells the script resolver we're done loading wasm modules, and to finalize the resolver.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void webassembly_script_resolver_finalize(IntPtr resolver);
#endif
}
}

View File

@ -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
{
/// <summary>
/// Instantiates a new Pokemon.
/// </summary>
[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);
/// <summary>
/// Drops an Arc reference held by the FFI.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void pokemon_drop(IntPtr pokemon);
/// <summary>
/// The library data of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_library(IntPtr pokemon);
/// <summary>
/// The species of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_species(IntPtr pokemon);
/// <summary>
/// The form of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_form(IntPtr pokemon);
/// <summary>
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_display_species(IntPtr pokemon);
/// <summary>
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
/// </summary>
[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);
/// <summary>
/// Gets the held item of a Pokemon
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_held_item(IntPtr pokemon);
/// <summary>
/// Checks whether the Pokemon is holding a specific item.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_has_held_item(IntPtr pokemon, IntPtr itemName);
/// <summary>
/// Changes the held item of the Pokemon. Returns the previously held item.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_set_held_item(IntPtr pokemon, IntPtr item);
/// <summary>
/// Removes the held item from the Pokemon. Returns the previously held item.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_remove_held_item(IntPtr pokemon);
/// <summary>
/// Makes the Pokemon uses its held item.
/// </summary>
[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);
/// <summary>
/// An optional nickname of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IntPtr pokemon_nickname(IntPtr pokemon);
/// <summary>
/// Whether the actual ability on the form is a hidden ability.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_real_ability_is_hidden(IntPtr pokemon);
/// <summary>
/// The index of the actual ability on the form.
/// </summary>
[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);
/// <summary>
/// Gets a learned move of the Pokemon. Index should generally be below [`MAX_MOVES`], you will get
/// a null pointer otherwise.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_learned_move_get(IntPtr pokemon, ulong index);
/// <summary>
/// The stats of the Pokemon when disregarding any stat boosts.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_flat_stats(IntPtr pokemon);
/// <summary>
/// The stats of the Pokemon including the stat boosts.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_boosted_stats(IntPtr pokemon);
/// <summary>
/// Get the stat boosts for a specific stat.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern sbyte pokemon_get_stat_boost(IntPtr pokemon, Statistic statistic);
/// <summary>
/// Change a boosted stat by a certain amount.
/// </summary>
[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);
/// <summary>
/// Gets a <a href="https://bulbapedia.bulbagarden.net/wiki/Individual_values">individual value</a> of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_get_individual_value(IntPtr pokemon, Statistic statistic);
/// <summary>
/// Modifies a <a href="https://bulbapedia.bulbagarden.net/wiki/Individual_values">individual value</a> of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void pokemon_set_individual_value(IntPtr pokemon, Statistic statistic, byte value);
/// <summary>
/// Gets a <a href="https://bulbapedia.bulbagarden.net/wiki/Effort_values">effort value</a> of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_get_effort_value(IntPtr pokemon, Statistic statistic);
/// <summary>
/// Modifies a <a href="https://bulbapedia.bulbagarden.net/wiki/Effort_values">effort value</a> of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void pokemon_set_effort_value(IntPtr pokemon, Statistic statistic, byte value);
/// <summary>
/// Gets the data for the battle the Pokemon is currently in. If the Pokemon is not in a battle, this
/// returns null.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_get_battle(IntPtr pokemon);
/// <summary>
/// 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.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_get_battle_side_index(IntPtr pokemon);
/// <summary>
/// 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.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_get_battle_index(IntPtr pokemon);
/// <summary>
/// Returns whether something overrides the ability.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_is_ability_overriden(IntPtr pokemon);
/// <summary>
/// Returns the currently active ability.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_active_ability(IntPtr pokemon);
/// <summary>
/// Whether or not the Pokemon is allowed to gain experience.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_allowed_experience_gain(IntPtr pokemon);
/// <summary>
/// The <a href="https://bulbapedia.bulbagarden.net/wiki/Nature">nature</a> of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern IdentifiablePointer pokemon_nature(IntPtr pokemon);
/// <summary>
/// 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.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void pokemon_recalculate_flat_stats(IntPtr pokemon);
/// <summary>
/// Calculates the boosted stats on the Pokemon. This should be called when a stat boost changes.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void pokemon_recalculate_boosted_stats(IntPtr pokemon);
/// <summary>
/// Change the species of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void pokemon_change_species(IntPtr pokemon, IntPtr species, IntPtr form);
/// <summary>
/// Change the form of the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void pokemon_change_form(IntPtr pokemon, IntPtr form);
/// <summary>
/// Whether or not the Pokemon is usable in a battle.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_is_usable(IntPtr pokemon);
/// <summary>
/// Returns whether the Pokemon is fainted.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_is_fainted(IntPtr pokemon);
/// <summary>
/// Whether or not the Pokemon is on the battlefield.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_is_on_battlefield(IntPtr pokemon);
/// <summary>
/// Damages the Pokemon by a certain amount of damage, from a damage source.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void pokemon_damage(IntPtr pokemon, uint damage, DamageSource damageSource);
/// <summary>
/// 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.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern byte pokemon_heal(IntPtr pokemon, uint damage, byte allowRevive);
/// <summary>
/// Learn a move.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void pokemon_learn_move(IntPtr pokemon, IntPtr moveName, MoveLearnMethod learnMethod);
/// <summary>
/// Removes the current non-volatile status from the Pokemon.
/// </summary>
[DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern void pokemon_clear_status(IntPtr pokemon);
}
}

View File

@ -8,5 +8,7 @@ namespace PkmnLibSharp.FFI
{
public readonly IntPtr Ptr;
public readonly nuint Identifier;
public bool IsNull => Ptr == IntPtr.Zero;
}
}

View File

@ -11,11 +11,14 @@
<WarningLevel>6</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors>;NU1605;CA2000</WarningsAsErrors>
<NoWarn>IDISP012</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>TRACE;WASM;</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>TRACE;WASM;</DefineConstants>
</PropertyGroup>
<ItemGroup>

View File

@ -28,7 +28,7 @@ namespace PkmnLibSharp.StaticData
true);
}
internal Ability(IdentifiablePointer ptr, bool isOwner) : base(ptr, isOwner)
internal Ability(IdentifiablePointer ptr) : base(ptr, true)
{
}

View File

@ -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)
{
}

View File

@ -0,0 +1,20 @@
namespace PkmnLibSharp.StaticData
{
public enum Gender : byte
{
/// <summary>
/// The Pokemon has no gender.
/// </summary>
Genderless = 0,
/// <summary>
/// The Pokemon is male.
/// </summary>
Male = 1,
/// <summary>
/// The Pokemon is female.
/// </summary>
Female = 2,
}
}

View File

@ -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)
{
}

View File

@ -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) =>

View File

@ -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) =>

View File

@ -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) =>

View File

@ -19,7 +19,7 @@ namespace PkmnLibSharp.StaticData
public Dictionary<string, Form> 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();

View File

@ -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<T> : ExternPointer<object> 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();

View File

@ -0,0 +1,35 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace PkmnLibSharp.Utils
{
public class ExternValueArray<T> : IReadOnlyList<T> where T : struct
{
private readonly Func<ulong> _getLength;
private readonly Func<ulong, T> _getItem;
public ExternValueArray(Func<ulong> getSize, Func<ulong, T> getItem)
{
_getLength = getSize;
_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 => (int)_getLength();
public T this[int index] => _getItem((ulong)index);
}
}

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

Binary file not shown.