Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
jhett12321 committed Jan 30, 2023
2 parents 63f54c1 + 9c3afdb commit cdb00a0
Show file tree
Hide file tree
Showing 36 changed files with 841 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
NWN_VERSION=8193.34
NWNX_VERSION=fe195ec
NWNX_VERSION=2692ecb
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,44 @@ 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.34.23
https://github.com/nwn-dotnet/Anvil/compare/v8193.34.22...v8193.34.23

### Added
- Added `ANVIL_ENCODING` environment variable for specifying a custom encoding when converting native strings from nwserver.
- Added `EncodingService` for changing the server encoding at runtime.
- NUI: Added StrRef support with `NuiBindStrRef` and `NuiValueStrRef` types.
- Events: Added `OnDoorSetOpenState` event.
- Events: Added `OnObjectUse` event.
- Extensions: Added `TryParseObject` extension for parsing object ID strings.
- NwCreature: Added `GetInitiativeModifier`,`SetInitiativeModifier`,`ClearInitiativeModifier` methods.
- NwCreature: Added `IsDMAvatar` property.
- NwCreature: Added `IsFlanking` method.
- NwDoor: Added `DoorOpenState` property.
- NwRuleset: Added NwDomain ruleset table and replaced constant usages with table references.
- NwServer: Added `IsActivePaused` property.
- NwServer: Added `IsTimestopPaused` property.

### Package Updates
- Microsoft.CodeAnalysis.CSharp: 4.3.1 -> 4.4.0
- NWN.Core: 8193.34.7 -> 8193.34.10
- NWN.Native: 8193.34.4 -> 8193.34.5
- LightInject: 6.6.1 -> 6.6.3
- Newtonsoft.Json: 13.0.1 -> 13.0.2
- NLog: 5.0.5 -> 5.1.1
- Paket.Core: 7.1.5 -> 7.2.0
- NWNX: fe195ec -> 2692ecb

### Changed
- Events: `OnSpellAction` Domain and Feat is now nullable.
- Events: `OnSpellInterrupt` Domain and Feat is now nullable.
- Events: `OnSpellSlotMemorize` Domain is now nullable.
- `System.Random` usages now use the `System.Random.Shared` instance, instead of individual instances.

### Fixed
- Fixed an issue where a GameObject or Player could become stuck in a hash-based collection when it became invalid.
- NwPlayer: `IsDM` now correctly returns true when a DM is possessing a creature. Use `ControlledCreature.IsDM` for the prior behaviour.

## 8193.34.22
https://github.com/nwn-dotnet/Anvil/compare/v8193.34.21...v8193.34.22

Expand Down
2 changes: 1 addition & 1 deletion NWN.Anvil.TestRunner/NWN.Anvil.TestRunner.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
</ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions NWN.Anvil.Tests/NWN.Anvil.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="NWN.Native" Version="8193.34.4" PrivateAssets="compile" />
<PackageReference Include="NWN.Core" Version="8193.34.7" PrivateAssets="compile" />
<PackageReference Include="NWN.Core" Version="8193.34.10" PrivateAssets="compile" />
<PackageReference Include="NWN.Native" Version="8193.34.5" PrivateAssets="compile" />
</ItemGroup>

<ItemGroup>
Expand Down
18 changes: 16 additions & 2 deletions NWN.Anvil.Tests/src/main/API/Nui/Bindings/NuiBindTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,35 @@ public void SerializeNuiBindStringReturnsValidJsonStructure()
Assert.That(JsonUtility.ToJson(test), Is.EqualTo(@"{""bind"":""test""}"));
}

[Test(Description = "Serializing a NuiBind<string> creates a valid JSON structure.")]
public void SerializeNuiBindStrRefReturnsValidJsonStructure()
{
NuiBindStrRef test = new NuiBindStrRef("test");
Assert.That(JsonUtility.ToJson(test), Is.EqualTo(@"{""bind"":""test""}"));
}

[Test(Description = "Serializing a NuiBind<NuiRect> creates a valid JSON structure.")]
public void SerializeNuiBindNuiRectReturnsValidJsonStructure()
{
NuiBind<NuiRect> test = new NuiBind<NuiRect>("test");
Assert.That(JsonUtility.ToJson(test), Is.EqualTo(@"{""bind"":""test""}"));
}

