chore: fix contract catalog analyzer warnings.

Primary constructor on ContractTemplateCatalog; concrete List return
types in loader parse helpers; collection spread in NormalizeBundle;
const emptyCatalog in roster gate test.
pull/186/head
VinPropane 2026-06-20 19:46:39 -04:00
parent e3988874d2
commit 93fd8864dc
4 changed files with 15 additions and 30 deletions

View File

@ -155,7 +155,7 @@ public class ContractTemplateCatalogLoaderTests
{ {
// Arrange // Arrange
var (_, contractsDir, schemaPath) = CreateTempContentLayout(); var (_, contractsDir, schemaPath) = CreateTempContentLayout();
var emptyCatalog = """{"schemaVersion": 1, "contractTemplates": []}"""; const string emptyCatalog = """{"schemaVersion": 1, "contractTemplates": []}""";
File.WriteAllText(Path.Combine(contractsDir, "prototype_contract_templates.json"), emptyCatalog, Encoding.UTF8); File.WriteAllText(Path.Combine(contractsDir, "prototype_contract_templates.json"), emptyCatalog, Encoding.UTF8);
// Act // Act
var ex = Record.Exception(() => LoadCatalog(contractsDir, schemaPath)); var ex = Record.Exception(() => LoadCatalog(contractsDir, schemaPath));

View File

@ -3,25 +3,19 @@ using System.Collections.ObjectModel;
namespace NeonSprawl.Server.Game.Contracts; namespace NeonSprawl.Server.Game.Contracts;
/// <summary>In-memory contract template catalog loaded at startup (NEO-145). Game code should prefer <see cref="IContractTemplateRegistry"/> for lookups.</summary> /// <summary>In-memory contract template catalog loaded at startup (NEO-145). Game code should prefer <see cref="IContractTemplateRegistry"/> for lookups.</summary>
public sealed class ContractTemplateCatalog public sealed class ContractTemplateCatalog(
{
public ContractTemplateCatalog(
string contractsDirectory, string contractsDirectory,
IReadOnlyDictionary<string, ContractTemplateRow> byId, IReadOnlyDictionary<string, ContractTemplateRow> byId,
int catalogJsonFileCount) int catalogJsonFileCount)
{ {
ContractsDirectory = contractsDirectory;
ById = new ReadOnlyDictionary<string, ContractTemplateRow>(new Dictionary<string, ContractTemplateRow>(byId, StringComparer.Ordinal));
CatalogJsonFileCount = catalogJsonFileCount;
}
/// <summary>Absolute path to the directory that was enumerated for <c>*_contract_templates.json</c> catalogs.</summary> /// <summary>Absolute path to the directory that was enumerated for <c>*_contract_templates.json</c> catalogs.</summary>
public string ContractsDirectory { get; } public string ContractsDirectory { get; } = contractsDirectory;
public IReadOnlyDictionary<string, ContractTemplateRow> ById { get; } public IReadOnlyDictionary<string, ContractTemplateRow> ById { get; } =
new ReadOnlyDictionary<string, ContractTemplateRow>(new Dictionary<string, ContractTemplateRow>(byId, StringComparer.Ordinal));
public int DistinctTemplateCount => ById.Count; public int DistinctTemplateCount => ById.Count;
/// <summary>Number of <c>*_contract_templates.json</c> files under <see cref="ContractsDirectory"/>.</summary> /// <summary>Number of <c>*_contract_templates.json</c> files under <see cref="ContractsDirectory"/>.</summary>
public int CatalogJsonFileCount { get; } public int CatalogJsonFileCount { get; } = catalogJsonFileCount;
} }

View File

@ -233,7 +233,7 @@ public static class ContractTemplateCatalogLoader
return new QuestRewardBundleRow(itemGrants, skillXpGrants, reputationGrants); return new QuestRewardBundleRow(itemGrants, skillXpGrants, reputationGrants);
} }
private static IReadOnlyList<ReputationGrantRow> ParseReputationGrantRows(JsonArray? array) private static List<ReputationGrantRow> ParseReputationGrantRows(JsonArray? array)
{ {
if (array is null || array.Count == 0) if (array is null || array.Count == 0)
return []; return [];
@ -252,7 +252,7 @@ public static class ContractTemplateCatalogLoader
return rows; return rows;
} }
private static IReadOnlyList<RewardGrantRow> ParseItemGrantRows(JsonArray? array) private static List<RewardGrantRow> ParseItemGrantRows(JsonArray? array)
{ {
if (array is null || array.Count == 0) if (array is null || array.Count == 0)
return []; return [];
@ -271,7 +271,7 @@ public static class ContractTemplateCatalogLoader
return rows; return rows;
} }
private static IReadOnlyList<QuestSkillXpGrantRow> ParseSkillXpGrantRows(JsonArray? array) private static List<QuestSkillXpGrantRow> ParseSkillXpGrantRows(JsonArray? array)
{ {
if (array is null || array.Count == 0) if (array is null || array.Count == 0)
return []; return [];

View File

@ -237,18 +237,9 @@ public static class PrototypeE7M4ContractCatalogRules
private static NormalizedBundle NormalizeBundle(QuestRewardBundleRow bundle) => private static NormalizedBundle NormalizeBundle(QuestRewardBundleRow bundle) =>
new( new(
bundle.ItemGrants [.. bundle.ItemGrants.OrderBy(g => g.ItemId, StringComparer.Ordinal).ThenBy(g => g.Quantity)],
.OrderBy(g => g.ItemId, StringComparer.Ordinal) [.. bundle.SkillXpGrants.OrderBy(g => g.SkillId, StringComparer.Ordinal).ThenBy(g => g.Amount)],
.ThenBy(g => g.Quantity) [.. bundle.ReputationGrants.OrderBy(g => g.FactionId, StringComparer.Ordinal).ThenBy(g => g.Amount)]);
.ToArray(),
bundle.SkillXpGrants
.OrderBy(g => g.SkillId, StringComparer.Ordinal)
.ThenBy(g => g.Amount)
.ToArray(),
bundle.ReputationGrants
.OrderBy(g => g.FactionId, StringComparer.Ordinal)
.ThenBy(g => g.Amount)
.ToArray());
private static bool BundlesEqual(NormalizedBundle left, NormalizedBundle right) private static bool BundlesEqual(NormalizedBundle left, NormalizedBundle right)
{ {