diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..8d20e10
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,69 @@
+name: Releasing ModVerify
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+
+# Builds and tests the solution.
+ test:
+ uses: ./.github/workflows/test.yml
+
+ pack:
+ name: Pack
+ needs: [test]
+ runs-on: windows-latest
+ steps:
+ - name: Checkout sources
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ submodules: recursive
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ - name: Create NetFramework Release
+ run: dotnet publish .\src\ModVerify.CliApp\ModVerify.CliApp.csproj --configuration Release -f net48 --output ./releases/net48
+ - name: Create Net Core Release
+ run: dotnet publish .\src\ModVerify.CliApp\ModVerify.CliApp.csproj --configuration Release -f net8.0 --output ./releases/net8.0
+ - name: Upload a Build Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: Binary Releases
+ path: ./releases
+ if-no-files-found: error
+ retention-days: 1
+
+ deploy:
+ name: Deploy
+ if: |
+ github.ref == 'refs/heads/main' && github.event_name == 'push'
+ needs: [pack]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout sources
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - uses: actions/download-artifact@v4
+ with:
+ name: Binary Releases
+ path: ./releases
+ - name: Create NET Core zip
+ # Change into the artifacts directory to avoid including the directory itself in the zip archive
+ working-directory: ./releases/net8.0
+ run: zip -r ./releases/ModVerify-Net8.zip .
+ - uses: dotnet/nbgv@v0.4.2
+ id: nbgv
+ - name: Create GitHub release
+ uses: softprops/action-gh-release@v2
+ with:
+ name: v${{ steps.nbgv.outputs.SemVer2 }}
+ tag_name: v${{ steps.nbgv.outputs.SemVer2 }}
+ token: ${{ secrets.GITHUB_TOKEN }}
+ generate_release_notes: true
+ files: |
+ ./releases/net48/ModVerify.CliApp.exe
+ ./releases/ModVerify-Net8.zip
\ No newline at end of file
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a34d7ac..20a36cc 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,12 +1,12 @@
-name: Petroglyph Tools .NET Build & Test
+name: ModVerify Build & Test
on:
workflow_call:
workflow_dispatch:
push:
- branches: [ main ]
+ branches: [ develop ]
pull_request:
- branches: [ main ]
+ branches: [ develop ]
jobs:
build-test:
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..1dda2dd
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,9 @@
+
+
+
+
+ all
+ 3.6.133
+
+
+
\ No newline at end of file
diff --git a/src/ModVerify.CliApp/FodyWeavers.xml b/src/ModVerify.CliApp/FodyWeavers.xml
new file mode 100644
index 0000000..5029e70
--- /dev/null
+++ b/src/ModVerify.CliApp/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/ModVerify.CliApp/ModVerify.CliApp.csproj b/src/ModVerify.CliApp/ModVerify.CliApp.csproj
index 82c06b5..66924d6 100644
--- a/src/ModVerify.CliApp/ModVerify.CliApp.csproj
+++ b/src/ModVerify.CliApp/ModVerify.CliApp.csproj
@@ -18,6 +18,10 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/src/ModVerify.CliApp/Program.cs b/src/ModVerify.CliApp/Program.cs
index f3a46f1..b4157d8 100644
--- a/src/ModVerify.CliApp/Program.cs
+++ b/src/ModVerify.CliApp/Program.cs
@@ -80,7 +80,7 @@ static async Task Main(string[] args)
}
}
- private static VerifyFocPipeline BuildPipeline(IPlayableObject playableObject, IGame fallbackGame)
+ private static VerifyGamePipeline BuildPipeline(IPlayableObject playableObject, IGame fallbackGame)
{
IList mods = Array.Empty();
if (playableObject is IMod mod)
@@ -97,7 +97,9 @@ private static VerifyFocPipeline BuildPipeline(IPlayableObject playableObject, I
playableObject.Game.Directory.FullName,
fallbackGame.Directory.FullName);
- return new VerifyFocPipeline(gameLocations, VerificationSettings.Default, _services);
+ var repo = _services.GetRequiredService().Create(GameEngineType.Foc, gameLocations);
+
+ return new VerifyGamePipeline(repo, VerificationSettings.Default, _services);
}
private static IServiceProvider CreateAppServices()
diff --git a/src/ModVerify/GameVerificationException.cs b/src/ModVerify/GameVerificationException.cs
index 036dfa4..0844557 100644
--- a/src/ModVerify/GameVerificationException.cs
+++ b/src/ModVerify/GameVerificationException.cs
@@ -11,6 +11,10 @@ public sealed class GameVerificationException(IEnumerable
private readonly string? _error = null;
private readonly IEnumerable _failedSteps = failedSteps ?? throw new ArgumentNullException(nameof(failedSteps));
+ public GameVerificationException(GameVerificationStep step) : this([step])
+ {
+ }
+
///
public override string Message => Error;
diff --git a/src/ModVerify/ModVerify.csproj b/src/ModVerify/ModVerify.csproj
index a77fbcc..8febcd9 100644
--- a/src/ModVerify/ModVerify.csproj
+++ b/src/ModVerify/ModVerify.csproj
@@ -25,6 +25,10 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/src/ModVerify/Steps/GameVerificationStep.cs b/src/ModVerify/Steps/GameVerificationStep.cs
index 6a7df65..295cd70 100644
--- a/src/ModVerify/Steps/GameVerificationStep.cs
+++ b/src/ModVerify/Steps/GameVerificationStep.cs
@@ -12,7 +12,11 @@
namespace AET.ModVerify.Steps;
-public abstract class GameVerificationStep(CreateGameDatabaseStep createDatabaseStep, IGameRepository repository, IServiceProvider serviceProvider)
+public abstract class GameVerificationStep(
+ CreateGameDatabaseStep createDatabaseStep,
+ IGameRepository repository,
+ VerificationSettings settings,
+ IServiceProvider serviceProvider)
: PipelineStep(serviceProvider)
{
protected readonly IFileSystem FileSystem = serviceProvider.GetRequiredService();
@@ -22,6 +26,8 @@ public abstract class GameVerificationStep(CreateGameDatabaseStep createDatabase
public IReadOnlyCollection VerifyErrors => _verifyErrors;
+ protected VerificationSettings Settings { get; } = settings;
+
protected GameDatabase Database { get; private set; } = null!;
protected IGameRepository Repository => repository;
@@ -34,7 +40,8 @@ protected sealed override void RunCore(CancellationToken token)
{
createDatabaseStep.Wait();
Database = createDatabaseStep.GameDatabase;
-
+
+ Logger?.LogInformation($"Running verifier '{Name}'...");
try
{
_errorLog = CreateVerificationLogFile();
@@ -42,6 +49,7 @@ protected sealed override void RunCore(CancellationToken token)
}
finally
{
+ Logger?.LogInformation($"Finished verifier '{Name}'");
_errorLog.Dispose();
_errorLog = null!;
}
@@ -57,9 +65,11 @@ protected void AddError(VerificationError error)
Logger?.LogTrace($"Error suppressed: '{error}'");
return;
}
-
_verifyErrors.Add(error);
_errorLog.WriteLine(error.Message);
+
+ if (Settings.ThrowBehavior == VerifyThrowBehavior.FailFast)
+ throw new GameVerificationException(this);
}
protected virtual bool OnError(VerificationError error)
diff --git a/src/ModVerify/Steps/VerifyReferencedModelsStep.cs b/src/ModVerify/Steps/VerifyReferencedModelsStep.cs
index 293a8c3..5151e5b 100644
--- a/src/ModVerify/Steps/VerifyReferencedModelsStep.cs
+++ b/src/ModVerify/Steps/VerifyReferencedModelsStep.cs
@@ -17,8 +17,12 @@
namespace AET.ModVerify.Steps;
-internal sealed class VerifyReferencedModelsStep(CreateGameDatabaseStep createDatabaseStep, IGameRepository repository, IServiceProvider serviceProvider)
- : GameVerificationStep(createDatabaseStep, repository, serviceProvider)
+internal sealed class VerifyReferencedModelsStep(
+ CreateGameDatabaseStep createDatabaseStep,
+ IGameRepository repository,
+ VerificationSettings settings,
+ IServiceProvider serviceProvider)
+ : GameVerificationStep(createDatabaseStep, repository, settings, serviceProvider)
{
public const string ModelNotFound = "ALO00";
public const string ModelBroken = "ALO01";
diff --git a/src/ModVerify/VerificationSettings.cs b/src/ModVerify/VerificationSettings.cs
new file mode 100644
index 0000000..ab5e618
--- /dev/null
+++ b/src/ModVerify/VerificationSettings.cs
@@ -0,0 +1,11 @@
+namespace AET.ModVerify;
+
+public record VerificationSettings
+{
+ public static readonly VerificationSettings Default = new()
+ {
+ ThrowBehavior = VerifyThrowBehavior.None
+ };
+
+ public VerifyThrowBehavior ThrowBehavior { get; init; }
+}
\ No newline at end of file
diff --git a/src/ModVerify/VerifyPipeline.cs b/src/ModVerify/VerifyGamePipeline.cs
similarity index 71%
rename from src/ModVerify/VerifyPipeline.cs
rename to src/ModVerify/VerifyGamePipeline.cs
index 86091cd..8b51723 100644
--- a/src/ModVerify/VerifyPipeline.cs
+++ b/src/ModVerify/VerifyGamePipeline.cs
@@ -11,36 +11,26 @@
namespace AET.ModVerify;
-
-public record VerificationSettings
-{
- public static readonly VerificationSettings Default = new();
-
- public bool ThrowOnError { get; init; }
-}
-
-
-public class VerifyFocPipeline : ParallelPipeline
+public class VerifyGamePipeline : ParallelPipeline
{
private IList _verificationSteps = null!;
- private readonly GameLocations _gameLocations;
+ private readonly IGameRepository _repository;
private readonly VerificationSettings _settings;
- public VerifyFocPipeline(GameLocations gameLocations, VerificationSettings settings, IServiceProvider serviceProvider)
+ public VerifyGamePipeline(IGameRepository gameRepository, VerificationSettings settings, IServiceProvider serviceProvider)
: base(serviceProvider, 4, false)
{
- _gameLocations = gameLocations;
+ _repository = gameRepository;
_settings = settings;
}
protected override Task> BuildSteps()
{
- var repository = new FocGameRepository(_gameLocations, ServiceProvider);
+ var buildIndexStep = new CreateGameDatabaseStep(_repository, ServiceProvider);
- var buildIndexStep = new CreateGameDatabaseStep(repository, ServiceProvider);
_verificationSteps = new List
{
- new VerifyReferencedModelsStep(buildIndexStep, repository, ServiceProvider),
+ new VerifyReferencedModelsStep(buildIndexStep, _repository, _settings, ServiceProvider),
};
var allSteps = new List
@@ -71,7 +61,7 @@ public override async Task RunAsync(CancellationToken token = default)
}
}
- if (_settings.ThrowOnError && failedSteps.Count > 0)
+ if (_settings.ThrowBehavior == VerifyThrowBehavior.FinalThrow && failedSteps.Count > 0)
throw new GameVerificationException(stepsWithVerificationErrors);
}
finally
diff --git a/src/ModVerify/VerifyThrowBehavior.cs b/src/ModVerify/VerifyThrowBehavior.cs
new file mode 100644
index 0000000..d1e9192
--- /dev/null
+++ b/src/ModVerify/VerifyThrowBehavior.cs
@@ -0,0 +1,8 @@
+namespace AET.ModVerify;
+
+public enum VerifyThrowBehavior
+{
+ None,
+ FinalThrow,
+ FailFast
+}
\ No newline at end of file
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/GameRepository.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/GameRepository.cs
index 37915f5..f7b1c63 100644
--- a/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/GameRepository.cs
+++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/GameRepository.cs
@@ -34,6 +34,8 @@ public class FocGameRepository : IGameRepository
private readonly IVirtualMegArchive? _masterMegArchive;
+ public GameEngineType EngineType => GameEngineType.Foc;
+
public IRepository EffectsRepository { get; }
public FocGameRepository(GameLocations gameLocations, IServiceProvider serviceProvider)
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/GameRepositoryFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/GameRepositoryFactory.cs
new file mode 100644
index 0000000..02e24d2
--- /dev/null
+++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/GameRepositoryFactory.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace PG.StarWarsGame.Engine.FileSystem;
+
+internal sealed class GameRepositoryFactory(IServiceProvider serviceProvider) : IGameRepositoryFactory
+{
+ public IGameRepository Create(GameEngineType engineType, GameLocations gameLocations)
+ {
+ if (engineType == GameEngineType.Eaw)
+ throw new NotImplementedException("Empire at War is currently not supported.");
+ return new FocGameRepository(gameLocations, serviceProvider);
+ }
+}
\ No newline at end of file
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/IGameRepository.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/IGameRepository.cs
index 788d0f2..8965189 100644
--- a/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/IGameRepository.cs
+++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/IGameRepository.cs
@@ -2,7 +2,9 @@
public interface IGameRepository : IRepository
{
- IRepository EffectsRepository { get; }
+ public GameEngineType EngineType { get; }
- bool FileExists(string filePath, string[] extensions, bool megFileOnly = false);
+ IRepository EffectsRepository { get; }
+
+ bool FileExists(string filePath, string[] extensions, bool megFileOnly = false);
}
\ No newline at end of file
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/IGameRepositoryFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/IGameRepositoryFactory.cs
new file mode 100644
index 0000000..ed6600f
--- /dev/null
+++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/FileSystem/IGameRepositoryFactory.cs
@@ -0,0 +1,6 @@
+namespace PG.StarWarsGame.Engine.FileSystem;
+
+public interface IGameRepositoryFactory
+{
+ IGameRepository Create(GameEngineType engineType, GameLocations gameLocations);
+}
\ No newline at end of file
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameDatabase.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameDatabase.cs
index a30a206..7abf073 100644
--- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameDatabase.cs
+++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameDatabase.cs
@@ -5,6 +5,8 @@ namespace PG.StarWarsGame.Engine;
public class GameDatabase
{
+ public required GameEngineType EngineType { get; init; }
+
public required GameConstants GameConstants { get; init; }
public required IList GameObjects { get; init; }
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameEngineType.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameEngineType.cs
new file mode 100644
index 0000000..962c389
--- /dev/null
+++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameEngineType.cs
@@ -0,0 +1,16 @@
+namespace PG.StarWarsGame.Engine;
+
+///
+/// The type of engine can be either "Empire at War" of "Forces of Corruption"
+///
+public enum GameEngineType
+{
+ ///
+ /// Empire at War
+ ///
+ Eaw = 0,
+ ///
+ /// Forces of Corruption
+ ///
+ Foc = 1
+}
\ No newline at end of file
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs
index fd5364e..f1ff96c 100644
--- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs
+++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs
@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
+using PG.StarWarsGame.Engine.FileSystem;
using PG.StarWarsGame.Engine.Language;
using PG.StarWarsGame.Engine.Xml;
@@ -8,6 +9,7 @@ public static class PetroglyphEngineServiceContribution
{
public static void ContributeServices(IServiceCollection serviceCollection)
{
+ serviceCollection.AddSingleton(sp => new GameRepositoryFactory(sp));
serviceCollection.AddSingleton(sp => new GameLanguageManager(sp));
serviceCollection.AddSingleton(sp => new PetroglyphXmlFileParserFactory(sp));
}
diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Pipeline/CreateGameDatabasePipeline.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Pipeline/CreateGameDatabasePipeline.cs
index 2da1ef1..53fb102 100644
--- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Pipeline/CreateGameDatabasePipeline.cs
+++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Pipeline/CreateGameDatabasePipeline.cs
@@ -75,6 +75,7 @@ protected override async Task RunCoreAsync(CancellationToken token)
GameDatabase = new GameDatabase
{
+ EngineType = repository.EngineType,
GameConstants = _parseGameConstants.Database,
GameObjects = _parseGameObjects.Database
};
diff --git a/version.json b/version.json
new file mode 100644
index 0000000..251e6e2
--- /dev/null
+++ b/version.json
@@ -0,0 +1,18 @@
+{
+ "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
+ "version": "0.0-alpha",
+ "publicReleaseRefSpec": [
+ "^refs/heads/main$"
+ ],
+ "assemblyVersion" : {
+ "precision": "major"
+ },
+ "cloudBuild": {
+ "buildNumber": {
+ "enabled": true
+ }
+ },
+ "nugetPackageVersion": {
+ "semVer": 2
+ }
+}
\ No newline at end of file