[Test(Description = "Deerializing a NuiBind<string> creates a valid JSON structure.")]
[Test(Description = "Deerializing a NuiBind<string> creates a valid value/object.")]
public void DeserializeNuiBindStringReturnsValidJsonStructure()
{
NuiBind<string>? test = JsonUtility.FromJson<NuiBind<string>>(@"{""bind"":""test""}");
Assert.That(test?.Key, Is.EqualTo("test"));
}

[Test(Description = "Deerializing a NuiBind<NuiRect> creates a valid JSON structure.")]
[Test(Description = "Deerializing a NuiBind<string> creates a valid value/object.")]
public void DeserializeNuiBindStrRefReturnsValidJsonStructure()
{
NuiBind<NuiBindStrRef>? test = JsonUtility.FromJson<NuiBind<NuiBindStrRef>>(@"{""bind"":""test""}");
Assert.That(test?.Key, Is.EqualTo("test"));
}

[Test(Description = "Deerializing a NuiBind<NuiRect> creates a valid value/object.")]
public void DeserializeNuiBindNuiRectReturnsValidJsonStructure()
{
NuiBind<NuiRect>? test = JsonUtility.FromJson<NuiBind<NuiRect>>(@"{""bind"":""test""}");
Expand Down
34 changes: 27 additions & 7 deletions NWN.Anvil.Tests/src/main/API/Nui/Bindings/NuiValueTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ public void SerializeNuiValueStringReturnsValidJsonStructure(string value, strin
Assert.That(JsonUtility.ToJson(test), Is.EqualTo(expected));
}

[Test(Description = "Serializing a NuiValueStrRef creates a valid JSON structure.")]
[TestCase(0u, @"{""strref"":0}")]
[TestCase(null, @"null")]
[TestCase(1000u, @"{""strref"":1000}")]
public void SerializeNuiValueStrRefReturnsValidJsonStructure(uint? value, string expected)
{
NuiValueStrRef test = new NuiValueStrRef(value != null ? new StrRef(value.Value) : null);
Assert.That(JsonUtility.ToJson(test), Is.EqualTo(expected));
}

[Test(Description = "Serializing a NuiValue<int> creates a valid JSON structure.")]
[TestCase(0, @"0")]
[TestCase(-0, @"0")]
Expand Down Expand Up @@ -91,7 +101,7 @@ public void SerializeNuiValueIntListReturnsValidJsonStructure()
Assert.That(JsonUtility.ToJson(test), Is.EqualTo(@"[1,2,3]"));
}

[Test(Description = "Deerializing a NuiValue<string> creates a valid JSON structure.")]
[Test(Description = "Deerializing a NuiValue<string> creates a valid value/object.")]
[TestCase("test", @"""test""")]
[TestCase(null, @"null")]
[TestCase("", @"""""")]
Expand All @@ -101,7 +111,17 @@ public void DeserializeNuiValueStringReturnsValidJsonStructure(string expected,
Assert.That(test?.Value, Is.EqualTo(expected));
}

[Test(Description = "Deerializing a NuiValue<int> creates a valid JSON structure.")]
[Test(Description = "Deerializing a NuiValueStrRef creates a valid value/object.")]
[TestCase(0u, @"{""strref"":0}")]
[TestCase(null, @"null")]
[TestCase(1000u, @"{""strref"":1000}")]
public void DeserializeNuiValueStrRefReturnsValidJsonStructure(uint? expected, string serialized)
{
NuiValueStrRef? test = JsonUtility.FromJson<NuiValueStrRef>(serialized);
Assert.That(test?.Value?.Id, Is.EqualTo(expected));
}

[Test(Description = "Deerializing a NuiValue<int> creates a valid value/object.")]
[TestCase(0, @"0")]
[TestCase(-0, @"0")]
[TestCase(10, @"10")]
Expand All @@ -114,7 +134,7 @@ public void DeserializeNuiValueIntReturnsValidJsonStructure(int expected, string
Assert.That(test?.Value, Is.EqualTo(expected));
}

[Test(Description = "Deerializing a NuiValue<int?> creates a valid JSON structure.")]
[Test(Description = "Deerializing a NuiValue<int?> creates a valid value/object.")]
[TestCase(0, @"0")]
[TestCase(-0, @"0")]
[TestCase(10, @"10")]
Expand All @@ -128,7 +148,7 @@ public void DeserializeNuiValueNullableIntReturnsValidJsonStructure(int? expecte
Assert.That(test?.Value, Is.EqualTo(expected));
}

