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.
Builders can add functionality like opening a store from a dialogue with a few lines of code, while plugin developers can leverage NuGet to add new functionality with external packages and the NWN.Native library to completely rewrite existing game systems and mechanics.
- Latest Release
- View Community Submitted Plugins
- Join the community:
Anvil has its own docker images that are automatically configured to start and run Anvil and NWNXEE. Similar to the parent images, Anvil is configured by environment variables passed during docker run
.
By default, Anvil will look in the /nwn/anvil/Plugins
directory in the container for managed plugins. A volume containing your plugins can be mounted here to automatically run on startup.
Running the image is exactly the same as running the beamdog/nwserver
or nwnxee/unified
images. See the NWNX and NWServer README's for configuring these images.
The following tags are supported:
Tag | Example |
---|---|
latest |
nwndotnet/anvil:latest |
<version> |
nwndotnet/anvil:8193.22.1 |
<commit-hash> |
nwndotnet/anvil:c09d2f6 |
- Download and extract the dedicated server package: Server packages
- Download and extract NWNX: https://github.com/nwnxee/unified/releases
- Download and extract the Anvil Release for your server/NWNX version.
- The directory structure should look like the following:
bin/
|----linux-x86
|----nwserver-linux
|----NWNX_DotNET.so
|----NWNX_Object.so
|----NWNX_SWIG_DotNET.so
|----NWNX_Util.so
modbin/
|----NLog.dll
|----NWN.Core.dll
|----NWN.Anvil.deps.json
|----NWN.Anvil.dll
|----NWN.Anvil.runtimeconfig.dev.json
|----NWN.Anvil.runtimeconfig.json
|----NWN.Anvil.xml
|----NWN.Native.dll
|----LightInject.dll
|----Plugins/
|----YourPlugin/
|----YourPlugin.dll
- Configure NWNX options to the following:
NWNX_DOTNET_SKIP=n
NWNX_SWIG_DOTNET_SKIP=n
NWNX_DOTNET_ASSEMBLY=/your/path/to/NWN.Anvil # Where "NWN.Anvil.dll" was extracted in step 3, without the extension. E.g: NWNX_DOTNET_ASSEMBLY=/nwn/home/modbin/Anvil
# NWNX_DOTNET_ENTRYPOINT= # Make sure this option does not exist in your config
The DotNET, Object and Util plugins are required for the library to work. Make sure they are enabled!
Other plugins are optional, but may be required to access some extension APIs. An exception will be raised if you try to use an extension without the dependent plugin loaded.
For a step by step guide how to set up a local developement environment using your IDE of choice and windows. see Development with Docker on Windows.
The following options can be configured via environment variables:
Variable | Default | Description |
---|---|---|
ANVIL_PLUGIN_PATH |
/path/to/NWN.Anvil/Plugins |
The root plugin path that Anvil will search for plugins. |
ANVIL_NLOG_CONFIG |
Custom path to a NLog XML config file. See the NLog Wiki for configuration options. | |
ANVIL_RELOAD_ENABLED |
false |
Enables support for plugin hot-reloading via AnvilCore.Reload() . Recommended for advanced users. |
Adding module behaviours starts by creating your own plugin assembly (.dll).
To get started, it is recommended to start by making a copy of the sample project found HERE with the package dependencies already setup for you.
The core of Anvil is built around a dependency injection model, and the library expects you to implement features in your plugins a similar way.
Using a class attribute (ServiceBinding), the system will automatically wire up all of the dependencies for that class as defined in the parameters of its constructor:
using NLog;
using NWN.Services;
// The "ServiceBinding" attribute indicates this class will be created on start, and available to other classes as "ServiceA".
[ServiceBinding(typeof(ServiceA))]
public class ServiceA
{
// Gets the logger for this service. By default, this reports to "logs.0/anvil.log"
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
// As "ServiceA" has the ServiceBinding attribute, this constructor will be called during server startup.
public ServiceA()
{
Log.Info("Service A Loaded!");
}
}
// This class will be available to other classes as "ServiceB".
[ServiceBinding(typeof(ServiceB))]
public class ServiceB
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
// As "ServiceB" also has the ServiceBinding attribute, this constructor will also be called during server startup,
// but since "ServiceA" is specified as a parameter (dependency), it will only be started after "ServiceA" has loaded.
public ServiceB(ServiceA serviceA)
{
Log.Info("Service B Loaded!");
}
}
Checking in the console or server logs, you should get the following output:
[ServiceA] Service A Loaded!
[ServiceB] Service B Loaded!
Anvil is bundled with a core set of services that you can depend on in your own plugins and systems.
These services handle game events, task scheduling, and more! Examples of how to use these services can be found in the Anvil docs.
You can also find a full list of the services bundled by Anvil HERE.