diff --git a/.gitignore b/.gitignore
index 14682006a..7545af41e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
user.config
engine
+.worktrees
# Visual Studio
Release
diff --git a/OpenRA.Mods.RA2.Test/EngineCompatibilityTests.cs b/OpenRA.Mods.RA2.Test/EngineCompatibilityTests.cs
new file mode 100644
index 000000000..94b5004d0
--- /dev/null
+++ b/OpenRA.Mods.RA2.Test/EngineCompatibilityTests.cs
@@ -0,0 +1,55 @@
+#region Copyright & License Information
+/*
+ * Copyright (c) The OpenRA Developers and Contributors
+ * This file is part of OpenRA, which is free software. It is made
+ * available to you under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System.Linq;
+using NUnit.Framework;
+using OpenRA.Mods.Common.Traits;
+using OpenRA.Mods.Common.Traits.Render;
+using OpenRA.Mods.RA2.Traits;
+
+namespace OpenRA.Mods.RA2.Test
+{
+ // Guards against engine API drift: these traits implement engine-supplied interfaces
+ // directly (OpenRA's trait system is the composition root - there is no adapter layer
+ // to isolate the mod from an interface being renamed, removed, or changed upstream).
+ // If either test below stops compiling or fails after bumping ENGINE_VERSION, that is
+ // exactly the signal it's meant to give: go update the corresponding trait.
+ [TestFixture]
+ public class EngineCompatibilityTests
+ {
+ [Test]
+ public void ChronoResourceDelivery_ImplementsINotifyHarvesterAction()
+ {
+ Assert.That(typeof(ChronoResourceDelivery).GetInterfaces(), Does.Contain(typeof(INotifyHarvesterAction)));
+ }
+
+ [Test]
+ public void WithVoxelHelicopterBodyInfo_ImplementsIRenderActorPreviewVoxelsInfo()
+ {
+ Assert.That(typeof(WithVoxelHelicopterBodyInfo).GetInterfaces(), Does.Contain(typeof(IRenderActorPreviewVoxelsInfo)));
+ }
+
+ [Test]
+ public void WithVoxelHelicopterBodyInfo_RenderPreviewVoxels_MatchesInterfaceSignature()
+ {
+ var interfaceMethod = typeof(IRenderActorPreviewVoxelsInfo).GetMethod("RenderPreviewVoxels");
+ var implementationMethod = typeof(WithVoxelHelicopterBodyInfo).GetMethod("RenderPreviewVoxels");
+
+ Assert.That(implementationMethod, Is.Not.Null);
+
+ var expectedParameterTypes = interfaceMethod.GetParameters().Select(p => p.ParameterType);
+ var actualParameterTypes = implementationMethod.GetParameters().Select(p => p.ParameterType);
+
+ Assert.That(actualParameterTypes, Is.EqualTo(expectedParameterTypes));
+ Assert.That(implementationMethod.ReturnType, Is.EqualTo(interfaceMethod.ReturnType));
+ }
+ }
+}
diff --git a/OpenRA.Mods.RA2.Test/OpenRA.Mods.RA2.Test.csproj b/OpenRA.Mods.RA2.Test/OpenRA.Mods.RA2.Test.csproj
new file mode 100644
index 000000000..8c3145643
--- /dev/null
+++ b/OpenRA.Mods.RA2.Test/OpenRA.Mods.RA2.Test.csproj
@@ -0,0 +1,21 @@
+
+
+
+
+ ../engine
+ false
+
+
+
+
+
+
+ True
+
+
+
+
+
+
+
+
diff --git a/OpenRA.Mods.RA2.sln b/OpenRA.Mods.RA2.sln
index 81bcf47ff..98f8001fe 100644
--- a/OpenRA.Mods.RA2.sln
+++ b/OpenRA.Mods.RA2.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
@@ -11,37 +11,111 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRA.Mods.Cnc", "engine\O
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRA.Game", "engine\OpenRA.Game\OpenRA.Game.csproj", "{780F7FD2-B383-4305-B9E6-25F2D384E601}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRA.Mods.RA2.Test", "OpenRA.Mods.RA2.Test\OpenRA.Mods.RA2.Test.csproj", "{F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
Release-x86|Any CPU = Release-x86|Any CPU
+ Release-x86|x64 = Release-x86|x64
+ Release-x86|x86 = Release-x86|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Debug|x64.Build.0 = Debug|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Debug|x86.Build.0 = Debug|Any CPU
{C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release|x64.ActiveCfg = Release|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release|x64.Build.0 = Release|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release|x86.ActiveCfg = Release|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release|x86.Build.0 = Release|Any CPU
{C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release-x86|Any CPU.ActiveCfg = Release|Any CPU
{C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release-x86|Any CPU.Build.0 = Release|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release-x86|x64.ActiveCfg = Release-x86|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release-x86|x64.Build.0 = Release-x86|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release-x86|x86.ActiveCfg = Release-x86|Any CPU
+ {C1D526FE-C83A-4B6A-BB57-3443A8DA3968}.Release-x86|x86.Build.0 = Release-x86|Any CPU
{20034360-3638-489C-80E1-0A1104DBBCE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{20034360-3638-489C-80E1-0A1104DBBCE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Debug|x64.Build.0 = Debug|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Debug|x86.Build.0 = Debug|Any CPU
{20034360-3638-489C-80E1-0A1104DBBCE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20034360-3638-489C-80E1-0A1104DBBCE9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Release|x64.ActiveCfg = Release|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Release|x64.Build.0 = Release|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Release|x86.ActiveCfg = Release|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Release|x86.Build.0 = Release|Any CPU
{20034360-3638-489C-80E1-0A1104DBBCE9}.Release-x86|Any CPU.ActiveCfg = Release|Any CPU
{20034360-3638-489C-80E1-0A1104DBBCE9}.Release-x86|Any CPU.Build.0 = Release|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Release-x86|x64.ActiveCfg = Release-x86|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Release-x86|x64.Build.0 = Release-x86|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Release-x86|x86.ActiveCfg = Release-x86|Any CPU
+ {20034360-3638-489C-80E1-0A1104DBBCE9}.Release-x86|x86.Build.0 = Release-x86|Any CPU
{95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Debug|x64.Build.0 = Debug|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Debug|x86.Build.0 = Debug|Any CPU
{95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release|Any CPU.Build.0 = Release|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release|x64.ActiveCfg = Release|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release|x64.Build.0 = Release|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release|x86.ActiveCfg = Release|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release|x86.Build.0 = Release|Any CPU
{95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release-x86|Any CPU.ActiveCfg = Release|Any CPU
{95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release-x86|Any CPU.Build.0 = Release|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release-x86|x64.ActiveCfg = Release-x86|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release-x86|x64.Build.0 = Release-x86|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release-x86|x86.ActiveCfg = Release-x86|Any CPU
+ {95F49A14-DDCA-4A9D-901D-FCCA4B659069}.Release-x86|x86.Build.0 = Release-x86|Any CPU
{780F7FD2-B383-4305-B9E6-25F2D384E601}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{780F7FD2-B383-4305-B9E6-25F2D384E601}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Debug|x64.Build.0 = Debug|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Debug|x86.Build.0 = Debug|Any CPU
{780F7FD2-B383-4305-B9E6-25F2D384E601}.Release|Any CPU.ActiveCfg = Release|Any CPU
{780F7FD2-B383-4305-B9E6-25F2D384E601}.Release|Any CPU.Build.0 = Release|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Release|x64.ActiveCfg = Release|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Release|x64.Build.0 = Release|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Release|x86.ActiveCfg = Release|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Release|x86.Build.0 = Release|Any CPU
{780F7FD2-B383-4305-B9E6-25F2D384E601}.Release-x86|Any CPU.ActiveCfg = Release-x86|Any CPU
{780F7FD2-B383-4305-B9E6-25F2D384E601}.Release-x86|Any CPU.Build.0 = Release-x86|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Release-x86|x64.ActiveCfg = Release-x86|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Release-x86|x64.Build.0 = Release-x86|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Release-x86|x86.ActiveCfg = Release-x86|Any CPU
+ {780F7FD2-B383-4305-B9E6-25F2D384E601}.Release-x86|x86.Build.0 = Release-x86|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Debug|x64.Build.0 = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Debug|x86.Build.0 = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release|x64.ActiveCfg = Release|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release|x64.Build.0 = Release|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release|x86.ActiveCfg = Release|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release|x86.Build.0 = Release|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release-x86|Any CPU.ActiveCfg = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release-x86|Any CPU.Build.0 = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release-x86|x64.ActiveCfg = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release-x86|x64.Build.0 = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release-x86|x86.ActiveCfg = Debug|Any CPU
+ {F7C97111-FE06-43EA-A2E0-5AEC4AF236C7}.Release-x86|x86.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/OpenRA.Mods.RA2/OpenRA.Mods.RA2.csproj b/OpenRA.Mods.RA2/OpenRA.Mods.RA2.csproj
index cbff42e26..9c57fa479 100644
--- a/OpenRA.Mods.RA2/OpenRA.Mods.RA2.csproj
+++ b/OpenRA.Mods.RA2/OpenRA.Mods.RA2.csproj
@@ -1,7 +1,8 @@
- ../engine
+
+ ../engine