[Test(Description = "Deerializing a NuiValue<float> creates a valid JSON structure.")]
[Test(Description = "Deerializing a NuiValue<float> creates a valid value/object.")]
[TestCase(0f, @"0.0")]
[TestCase(0.1f, @"0.1")]
[TestCase(0.125f, @"0.125")]
Expand All @@ -144,7 +164,7 @@ public void DeserializeNuiValueFloatReturnsValidJsonStructure(float expected, st
Assert.That(test?.Value, Is.EqualTo(expected));
}

[Test(Description = "Deerializing a NuiValue<float?> creates a valid JSON structure.")]
[Test(Description = "Deerializing a NuiValue<float?> creates a valid value/object.")]
[TestCase(0f, @"0.0")]
[TestCase(0.1f, @"0.1")]
[TestCase(0.125f, @"0.125")]
Expand All @@ -161,7 +181,7 @@ public void DeserializeNuiValueFloatNullableReturnsValidJsonStructure(float? exp
Assert.That(test?.Value, Is.EqualTo(expected));
}

[Test(Description = "Deerializing a NuiValue<NuiRect> creates a valid JSON structure.")]
[Test(Description = "Deerializing a NuiValue<NuiRect> creates a valid value/object.")]
public void DeserializeNuiValueNuiRectReturnsValidJsonStructure()
{
NuiValue<NuiRect>? test = JsonUtility.FromJson<NuiValue<NuiRect>>(@"{""h"":20.0,""w"":30.11,""x"":100.0,""y"":50.251}");
Expand All @@ -170,7 +190,7 @@ public void DeserializeNuiValueNuiRectReturnsValidJsonStructure()
Assert.That(test?.Value, Is.EqualTo(expected));
}

