Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,37 @@ on:
jobs:
# This workflow contains a single job called "build"
build:
strategy:
fail-fast: false
matrix:
os: [
{
name: Windows,
runs-on: windows-latest,
},
{
name: Ubuntu,
runs-on: ubuntu-latest,
},
{
name: MacOS,
runs-on: macos-latest,
}
]

# The type of runner that the job will run on
runs-on: windows-latest
runs-on: ${{ matrix.os.runs-on }}

name: ${{ matrix.os.name }}

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v3
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '6.0.100'
dotnet-version: 9.0.x

- name: MonoMod dev build
run: dotnet nuget add source https://pkgs.dev.azure.com/MonoMod/MonoMod/_packaging/DevBuilds%40Local/nuget/v3/index.json -n DevBuilds@Local
Expand All @@ -32,9 +52,3 @@ jobs:

- name: Run tests
run: dotnet test --filter "FullyQualifiedName!~TerrariaServerAPI.Tests.Benchmarks"

# example task for the release CI
# - name: "Releasing to NuGet: TSAPI"
# env:
# NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
# run: dotnet nuget push ./TerrariaServerAPI/bin/Release/TerrariaServer.*.nupkg --source https://api.nuget.org/v3/index.json --api-key "$env:NUGET_API_KEY"
6 changes: 3 additions & 3 deletions .github/workflows/nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ jobs:
environment: release

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.400
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
27 changes: 14 additions & 13 deletions TerrariaServerAPI.Tests/BaseTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using NUnit.Framework;
using System;
using System.Threading;
using System.Runtime.InteropServices;

namespace TerrariaServerAPI.Tests;

Expand All @@ -13,24 +12,26 @@ public void EnsureInitialised()
{
if (!_initialized)
{
var are = new AutoResetEvent(false);
Exception? error = null;
On.Terraria.Main.hook_DedServ cb = (On.Terraria.Main.orig_DedServ orig, Terraria.Main instance) =>
TestContext.Out.WriteLine($"Test architecture {RuntimeInformation.ProcessArchitecture}");

bool invoked = false;
HookEvents.HookDelegate<Terraria.Main, HookEvents.Terraria.Main.DedServEventArgs> cb = (instance, args) =>
{
invoked = true;
// DedServ typically requires input, so no need to continue execution
args.ContinueExecution = false;
// DedServ calls the following, which is needed for subsequent tests
instance.Initialize();
are.Set();
_initialized = true;
};
On.Terraria.Main.DedServ += cb;
HookEvents.Terraria.Main.DedServ += cb;

global::TerrariaApi.Server.Program.Main(new string[] { });
TerrariaApi.Server.Program.Main([]);

_initialized = are.WaitOne(TimeSpan.FromSeconds(30));
HookEvents.Terraria.Main.DedServ -= cb;

On.Terraria.Main.DedServ -= cb;
Assert.That(invoked, Is.True);

Assert.That(_initialized, Is.True);
Assert.That(error, Is.Null);
_initialized = true;
}
}
}
22 changes: 22 additions & 0 deletions TerrariaServerAPI.Tests/ServerInitTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NUnit.Framework;
using System.Runtime.InteropServices;

namespace TerrariaServerAPI.Tests;

Expand All @@ -9,4 +10,25 @@ public void EnsureBoots()
{
EnsureInitialised();
}

