Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
jhett12321 committed Nov 10, 2021
2 parents bf388a1 + 3fd20d9 commit da3b849
Show file tree
Hide file tree
Showing 38 changed files with 1,047 additions and 131 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,28 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## 8193.33.2
https://github.com/nwn-dotnet/Anvil/compare/v8193.33.1...v8193.33.2

### Added
- ResourceManager: Implemented GffResource API.
- [Inject]: Property-based dependencies can now be flagged as "Optional". Optional dependencies do not throw exceptions if the service could not be loaded from a missing plugin assembly.

### Changed
- `[ServiceBindingOptions]` - The `BindingPriority` property defines the initialization order of a service. (Higher priority = initialized first).
- When injecting a dependency of an interface/base class and multiple candidates are available, the service with the highest `BindingPriority` will be injected.
- `NwCreature.Age` can now be set.

### Deprecated
- `[ServiceBindingOptions]` - `Order` has been deprecated and replaced with the `BindingPriority` property.
- `[ServiceBindingOptions]` - `MissingPluginDependencies` has been deprecated as functionality is covered by the `BindingPriority` dependency resolve behaviour.
- `AttributeExtensions` - moved to `ReflectionExtensions`.
- `NwPlayer.NuiSetGroupLayout` - moved to `NuiGroup.SetLayout`.

### Fixed
- Properties injected into service classes with plugin dependency requirements will no-longer throw an exception when the assembly is missing.
- Fixed NuiGroup.SetLayout creating nested layout elements instead of updating the existing element (`NwPlayer.NuiSetGroupLayout` still has the old behaviour.)

## 8193.33.1
https://github.com/nwn-dotnet/Anvil/compare/v8193.33.0...v8193.33.1

Expand Down
143 changes: 81 additions & 62 deletions NWN.Anvil.csproj
Original file line number Diff line number Diff line change
@@ -1,64 +1,83 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<PackageId>NWN.Anvil</PackageId>
<Authors>NWN.NET</Authors>
<Description>
Anvil is a C# framework for building behaviours and adding new functionalty to Neverwinter Nights: Enhanced Edition. The library allows server owners and builders to create simple behaviours, while giving plugin developers the option to implement complex systems or modify existing hardcoded rules.
API Reference/Documentation - https://nwn-dotnet.github.io/Anvil/
GitHub, Issues and Discussions - https://github.com/nwn-dotnet/Anvil
Discord, Latest News, Help and Support - https://discord.gg/gKt495UBgS
</Description>
<!-- https://github.com/NuGet/Home/issues/10791 -->
<!-- <PackageReadmeFile>README.md</PackageReadmeFile> -->
<PackageTags>Neverwinter Nights;NWN;</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableDynamicLoading>true</EnableDynamicLoading>
<IncludeSymbols>true</IncludeSymbols>
<DebugSymbols>true</DebugSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<RepositoryUrl>https://github.com/nwn-dotnet/Anvil</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<NoWarn>1591</NoWarn>
<RootNamespace />
<LangVersion>9.0</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Configurations>Debug;Release;Samples</Configurations>
<Platforms>AnyCPU</Platforms>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="LightInject" Version="6.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NLog" Version="4.7.11" />
<PackageReference Include="NWN.Core" Version="8193.33.1" PrivateAssets="compile" />
<PackageReference Include="NWN.Native" Version="8193.33.0" PrivateAssets="compile" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="/" />
</ItemGroup>

<ItemGroup Condition=" '$(Configuration)' != 'Samples'">
<None Remove="docs\**" />
<EmbeddedResource Remove="docs\**" />
<Compile Remove="docs\**" />
</ItemGroup>

<Target Name="CreatePluginsFolder" AfterTargets="Build">
<MakeDir Directories="$(OutputPath)\Plugins" Condition="!Exists('$(OutputPath)\Plugins')" />
</Target>

<Target Name="ZipOutputPath" AfterTargets="CreatePluginsFolder">
<ZipDirectory Overwrite="true" SourceDirectory="$(OutputPath)" DestinationFile="$(OutputPath)\..\$(MSBuildProjectName).zip" />
</Target>
<!--Build-->
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>9.0</LangVersion>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>

<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>

<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<EnableDynamicLoading>true</EnableDynamicLoading>

<NoWarn>1591</NoWarn>

<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Configurations>Debug;Release;Samples</Configurations>
<Platforms>AnyCPU</Platforms>

<RootNamespace/>
</PropertyGroup>

<!--Package-->
<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>

<PackageId>$(AssemblyName)</PackageId>
<Authors>NWN.NET</Authors>

<RepositoryUrl>https://github.com/nwn-dotnet/Anvil</RepositoryUrl>
<RepositoryType>git</RepositoryType>

