An experiment-friendly Terraria server launcher based on OTAPI USP, hosting multiple worlds in a single process with per-instance consoles, a release assistant, and plugin scaffolding
$ dotnet add package UnifierTSLAn experiment-friendly Terraria server launcher built on OTAPI USP, bundling per-instance consoles, early publishing helpers, and plugin scaffolding.
UnifierTSL is a plugin framework for Terraria servers that enables:
dotnet add package UnifierTSL
using System;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using UnifierTSL;
using UnifierTSL.Events.Core;
using UnifierTSL.Events.Handlers;
using UnifierTSL.Logging;
using UnifierTSL.Plugins;
[assembly: CoreModule]
namespace MyPlugin
{
[PluginMetadata("MyPlugin", "1.0.0", "Author", "My awesome plugin")]
public sealed class Plugin : BasePlugin, ILoggerHost
{
readonly RoleLogger logger;
public Plugin()
{
logger = UnifierApi.CreateLogger(this);
}
public string Name => "MyPlugin";
public string? CurrentLogCategory => null;
public override Task InitializeAsync(
IPluginConfigRegistrar registrar,
ImmutableArray<PluginInitInfo> prior,
CancellationToken cancellationToken = default)
{
// Hook into UnifierApi.EventHub
UnifierApi.EventHub.Chat.MessageEvent.Register(OnChatMessage, HandlerPriority.Normal);
logger.Info("MyPlugin initialized!");
return Task.CompletedTask;
}
public override ValueTask DisposeAsync(bool isDisposing)
{
if (isDisposing)
{
UnifierApi.EventHub.Chat.MessageEvent.UnRegister(OnChatMessage);
}
return ValueTask.CompletedTask;
}
static void OnChatMessage(ref ReadonlyEventArgs<MessageEvent> args)
{
if (!args.Content.Sender.IsClient)
return;
if (args.Content.Text.Trim().Equals("!hello", StringComparison.OrdinalIgnoreCase))
{
args.Content.Sender.Chat("Hello from MyPlugin!", Color.LightGreen);
args.Handled = true;
}
}
}
}
Module System
[CoreModule]: Mark your main plugin assembly[RequiresCoreModule("Name")]: Create dependent modules[ModuleDependencies]: Declare NuGet or embedded dependenciesConfiguration Management
var configHandle = registrar
.CreateConfigRegistration<MyConfig>("config.json")
.WithDefault(() => new MyConfig { Enabled = true })
.TriggerReloadOnExternalChange(true)
.Complete();
MyConfig config = await configHandle.RequestAsync(cancellationToken);
Logging
// Plugin should implement ILoggerHost
var logger = UnifierApi.CreateLogger(this);
logger.Info("Plugin initialized");
logger.Warning("This is a warning");
logger.Error("An error occurred", exception: ex);
Event Hub
Access event providers through UnifierApi.EventHub domains:
Game: PreUpdate, PostUpdate, GameHardmodeTileUpdateChat: ChatEvent, MessageEventNetplay: ConnectEvent, ReceiveFullClientInfoEvent, LeaveEventCoordinator: SwitchJoinServerEvent, PreServerTransfer, PostServerTransferServer: CreateConsoleService, AddServer, RemoveServerBuild your plugin as a class library targeting net9.0:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="UnifierTSL" Version="*" />
</ItemGroup>
</Project>
Drop the compiled DLL into the server's plugins/ directory.
This NuGet package includes:
UnifierTSL.dll - Launcher, orchestration services, module loader, event hub, and plugin hostGPL-3.0 - See LICENSE for details