Anvil
Anvil.Services.ServiceBindingAttribute Class Reference

The main attribute used to define new services and run them.
Each class flagged with a ServiceBindingAttribute will be automatically constructed on startup, and any services specified in the constructor will be injected as dependencies. More...

+ Inheritance diagram for Anvil.Services.ServiceBindingAttribute:
+ Collaboration diagram for Anvil.Services.ServiceBindingAttribute:

Public Member Functions

 ServiceBindingAttribute (Type bindFrom)
 Defines this class as a service. More...
 

Public Attributes

readonly Type BindFrom
 

Detailed Description

The main attribute used to define new services and run them.
Each class flagged with a ServiceBindingAttribute will be automatically constructed on startup, and any services specified in the constructor will be injected as dependencies.

Examples

/*
* Service binding basics - starts two services and logs a message for each.
*/
using NLog;
namespace NWN.Anvil.Samples
{
// 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 after {serviceA.GetType().Name}!");
}
}
// Checking in the console, or "logs.0/anvil.log", the output should look like this:
/*
[ServiceA] Service A Loaded!
[ServiceB] Service B Loaded after ServiceA!
*/
}
/*
* Define a method (OnScriptCalled) to be called when the NwScript "test_nwscript" would be called by the game.
*/
using Anvil.API;
using NLog;
// The "ServiceBinding" attribute indicates this class should be created on start, and available to other classes as a dependency "MyScriptHandler"
// You can also bind yourself to an interface or base class. The system also supports multiple bindings.
namespace NWN.Anvil.Samples
{
[ServiceBinding(typeof(BasicScriptHandler))]
public class BasicScriptHandler
{
// Gets the server log. By default, this reports to "anvil.log"
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
// This function will be called as if the same script was called by a toolset event, or by another script.
// Script name must be <= 16 characters similar to the toolset.
// This function must always return void, or a bool in the case of a conditional.
// The NwObject parameter is optional, but if defined, must always be a single parameter of the NWObject type.
[ScriptHandler("test_nwscript")]
private void OnScriptCalled(CallInfo callInfo)
{
Log.Info($"test_nwscript called by {callInfo.ObjectSelf?.Name}");
}
}
}
/*
* Find a trigger with the tag "mytrigger" and create a handler for its "OnEnter" event.
*/
using System.Linq;
using Anvil.API;
using NLog;
namespace NWN.Anvil.Samples
{
[ServiceBinding(typeof(TriggerHandlerService))]
public class TriggerHandlerService
{
// Gets the server log. By default, this reports to "anvil.log"
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
public TriggerHandlerService()
{
NwTrigger? trigger = NwObject.FindObjectsWithTag<NwTrigger>("mytrigger").FirstOrDefault();
if (trigger != null)
{
trigger.OnEnter += OnTriggerEnter;
}
}
private void OnTriggerEnter(TriggerEvents.OnEnter obj)
{
if (obj.EnteringObject.IsPlayerControlled(out NwPlayer? player))
{
Log.Info("Player entered trigger: " + player.PlayerName);
}
}
}
}
/*
* Implement a "Chat Command System" using a common interface, and binding to the interface.
*/
using System.Collections.Generic;
using System.Linq;
using Anvil.API;
namespace NWN.Anvil.Samples
{
// Our base chat command interface...
public interface IChatCommand
{
string Command { get; }
void ExecuteCommand(NwPlayer caller);
}
// ...Each one of our commands implements the IChatCommand interface...
[ServiceBinding(typeof(IChatCommand))]
public class GpCommand : IChatCommand
{
public string Command => "!gp";
private const int Amount = 10000;
public void ExecuteCommand(NwPlayer caller)
{
caller.ControlledCreature?.GiveGold(Amount);
}
}
[ServiceBinding(typeof(IChatCommand))]
public class SaveCommand : IChatCommand
{
public string Command => "!save";
public void ExecuteCommand(NwPlayer caller)
{
caller.ExportCharacter();
caller.SendServerMessage("Character Saved");
}
}
[ServiceBinding(typeof(ChatHandler))]
public class ChatHandler
{
private readonly List<IChatCommand> chatCommands;
// We add a dependency to the chat commands created above by defining an IEnumerable parameter of the interface type.
public ChatHandler(IEnumerable<IChatCommand> commands)
{
// Store all define chat commands.
chatCommands = commands.ToList();
// Subscribe to the global module chat event. When this event occurs, we call the OnChatMessage method.
NwModule.Instance.OnPlayerChat += OnChatMessage;
}
public void OnChatMessage(ModuleEvents.OnPlayerChat eventInfo)
{
// Get the message from the event.
string message = eventInfo.Message;
// Loop through all of our created commands, and execute the behaviour of the one that matches.
foreach (IChatCommand command in chatCommands)
{
if (command.Command == message)
{
command.ExecuteCommand(eventInfo.Sender);
break;
}
}
}
}
}

Constructor & Destructor Documentation

◆ ServiceBindingAttribute()

Anvil.Services.ServiceBindingAttribute.ServiceBindingAttribute ( Type  bindFrom)
inline

Defines this class as a service.

Parameters
bindFromThe type to bind to. This should usually be the class name, but may be a base class or interface implemented by the class too.

The documentation for this class was generated from the following file: