Skip to content

Commit

Permalink
Merge pull request #254 from SignatureBeef/net9-upgrade
Browse files Browse the repository at this point in the history
Upgrade to .NET 9 and OTAPI Static Hooks for ARM64
  • Loading branch information
hakusaro authored Jan 26, 2025
2 parents d4bb7e3 + d712022 commit 2c82f67
Show file tree
Hide file tree
Showing 15 changed files with 625 additions and 602 deletions.
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 / 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

0 comments on commit 2c82f67

Please sign in to comment.