Skip to content

Commit 52f68c0

Browse files
committed
update mod verify
1 parent a677fb9 commit 52f68c0

65 files changed

Lines changed: 955 additions & 372 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ jobs:
5555
# Change into the artifacts directory to avoid including the directory itself in the zip archive
5656
working-directory: ./releases/net8.0
5757
run: zip -r ../ModVerify-Net8.zip .
58+
- name: Rename .NET Framework executable
59+
run: mv ./releases/net48/ModVerify.CliApp.exe ./releases/net48/ModVerify.exe
5860
- uses: dotnet/nbgv@v0.4.2
5961
id: nbgv
6062
- name: Create GitHub release
@@ -65,5 +67,5 @@ jobs:
6567
token: ${{ secrets.GITHUB_TOKEN }}
6668
generate_release_notes: true
6769
files: |
68-
./releases/net48/ModVerify.CliApp.exe
70+
./releases/net48/ModVerify.exe
6971
./releases/ModVerify-Net8.zip

README.md

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,77 @@
1-
# ModVerify
1+
# ModVerify: A Mod Verification Tool
2+
3+
ModVerify is a command-line tool designed to verify mods for the game Star Wars: Empire at War and its expansion Forces of Corruption.
4+
5+
## Table of Contents
6+
7+
- [Installation](#installation)
8+
- [Usage](#usage)
9+
- [Options](#options)
10+
- [Available Checks](#available-checks)
11+
12+
## Installation
13+
14+
Download the latest release from the [releases page](https://github.com/AlamoEngine-Tools/ModVerify/releases). There are two versions of the application available.
15+
16+
1. `ModVerify.exe` is the default version. Use this if you simply want to verify your mods. This version only works on Windows.
17+
2. `ModVerify-NetX.zip` is the cross-platform app. It works on Windows and Linux and is most likely the version you want to use to include it in some CI/CD scenarios.
18+
19+
You can place the files anywhere on your system, eg. your Desktop. There is no need to place it inside a mod's directory.
20+
21+
*Note: Both versions have the exact same feature set. They just target a different .NET runtime. Linux and CI/CD support is not fully tested yet. Current priority is on the Windows-only version.*
22+
23+
## Usage
24+
25+
Simply run the executable file `ModVerify.exe`.
26+
27+
When given no specific argument through the command line, the app will ask you which game or mod you want to verify. When the tool is done, it will write the verification results into new files next to the executable.
28+
29+
A `.JSON` file lists all found issues. Into seperate `.txt` files the same errors get grouped by a category of the finding. The text files may be easier to read, while the json file is more useful for 3rd party tool processing.
30+
31+
## Options
32+
33+
You can also run the tool with command line arguments to adjust the tool to your needs.
34+
35+
To see all available options, open the command line and type:
36+
37+
```bash
38+
ModVerify.exe --help
39+
```
40+
41+
Here is a list of the most relevant options:
42+
43+
### `--path`
44+
Specifies a path that shall be analyzed. **There will be no user input required when using this option**
45+
46+
### `--output`
47+
Specified the output path where analysis result shall be written to.
48+
49+
### `--baseline`
50+
Specifies a baseline file that shall be used to filter out known errors. You can download the [FoC baseline](focBaseline.json) which includes all errors produced by the vanilla game.
51+
52+
### `--createBaseline`
53+
If you want to create your own baseline, add this option with a file path such as `myModBaseline.json`.
54+
55+
### Example
56+
This is an example run configuration that analyzes a specific mod, uses a the FoC basline and writes the output into a dedicated directory:
57+
58+
```bash
59+
ModVerify.exe --path "C:\My Games\FoC\Mods\MyMod" --output "C:\My Games\FoC\Mods\MyMod\verifyResults" --baseline focBaseline.json
60+
```
61+
62+
63+
## Available Checks
64+
65+
The following verifiers are currently implemented:
66+
67+
### For SFX Events:
68+
- Checks whether coded preset exists
69+
- Checks the referenced samples for validity (bit rate, sample size, channels, etc.)
70+
- Duplicates
71+
72+
73+
### For GameObjects
74+
- Checks the referenced models for validity (textures, particles and shaders)
75+
- Duplicates
76+
77+

src/ModVerify.CliApp/ModVerify.CliApp.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
</PropertyGroup>
1919

2020
<ItemGroup>
21+
<PackageReference Include="Nullable" Version="1.3.1">
22+
<PrivateAssets>all</PrivateAssets>
23+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
24+
</PackageReference>
2125
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
2226
<PackageReference Include="AlamoEngineTools.PG.StarWarsGame.Infrastructure.Clients" Version="3.1.5" />
2327
<PackageReference Include="AlamoEngineTools.SteamAbstraction" Version="3.1.5" />
@@ -36,6 +40,7 @@
3640
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3741
</PackageReference>
3842
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
43+
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
3944
<PackageReference Include="Required" Version="1.0.0">
4045
<PrivateAssets>all</PrivateAssets>
4146
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,90 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.IO;
34
using System.IO.Abstractions;
5+
using System.Linq;
46
using System.Threading.Tasks;
57
using AET.ModVerify;
68
using AET.ModVerify.Reporting;
7-
using AET.ModVerify.Settings;
89
using Microsoft.Extensions.DependencyInjection;
910
using Microsoft.Extensions.Logging;
11+
using PG.StarWarsGame.Engine;
12+
using PG.StarWarsGame.Infrastructure.Mods;
13+
using PG.StarWarsGame.Infrastructure.Services.Dependencies;
1014

1115
namespace ModVerify.CliApp;
1216

13-
internal class ModVerifyApp(GameVerifySettings settings, IServiceProvider services)
17+
internal class ModVerifyApp(ModVerifyAppSettings settings, IServiceProvider services)
1418
{
1519
private readonly ILogger? _logger = services.GetService<ILoggerFactory>()?.CreateLogger(typeof(ModVerifyApp));
1620
private readonly IFileSystem _fileSystem = services.GetRequiredService<IFileSystem>();
1721

18-
private IReadOnlyCollection<VerificationError> Errors { get; set; } = Array.Empty<VerificationError>();
19-
20-
public async Task RunVerification(VerifyGameSetupData gameSetupData)
22+
public async Task<int> RunApplication()
2123
{
22-
var verifyPipeline = BuildPipeline(gameSetupData);
23-
_logger?.LogInformation($"Verifying {gameSetupData.VerifyObject.Name}...");
24-
await verifyPipeline.RunAsync();
25-
_logger?.LogInformation("Finished Verifying");
24+
var returnCode = 0;
25+
26+
var gameSetupData = CreateGameSetupData(settings, services);
27+
var verifyPipeline = new ModVerifyPipeline(gameSetupData.EngineType, gameSetupData.GameLocations, settings.GameVerifySettigns, services);
28+
29+
try
30+
{
31+
_logger?.LogInformation($"Verifying {gameSetupData.VerifyObject.Name}...");
32+
await verifyPipeline.RunAsync().ConfigureAwait(false);
33+
_logger?.LogInformation("Finished Verifying");
34+
}
35+
catch (GameVerificationException e)
36+
{
37+
returnCode = e.HResult;
38+
}
39+
40+
if (settings.CreateNewBaseline)
41+
await WriteBaseline(verifyPipeline.Errors, settings.NewBaselinePath).ConfigureAwait(false);
42+
43+
return returnCode;
2644
}
2745

28-
private VerifyGamePipeline BuildPipeline(VerifyGameSetupData setupData)
46+
private async Task WriteBaseline(IEnumerable<VerificationError> errors, string baselineFile)
2947
{
30-
return new ModVerifyPipeline(setupData.EngineType, setupData.GameLocations, settings, services);
48+
var fullPath = _fileSystem.Path.GetFullPath(baselineFile);
49+
#if NET
50+
await
51+
#endif
52+
using var fs = _fileSystem.FileStream.New(fullPath, FileMode.Create, FileAccess.Write, FileShare.None);
53+
var baseline = new VerificationBaseline(errors);
54+
await baseline.ToJsonAsync(fs);
3155
}
3256

33-
public async Task WriteBaseline(string baselineFile)
57+
private static VerifyGameSetupData CreateGameSetupData(ModVerifyAppSettings options, IServiceProvider services)
3458
{
59+
var selectionResult = new ModOrGameSelector(services).SelectModOrGame(options.PathToVerify);
60+
61+
IList<string> mods = Array.Empty<string>();
62+
if (selectionResult.ModOrGame is IMod mod)
63+
{
64+
var traverser = services.GetRequiredService<IModDependencyTraverser>();
65+
mods = traverser.Traverse(mod)
66+
.Select(x => x.Mod)
67+
.OfType<IPhysicalMod>().Select(x => x.Directory.FullName)
68+
.ToList();
69+
}
70+
71+
var fallbackPaths = new List<string>();
72+
if (selectionResult.FallbackGame is not null)
73+
fallbackPaths.Add(selectionResult.FallbackGame.Directory.FullName);
74+
75+
if (!string.IsNullOrEmpty(options.AdditionalFallbackPath))
76+
fallbackPaths.Add(options.AdditionalFallbackPath);
77+
78+
var gameLocations = new GameLocations(
79+
mods,
80+
selectionResult.ModOrGame.Game.Directory.FullName,
81+
fallbackPaths);
82+
83+
return new VerifyGameSetupData
84+
{
85+
EngineType = GameEngineType.Foc,
86+
GameLocations = gameLocations,
87+
VerifyObject = selectionResult.ModOrGame,
88+
};
3589
}
3690
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using AET.ModVerify.Settings;
3+
using System.Diagnostics.CodeAnalysis;
4+
5+
namespace ModVerify.CliApp;
6+
7+
public record ModVerifyAppSettings
8+
{
9+
public GameVerifySettings GameVerifySettigns { get; init; }
10+
11+
public string? PathToVerify { get; init; } = null;
12+
13+
public string Output { get; init; } = Environment.CurrentDirectory;
14+
15+
public string? AdditionalFallbackPath { get; init; } = null;
16+
17+
[MemberNotNullWhen(true, nameof(NewBaselinePath))]
18+
public bool CreateNewBaseline => !string.IsNullOrEmpty(NewBaselinePath);
19+
20+
public string? NewBaselinePath { get; init; }
21+
}

src/ModVerify.CliApp/ModVerifyOptions.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
using CommandLine;
1+
using AET.ModVerify.Reporting;
2+
using CommandLine;
23

34
namespace ModVerify.CliApp;
45

56
internal class ModVerifyOptions
67
{
78
[Option('p', "path", Required = false,
89
HelpText = "The path to a mod directory to verify. If not path is specified, " +
9-
"the app search for mods and asks the user to select a game or mod.")]
10+
"the app searches for game installations and asks the user to select a game or mod.")]
1011
public string? Path { get; set; }
1112

13+
[Option('o', "output", Required = false, HelpText = "directory where result files shall be stored to.")]
14+
public string? Output { get; set; }
15+
1216
[Option('v', "verbose", Required = false, HelpText = "Set output to verbose messages.")]
1317
public bool Verbose { get; set; }
1418

@@ -18,7 +22,16 @@ internal class ModVerifyOptions
1822
[Option("suppressions", Required = false, HelpText = "Path to a JSON suppression file.")]
1923
public string? Suppressions { get; set; }
2024

21-
[Option("createBaseLine", Required = false,
25+
[Option("minFailSeverity", Required = false, Default = null,
26+
HelpText = "When set, the application return with an error, if any finding has at least the specified severity value.")]
27+
public VerificationSeverity? MinimumFailureSeverity { get; set; }
28+
29+
30+
[Option("failFast", Required = false, Default = false,
31+
HelpText = "When set, the application will abort on the first failure. The option also recognized the 'MinimumFailureSeverity' setting.")]
32+
public bool FailFast { get; set; }
33+
34+
[Option("createBaseline", Required = false,
2235
HelpText = "When a path is specified, the tools creates a new baseline file. " +
2336
"An existing file will be overwritten. " +
2437
"Previous baselines are merged into the new baseline.")]

0 commit comments

Comments
 (0)