diff --git a/PkmnLibSharp/Library/GrowthRates/GrowthRateLibrary.cs b/PkmnLibSharp/Library/GrowthRates/GrowthRateLibrary.cs index 139de1a..463d97f 100644 --- a/PkmnLibSharp/Library/GrowthRates/GrowthRateLibrary.cs +++ b/PkmnLibSharp/Library/GrowthRates/GrowthRateLibrary.cs @@ -1,3 +1,4 @@ +using System; using PkmnLibSharp.Utilities; namespace PkmnLibSharp.Library.GrowthRates @@ -28,7 +29,7 @@ namespace PkmnLibSharp.Library.GrowthRates { Creatureliblibrary.Generated.GrowthRateLibrary.AddGrowthRate(Ptr, name.ToPtr(), gr.Ptr).Assert(); } - + protected override void DeletePtr() { Creatureliblibrary.Generated.GrowthRateLibrary.Destruct(Ptr); diff --git a/PkmnLibSharp/Library/GrowthRates/LookupGrowthRate.cs b/PkmnLibSharp/Library/GrowthRates/LookupGrowthRate.cs index f2bc8bd..c8dd8c7 100644 --- a/PkmnLibSharp/Library/GrowthRates/LookupGrowthRate.cs +++ b/PkmnLibSharp/Library/GrowthRates/LookupGrowthRate.cs @@ -1,3 +1,4 @@ +using System; using PkmnLibSharp.Utilities; namespace PkmnLibSharp.Library.GrowthRates diff --git a/PkmnLibSharp/Library/Items/ItemLibrary.cs b/PkmnLibSharp/Library/Items/ItemLibrary.cs index 3cd01c0..5d14ae3 100644 --- a/PkmnLibSharp/Library/Items/ItemLibrary.cs +++ b/PkmnLibSharp/Library/Items/ItemLibrary.cs @@ -54,6 +54,10 @@ namespace PkmnLibSharp.Library.Items return item; } + internal ItemLibrary(IntPtr ptr) : base(ptr) + { + } + public ItemLibrary(ulong initialCapacity) : base( Creatureliblibrary.Generated.ItemLibrary.Construct(initialCapacity)) { diff --git a/PkmnLibSharp/Library/LibrarySettings.cs b/PkmnLibSharp/Library/LibrarySettings.cs index 1de223d..d91882c 100644 --- a/PkmnLibSharp/Library/LibrarySettings.cs +++ b/PkmnLibSharp/Library/LibrarySettings.cs @@ -1,3 +1,4 @@ +using System; using PkmnLibSharp.Utilities; namespace PkmnLibSharp.Library @@ -7,7 +8,15 @@ namespace PkmnLibSharp.Library public byte MaximalLevel => Creatureliblibrary.Generated.LibrarySettings.GetMaximalLevel(Ptr); public byte MaximalMoves => Creatureliblibrary.Generated.LibrarySettings.GetMaximalMoves(Ptr); public ushort ShinyRate => Pkmnlib.Generated.LibrarySettings.GetShinyRate(Ptr); - + + internal LibrarySettings() + { + } + + internal LibrarySettings(IntPtr ptr) : base(ptr) + { + } + public LibrarySettings(byte maximalLevel, byte maximalMoves, ushort shinyRate) : base( Pkmnlib.Generated.LibrarySettings.Construct(maximalLevel, maximalMoves, shinyRate)) { diff --git a/PkmnLibSharp/Library/PokemonLibrary.cs b/PkmnLibSharp/Library/PokemonLibrary.cs new file mode 100644 index 0000000..0ef191a --- /dev/null +++ b/PkmnLibSharp/Library/PokemonLibrary.cs @@ -0,0 +1,63 @@ +using System; +using Creatureliblibrary.Generated; +using PkmnLibSharp.Library.Moves; +using PkmnLibSharp.Utilities; +using GrowthRateLibrary = PkmnLibSharp.Library.GrowthRates.GrowthRateLibrary; +using ItemLibrary = PkmnLibSharp.Library.Items.ItemLibrary; + +namespace PkmnLibSharp.Library +{ + public class PokemonLibrary : PointerWrapper + { + private LibrarySettings _settings; + + public LibrarySettings Settings => + _settings ??= ResolveOrCreatePtr(DataLibrary.GetSettings(Ptr)); + + private SpeciesLibrary _species; + + public SpeciesLibrary SpeciesLibrary => + _species ??= ResolveOrCreatePtr(DataLibrary.GetSpeciesLibrary(Ptr)); + + private MoveLibrary _moves; + public MoveLibrary MoveLibrary => _moves ??= ResolveOrCreatePtr(DataLibrary.GetAttackLibrary(Ptr)); + + private ItemLibrary _items; + public ItemLibrary ItemLibrary => _items ??= ResolveOrCreatePtr(DataLibrary.GetItemLibrary(Ptr)); + + private GrowthRateLibrary _growthRateLibrary; + + public GrowthRateLibrary GrowthRateLibrary => _growthRateLibrary ??= + ResolveOrCreatePtr(DataLibrary.GetGrowthRates(Ptr)); + + private TypeLibrary _typeLibrary; + + public TypeLibrary TypeLibrary => + _typeLibrary ??= ResolveOrCreatePtr(DataLibrary.GetTypeLibrary(Ptr)); + + private NatureLibrary _natureLibrary; + + public NatureLibrary NatureLibrary => _natureLibrary ??= + ResolveOrCreatePtr(Pkmnlib.Generated.PokemonLibrary.GetNatureLibrary(Ptr)); + + + internal PokemonLibrary(IntPtr ptr) : base(ptr) + { + } + + public static PokemonLibrary Create(LibrarySettings settings, SpeciesLibrary species, MoveLibrary moves, + ItemLibrary items, + GrowthRateLibrary growthRates, TypeLibrary types, NatureLibrary natures) + { + var ptr = IntPtr.Zero; + Pkmnlib.Generated.PokemonLibrary.Construct(ref ptr, settings.Ptr, species.Ptr, moves.Ptr, items.Ptr, + growthRates.Ptr, types.Ptr, natures.Ptr).Assert(); + return new PokemonLibrary(ptr); + } + + protected override void DeletePtr() + { + Pkmnlib.Generated.PokemonLibrary.Destruct(Ptr); + } + } +} \ No newline at end of file diff --git a/PkmnLibSharp/Library/SpeciesLibrary.cs b/PkmnLibSharp/Library/SpeciesLibrary.cs index 5d65c64..08d4124 100644 --- a/PkmnLibSharp/Library/SpeciesLibrary.cs +++ b/PkmnLibSharp/Library/SpeciesLibrary.cs @@ -54,6 +54,10 @@ namespace PkmnLibSharp.Library return species; } + internal SpeciesLibrary(IntPtr ptr) : base(ptr) + { + } + public SpeciesLibrary(ulong initialCapacity) : base( Creatureliblibrary.Generated.SpeciesLibrary.Construct(initialCapacity)) { diff --git a/PkmnLibSharp/Utilities/PointerWrapper.cs b/PkmnLibSharp/Utilities/PointerWrapper.cs index aa10ba1..380264e 100644 --- a/PkmnLibSharp/Utilities/PointerWrapper.cs +++ b/PkmnLibSharp/Utilities/PointerWrapper.cs @@ -1,19 +1,24 @@ using System; using System.Collections.Concurrent; +using System.Linq; +using System.Reflection; namespace PkmnLibSharp.Utilities { public abstract class PointerWrapper : IDisposable { private readonly IntPtr _ptr; + internal IntPtr Ptr { get { if (_isDeleted) { - throw new Exception("Pointer access after dispose detected. This is not legal, and will cause native exceptions."); + throw new Exception( + "Pointer access after dispose detected. This is not legal, and will cause native exceptions."); } + return _ptr; } } @@ -23,13 +28,17 @@ namespace PkmnLibSharp.Utilities private static readonly ConcurrentDictionary> Cached = new ConcurrentDictionary>(); + private protected PointerWrapper() + { + } + protected PointerWrapper(IntPtr ptr) { _ptr = ptr; var weakRef = new WeakReference(this); - Cached.TryAdd(ptr, weakRef); + Cached.AddOrUpdate(ptr, weakRef, (intPtr, reference) => weakRef); } - + ~PointerWrapper() { if (!_isDeleted) @@ -42,15 +51,43 @@ namespace PkmnLibSharp.Utilities { if (val.TryGetTarget(out var target)) { - result = (T) target; - return true; + if (target is T r) + { + result = r; + return true; + } } } + result = null; return false; } + public static T ResolveOrCreatePtr(IntPtr p) where T : PointerWrapper + { + if (TryResolvePointer(p, out var result)) + return result; + var ctor = typeof(T) + .GetConstructors( + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.Instance + ) + .FirstOrDefault(x => + { + var pars = x.GetParameters(); + return pars.Length == 1 && pars[0].ParameterType == typeof(IntPtr); + }); + if (ctor == null) + { + throw new Exception($"Unable to find constructor of type {typeof(T).FullName} with a single parameter of IntPtr."); + } + var instance = ctor.Invoke(new object[] {p}) as T; + return instance; + } + protected abstract void DeletePtr(); + public virtual void Dispose() { if (_isDeleted) @@ -59,5 +96,23 @@ namespace PkmnLibSharp.Utilities DeletePtr(); _isDeleted = true; } + + protected bool Equals(PointerWrapper other) + { + return _ptr.Equals(other._ptr); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((PointerWrapper) obj); + } + + public override int GetHashCode() + { + return _ptr.GetHashCode(); + } } } \ No newline at end of file diff --git a/PkmnLibSharpTests/Library/PokemonLibraryTests.cs b/PkmnLibSharpTests/Library/PokemonLibraryTests.cs new file mode 100644 index 0000000..6d1931e --- /dev/null +++ b/PkmnLibSharpTests/Library/PokemonLibraryTests.cs @@ -0,0 +1,146 @@ +using NUnit.Framework; +using PkmnLibSharp.Library; +using PkmnLibSharp.Library.GrowthRates; +using PkmnLibSharp.Library.Items; +using PkmnLibSharp.Library.Moves; + +namespace PkmnLibSharpTests.Library +{ + public class PokemonLibraryTests + { + [Test] + public void ConstructDestruct() + { + var settings = new LibrarySettings(100, 4, 4096); + var species = new SpeciesLibrary(10); + var moves = MoveLibrary.Create(10); + var items = new ItemLibrary(10); + var gr = new GrowthRateLibrary(10); + var types = new TypeLibrary(10); + var natures = new NatureLibrary(10); + + var lib = PokemonLibrary.Create(settings, species, moves, items, gr, types, natures); + lib.Dispose(); + } + + [Test] + public void GetSpeciesLibrary() + { + var settings = new LibrarySettings(100, 4, 4096); + var species = new SpeciesLibrary(10); + var moves = MoveLibrary.Create(10); + var items = new ItemLibrary(10); + var gr = new GrowthRateLibrary(10); + var types = new TypeLibrary(10); + var natures = new NatureLibrary(10); + + var lib = PokemonLibrary.Create(settings, species, moves, items, gr, types, natures); + var s = lib.SpeciesLibrary; + Assert.AreEqual(species, s); + lib.Dispose(); + } + + [Test] + public void GetLibrarySettings() + { + var settings = new LibrarySettings(100, 4, 4096); + var species = new SpeciesLibrary(10); + var moves = MoveLibrary.Create(10); + var items = new ItemLibrary(10); + var gr = new GrowthRateLibrary(10); + var types = new TypeLibrary(10); + var natures = new NatureLibrary(10); + + var lib = PokemonLibrary.Create(settings, species, moves, items, gr, types, natures); + var s = lib.Settings; + Assert.AreEqual(settings, s); + lib.Dispose(); + } + + [Test] + public void GetMoveLibrary() + { + var settings = new LibrarySettings(100, 4, 4096); + var species = new SpeciesLibrary(10); + var moves = MoveLibrary.Create(10); + var items = new ItemLibrary(10); + var gr = new GrowthRateLibrary(10); + var types = new TypeLibrary(10); + var natures = new NatureLibrary(10); + + var lib = PokemonLibrary.Create(settings, species, moves, items, gr, types, natures); + var m = lib.MoveLibrary; + Assert.AreEqual(moves, m); + lib.Dispose(); + } + + [Test] + public void GetItemLibrary() + { + var settings = new LibrarySettings(100, 4, 4096); + var species = new SpeciesLibrary(10); + var moves = MoveLibrary.Create(10); + var items = new ItemLibrary(10); + var gr = new GrowthRateLibrary(10); + var types = new TypeLibrary(10); + var natures = new NatureLibrary(10); + + var lib = PokemonLibrary.Create(settings, species, moves, items, gr, types, natures); + var i = lib.ItemLibrary; + Assert.AreEqual(items, i); + lib.Dispose(); + } + + [Test] + public void GetGrowthRateLibrary() + { + var settings = new LibrarySettings(100, 4, 4096); + var species = new SpeciesLibrary(10); + var moves = MoveLibrary.Create(10); + var items = new ItemLibrary(10); + var gr = new GrowthRateLibrary(10); + var types = new TypeLibrary(10); + var natures = new NatureLibrary(10); + + var lib = PokemonLibrary.Create(settings, species, moves, items, gr, types, natures); + var g = lib.GrowthRateLibrary; + Assert.AreEqual(gr, g); + lib.Dispose(); + } + + [Test] + public void GetTypeLibrary() + { + var settings = new LibrarySettings(100, 4, 4096); + var species = new SpeciesLibrary(10); + var moves = MoveLibrary.Create(10); + var items = new ItemLibrary(10); + var gr = new GrowthRateLibrary(10); + var types = new TypeLibrary(10); + var natures = new NatureLibrary(10); + + var lib = PokemonLibrary.Create(settings, species, moves, items, gr, types, natures); + var t = lib.TypeLibrary; + Assert.AreEqual(types, t); + lib.Dispose(); + } + + [Test] + public void GetNatureLibrary() + { + var settings = new LibrarySettings(100, 4, 4096); + var species = new SpeciesLibrary(10); + var moves = MoveLibrary.Create(10); + var items = new ItemLibrary(10); + var gr = new GrowthRateLibrary(10); + var types = new TypeLibrary(10); + var natures = new NatureLibrary(10); + + var lib = PokemonLibrary.Create(settings, species, moves, items, gr, types, natures); + var n = lib.NatureLibrary; + Assert.AreEqual(natures, n); + lib.Dispose(); + } + + } +} \ No newline at end of file