[Test]
public void EnsureRuntimeDetours()
{
// Platform exclude doesnt support arm64, so manual check it is...
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
Assert.Ignore("Test is not supported on ARM64 architecture.");

TestContext.Out.WriteLine($"Test architecture {RuntimeInformation.ProcessArchitecture}");

bool invoked = false;

On.Terraria.Program.hook_RunGame callback = (orig) => invoked = true;
On.Terraria.Program.RunGame += callback;

Terraria.Program.RunGame();

On.Terraria.Program.RunGame -= callback;

Assert.That(invoked, Is.True);
}
}
17 changes: 10 additions & 7 deletions TerrariaServerAPI.Tests/TerrariaServerAPI.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit.Analyzers" Version="3.3.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.3.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.5.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
2 changes: 1 addition & 1 deletion TerrariaServerAPI/TerrariaApi.Server/HookManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static void InitialiseAPI()
ServerApi.ApiVersion,
Main.versionNumber2,
Main.curRelease,
typeof(OTAPI.Hooks).Assembly.GetName().Version
OTAPI.Common.VersionShort
);
ServerApi.Initialize(Environment.GetCommandLineArgs(), Main.instance);
}
Expand Down
140 changes: 70 additions & 70 deletions TerrariaServerAPI/TerrariaApi.Server/Hooking/GameHooks.cs
Original file line number Diff line number Diff line change
@@ -1,96 +1,96 @@
using Microsoft.Xna.Framework;
using OTAPI;
using OTAPI;

namespace TerrariaApi.Server.Hooking
namespace TerrariaApi.Server.Hooking;

internal static class GameHooks
{
internal static class GameHooks
private static HookManager _hookManager;

/// <summary>
/// Attaches any of the OTAPI Game hooks to the existing <see cref="HookManager"/> implementation
/// </summary>
/// <param name="hookManager">HookManager instance which will receive the events</param>
public static void AttachTo(HookManager hookManager)
{
private static HookManager _hookManager;
_hookManager = hookManager;

/// <summary>
/// Attaches any of the OTAPI Game hooks to the existing <see cref="HookManager"/> implementation
/// </summary>
/// <param name="hookManager">HookManager instance which will receive the events</param>
public static void AttachTo(HookManager hookManager)
{
_hookManager = hookManager;
HookEvents.Terraria.Main.Update += OnUpdate;
HookEvents.Terraria.Main.Initialize += OnInitialize;
HookEvents.Terraria.Netplay.StartServer += OnStartServer;

On.Terraria.Main.Update += OnUpdate;
On.Terraria.Main.Initialize += OnInitialize;
On.Terraria.Netplay.StartServer += OnStartServer;
Hooks.WorldGen.HardmodeTilePlace += OnHardmodeTilePlace;
Hooks.WorldGen.HardmodeTileUpdate += OnHardmodeTileUpdate;
Hooks.Item.MechSpawn += OnItemMechSpawn;
Hooks.NPC.MechSpawn += OnNpcMechSpawn;
}

Hooks.WorldGen.HardmodeTilePlace += OnHardmodeTilePlace;
Hooks.WorldGen.HardmodeTileUpdate += OnHardmodeTileUpdate;
Hooks.Item.MechSpawn += OnItemMechSpawn;
Hooks.NPC.MechSpawn += OnNpcMechSpawn;
}
private static void OnUpdate(Terraria.Main instance, HookEvents.Terraria.Main.UpdateEventArgs args)
{
if (!args.ContinueExecution) return;
args.ContinueExecution = false;
_hookManager.InvokeGameUpdate();
args.OriginalMethod(args.gameTime);
_hookManager.InvokeGamePostUpdate();
}

private static void OnUpdate(On.Terraria.Main.orig_Update orig, Terraria.Main instance, GameTime gameTime)
private static void OnHardmodeTileUpdate(object sender, Hooks.WorldGen.HardmodeTileUpdateEventArgs e)
{
if (e.Result == HookResult.Cancel)
{
_hookManager.InvokeGameUpdate();
orig(instance, gameTime);
_hookManager.InvokeGamePostUpdate();
return;
}

private static void OnHardmodeTileUpdate(object sender, Hooks.WorldGen.HardmodeTileUpdateEventArgs e)
if (_hookManager.InvokeGameHardmodeTileUpdate(e.X, e.Y, e.Type))
{
if (e.Result == HookResult.Cancel)
{
return;
}
if (_hookManager.InvokeGameHardmodeTileUpdate(e.X, e.Y, e.Type))
{
e.Result = HookResult.Cancel;
}
e.Result = HookResult.Cancel;
}
}

private static void OnHardmodeTilePlace(object sender, Hooks.WorldGen.HardmodeTilePlaceEventArgs e)
private static void OnHardmodeTilePlace(object sender, Hooks.WorldGen.HardmodeTilePlaceEventArgs e)
{
if (e.Result == HardmodeTileUpdateResult.Cancel)
{
if (e.Result == HardmodeTileUpdateResult.Cancel)
{
return;
}
if (_hookManager.InvokeGameHardmodeTileUpdate(e.X, e.Y, e.Type))
{
e.Result = HardmodeTileUpdateResult.Cancel;
}
return;
}

private static void OnInitialize(On.Terraria.Main.orig_Initialize orig, Terraria.Main instance)
if (_hookManager.InvokeGameHardmodeTileUpdate(e.X, e.Y, e.Type))
{
HookManager.InitialiseAPI();
_hookManager.InvokeGameInitialize();
orig(instance);
e.Result = HardmodeTileUpdateResult.Cancel;
}
}

private static void OnStartServer(On.Terraria.Netplay.orig_StartServer orig)
private static void OnInitialize(Terraria.Main instance, HookEvents.Terraria.Main.InitializeEventArgs args)
{
if (!args.ContinueExecution) return;
HookManager.InitialiseAPI();
_hookManager.InvokeGameInitialize();
}

private static void OnStartServer(object? sender, HookEvents.Terraria.Netplay.StartServerEventArgs args)

Check warning on line 67 in TerrariaServerAPI/TerrariaApi.Server/Hooking/GameHooks.cs

View workflow job for this annotation

GitHub Actions / MacOS

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 67 in TerrariaServerAPI/TerrariaApi.Server/Hooking/GameHooks.cs

View workflow job for this annotation

GitHub Actions / MacOS

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 67 in TerrariaServerAPI/TerrariaApi.Server/Hooking/GameHooks.cs

View workflow job for this annotation

GitHub Actions / Ubuntu

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 67 in TerrariaServerAPI/TerrariaApi.Server/Hooking/GameHooks.cs

View workflow job for this annotation

GitHub Actions / Ubuntu

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 67 in TerrariaServerAPI/TerrariaApi.Server/Hooking/GameHooks.cs

View workflow job for this annotation

GitHub Actions / Windows

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 67 in TerrariaServerAPI/TerrariaApi.Server/Hooking/GameHooks.cs

View workflow job for this annotation

GitHub Actions / Windows

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
if (!args.ContinueExecution) return;
_hookManager.InvokeGamePostInitialize();
}