[Test(Description = "Deserializing a NuiValue<List<int>> creates a valid JSON structure.")]
[Test(Description = "Deserializing a NuiValue<List<int>> creates a valid value/object.")]
public void DeserializeNuiValueIntListReturnsValidJsonStructure()
{
NuiValue<List<int>>? test = JsonUtility.FromJson<NuiValue<List<int>>>(@"[1,2,3]");
Expand Down
4 changes: 2 additions & 2 deletions NWN.Anvil.Tests/src/main/API/TwoDimArray/TwoDimArrayTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ public void Custom2daReturnsValidValues()
@"2DA V2.0
LABEL TESTSTR TESTINT TESTFLOAT
0 Test0 ""Test 0"" 0 0.0f
0 Test0 ""Test 0"" 0 0.0f
1 Test1 ""Test 1"" 0x1 1.0f
2 Test2 ""Test 2"" 0x00000002 2.0f";

string resourceName = "testtemp.2da";
ResourceManager.WriteTempResource(resourceName, StringHelper.Cp1252Encoding.GetBytes(twoDimArray));
ResourceManager.WriteTempResource(resourceName, StringHelper.Encoding.GetBytes(twoDimArray));
createdTempResources.Add(resourceName);

TwoDimArray array = NwGameTables.GetTable(resourceName);
Expand Down
1 change: 1 addition & 0 deletions NWN.Anvil.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=TabsAndSpacesMismatch/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=TabsAreDisallowed/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=TabsOutsideIndent/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnknownTask/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnnecessaryWhitespace/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedAutoPropertyAccessor_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedMemberHierarchy_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
Expand Down
12 changes: 6 additions & 6 deletions NWN.Anvil/NWN.Anvil.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="LightInject" Version="6.6.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NLog" Version="5.0.5" />
<PackageReference Include="Paket.Core" Version="7.1.5" PrivateAssets="all" />
<PackageReference Include="NWN.Core" Version="8193.34.7" PrivateAssets="compile" />
<PackageReference Include="NWN.Native" Version="8193.34.4" PrivateAssets="compile" />
<PackageReference Include="LightInject" Version="6.6.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="NLog" Version="5.1.1" />
<PackageReference Include="Paket.Core" Version="7.2.0" PrivateAssets="all" />
<PackageReference Include="NWN.Core" Version="8193.34.10" PrivateAssets="compile" />
<PackageReference Include="NWN.Native" Version="8193.34.5" PrivateAssets="compile" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion NWN.Anvil/src/main/API/Color.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public string ToColorToken()
{
const byte tokenMinVal = 1;
ReadOnlySpan<byte> tokenBytes = stackalloc[] { Math.Max(Red, tokenMinVal), Math.Max(Green, tokenMinVal), Math.Max(Blue, tokenMinVal) };
return StringHelper.Cp1252Encoding.GetString(tokenBytes);
return StringHelper.Encoding.GetString(tokenBytes);
}

[Obsolete("Use Color.ToRGBA() instead.")]
Expand Down
25 changes: 25 additions & 0 deletions NWN.Anvil/src/main/API/Constants/DoorOpenState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Anvil.API
{
public enum DoorOpenState
{
/// <summary>
/// The closed state of the door.
/// </summary>
Closed = 0,

/// <summary>
/// The forward open state of the door. This is the direction of the arrow as shown in the toolset.
/// </summary>
OpenForward = 1,

/// <summary>
/// The backward open state of the door. This is the opposite direction of the arrow as shown in the toolset.
/// </summary>
OpenBackward = 2,

/// <summary>
/// The destroyed state of the door.
/// </summary>
Destroyed = 3,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System;
using System.Runtime.InteropServices;
using Anvil.API.Events;
using Anvil.Services;
using NWN.Native.API;

namespace Anvil.API.Events
{
/// <summary>
/// Called when a door's open state is changed (open/closed/destroyed).
/// </summary>
public sealed class OnDoorSetOpenState : IEvent
{
/// <summary>
/// The door that is being open/closed.
/// </summary>
public NwDoor Door { get; private init; } = null!;

/// <summary>
/// The new open state of the door.
/// </summary>
public DoorOpenState OpenState { get; set; }

/// <summary>
/// Gets or sets if the door state should not be changed.
/// </summary>
public bool PreventStateChange { get; set; }

NwObject IEvent.Context => Door;

public sealed unsafe class Factory : HookEventFactory
{
private static FunctionHook<SetOpenStateHook> Hook { get; set; } = null!;

private delegate void SetOpenStateHook(void* pDoor, byte nOpenState);

protected override IDisposable[] RequestHooks()
{
delegate* unmanaged<void*, byte, void> pHook = &OnSetOpenState;
Hook = HookService.RequestHook<SetOpenStateHook>(pHook, FunctionsLinux._ZN8CNWSDoor12SetOpenStateEh, HookOrder.Early);
return new IDisposable[] { Hook };
}

[UnmanagedCallersOnly]
private static void OnSetOpenState(void* pDoor, byte nOpenState)
{
NwDoor? door = CNWSDoor.FromPointer(pDoor).ToNwObject<NwDoor>();
if (door == null)
{
Hook.CallOriginal(pDoor, nOpenState);
return;
}

OnDoorSetOpenState eventData = ProcessEvent(EventCallbackType.Before, new OnDoorSetOpenState
{
Door = door,
OpenState = (DoorOpenState)nOpenState,
});

if (!eventData.PreventStateChange)
{
Hook.CallOriginal(pDoor, (byte)eventData.OpenState);
}

ProcessEvent(EventCallbackType.After, eventData);
}
}
}
}

namespace Anvil.API
{
public sealed partial class NwDoor
{
/// <inheritdoc cref="Events.OnDoorSetOpenState"/>
public event Action<OnDoorSetOpenState> OnDoorSetOpenState
{
add => EventService.Subscribe<OnDoorSetOpenState, OnDoorSetOpenState.Factory>(this, value);
remove => EventService.Unsubscribe<OnDoorSetOpenState, OnDoorSetOpenState.Factory>(this, value);
}
}

public sealed partial class NwModule
{
/// <inheritdoc cref="Events.OnDoorSetOpenState"/>
public event Action<OnDoorSetOpenState> OnDoorSetOpenState
{
add => EventService.SubscribeAll<OnDoorSetOpenState, OnDoorSetOpenState.Factory>(value);
remove => EventService.UnsubscribeAll<OnDoorSetOpenState, OnDoorSetOpenState.Factory>(value);
}
}
}
Loading

0 comments on commit cdb00a0

Please sign in to comment.