Skip to content

Commit 0ec1eac

Browse files
committed
parsing is engine type aware
1 parent 99d81be commit 0ec1eac

31 files changed

Lines changed: 396 additions & 296 deletions

src/ModVerify/Verifiers/ReferencedModelsVerifier.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ public override void Verify(CancellationToken token)
2020
var gameObjectEntries = GameEngine.GameObjectTypeManager.Entries.ToList();
2121
var hardcodedModels = FocHardcodedConstants.HardcodedModels.ToList();
2222

23-
var totalModelsCount = gameObjectEntries.Sum(x => x.Models.Count()) + hardcodedModels.Count;
23+
var totalModelsCount =
24+
gameObjectEntries
25+
.Sum(x => GameEngine.GameObjectTypeManager.GetModels(x).Count())
26+
+ hardcodedModels.Count;
2427

2528
if (totalModelsCount == 0)
2629
return;
@@ -36,7 +39,7 @@ public override void Verify(CancellationToken token)
3639
foreach (var gameObject in gameObjectEntries)
3740
{
3841
context[0] = $"GameObject: {gameObject.Name}";
39-
foreach (var model in gameObject.Models)
42+
foreach (var model in GameEngine.GameObjectTypeManager.GetModels(gameObject))
4043
{
4144
OnProgress((double)++counter / totalModelsCount, $"Model - '{model}'");
4245
inner.Verify(model, context, token);

src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@
1212
namespace PG.StarWarsGame.Engine.Audio.Sfx;
1313

1414
internal class SfxEventGameManager(
15-
GameEngineType engineType,
1615
GameRepository repository,
1716
GameEngineErrorReporterWrapper errorReporter,
1817
IServiceProvider serviceProvider)
19-
: GameManagerBase<SfxEvent>(engineType, repository, errorReporter, serviceProvider), ISfxEventGameManager
18+
: GameManagerBase<SfxEvent>(repository, errorReporter, serviceProvider), ISfxEventGameManager
2019
{
2120
public IEnumerable<LanguageType> InstalledLanguages { get; private set; } = [];
2221

src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,13 @@
1515
namespace PG.StarWarsGame.Engine.CommandBar;
1616

1717
internal partial class CommandBarGameManager(
18-
GameEngineType engineType,
1918
GameRepository repository,
2019
PGRender pgRender,
2120
IGameConstants gameConstants,
2221
IFontManager fontManager,
2322
GameEngineErrorReporterWrapper errorReporter,
2423
IServiceProvider serviceProvider)
25-
: GameManagerBase<CommandBarBaseComponent>(engineType, repository, errorReporter, serviceProvider), ICommandBarGameManager
24+
: GameManagerBase<CommandBarBaseComponent>(repository, errorReporter, serviceProvider), ICommandBarGameManager
2625
{
2726
private readonly ICrc32HashingService _hashingService = serviceProvider.GetRequiredService<ICrc32HashingService>();
2827
private readonly IMtdFileService _mtdFileService = serviceProvider.GetRequiredService<IMtdFileService>();

src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstants.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77
namespace PG.StarWarsGame.Engine.GameConstants;
88

99
internal class GameConstants(
10-
GameEngineType engineType,
1110
GameRepository repository,
1211
GameEngineErrorReporterWrapper errorReporter,
1312
IServiceProvider serviceProvider)
14-
: GameManagerBase(engineType, repository, errorReporter, serviceProvider), IGameConstants
13+
: GameManagerBase(repository, errorReporter, serviceProvider), IGameConstants
1514
{
1615
protected override Task InitializeCoreAsync(CancellationToken token)
1716
{

src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@
1313
namespace PG.StarWarsGame.Engine;
1414

1515
internal abstract class GameManagerBase<T>(
16-
GameEngineType engineType,
1716
GameRepository repository,
1817
GameEngineErrorReporterWrapper errorReporter,
1918
IServiceProvider serviceProvider)
20-
: GameManagerBase(engineType, repository, errorReporter, serviceProvider), IGameManager<T>
19+
: GameManagerBase(repository, errorReporter, serviceProvider), IGameManager<T>
2120
{
2221
protected readonly FrugalValueListDictionary<Crc32, T> NamedEntries = new();
2322

@@ -48,14 +47,13 @@ internal abstract class GameManagerBase
4847
public GameEngineType EngineType { get; }
4948

5049
protected GameManagerBase(
51-
GameEngineType engineType,
5250
GameRepository repository,
5351
GameEngineErrorReporterWrapper errorReporter,
5452
IServiceProvider serviceProvider)
5553
{
5654
GameRepository = repository ?? throw new ArgumentNullException(nameof(repository));
5755
ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
58-
EngineType = engineType;
56+
EngineType = repository.EngineType;
5957
Logger = serviceProvider.GetService<ILoggerFactory>()?.CreateLogger(GetType());
6058
FileSystem = serviceProvider.GetRequiredService<IFileSystem>();
6159
ErrorReporter = errorReporter ?? throw new ArgumentNullException(nameof(errorReporter));

src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs

Lines changed: 17 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,7 @@ namespace PG.StarWarsGame.Engine.GameObjects;
1111
[DebuggerDisplay("{Name} ({ClassificationName})")]
1212
public sealed class GameObject : NamedXmlObject
1313
{
14-
internal GameObject(
15-
string name,
16-
string classification,
17-
Crc32 nameCrc,
18-
int index,
19-
XmlLocationInfo location)
20-
: base(name, nameCrc, location)
21-
{
22-
if (index < 0)
23-
throw new ArgumentOutOfRangeException(nameof(index), "Index must be greater than 0.");
24-
Index = index;
25-
Id = (int)nameCrc;
26-
ClassificationName = classification ?? throw new ArgumentNullException(nameof(classification));
27-
LandTerrainModelMapping = new ReadOnlyDictionary<string, string>(InternalLandTerrainModelMapping);
28-
}
14+
internal readonly List<(string terrain, string model)> InternalLandTerrainModelMapping = [];
2915

3016
internal int Id { get; }
3117

@@ -61,48 +47,24 @@ internal GameObject(
6147

6248
public string? DamagedSmokeAssetModel { get; internal set; }
6349

64-
public IReadOnlyDictionary<string, string> LandTerrainModelMapping { get; }
65-
66-
internal Dictionary<string, string> InternalLandTerrainModelMapping { get; } = new(StringComparer.OrdinalIgnoreCase);
67-
68-
/// <summary>
69-
/// Gets all model files (including particles) the game object references.
70-
/// </summary>
71-
public IEnumerable<string> Models
72-
{
73-
get
74-
{
75-
var models = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
76-
AddNotEmpty(models, GalacticModel);
77-
AddNotEmpty(models, DestroyedGalacticModel);
78-
AddNotEmpty(models, LandModel);
79-
AddNotEmpty(models, SpaceModel);
80-
AddNotEmpty(models, TacticalModel);
81-
AddNotEmpty(models, GalacticFleetOverrideModel);
82-
AddNotEmpty(models, GuiModel);
83-
AddNotEmpty(models, ModelName);
84-
85-
// TODO: Is this really correct?
86-
AddNotEmpty(models, LandAnimOverrideModel, s => s.EndsWith(".alo", StringComparison.OrdinalIgnoreCase));
87-
AddNotEmpty(models, SpaceAnimOverrideModel, s => s.EndsWith(".alo", StringComparison.OrdinalIgnoreCase));
88-
89-
AddNotEmpty(models, DamagedSmokeAssetModel);
90-
foreach (var model in InternalLandTerrainModelMapping.Values)
91-
models.Add(model);
92-
93-
return models;
94-
}
95-
96-
}
97-
98-
private static void AddNotEmpty(ISet<string> set, string? value, Predicate<string>? predicate = null)
50+
public IReadOnlyList<(string terrain, string model)> LandTerrainModelMappingValues { get; }
51+
52+
internal GameObject(
53+
string name,
54+
string classification,
55+
Crc32 nameCrc,
56+
int index,
57+
XmlLocationInfo location)
58+
: base(name, nameCrc, location)
9959
{
100-
if (value is null)
101-
return;
102-
if (predicate is null || predicate(value))
103-
set.Add(value);
60+
if (index < 0)
61+
throw new ArgumentOutOfRangeException(nameof(index), "Index must be greater than 0.");
62+
Index = index;
63+
Id = (int)nameCrc;
64+
ClassificationName = classification ?? throw new ArgumentNullException(nameof(classification));
65+
LandTerrainModelMappingValues = new ReadOnlyCollection<(string, string)>(InternalLandTerrainModelMapping);
10466
}
105-
67+
10668
public void PostLoadFixup()
10769
{
10870
// TODO:
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
using Microsoft.Extensions.Logging;
2+
using PG.StarWarsGame.Engine.ErrorReporting;
3+
using PG.StarWarsGame.Engine.Xml;
4+
using PG.StarWarsGame.Engine.Xml.Parsers;
5+
using System.Linq;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
namespace PG.StarWarsGame.Engine.GameObjects;
10+
11+
internal partial class GameObjectTypeGameManager
12+
{
13+
protected override async Task InitializeCoreAsync(CancellationToken token)
14+
{
15+
Logger?.LogInformation("Parsing GameObjects...");
16+
await Task.Run(ParseGameObjectDatabases, token);
17+
}
18+
19+
private void ParseGameObjectDatabases()
20+
{
21+
var gameParser = new PetroglyphStarWarsGameXmlParser(GameRepository,
22+
new PetroglyphStarWarsGameXmlParseSettings
23+
{
24+
GameManager = ToString(),
25+
InvalidFilesListXmlFailsInitialization = true,
26+
InvalidObjectXmlFailsInitialization = false,
27+
}, ServiceProvider, ErrorReporter);
28+
29+
var xmlFileList = gameParser.ParseFileList(@"DATA\XML\GAMEOBJECTFILES.XML").Files
30+
.Select(x => FileSystem.Path.Combine(@".\DATA\XML\", x))
31+
.Where(VerifyFilePathLength)
32+
.ToList();
33+
34+
var gameObjectFileParser = new GameObjectFileParser(EngineType, ServiceProvider, ErrorReporter);
35+
36+
var allLoaded = false;
37+
38+
// This also acts a guard against infinite loops in case of unexpected circular dependencies or
39+
// when a unit declares itself as its own <Variant_Of_Existing_Type>
40+
for (var passNumber = 0; !allLoaded && passNumber < 10; passNumber++)
41+
{
42+
Logger?.LogDebug("***** Parsing game object types - pass {PassNumber} *****", passNumber);
43+
44+
if (passNumber != 0)
45+
gameObjectFileParser.OverlayLoad = true;
46+
47+
foreach (var gameObjectXmlFile in xmlFileList)
48+
{
49+
if (passNumber == 0)
50+
{
51+
try
52+
{
53+
gameObjectFileParser.GameObjectParsed += OnGameObjectParsed!;
54+
ParseSingleGameObjectFile(gameObjectXmlFile, gameParser, gameObjectFileParser);
55+
}
56+
finally
57+
{
58+
gameObjectFileParser.GameObjectParsed -= OnGameObjectParsed!;
59+
}
60+
}
61+
else
62+
{
63+
foreach (var gameObject in _gameObjects)
64+
{
65+
if (!gameObject.IsLoadingComplete && gameObject.Location.XmlFile == gameObjectXmlFile)
66+
ParseSingleGameObjectFile(gameObjectXmlFile, gameParser, gameObjectFileParser);
67+
}
68+
}
69+
}
70+
71+
72+
73+
//GameObjectTypeClass::Static_Post_Load_Fixup();
74+
//SFXEventReferenceClass::Static_Post_Load_Fixup();
75+
//SpeechEventReferenceClass::Static_Post_Load_Fixup();
76+
//MusicEventReferenceClass::Static_Post_Load_Fixup();
77+
//FactionReferenceClass::Static_Post_Load_Fixup();
78+
//...
79+
}
80+
}
81+
82+
private void OnGameObjectParsed(object sender, GameObjectParsedEventArgs e)
83+
{
84+
if (!e.Unique)
85+
{
86+
var entries = NamedEntries.GetValues(e.GameObject.Crc32)
87+
.Select(x => x.Name);
88+
ErrorReporter.Assert(EngineAssert.Create(
89+
EngineAssertKind.DuplicateEntry,
90+
e.GameObject.Crc32, entries,
91+
$"Error: Game object type {e.GameObject.Name} is defined multiple times."));
92+
}
93+
94+
if (NamedEntries.ValueCount >= 0x10000)
95+
{
96+
ErrorReporter.Assert(
97+
EngineAssert.Create(
98+
EngineAssertKind.ValueOutOfRange,
99+
NamedEntries.ValueCount,
100+
[ToString()],
101+
"Too many game object types defined."));
102+
}
103+
104+
_gameObjects.Add(e.GameObject);
105+
}
106+
107+
private void ParseSingleGameObjectFile(
108+
string file,
109+
PetroglyphStarWarsGameXmlParser gameParser,
110+
GameObjectFileParser gameObjectFileParser)
111+
{
112+
gameParser.ParseObjectsFromContainerFile(file, gameObjectFileParser, NamedEntries);
113+
}
114+
115+
private bool VerifyFilePathLength(string filePath)
116+
{
117+
if (filePath.Length > PGConstants.MaxGameObjectDatabaseFileName)
118+
{
119+
// Technically this is an assert in the engine, but in Release Mode, the game CTDs.
120+
// Thus, we rank this as an initialization error.
121+
ErrorReporter.Report(new InitializationError
122+
{
123+
GameManager = ToString(),
124+
Message = $"Game object file '{filePath}' is longer than {PGConstants.MaxGameObjectDatabaseFileName} characters."
125+
});
126+
return false;
127+
}
128+
129+
return true;
130+
}
131+
}

0 commit comments

Comments
 (0)