private static void OnItemMechSpawn(object sender, Hooks.Item.MechSpawnEventArgs e)
{
if (e.Result == HookResult.Cancel)
{
_hookManager.InvokeGamePostInitialize();
orig();
return;
}

private static void OnItemMechSpawn(object sender, Hooks.Item.MechSpawnEventArgs e)
if (!_hookManager.InvokeGameStatueSpawn(e.Num2, e.Num3, e.Num, (int)(e.X / 16f), (int)(e.Y / 16f), e.Type, false))
{
if (e.Result == HookResult.Cancel)
{
return;
}
if (!_hookManager.InvokeGameStatueSpawn(e.Num2, e.Num3, e.Num, (int)(e.X / 16f), (int)(e.Y / 16f), e.Type, false))
{
e.Result = HookResult.Cancel;
}
e.Result = HookResult.Cancel;
}
}

private static void OnNpcMechSpawn(object sender, Hooks.NPC.MechSpawnEventArgs e)
private static void OnNpcMechSpawn(object sender, Hooks.NPC.MechSpawnEventArgs e)
{
if (e.Result == HookResult.Cancel)
{
return;
}
if (!_hookManager.InvokeGameStatueSpawn(e.Num2, e.Num3, e.Num, (int)(e.X / 16f), (int)(e.Y / 16f), e.Type, true))
{
if (e.Result == HookResult.Cancel)
{
return;
}
if (!_hookManager.InvokeGameStatueSpawn(e.Num2, e.Num3, e.Num, (int)(e.X / 16f), (int)(e.Y / 16f), e.Type, true))
{
e.Result = HookResult.Cancel;
}
e.Result = HookResult.Cancel;
}
}
}
Loading
Loading