<Description>
Anvil is a C# framework for building behaviours and adding new functionalty to Neverwinter Nights: Enhanced Edition. The library allows server owners and builders to create simple behaviours, while giving plugin developers the option to implement complex systems or modify existing hardcoded rules.
API Reference/Documentation - https://nwn-dotnet.github.io/Anvil/
GitHub, Issues and Discussions - https://github.com/nwn-dotnet/Anvil
Discord, Latest News, Help and Support - https://discord.gg/gKt495UBgS
</Description>

<!-- https://github.com/NuGet/Home/issues/10791 -->
<!-- <PackageReadmeFile>README.md</PackageReadmeFile> -->
<PackageTags>Neverwinter Nights;NWN;</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>

<!--Debug/Source Link-->
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<DebugSymbols>true</DebugSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="LightInject" Version="6.4.0"/>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
<PackageReference Include="NLog" Version="4.7.12"/>
<PackageReference Include="NWN.Core" Version="8193.33.3" PrivateAssets="compile"/>
<PackageReference Include="NWN.Native" Version="8193.33.2" PrivateAssets="compile"/>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup>

<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="/"/>
</ItemGroup>

<ItemGroup Condition=" '$(Configuration)' != 'Samples'">
<None Remove="docs\**"/>
<EmbeddedResource Remove="docs\**"/>
<Compile Remove="docs\**"/>
</ItemGroup>

<Target Name="CreatePluginsFolder" AfterTargets="Build">
<MakeDir Directories="$(OutputPath)\Plugins" Condition="!Exists('$(OutputPath)\Plugins')"/>
</Target>

