Add core content definitions

This commit is contained in:
2026-04-21 19:47:25 +02:00
parent d4b3c221b2
commit efcc1ba209
74 changed files with 1196 additions and 13 deletions

View File

@@ -0,0 +1,111 @@
using SideScrollerGame.Content.Definitions;
using SideScrollerGame.Content.Samples;
using SideScrollerGame.Content.Validation;
namespace SideScrollerGame.Content.Tests;
public class ContentValidationTests
{
[Fact]
public void SampleContent_ValidatesWithoutErrors()
{
ContentRegistry registry = SampleContent.CreateRegistry();
ContentValidationResult result = new ContentValidator().Validate(registry);
Assert.False(result.HasErrors, string.Join(Environment.NewLine, result.Messages.Select(message => message.Message)));
}
[Fact]
public void Registry_CanLookUpCoreSampleDefinitions()
{
ContentRegistry registry = SampleContent.CreateRegistry();
Assert.True(registry.TryGetMission("mission.test", out MissionDefinition? mission));
Assert.NotNull(mission);
Assert.Equal("Test Mission", mission.DisplayName);
Assert.True(registry.TryGetEnemyType("enemy.serial", out EnemyTypeDefinition? enemy));
Assert.NotNull(enemy);
Assert.Equal(12, enemy.Health);
Assert.True(registry.Weapons.ContainsKey("weapon.primary.basic"));
Assert.True(registry.TryGetDifficulty("difficulty.normal", out DifficultyDefinition? difficulty));
Assert.NotNull(difficulty);
Assert.Equal(3, difficulty.HeroStartingShieldCharges);
}
[Fact]
public void Validate_DuplicateIds_ReportsDuplicatedId()
{
ContentRegistry sample = SampleContent.CreateRegistry();
ContentRegistry registry = CreateRegistry(sample, difficulties: sample.DifficultyDefinitions.Append(sample.DifficultyDefinitions[0] with { DisplayName = "Duplicate Easy" }).ToList());
ContentValidationResult result = new ContentValidator().Validate(registry);
Assert.Contains(result.Messages, message => message.Code == "content.id.duplicate" && message.Message.Contains("difficulty.easy", StringComparison.Ordinal));
}
[Fact]
public void Validate_MissionWithMissingCluster_ReportsMissingCluster()
{
ContentRegistry sample = SampleContent.CreateRegistry();
ContentRegistry registry = CreateRegistry(sample, missions:
[
sample.MissionDefinitions[0] with { ClusterIds = ["cluster.opening", "cluster.missing"] }
]);
ContentValidationResult result = new ContentValidator().Validate(registry);
Assert.Contains(result.Messages, message => message.Code == "mission.cluster.missing" && message.DefinitionId == "mission.test" && message.Message.Contains("cluster.missing", StringComparison.Ordinal));
}
[Fact]
public void Validate_ClusterWithMissingEnemyType_ReportsMissingEnemy()
{
ContentRegistry sample = SampleContent.CreateRegistry();
ContentRegistry registry = CreateRegistry(sample, enemyClusters:
[
sample.EnemyClusterDefinitions[0] with { Spawns = [new SpawnScheduleEntryDefinition("enemy.missing", 1.0, 1.0, 0.5)] }
]);
ContentValidationResult result = new ContentValidator().Validate(registry);
Assert.Contains(result.Messages, message => message.Code == "cluster.enemy.missing" && message.DefinitionId == "cluster.opening" && message.Message.Contains("enemy.missing", StringComparison.Ordinal));
}
[Fact]
public void Validate_BehaviorTrackWithNoEvents_ReportsBehavior()
{
ContentRegistry sample = SampleContent.CreateRegistry();
ContentRegistry registry = CreateRegistry(sample, enemyBehaviors:
[
sample.EnemyBehaviorDefinitions[0] with { Tracks = [new BehaviorTrackDefinition("track.empty", BehaviorTrackMode.Serial, [])] },
sample.EnemyBehaviorDefinitions[1]
]);
ContentValidationResult result = new ContentValidator().Validate(registry);
Assert.Contains(result.Messages, message => message.Code == "behavior.track.events.empty" && message.DefinitionId == "behavior.enemy.serial");
}
[Fact]
public void Validate_DifficultyWithNonPositiveMultiplier_ReportsDifficulty()
{
ContentRegistry sample = SampleContent.CreateRegistry();
DifficultyDefinition invalidDifficulty = sample.DifficultyDefinitions[1] with { Modifiers = sample.DifficultyDefinitions[1].Modifiers with { EnemyHealthMultiplier = 0.0 } };
ContentRegistry registry = CreateRegistry(sample, difficulties:
[
sample.DifficultyDefinitions[0],
invalidDifficulty,
sample.DifficultyDefinitions[2]
]);
ContentValidationResult result = new ContentValidator().Validate(registry);
Assert.Contains(result.Messages, message => message.Code == "difficulty.multiplier.invalid" && message.DefinitionId == "difficulty.normal" && message.Message.Contains("EnemyHealthMultiplier", StringComparison.Ordinal));
}
private static ContentRegistry CreateRegistry(ContentRegistry sample, IReadOnlyList<MissionDefinition>? missions = null, IReadOnlyList<DifficultyDefinition>? difficulties = null, IReadOnlyList<CameraPathDefinition>? cameraPaths = null, IReadOnlyList<LevelLayerDefinition>? levelLayers = null, IReadOnlyList<EnemyTypeDefinition>? enemyTypes = null, IReadOnlyList<EnemyBehaviorDefinition>? enemyBehaviors = null, IReadOnlyList<EnemyClusterDefinition>? enemyClusters = null, IReadOnlyList<CollectibleDefinition>? collectibles = null, IReadOnlyList<WeaponDefinition>? weapons = null, IReadOnlyList<SpecialWeaponDefinition>? specialWeapons = null, IReadOnlyList<SquadronMateTypeDefinition>? squadronMateTypes = null)
{
return new ContentRegistry(missions ?? sample.MissionDefinitions, difficulties ?? sample.DifficultyDefinitions, cameraPaths ?? sample.CameraPathDefinitions, levelLayers ?? sample.LevelLayerDefinitions, enemyTypes ?? sample.EnemyTypeDefinitions, enemyBehaviors ?? sample.EnemyBehaviorDefinitions, enemyClusters ?? sample.EnemyClusterDefinitions, collectibles ?? sample.CollectibleDefinitions, weapons ?? sample.WeaponDefinitions, specialWeapons ?? sample.SpecialWeaponDefinitions, squadronMateTypes ?? sample.SquadronMateTypeDefinitions);
}
}

View File

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<GodotProjectDir>$(MSBuildProjectDirectory)\..\..\godot\</GodotProjectDir>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
<CompilerVisibleProperty Include="GodotProjectDir" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\godot\SideScrollerGame.Godot.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,9 @@
namespace SideScrollerGame.Content.Tests;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}