<Target Name="ZipOutputPath" AfterTargets="CreatePluginsFolder">
<ZipDirectory Overwrite="true" SourceDirectory="$(OutputPath)" DestinationFile="$(OutputPath)\..\$(MSBuildProjectName).zip"/>
</Target>
</Project>
3 changes: 3 additions & 0 deletions NWN.Anvil.csproj.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cnui_005Cwidgets/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cnui_005Cwidgets_005Cdrawlist/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cobject/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cresources/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cresources_005Cgff/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cresources_005Cgff_005Cfields/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cscripts/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cserver/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Ctransform/@EntryIndexedValue">True</s:Boolean>
Expand Down
2 changes: 2 additions & 0 deletions NWN.Anvil.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassCanBeSealed_002ELocal/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassNeverInstantiated_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassWithVirtualMembersNeverInherited_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CollectionNeverQueried_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CollectionNeverUpdated_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceDoWhileStatementBraces/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceFixedStatementBraces/@EntryIndexedValue">SUGGESTION</s:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Anvil.API
{
[ServiceBinding(typeof(MainThreadSynchronizationContext))]
[ServiceBinding(typeof(IUpdateable))]
[ServiceBindingOptions(BindingOrder.API)]
[ServiceBindingOptions(InternalBindingPriority.API)]
public sealed class MainThreadSynchronizationContext : SynchronizationContext, IUpdateable, IAwaitable
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
Expand Down
3 changes: 2 additions & 1 deletion src/main/Anvil/API/Extensions/AttributeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ namespace Anvil.API
{
public static class AttributeExtensions
{
public static T[] GetCustomAttributes<T>(this Type type, bool inherit = true) where T : Attribute
[Obsolete("Use ReflectionExtensions.GetCustomAttributes instead.")]
public static T[] GetCustomAttributes<T>(Type type, bool inherit = true) where T : Attribute
{
return (T[])type.GetCustomAttributes(typeof(T), inherit);
}
Expand Down
12 changes: 12 additions & 0 deletions src/main/Anvil/API/Extensions/CollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ public static IEnumerable<T> Yield<T>(this T item)
yield return item;
}

/// <summary>
/// Wraps this object instance into an IEnumerable&lt;T&gt; consisting of a single item.<br/>
/// If the item is null, returns an empty enumerable instead.
/// </summary>
/// <typeparam name="T">Type of the object.</typeparam>
/// <param name="item">The instance that will be wrapped.</param>
/// <returns>An IEnumerable&lt;T&gt; consisting of a single item. </returns>
public static IEnumerable<T> SafeYield<T>(this T item)
{
return item != null ? item.Yield() : Enumerable.Empty<T>();
}

public static void DisposeAll(this IEnumerable<IDisposable> disposables)
{
if (disposables == null)
Expand Down
39 changes: 38 additions & 1 deletion src/main/Anvil/API/Extensions/ReflectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,49 @@
using System;
using System.Linq;
using System.Reflection;

namespace Anvil.API
{
internal static class ReflectionExtensions
public static class ReflectionExtensions
{
/// <summary>
/// Gets all attributes of a specific type on the specified type.
/// </summary>
/// <param name="type">The type to get attributes from</param>
/// <param name="inherit">true if attributes should be inherited from base types</param>
/// <typeparam name="T">The type of attribute to get</typeparam>
/// <returns>An array of attributes applied to this type, or an empty array if no attributes are found.</returns>
public static T[] GetCustomAttributes<T>(this Type type, bool inherit = true) where T : Attribute
{
return (T[])type.GetCustomAttributes(typeof(T), inherit);
}

/// <summary>
/// Gets all attributes of a specific type on the specified member.
/// </summary>
/// <param name="member">The member to get attributes from</param>
/// <param name="inherit">true if attributes should be inherited from base types</param>
/// <typeparam name="T">The type of attribute to get</typeparam>
/// <returns>An array of attributes applied to this member, or an empty array if no attributes are found.</returns>
public static T[] GetCustomAttributes<T>(this MemberInfo member, bool inherit = true) where T : Attribute
{
return (T[])member.GetCustomAttributes(typeof(T), inherit);
}

/// <summary>
/// Gets the full name of the specified type member.
/// </summary>
/// <param name="member">The member to get the name of.</param>
/// <returns>The full name of the member, prefixed with the namespace and enclosing type (if valid). If the member is not declared in a type, returns the member name.</returns>
public static string GetFullName(this MemberInfo member)
{
return member.DeclaringType != null ? $"{member.DeclaringType.FullName}.{member.Name}" : member.Name;
}

public static T SafeGetCustomAttribute<T>(this MemberInfo memberInfo, bool inherit = true)
{
// GetCustomAttribute(Type) or GetCustomAttribute<T>() will throw an exception on types with missing assembly references, as they navigate into the type.
return memberInfo.GetCustomAttributes(inherit).OfType<T>().FirstOrDefault();
}
}
}
11 changes: 11 additions & 0 deletions src/main/Anvil/API/Nui/Layout/NuiColumn.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Anvil.API
{
/// <summary>
Expand All @@ -6,5 +9,13 @@ namespace Anvil.API
public sealed class NuiColumn : NuiLayout
{
public override string Type { get => "col"; }

[JsonIgnore]
public List<NuiElement> Children { get; set; } = new List<NuiElement>();

protected override IEnumerable<NuiElement> SerializedChildren
{
get => Children;
}
}
}
29 changes: 29 additions & 0 deletions src/main/Anvil/API/Nui/Layout/NuiGroup.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using NWN.Core;

namespace Anvil.API
{
Expand All @@ -15,5 +18,31 @@ public sealed class NuiGroup : NuiLayout

[JsonProperty("scrollbars")]
public NuiScrollbars Scrollbars { get; set; } = NuiScrollbars.Auto;

[JsonIgnore]
public NuiLayout Layout { get; set; }

protected override IEnumerable<NuiElement> SerializedChildren
{
get => Layout.SafeYield();
}

/// <summary>
/// Sets the group layout for a specific player + window token (override/partial update).<br/>
/// </summary>
/// <param name="player">The player with the window containing this group.</param>
/// <param name="token">The token of the window to update.</param>
/// <param name="newLayout">The new layout to apply to this group.</param>
/// <exception cref="InvalidOperationException">Thrown if this group does not have an Id assigned.</exception>
public void SetLayout(NwPlayer player, int token, NuiLayout newLayout)
{
if (string.IsNullOrEmpty(Id))
{
throw new InvalidOperationException("Layout cannot be updated as the NuiGroup does not have an ID.");
}

Json json = Json.Parse(JsonConvert.SerializeObject(newLayout));
NWScript.NuiSetGroupLayout(player.ControlledCreature, token, Id, json);
}
}
}
2 changes: 1 addition & 1 deletion src/main/Anvil/API/Nui/Layout/NuiLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ namespace Anvil.API
public abstract class NuiLayout : NuiElement
{
[JsonProperty("children")]
public List<NuiElement> Children { get; set; } = new List<NuiElement>();
protected abstract IEnumerable<NuiElement> SerializedChildren { get; }
}
}
11 changes: 11 additions & 0 deletions src/main/Anvil/API/Nui/Layout/NuiRow.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Anvil.API
{
/// <summary>
Expand All @@ -6,5 +9,13 @@ namespace Anvil.API
public sealed class NuiRow : NuiLayout
{
public override string Type { get; } = "row";

[JsonIgnore]
public List<NuiElement> Children { get; set; } = new List<NuiElement>();

protected override IEnumerable<NuiElement> SerializedChildren
{
get => Children;
}
}
}
5 changes: 3 additions & 2 deletions src/main/Anvil/API/Object/NwCreature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,12 @@ public byte BaseAttackBonus
}

/// <summary>
/// Gets this creature's age, in years.
/// Gets or sets this creature's age, in years.
/// </summary>
public int Age
{
get => NWScript.GetAge(this);
get => Creature.m_pStats.m_nAge;
set => Creature.m_pStats.m_nAge = value;
}

/// <summary>
Expand Down
Loading

0 comments on commit da3b849

Please sign in to comment.