diff --git a/.cursor/rules/csharp-style.md b/.cursor/rules/csharp-style.md index adf9152..10f179f 100644 --- a/.cursor/rules/csharp-style.md +++ b/.cursor/rules/csharp-style.md @@ -50,31 +50,57 @@ if (string.IsNullOrEmpty(key)) return false; ``` - **Indentation:** **4 spaces** per level; no tabs unless the file already uses tabs—never mix. +- **Trailing whitespace:** do not leave spaces or tabs at the end of a line, including blank lines between statements (RCS1037). - **`var`:** use when the type is obvious from the right-hand side; use explicit types when it improves readability or for literals where the type matters. - **File-scoped namespaces** (`namespace X;`) for new single-namespace files when the SDK/version allows. +- **Empty marker types** (collection fixtures, `[CollectionDefinition]`, marker interfaces): omit `{ }` and end with `;` when the type has no members (RCS1251). - **Pattern matching / nullability:** prefer modern C# features where they simplify code; honor **nullable reference type** annotations when the project enables them. -## Collection expressions (IDE0305) +## Collection expressions (IDE0300 / IDE0305) +- Prefer **`["a", "b"]`** over **`new[] { "a", "b" }`** for inline string (and other) array/list literals. - Prefer **collection spread** (`[.. source]`) over **`.ToArray()`** / **`.ToList()`** when materializing a sequence into a new array or list for return values, record `with` copies, or local snapshots. - Give an **explicit target type** when the compiler cannot infer one (CS9176), e.g. `string[] ids = [.. query.Select(static x => x.Id)];`. -- In **assertions**, avoid passing a bare spread directly to APIs with span overloads (e.g. `Assert.Equal`) — assign to a typed local first: +- In **assertions**, avoid passing a bare spread directly to APIs with span overloads (e.g. `Assert.Equal`) — assign to a typed local first, or use a **`private static readonly`** field when the same literal is reused (CA1861): ```csharp // Prefer return [.. query]; GrantedItems = [.. row.GrantedItems], +new SkillDefRow("salvage", "gather", "Salvage", ["activity", "mission_reward"]), // When type inference fails string[] expectedOrder = [.. registry.GetDefinitionsInIdOrder().Select(static d => d.Id)]; string[] actualOrder = [.. body.Quests.Select(static row => row.QuestId)]; Assert.Equal(expectedOrder, actualOrder); +// Reused expected literals in tests +private static readonly string[] ExpectedSkillIds = ["intrusion", "refine", "salvage"]; +Assert.Equal(ExpectedSkillIds, ids); + // Avoid (ambiguous Assert overloads; unnecessary allocation helper) Assert.Equal(expectedOrder, [.. body.Quests.Select(static row => row.QuestId)]); return query.ToArray(); +new[] { "activity", "mission_reward" } ``` +## Target-typed `new` (IDE0090) + +- When the return type or variable type is already explicit, prefer **`new()`** over repeating the type name in object initializers (common in test request helpers): + +```csharp +private static SkillProgressionGrantRequest Grant(...) => + new() + { + SchemaVersion = schemaVersion, + SkillId = skillId, + }; +``` + +## Async pass-through (CDT1003) + +- Do not mark a method **`async`** when it only **`await`**s and returns a single **`Task`** — return that task directly with an expression body or **`return`** statement. + ## `using` / `await using` (IDE0063) - When a **`using` or `await using` block contains exactly one statement**, prefer the declaration form without braces: `await using var conn = …;` then the single statement on following lines **only if** it is still logically one resource scope (typical for `NpgsqlConnection` + one command in integration-test reset helpers). @@ -83,15 +109,19 @@ return query.ToArray(); ## Local `const` (RCS1118) -- When a local is initialized from a **compile-time constant** (string literal, numeric literal, or `public const` field), declare it **`const`** instead of **`var`**. +- When a local is initialized from a **compile-time constant** (string literal, raw string literal, numeric literal, or `public const` field), declare it **`const`** instead of **`var`**. ```csharp const string questId = PrototypeE7M1QuestCatalogRules.GatherIntroQuestId; +const string fixtureJson = """ + { "schemaVersion": 1 } + """; ``` -## Inline declarations (IDE0018) +## Inline declarations (IDE0018 / IDE0059) - Prefer **inline initialization** over declare-then-assign when the analyzer suggests it, e.g. `var outcome = Operation(...)` and `TryGet(..., out var snapshot)` instead of separate upfront declarations. +- Do **not** pre-initialize locals with **`default`**, **`null`**, or **`false`** when the variable is assigned in the next block before its first read (IDE0059) — declare without an initializer instead. ```csharp // Prefer — single disposable, single follow-on statement @@ -119,8 +149,27 @@ var store = secondScope.ServiceProvider.GetRequiredService(); // ## Concrete return types (CA1859) -- When a private helper always returns a materialized array, prefer the **concrete array type** as the return type (e.g. `RewardItemGrantApplied[]`) instead of `IReadOnlyList` if callers only need the array and analyzers suggest it. +- When a private helper always returns a materialized array or list, prefer the **concrete type** as the return type (e.g. `List`, `T[]`, `Dictionary<,>`) instead of `IReadOnlyList` / `IReadOnlyDictionary<,>` when callers only need the materialized value and analyzers suggest it. +- Same rule applies to **`BuildDefinitionsInIdOrder`**, **`MapSlots`**, **`ReadBindings`**, and similar helpers that always construct a new collection. +## Logging guards (CA1873) + +- Before **`LogInformation`**, **`LogDebug`**, or other structured logs whose arguments allocate (interpolated strings, exceptions, collection counts), guard with **`logger.IsEnabled(LogLevel.…)`** (or **`logger?.IsEnabled(...) is true`** when the logger is nullable). + +```csharp +if (logger.IsEnabled(LogLevel.Information)) +{ + logger.LogInformation("Loaded catalog from {Path} with {Count} rows.", path, rows.Count); +} +``` + +## SQL parameter names (RCS1015) + +- When an ADO.NET / Npgsql parameter name matches a local variable, prefer **`nameof(variable)`** over a string literal: **`AddWithValue(nameof(xp), xp)`**. + +## Arithmetic clarity (RCS1123) + +- In mixed products inside calls (e.g. **`Math.Sqrt((dx * dx) + (dz * dz))`**), parenthesize each product so precedence is explicit. - Prefer **expression-bodied** members only when they stay one clear idea. - **LINQ:** favor readability over micro-chains; break complex queries across lines. @@ -133,7 +182,14 @@ var store = secondScope.ServiceProvider.GetRequiredService(); // ## Documentation - Use **`///` XML doc comments** on public APIs (types and members) when behavior or contracts are not obvious. -- **Primary-constructor records:** include a **``** on the type. Prefer **``** in the summary for positional parameters. Do **not** use **``** on **`record struct`** primary constructors — Roslynator reports false-positive **RCS1263** ([roslynator#1730](https://github.com/dotnet/roslynator/issues/1730)). **`record class`** / **`class`** primary constructors may use `` when the analyzer accepts them. +- **Primary-constructor records:** include a **``** on the type. Document positional parameters with **``** inside the summary — **never** **`/// `** on **`record struct`** or **`record class`** primary constructors (Roslynator **RCS1263** false positive; [roslynator#1730](https://github.com/dotnet/roslynator/issues/1730)). +- **Property / field docs:** every **`///`** block must include a **``** — do not ship **``**-only comments (RCS1139). Put extra detail in **``** after the summary when needed. + +```csharp +/// Deny reason when is false. +/// Stable snake_case values; see README. +public string? ReasonCode { get; init; } +``` ## Null checks (IDE0270) @@ -207,3 +263,4 @@ public async Task PostExample_ShouldReturnOk_WhenBodyValid() ## Tooling - Prefer fixes that satisfy built-in **.NET analyzers** / `dotnet format` (if adopted) rather than fighting IDE warnings without reason. +- Remove **unnecessary `using` directives** (IDE0005 / CS8019) — with **implicit usings** and **global usings**, many `Microsoft.Extensions.*`, `System.Threading`, and `System.Linq` imports are redundant. Run `dotnet format .csproj --diagnostics IDE0005 --severity info` before merge on touched projects. diff --git a/docs/reviews/2026-06-27-chore-cleanup.md b/docs/reviews/2026-06-27-chore-cleanup.md new file mode 100644 index 0000000..1e67b05 --- /dev/null +++ b/docs/reviews/2026-06-27-chore-cleanup.md @@ -0,0 +1,57 @@ +# Code review — chore/cleanup analyzer pass + +**Date:** 2026-06-27 +**Scope:** Branch `chore/cleanup` — commit `b233fa0` vs `2cf8bcd` (merge base on `main`) +**Base:** `2cf8bcd` (merge of PR #190) + +**Follow-up:** Suggestions and nits below are **done** (strikethrough + **Done.**). + +## Verdict + +**Approve with nits** + +## Summary + +This is a broad mechanical refactor across `NeonSprawl.Server` and `NeonSprawl.Server.Tests` (231 files, net −524 lines): collection expressions, primary-constructor catalog types, concrete private helper return types (CA1859), logging `IsEnabled` guards (CA1873), record XML doc fixes (RCS1263/RCS1139), `nameof` for SQL parameters, quest-store mutator delegate → `Func` + `MutateRowResult` record struct, removal of redundant `using` directives via new `GlobalUsings.cs`, and a substantial `csharp-style.md` appendix documenting the patterns. No HTTP routes, request bodies, or game contracts change. Build is clean (0 warnings). Full `dotnet test` passed **905/906** locally with one intermittent Postgres integration failure under parallel load; the same Postgres specs pass in isolation on this branch and on the parent commit. + +## Documentation checked + +| Path | Result | +|------|--------| +| `docs/plans/` (NEO-* / E7M4 stories) | **N/A** — unticketed `chore:` branch; no feature acceptance criteria | +| `.cursor/rules/csharp-style.md` | **Matches** — new sections document patterns applied in this diff (collection expressions, CA1859/CA1873, RCS1015, record XML docs, test GlobalUsings) | +| `docs/decomposition/modules/module_dependency_register.md` | **N/A** — no module behavior or authority changes | +| `docs/decomposition/modules/documentation_and_implementation_alignment.md` | **N/A** — no implementation-status update required | +| `bruno/neon-sprawl-server/collection.bru` | **Matches** — ~~Partially matches~~ docs block removed (**Done.**) | + +## Blocking issues + +None. + +## Suggestions + +1. ~~**Remove the Bruno `docs { }` block** in `bruno/neon-sprawl-server/collection.bru`. The note (“chore/cleanup analyzer pass: no HTTP route or request-body changes”) belongs in the PR/commit message, not in the Bruno collection metadata consumers may read as API documentation.~~ **Done.** Removed the `docs { }` block from `collection.bru`. + +2. ~~**Preserve explicit `StringComparer.Ordinal` in quest objective counter copies.** In `PostgresPlayerQuestStateStore.MutateObjectiveCounter`, the old code used `new Dictionary(row.ObjectiveCounters, StringComparer.Ordinal)`. The new `ToDictionary` call relies on default string equality (ordinal in practice). For consistency with the rest of the quests module and defense-in-depth, pass `StringComparer.Ordinal` to `ToDictionary` or keep the dictionary copy constructor.~~ **Done.** `ToDictionary(..., StringComparer.Ordinal)` in `PostgresPlayerQuestStateStore.cs`. + +3. ~~**Confirm Postgres integration stability under parallel xUnit.** Full-suite runs intermittently fail one of `FactionStandingPersistenceIntegrationTests`, `GigProgressionGrantPersistenceIntegrationTests`, or `SkillProgressionGrantPersistenceIntegrationTests` (expected persisted value vs `0`), while filtered runs pass on both `2cf8bcd` and `b233fa0`. This looks like pre-existing collection/fixture contention rather than a logic regression from this diff, but worth a quick check that `[Collection("Postgres integration")]` isolation is sufficient before merge if CI runs the full suite in parallel.~~ **Done.** Root cause for gig flake: `GigProgressionGrantPersistenceIntegrationTests` used wall-clock `Task.Delay` while cooldown uses `TimeProvider`; casts could return HTTP 200 with `on_cooldown` (`Accepted: false`) without defeat. Fixed by registering `FakeTimeProvider` on `PostgresWebApplicationFactory` and advancing the fake clock in the gig persistence test (same pattern as `InMemoryWebApplicationFactory`). Full suite **906/906** after fix. + +## Nits + +- ~~Nit: `GlobalUsings.cs` pulls in domain namespaces (`NeonSprawl.Server.Game.Npc`, `NeonSprawl.Server.Tests.Game.Npc`, etc.). Works today (0 build warnings), but a one-line file comment listing intentional globals would help future contributors avoid accidental name clashes.~~ **Done.** File header comment added. +- ~~Nit: `QuestProgressIds.cs` has a whitespace-only trailing blank line before the closing brace — harmless; could drop in a follow-up.~~ **Done.** +- Nit: `QuestStateOperations.DenyAccept` no longer threads `playerId` / `questId`; telemetry comment correctly says “capture at call site when wiring E9.M1.” Fine for now — just remember at E9.M1. +- Nit: `NpcRuntimeOperations.AdvanceAll` drops the post–idle→aggro `TryGet` refresh; the while-loop `TryGet` on the first iteration makes this equivalent. No action needed. +- Nit: `PostgresPositionStateStore` drops unused `IOptions` / startup validation — correct dead-code removal; DI registration unchanged. + +## Verification + +```bash +cd server/NeonSprawl.Server && dotnet build +cd server/NeonSprawl.Server.Tests && dotnet test +cd server/NeonSprawl.Server.Tests && dotnet test --filter "FullyQualifiedName~PersistenceIntegrationTests" +``` + +Expect **906** passed; if a single Postgres persistence test fails under full parallel run, re-run filtered as above to distinguish flake from regression. + +Manual Godot QA: none (no client or player-visible surface changes). diff --git a/server/NeonSprawl.Server.Tests/Game/AbilityInput/AbilityCastApiTests.cs b/server/NeonSprawl.Server.Tests/Game/AbilityInput/AbilityCastApiTests.cs index 5cfb71a..205d291 100644 --- a/server/NeonSprawl.Server.Tests/Game/AbilityInput/AbilityCastApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/AbilityInput/AbilityCastApiTests.cs @@ -1,17 +1,10 @@ -using System.Net; -using System.Net.Http.Json; -using System.Text; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Combat; using NeonSprawl.Server.Game.Encounters; using NeonSprawl.Server.Game.Gigs; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.Targeting; -using Xunit; namespace NeonSprawl.Server.Tests.Game.AbilityInput; @@ -36,8 +29,8 @@ public sealed class AbilityCastApiTests post.EnsureSuccessStatusCode(); } - private static async Task LockPrototypeTargetAlphaAsync(HttpClient client) => - await LockPrototypeTargetAsync(client, PrototypeNpcRegistry.PrototypeNpcMeleeId); + private static Task LockPrototypeTargetAlphaAsync(HttpClient client) => + LockPrototypeTargetAsync(client, PrototypeNpcRegistry.PrototypeNpcMeleeId); private static async Task LockPrototypeTargetAsync(HttpClient client, string targetId) { diff --git a/server/NeonSprawl.Server.Tests/Game/AbilityInput/CooldownSnapshotApiTests.cs b/server/NeonSprawl.Server.Tests/Game/AbilityInput/CooldownSnapshotApiTests.cs index 049d4ad..972f7b0 100644 --- a/server/NeonSprawl.Server.Tests/Game/AbilityInput/CooldownSnapshotApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/AbilityInput/CooldownSnapshotApiTests.cs @@ -1,10 +1,5 @@ -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.AbilityInput; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.Targeting; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.AbilityInput; diff --git a/server/NeonSprawl.Server.Tests/Game/AbilityInput/HotbarLoadoutApiTests.cs b/server/NeonSprawl.Server.Tests/Game/AbilityInput/HotbarLoadoutApiTests.cs index 93f8ad5..d560332 100644 --- a/server/NeonSprawl.Server.Tests/Game/AbilityInput/HotbarLoadoutApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/AbilityInput/HotbarLoadoutApiTests.cs @@ -1,8 +1,4 @@ -using System.Net; -using System.Net.Http.Json; -using System.Text; using NeonSprawl.Server.Game.AbilityInput; -using Xunit; namespace NeonSprawl.Server.Tests.Game.AbilityInput; diff --git a/server/NeonSprawl.Server.Tests/Game/AbilityInput/HotbarLoadoutPersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/AbilityInput/HotbarLoadoutPersistenceIntegrationTests.cs index 3d838bc..e7244b7 100644 --- a/server/NeonSprawl.Server.Tests/Game/AbilityInput/HotbarLoadoutPersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/AbilityInput/HotbarLoadoutPersistenceIntegrationTests.cs @@ -1,9 +1,5 @@ -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.AbilityInput; diff --git a/server/NeonSprawl.Server.Tests/Game/AbilityInput/InMemoryPlayerAbilityCooldownStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/AbilityInput/InMemoryPlayerAbilityCooldownStoreTests.cs index 800eb93..24f2875 100644 --- a/server/NeonSprawl.Server.Tests/Game/AbilityInput/InMemoryPlayerAbilityCooldownStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/AbilityInput/InMemoryPlayerAbilityCooldownStoreTests.cs @@ -1,5 +1,4 @@ using NeonSprawl.Server.Game.AbilityInput; -using Xunit; namespace NeonSprawl.Server.Tests.Game.AbilityInput; diff --git a/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionCatalogLoaderTests.cs index 9dd7567..25c975e 100644 --- a/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionCatalogLoaderTests.cs @@ -1,12 +1,6 @@ -using System.Net; -using System.Text; using System.Text.Json.Nodes; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; diff --git a/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionRegistryTests.cs index dcb6123..366245b 100644 --- a/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionRegistryTests.cs @@ -1,10 +1,5 @@ -using System.IO; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; diff --git a/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionsWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionsWorldApiTests.cs index 3662ba2..990b04c 100644 --- a/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionsWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Combat/AbilityDefinitionsWorldApiTests.cs @@ -1,8 +1,4 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.Combat; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; diff --git a/server/NeonSprawl.Server.Tests/Game/Combat/CombatEntityHealthStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Combat/CombatEntityHealthStoreTests.cs index 4af5c53..4025f98 100644 --- a/server/NeonSprawl.Server.Tests/Game/Combat/CombatEntityHealthStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Combat/CombatEntityHealthStoreTests.cs @@ -1,9 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Game.Npc; -using NeonSprawl.Server.Tests; -using NeonSprawl.Server.Tests.Game.Npc; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; diff --git a/server/NeonSprawl.Server.Tests/Game/Combat/CombatOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Combat/CombatOperationsTests.cs index 081318c..a816d0e 100644 --- a/server/NeonSprawl.Server.Tests/Game/Combat/CombatOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Combat/CombatOperationsTests.cs @@ -1,10 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Game.Npc; -using NeonSprawl.Server.Tests; -using NeonSprawl.Server.Tests.Game.Npc; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; diff --git a/server/NeonSprawl.Server.Tests/Game/Combat/CombatTargetFixtureApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Combat/CombatTargetFixtureApiTests.cs index b80863a..0e1a1e4 100644 --- a/server/NeonSprawl.Server.Tests/Game/Combat/CombatTargetFixtureApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Combat/CombatTargetFixtureApiTests.cs @@ -1,13 +1,7 @@ -using System.Net; -using System.Net.Http.Json; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Combat; using NeonSprawl.Server.Game.Encounters; -using NeonSprawl.Server.Game.Npc; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; diff --git a/server/NeonSprawl.Server.Tests/Game/Combat/CombatTargetsWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Combat/CombatTargetsWorldApiTests.cs index a83a932..65b73f4 100644 --- a/server/NeonSprawl.Server.Tests/Game/Combat/CombatTargetsWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Combat/CombatTargetsWorldApiTests.cs @@ -1,13 +1,6 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.Targeting; -using NeonSprawl.Server.Tests; -using NeonSprawl.Server.Tests.Game.Npc; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; diff --git a/server/NeonSprawl.Server.Tests/Game/Combat/NpcAttackOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Combat/NpcAttackOperationsTests.cs index a6c934f..c3ff902 100644 --- a/server/NeonSprawl.Server.Tests/Game/Combat/NpcAttackOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Combat/NpcAttackOperationsTests.cs @@ -1,10 +1,6 @@ -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Tests.Game.Npc; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; diff --git a/server/NeonSprawl.Server.Tests/Game/Combat/PlayerCombatHealthApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Combat/PlayerCombatHealthApiTests.cs index c38c06b..23991a1 100644 --- a/server/NeonSprawl.Server.Tests/Game/Combat/PlayerCombatHealthApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Combat/PlayerCombatHealthApiTests.cs @@ -1,13 +1,7 @@ -using System.Net; -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Targeting; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; diff --git a/server/NeonSprawl.Server.Tests/Game/Combat/PlayerCombatHealthStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Combat/PlayerCombatHealthStoreTests.cs index 023785c..5a6399a 100644 --- a/server/NeonSprawl.Server.Tests/Game/Combat/PlayerCombatHealthStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Combat/PlayerCombatHealthStoreTests.cs @@ -1,7 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Combat; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractCompletionOperationsIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractCompletionOperationsIntegrationTests.cs index 4f729ff..77bc2ba 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractCompletionOperationsIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractCompletionOperationsIntegrationTests.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Encounters; using NeonSprawl.Server.Game.Factions; @@ -6,9 +5,6 @@ using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractCompletionOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractCompletionOperationsTests.cs index 17048e4..5f77030 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractCompletionOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractCompletionOperationsTests.cs @@ -1,12 +1,8 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorOperationsIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorOperationsIntegrationTests.cs index 7d20519..6e9580c 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorOperationsIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorOperationsIntegrationTests.cs @@ -1,8 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Factions; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorOperationsTests.cs index 32e53d3..f10f791 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorOperationsTests.cs @@ -1,11 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Quests; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorPersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorPersistenceIntegrationTests.cs index cdc7a2c..5278cc6 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorPersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractGeneratorPersistenceIntegrationTests.cs @@ -1,11 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractInstancePersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractInstancePersistenceIntegrationTests.cs index f828ba4..008f1a0 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractInstancePersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractInstancePersistenceIntegrationTests.cs @@ -1,10 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractOutcomePersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractOutcomePersistenceIntegrationTests.cs index d4f14f5..735fd37 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractOutcomePersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractOutcomePersistenceIntegrationTests.cs @@ -1,11 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Rewards; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractTemplateCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractTemplateCatalogLoaderTests.cs index 7eef3cd..9f91d29 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractTemplateCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractTemplateCatalogLoaderTests.cs @@ -1,13 +1,8 @@ using System.Collections.Frozen; -using System.Text; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Encounters; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Quests; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractTemplateRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractTemplateRegistryTests.cs index 89fc36c..b7d8d3e 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/ContractTemplateRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/ContractTemplateRegistryTests.cs @@ -1,14 +1,4 @@ -using System.Collections.Frozen; -using System.Text; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Contracts; -using NeonSprawl.Server.Game.Encounters; -using NeonSprawl.Server.Game.Factions; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using NeonSprawl.Server.Tests.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/InMemoryContractInstanceStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/InMemoryContractInstanceStoreTests.cs index e8215bf..cf6d087 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/InMemoryContractInstanceStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/InMemoryContractInstanceStoreTests.cs @@ -1,9 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Contracts/InMemoryContractOutcomeStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Contracts/InMemoryContractOutcomeStoreTests.cs index 2aa283d..a891d28 100644 --- a/server/NeonSprawl.Server.Tests/Game/Contracts/InMemoryContractOutcomeStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Contracts/InMemoryContractOutcomeStoreTests.cs @@ -1,8 +1,6 @@ -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Rewards; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Contracts; diff --git a/server/NeonSprawl.Server.Tests/Game/Crafting/CraftOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Crafting/CraftOperationsTests.cs index cee7760..782b2ff 100644 --- a/server/NeonSprawl.Server.Tests/Game/Crafting/CraftOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Crafting/CraftOperationsTests.cs @@ -1,13 +1,9 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Crafting; diff --git a/server/NeonSprawl.Server.Tests/Game/Crafting/PlayerCraftApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Crafting/PlayerCraftApiTests.cs index 3488291..bd5b1e3 100644 --- a/server/NeonSprawl.Server.Tests/Game/Crafting/PlayerCraftApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Crafting/PlayerCraftApiTests.cs @@ -1,12 +1,6 @@ -using System.Net; -using System.Net.Http.Json; using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Items; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Crafting; diff --git a/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionCatalogLoaderTests.cs index 04ee8c9..6a75d4e 100644 --- a/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionCatalogLoaderTests.cs @@ -1,14 +1,8 @@ using System.Collections.Frozen; -using System.Net; -using System.Text; using System.Text.Json.Nodes; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Items; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Crafting; diff --git a/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionRegistryTests.cs index 4a20715..655d709 100644 --- a/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionRegistryTests.cs @@ -1,11 +1,6 @@ using System.Collections.Frozen; -using System.IO; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Items; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Crafting; diff --git a/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionsWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionsWorldApiTests.cs index 6ecb771..f677078 100644 --- a/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionsWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionsWorldApiTests.cs @@ -1,8 +1,4 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.Crafting; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Crafting; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterCombatWiringTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterCombatWiringTests.cs index 1508193..f3d2b09 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterCombatWiringTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterCombatWiringTests.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Encounters; @@ -6,9 +5,6 @@ using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterCompletionOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterCompletionOperationsTests.cs index 9682d2e..4a585ec 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterCompletionOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterCompletionOperationsTests.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Encounters; @@ -6,9 +5,6 @@ using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionCatalogLoaderTests.cs index e286a5a..8fe65fc 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionCatalogLoaderTests.cs @@ -1,11 +1,5 @@ -using System.Net; -using System.Text; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Encounters; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionRegistryTests.cs index 32a9add..d5369a2 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionRegistryTests.cs @@ -1,7 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Encounters; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionsWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionsWorldApiTests.cs index 39e475b..f1c9a61 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionsWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterDefinitionsWorldApiTests.cs @@ -1,7 +1,4 @@ -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.Encounters; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterProgressApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterProgressApiTests.cs index c13ab43..f136de9 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterProgressApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterProgressApiTests.cs @@ -1,13 +1,7 @@ -using System.Net; -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Encounters; -using NeonSprawl.Server.Game.Items; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Targeting; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterProgressOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterProgressOperationsTests.cs index 6a99eaf..326d1d8 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterProgressOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/EncounterProgressOperationsTests.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Encounters; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterCompleteEventStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterCompleteEventStoreTests.cs index 8db7ede..143f3e7 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterCompleteEventStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterCompleteEventStoreTests.cs @@ -1,5 +1,4 @@ using NeonSprawl.Server.Game.Encounters; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterCompletionStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterCompletionStoreTests.cs index 875643c..d392c7b 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterCompletionStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterCompletionStoreTests.cs @@ -1,5 +1,4 @@ using NeonSprawl.Server.Game.Encounters; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterProgressStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterProgressStoreTests.cs index 9a6e52a..2461f85 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterProgressStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/InMemoryEncounterProgressStoreTests.cs @@ -1,5 +1,4 @@ using NeonSprawl.Server.Game.Encounters; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/RewardTableDefinitionCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/RewardTableDefinitionCatalogLoaderTests.cs index a996e08..164ab47 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/RewardTableDefinitionCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/RewardTableDefinitionCatalogLoaderTests.cs @@ -1,8 +1,4 @@ -using System.Text; -using System.Text.Json.Nodes; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Encounters; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Encounters/RewardTableDefinitionRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Encounters/RewardTableDefinitionRegistryTests.cs index 5dacc8a..ddd8b49 100644 --- a/server/NeonSprawl.Server.Tests/Game/Encounters/RewardTableDefinitionRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Encounters/RewardTableDefinitionRegistryTests.cs @@ -1,7 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Encounters; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Encounters; diff --git a/server/NeonSprawl.Server.Tests/Game/Factions/FactionDefinitionCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Factions/FactionDefinitionCatalogLoaderTests.cs index edc24d7..c7e1cb5 100644 --- a/server/NeonSprawl.Server.Tests/Game/Factions/FactionDefinitionCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Factions/FactionDefinitionCatalogLoaderTests.cs @@ -1,7 +1,4 @@ -using System.Text; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Factions; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Factions; @@ -90,7 +87,7 @@ public class FactionDefinitionCatalogLoaderTests { // Arrange var (_, factionsDir, schemaPath) = CreateTempContentLayout(); - var singleFaction = """ + const string singleFaction = """ { "schemaVersion": 1, "factions": [ @@ -118,7 +115,7 @@ public class FactionDefinitionCatalogLoaderTests { // Arrange var (_, factionsDir, schemaPath) = CreateTempContentLayout(); - var oneFaction = """ + const string oneFaction = """ { "schemaVersion": 1, "factions": [ diff --git a/server/NeonSprawl.Server.Tests/Game/Factions/FactionDefinitionRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Factions/FactionDefinitionRegistryTests.cs index 91b1a55..626d23d 100644 --- a/server/NeonSprawl.Server.Tests/Game/Factions/FactionDefinitionRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Factions/FactionDefinitionRegistryTests.cs @@ -1,9 +1,4 @@ -using System.Text; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Factions; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Factions; diff --git a/server/NeonSprawl.Server.Tests/Game/Factions/FactionGateOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Factions/FactionGateOperationsTests.cs index 2d235df..5600ca6 100644 --- a/server/NeonSprawl.Server.Tests/Game/Factions/FactionGateOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Factions/FactionGateOperationsTests.cs @@ -1,9 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Quests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Factions; diff --git a/server/NeonSprawl.Server.Tests/Game/Factions/FactionStandingApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Factions/FactionStandingApiTests.cs index bffc18b..22ac839 100644 --- a/server/NeonSprawl.Server.Tests/Game/Factions/FactionStandingApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Factions/FactionStandingApiTests.cs @@ -1,14 +1,8 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Factions; diff --git a/server/NeonSprawl.Server.Tests/Game/Factions/FactionStandingPersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Factions/FactionStandingPersistenceIntegrationTests.cs index 2b69e04..f50dea4 100644 --- a/server/NeonSprawl.Server.Tests/Game/Factions/FactionStandingPersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Factions/FactionStandingPersistenceIntegrationTests.cs @@ -1,10 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Factions; diff --git a/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryFactionStandingStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryFactionStandingStoreTests.cs index f418cb6..9f86bc7 100644 --- a/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryFactionStandingStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryFactionStandingStoreTests.cs @@ -1,8 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.PositionState; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Factions; diff --git a/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryReputationDeltaStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryReputationDeltaStoreTests.cs index ab1506d..2b938b9 100644 --- a/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryReputationDeltaStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Factions/InMemoryReputationDeltaStoreTests.cs @@ -1,5 +1,4 @@ using NeonSprawl.Server.Game.Factions; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Factions; diff --git a/server/NeonSprawl.Server.Tests/Game/Factions/ReputationDeltaPersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Factions/ReputationDeltaPersistenceIntegrationTests.cs index f69a434..20e05df 100644 --- a/server/NeonSprawl.Server.Tests/Game/Factions/ReputationDeltaPersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Factions/ReputationDeltaPersistenceIntegrationTests.cs @@ -1,10 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Factions; diff --git a/server/NeonSprawl.Server.Tests/Game/Factions/ReputationOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Factions/ReputationOperationsTests.cs index 68f9861..830a9c1 100644 --- a/server/NeonSprawl.Server.Tests/Game/Factions/ReputationOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Factions/ReputationOperationsTests.cs @@ -1,9 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Factions; diff --git a/server/NeonSprawl.Server.Tests/Game/Gathering/GatherOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Gathering/GatherOperationsTests.cs index f22a44a..f22b4e2 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gathering/GatherOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gathering/GatherOperationsTests.cs @@ -1,13 +1,9 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Gathering; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gathering; diff --git a/server/NeonSprawl.Server.Tests/Game/Gathering/InMemoryResourceNodeInstanceStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Gathering/InMemoryResourceNodeInstanceStoreTests.cs index 08d1f2f..090987f 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gathering/InMemoryResourceNodeInstanceStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gathering/InMemoryResourceNodeInstanceStoreTests.cs @@ -1,5 +1,4 @@ using NeonSprawl.Server.Game.Gathering; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gathering; diff --git a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeCatalogLoaderTests.cs index 2cd9af5..a653045 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeCatalogLoaderTests.cs @@ -1,12 +1,6 @@ -using System.Text; using System.Text.Json.Nodes; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Gathering; -using NeonSprawl.Server.Game.Items; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gathering; diff --git a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeDefinitionRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeDefinitionRegistryTests.cs index b334627..ca323ee 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeDefinitionRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeDefinitionRegistryTests.cs @@ -1,9 +1,4 @@ -using System.IO; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Gathering; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gathering; diff --git a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeDefinitionsWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeDefinitionsWorldApiTests.cs index 49b9671..ec23f60 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeDefinitionsWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeDefinitionsWorldApiTests.cs @@ -1,8 +1,4 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.Gathering; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gathering; diff --git a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeFixtureApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeFixtureApiTests.cs index 7456a11..2bf15a3 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeFixtureApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeFixtureApiTests.cs @@ -1,10 +1,5 @@ -using System.Net; -using System.Net.Http.Json; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Gathering; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gathering; diff --git a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeInstanceOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeInstanceOperationsTests.cs index d8f741e..eb56d2a 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeInstanceOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeInstanceOperationsTests.cs @@ -1,7 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Gathering; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gathering; diff --git a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeInstancePersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeInstancePersistenceIntegrationTests.cs index 06fbac7..c65bbb4 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeInstancePersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gathering/ResourceNodeInstancePersistenceIntegrationTests.cs @@ -1,8 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Gathering; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gathering; diff --git a/server/NeonSprawl.Server.Tests/Game/Gigs/CombatDefeatGigXpGrantTests.cs b/server/NeonSprawl.Server.Tests/Game/Gigs/CombatDefeatGigXpGrantTests.cs index 3b4ea58..9fdf589 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gigs/CombatDefeatGigXpGrantTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gigs/CombatDefeatGigXpGrantTests.cs @@ -1,7 +1,5 @@ using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Gigs; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gigs; diff --git a/server/NeonSprawl.Server.Tests/Game/Gigs/GigProgressionGrantPersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Gigs/GigProgressionGrantPersistenceIntegrationTests.cs index 8b89444..1651673 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gigs/GigProgressionGrantPersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gigs/GigProgressionGrantPersistenceIntegrationTests.cs @@ -1,15 +1,8 @@ -using System.Linq; -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Gigs; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Targeting; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gigs; @@ -31,7 +24,10 @@ public sealed class GigProgressionGrantPersistenceIntegrationTests(PostgresInteg TargetId = PrototypeNpcRegistry.PrototypeNpcMeleeId, }; - // Act — defeat alpha through first host (four pulses) + // Act — defeat alpha through first host (pulse loop; fake clock avoids wall-clock cooldown flakes) + Assert.NotNull(Factory.FakeClock); + var clock = Factory.FakeClock; + clock.Advance(TimeSpan.FromSeconds(3) + TimeSpan.FromMilliseconds(50)); using (var firstClient = Factory.CreateClient()) { await firstClient.PostAsJsonAsync( @@ -48,15 +44,26 @@ public sealed class GigProgressionGrantPersistenceIntegrationTests(PostgresInteg SchemaVersion = TargetSelectRequest.CurrentSchemaVersion, TargetId = PrototypeNpcRegistry.PrototypeNpcMeleeId, }); - for (var i = 0; i < 4; i++) + AbilityCastResponse? defeatBody = null; + for (var i = 0; i < 12; i++) { var response = await firstClient.PostAsJsonAsync("/game/players/dev-local-1/ability-cast", cast); response.EnsureSuccessStatusCode(); - if (i < 3) + var body = await response.Content.ReadFromJsonAsync(); + Assert.NotNull(body); + Assert.True(body!.Accepted, body.ReasonCode); + Assert.NotNull(body.CombatResolution); + if (body.CombatResolution!.TargetDefeated) { - await Task.Delay(TimeSpan.FromSeconds(3.2)); + defeatBody = body; + break; } + + clock.Advance(TimeSpan.FromSeconds(3) + TimeSpan.FromMilliseconds(50)); } + + Assert.NotNull(defeatBody); + Assert.True(defeatBody!.CombatResolution!.TargetDefeated); } await using var secondFactory = new PostgresWebApplicationFactory(); diff --git a/server/NeonSprawl.Server.Tests/Game/Gigs/GigProgressionSnapshotApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Gigs/GigProgressionSnapshotApiTests.cs index ed11013..93d60db 100644 --- a/server/NeonSprawl.Server.Tests/Game/Gigs/GigProgressionSnapshotApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Gigs/GigProgressionSnapshotApiTests.cs @@ -1,8 +1,4 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.Gigs; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Gigs; diff --git a/server/NeonSprawl.Server.Tests/Game/Interaction/HorizontalReachTests.cs b/server/NeonSprawl.Server.Tests/Game/Interaction/HorizontalReachTests.cs index f7876b3..847dadb 100644 --- a/server/NeonSprawl.Server.Tests/Game/Interaction/HorizontalReachTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Interaction/HorizontalReachTests.cs @@ -1,5 +1,4 @@ using NeonSprawl.Server.Game.World; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Interaction; @@ -62,10 +61,10 @@ public class HorizontalReachTests public void IsWithinHorizontalRadius_NegativeRadius_ThrowsArgumentOutOfRange() { // Arrange - Action act = () => HorizontalReach.IsWithinHorizontalRadius(0, 0, 0, 0, -1.0); // Act - var ex = Assert.Throws(act); + var ex = Assert.Throws( + () => HorizontalReach.IsWithinHorizontalRadius(0, 0, 0, 0, -1.0)); // Assert Assert.NotNull(ex); diff --git a/server/NeonSprawl.Server.Tests/Game/Interaction/InteractablesWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Interaction/InteractablesWorldApiTests.cs index 6d5e320..9af99f1 100644 --- a/server/NeonSprawl.Server.Tests/Game/Interaction/InteractablesWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Interaction/InteractablesWorldApiTests.cs @@ -1,8 +1,4 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.Interaction; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Interaction; @@ -28,7 +24,8 @@ public class InteractablesWorldApiTests Assert.Equal(5, body.Interactables.Count); var ids = body.Interactables.Select(static x => x.InteractableId).ToList(); - Assert.Equal(ids.OrderBy(static x => x, StringComparer.Ordinal).ToList(), ids); + string[] expectedOrder = [.. ids.OrderBy(static x => x, StringComparer.Ordinal)]; + Assert.Equal(expectedOrder, ids); var alpha = body.Interactables.Single(x => x.InteractableId == PrototypeInteractableRegistry.PrototypeResourceNodeAlphaId); Assert.Equal("resource_node", alpha.Kind); diff --git a/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionApiTests.cs index 4b09426..a14bbb5 100644 --- a/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionApiTests.cs @@ -1,9 +1,5 @@ -using System.Net; -using System.Net.Http.Json; -using System.Text; using NeonSprawl.Server.Game.Interaction; using NeonSprawl.Server.Game.PositionState; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Interaction; diff --git a/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionResourceNodeGatherIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionResourceNodeGatherIntegrationTests.cs index fff00ec..06862a2 100644 --- a/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionResourceNodeGatherIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionResourceNodeGatherIntegrationTests.cs @@ -1,13 +1,7 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.Gathering; using NeonSprawl.Server.Game.Interaction; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Game.World; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Interaction; diff --git a/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionResourceNodeGatherXpTests.cs b/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionResourceNodeGatherXpTests.cs index ee0daad..060c782 100644 --- a/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionResourceNodeGatherXpTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Interaction/InteractionResourceNodeGatherXpTests.cs @@ -1,11 +1,5 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.Interaction; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Game.World; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Interaction; diff --git a/server/NeonSprawl.Server.Tests/Game/Interaction/SalvageActivityDeniedRegistryWebApplicationFactory.cs b/server/NeonSprawl.Server.Tests/Game/Interaction/SalvageActivityDeniedRegistryWebApplicationFactory.cs index bd36417..0661988 100644 --- a/server/NeonSprawl.Server.Tests/Game/Interaction/SalvageActivityDeniedRegistryWebApplicationFactory.cs +++ b/server/NeonSprawl.Server.Tests/Game/Interaction/SalvageActivityDeniedRegistryWebApplicationFactory.cs @@ -2,7 +2,6 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Time.Testing; using NeonSprawl.Server.Game.AbilityInput; @@ -12,11 +11,8 @@ using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Gathering; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Quests; -using NeonSprawl.Server.Game.Skills; -using Npgsql; namespace NeonSprawl.Server.Tests.Game.Interaction; @@ -110,19 +106,19 @@ internal sealed class SalvageActivityDeniedSkillRegistry : ISkillDefinitionRegis "salvage", "gather", "Salvage", - new[] { "mission_reward" }); + ["mission_reward"]); private static readonly SkillDefRow Refine = new( "refine", "process", "Refine", - new[] { "activity", "mission_reward", "trainer" }); + ["activity", "mission_reward", "trainer"]); private static readonly SkillDefRow Intrusion = new( "intrusion", "tech", "Intrusion", - new[] { "activity", "mission_reward", "book_or_item" }); + ["activity", "mission_reward", "book_or_item"]); private static readonly IReadOnlyList Ordered = [ diff --git a/server/NeonSprawl.Server.Tests/Game/Items/InMemoryPlayerInventoryStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Items/InMemoryPlayerInventoryStoreTests.cs index b2b62f2..930e200 100644 --- a/server/NeonSprawl.Server.Tests/Game/Items/InMemoryPlayerInventoryStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Items/InMemoryPlayerInventoryStoreTests.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Items; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Items; diff --git a/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionCatalogLoaderTests.cs index a2ac9a8..83ed8a3 100644 --- a/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionCatalogLoaderTests.cs @@ -1,12 +1,6 @@ -using System.Net; -using System.Text; using System.Text.Json.Nodes; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Items; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Items; diff --git a/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionRegistryTests.cs index bd1d70a..8e2c5ad 100644 --- a/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionRegistryTests.cs @@ -1,9 +1,4 @@ -using System.IO; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Items; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Items; diff --git a/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionsWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionsWorldApiTests.cs index 9f6946c..81addc0 100644 --- a/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionsWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Items/ItemDefinitionsWorldApiTests.cs @@ -1,8 +1,4 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.Items; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Items; diff --git a/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryApiTests.cs index 814eb60..cbf5d9a 100644 --- a/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryApiTests.cs @@ -1,8 +1,4 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.Items; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Items; diff --git a/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryOperationsTests.cs index fa4be35..9c7d0fa 100644 --- a/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryOperationsTests.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Items; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Items; diff --git a/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryPersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryPersistenceIntegrationTests.cs index 17ec26b..5faa502 100644 --- a/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryPersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Items/PlayerInventoryPersistenceIntegrationTests.cs @@ -1,10 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Items; diff --git a/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryCatalogLoaderTests.cs index ca09f69..fa5fec4 100644 --- a/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryCatalogLoaderTests.cs @@ -1,11 +1,6 @@ using System.Collections.Frozen; -using System.Net; -using System.Text; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Mastery; -using NeonSprawl.Server.Tests.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Mastery; diff --git a/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryCatalogRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryCatalogRegistryTests.cs index 33330ce..8c7ea12 100644 --- a/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryCatalogRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryCatalogRegistryTests.cs @@ -1,8 +1,4 @@ -using System.Net; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Mastery; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Mastery; diff --git a/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryFixtureApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryFixtureApiTests.cs index 959254a..32ba2cb 100644 --- a/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryFixtureApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Mastery/MasteryFixtureApiTests.cs @@ -1,12 +1,5 @@ -using System.Net; -using System.Net.Http; -using System.Net.Http.Json; -using System.Text; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.Testing; using NeonSprawl.Server.Game.Mastery; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Mastery; @@ -18,7 +11,7 @@ public sealed class MasteryFixtureApiTests private static MasteryFixtureRequest ValidFixture( bool resetPerkState = true, Dictionary? skillXp = null) => - new MasteryFixtureRequest + new() { SchemaVersion = MasteryFixtureRequest.CurrentSchemaVersion, ResetPerkState = resetPerkState, diff --git a/server/NeonSprawl.Server.Tests/Game/Mastery/PerkStateApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Mastery/PerkStateApiTests.cs index 67aeb35..7ded60f 100644 --- a/server/NeonSprawl.Server.Tests/Game/Mastery/PerkStateApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Mastery/PerkStateApiTests.cs @@ -1,12 +1,4 @@ -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Json; -using System.Text.Json; -using System.Text; using NeonSprawl.Server.Game.Mastery; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Mastery; @@ -19,7 +11,7 @@ public sealed class PerkStateApiTests int tierIndex, string branchId, int schemaVersion = PerkBranchSelectRequest.CurrentSchemaVersion) => - new PerkBranchSelectRequest + new() { SchemaVersion = schemaVersion, SkillId = skillId, @@ -28,7 +20,7 @@ public sealed class PerkStateApiTests }; private static SkillProgressionGrantRequest SalvageGrant(int amount) => - new SkillProgressionGrantRequest + new() { SchemaVersion = SkillProgressionGrantRequest.CurrentSchemaVersion, SkillId = "salvage", diff --git a/server/NeonSprawl.Server.Tests/Game/Mastery/PerkStatePersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Mastery/PerkStatePersistenceIntegrationTests.cs index d06a1dd..31aae09 100644 --- a/server/NeonSprawl.Server.Tests/Game/Mastery/PerkStatePersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Mastery/PerkStatePersistenceIntegrationTests.cs @@ -1,11 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Mastery; diff --git a/server/NeonSprawl.Server.Tests/Game/Mastery/PerkUnlockEngineTests.cs b/server/NeonSprawl.Server.Tests/Game/Mastery/PerkUnlockEngineTests.cs index ba343c1..a865e82 100644 --- a/server/NeonSprawl.Server.Tests/Game/Mastery/PerkUnlockEngineTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Mastery/PerkUnlockEngineTests.cs @@ -1,11 +1,6 @@ -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Interaction; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Game.World; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Mastery; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/AggroOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Npc/AggroOperationsTests.cs index bdd64e6..78adb82 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/AggroOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/AggroOperationsTests.cs @@ -1,7 +1,4 @@ -using Microsoft.Extensions.Options; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/AggroThreatIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Npc/AggroThreatIntegrationTests.cs index fb33a1c..13116f0 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/AggroThreatIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/AggroThreatIntegrationTests.cs @@ -1,11 +1,6 @@ -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.AbilityInput; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Targeting; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/InMemoryNpcRuntimeStateStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Npc/InMemoryNpcRuntimeStateStoreTests.cs index c4984a4..fff03d7 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/InMemoryNpcRuntimeStateStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/InMemoryNpcRuntimeStateStoreTests.cs @@ -1,5 +1,3 @@ -using NeonSprawl.Server.Game.Npc; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/InMemoryThreatStateStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Npc/InMemoryThreatStateStoreTests.cs index 70b5492..108d931 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/InMemoryThreatStateStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/InMemoryThreatStateStoreTests.cs @@ -1,7 +1,3 @@ -using Microsoft.Extensions.Options; -using NeonSprawl.Server.Game.Npc; -using NeonSprawl.Server.Game.PositionState; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorCatalogTestPaths.cs b/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorCatalogTestPaths.cs index 0b41c6b..b6589ef 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorCatalogTestPaths.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorCatalogTestPaths.cs @@ -1,4 +1,3 @@ -using NeonSprawl.Server.Game.Npc; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionCatalogLoaderTests.cs index 5790a6e..0116126 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionCatalogLoaderTests.cs @@ -1,12 +1,5 @@ -using System.Net; -using System.Text; using System.Text.Json.Nodes; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; -using NeonSprawl.Server.Game.Npc; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionRegistryTests.cs index e0c50ac..fd283d2 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionRegistryTests.cs @@ -1,10 +1,4 @@ -using System.IO; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Game.Npc; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionsWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionsWorldApiTests.cs index 142bda1..16a44d9 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionsWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/NpcBehaviorDefinitionsWorldApiTests.cs @@ -1,8 +1,3 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; -using NeonSprawl.Server.Game.Npc; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/NpcRuntimeOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Npc/NpcRuntimeOperationsTests.cs index df437ac..60be39d 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/NpcRuntimeOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/NpcRuntimeOperationsTests.cs @@ -1,8 +1,5 @@ -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/NpcRuntimeSnapshotWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Npc/NpcRuntimeSnapshotWorldApiTests.cs index 259133b..c3c2843 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/NpcRuntimeSnapshotWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/NpcRuntimeSnapshotWorldApiTests.cs @@ -1,11 +1,5 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.AbilityInput; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.Targeting; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/PrototypeNpcRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Npc/PrototypeNpcRegistryTests.cs index 760cbbf..3a9ac29 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/PrototypeNpcRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/PrototypeNpcRegistryTests.cs @@ -1,7 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; -using NeonSprawl.Server.Game.Npc; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Npc; @@ -95,11 +91,11 @@ public class PrototypeNpcRegistryTests .ToList(); // Assert Assert.Equal(InstancesInIdOrder.Length, resolved.Count); - foreach (var row in resolved) + foreach (var (_, found, behaviorDefId, resolvedDef, resolvedId) in resolved) { - Assert.True(row.Found); - Assert.True(row.Resolved); - Assert.Equal(row.BehaviorDefId, row.ResolvedId); + Assert.True(found); + Assert.True(resolvedDef); + Assert.Equal(behaviorDefId, resolvedId); } } } diff --git a/server/NeonSprawl.Server.Tests/Game/Npc/PrototypeNpcTestFixtures.cs b/server/NeonSprawl.Server.Tests/Game/Npc/PrototypeNpcTestFixtures.cs index 9fd4bec..bb78e3a 100644 --- a/server/NeonSprawl.Server.Tests/Game/Npc/PrototypeNpcTestFixtures.cs +++ b/server/NeonSprawl.Server.Tests/Game/Npc/PrototypeNpcTestFixtures.cs @@ -1,6 +1,5 @@ using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Combat; -using NeonSprawl.Server.Game.Npc; namespace NeonSprawl.Server.Tests.Game.Npc; diff --git a/server/NeonSprawl.Server.Tests/Game/PositionState/MoveCommandApiTests.cs b/server/NeonSprawl.Server.Tests/Game/PositionState/MoveCommandApiTests.cs index 18fabe1..99b50ba 100644 --- a/server/NeonSprawl.Server.Tests/Game/PositionState/MoveCommandApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/PositionState/MoveCommandApiTests.cs @@ -1,14 +1,7 @@ -using System.Net; -using System.Net.Http.Json; -using System.Text; using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.AbilityInput; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Targeting; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.PositionState; @@ -151,12 +144,8 @@ public class MoveCommandApiTests // Arrange await using var factory = new InMemoryWebApplicationFactory().WithWebHostBuilder(b => - { b.ConfigureTestServices(services => - { - services.PostConfigure(o => o.MovementValidation.MaxVerticalStep = 0.5); - }); - }); + services.PostConfigure(o => o.MovementValidation.MaxVerticalStep = 0.5))); var client = factory.CreateClient(); var cmd = new MoveCommandRequest { diff --git a/server/NeonSprawl.Server.Tests/Game/PositionState/MoveCommandValidationTests.cs b/server/NeonSprawl.Server.Tests/Game/PositionState/MoveCommandValidationTests.cs index da6ca6a..4ed1297 100644 --- a/server/NeonSprawl.Server.Tests/Game/PositionState/MoveCommandValidationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/PositionState/MoveCommandValidationTests.cs @@ -1,5 +1,4 @@ using NeonSprawl.Server.Game.PositionState; -using Xunit; namespace NeonSprawl.Server.Tests.Game.PositionState; diff --git a/server/NeonSprawl.Server.Tests/Game/PositionState/MoveStreamApiTests.cs b/server/NeonSprawl.Server.Tests/Game/PositionState/MoveStreamApiTests.cs index 7b0e893..3b20ee1 100644 --- a/server/NeonSprawl.Server.Tests/Game/PositionState/MoveStreamApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/PositionState/MoveStreamApiTests.cs @@ -1,10 +1,5 @@ -using System.Net; -using System.Net.Http.Json; -using System.Text; using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.PositionState; -using Xunit; namespace NeonSprawl.Server.Tests.Game.PositionState; diff --git a/server/NeonSprawl.Server.Tests/Game/PositionState/PositionStateApiTests.cs b/server/NeonSprawl.Server.Tests/Game/PositionState/PositionStateApiTests.cs index e232a24..f2b770d 100644 --- a/server/NeonSprawl.Server.Tests/Game/PositionState/PositionStateApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/PositionState/PositionStateApiTests.cs @@ -1,7 +1,4 @@ -using System.Net; -using System.Net.Http.Json; using NeonSprawl.Server.Game.PositionState; -using Xunit; namespace NeonSprawl.Server.Tests.Game.PositionState; diff --git a/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresCollection.cs b/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresCollection.cs index dfb8d44..72a112e 100644 --- a/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresCollection.cs +++ b/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresCollection.cs @@ -1,8 +1,5 @@ -using Xunit; namespace NeonSprawl.Server.Tests.Game.PositionState; [CollectionDefinition("Postgres integration")] -public sealed class PostgresCollection : ICollectionFixture -{ -} +public sealed class PostgresCollection : ICollectionFixture; diff --git a/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresDockerHelper.cs b/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresDockerHelper.cs index 9ed5627..5ae4450 100644 --- a/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresDockerHelper.cs +++ b/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresDockerHelper.cs @@ -1,6 +1,4 @@ using System.Diagnostics; -using System.Threading; -using Npgsql; namespace NeonSprawl.Server.Tests.Game.PositionState; diff --git a/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresIntegrationHarness.cs b/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresIntegrationHarness.cs index 6ac21a9..3d09045 100644 --- a/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresIntegrationHarness.cs +++ b/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresIntegrationHarness.cs @@ -1,4 +1,3 @@ -using Xunit; namespace NeonSprawl.Server.Tests.Game.PositionState; diff --git a/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresPositionStateIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresPositionStateIntegrationTests.cs index e47922c..35b5c2f 100644 --- a/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresPositionStateIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresPositionStateIntegrationTests.cs @@ -1,10 +1,4 @@ -using System.Net; -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.PositionState; @@ -58,8 +52,8 @@ public sealed class PostgresPositionStateIntegrationTests(PostgresIntegrationHar Target = new PositionVector { X = 7, Y = 0.8, Z = 7 }, }; - HttpStatusCode postStatus = default; - PositionStateResponse? persisted = null; + HttpStatusCode postStatus; + PositionStateResponse? persisted; // Act using var first = Factory.CreateClient(); diff --git a/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresWebApplicationFactory.cs b/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresWebApplicationFactory.cs index f52eeb0..55538e2 100644 --- a/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresWebApplicationFactory.cs +++ b/server/NeonSprawl.Server.Tests/Game/PositionState/PostgresWebApplicationFactory.cs @@ -1,19 +1,22 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Time.Testing; using NeonSprawl.Server.Game.Combat; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Gathering; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; -using NeonSprawl.Server.Game.Npc; -using NeonSprawl.Server.Game.Skills; namespace NeonSprawl.Server.Tests.Game.PositionState; /// Integration host with bound from environment. public sealed class PostgresWebApplicationFactory : WebApplicationFactory { + /// Controllable UTC clock for cast cooldown integration tests (NEO-32). + public FakeTimeProvider? FakeClock { get; private set; } + protected override void ConfigureWebHost(IWebHostBuilder builder) { var cs = Environment.GetEnvironmentVariable("ConnectionStrings__NeonSprawl"); @@ -62,5 +65,20 @@ public sealed class PostgresWebApplicationFactory : WebApplicationFactory + { + for (var i = services.Count - 1; i >= 0; i--) + { + if (services[i].ServiceType == typeof(TimeProvider)) + { + services.RemoveAt(i); + } + } + + var fakeTime = new FakeTimeProvider(new DateTimeOffset(2026, 4, 30, 12, 0, 0, TimeSpan.Zero)); + FakeClock = fakeTime; + services.AddSingleton(fakeTime); + }); } } diff --git a/server/NeonSprawl.Server.Tests/Game/PositionState/RequirePostgresFactAttribute.cs b/server/NeonSprawl.Server.Tests/Game/PositionState/RequirePostgresFactAttribute.cs index 2f794b1..5784427 100644 --- a/server/NeonSprawl.Server.Tests/Game/PositionState/RequirePostgresFactAttribute.cs +++ b/server/NeonSprawl.Server.Tests/Game/PositionState/RequirePostgresFactAttribute.cs @@ -1,4 +1,3 @@ -using Xunit; namespace NeonSprawl.Server.Tests.Game.PositionState; @@ -9,12 +8,12 @@ public sealed class RequirePostgresFactAttribute : FactAttribute { var cs = Environment.GetEnvironmentVariable("ConnectionStrings__NeonSprawl"); var inCi = string.Equals(Environment.GetEnvironmentVariable("CI"), "true", StringComparison.Ordinal); - + if (!string.IsNullOrWhiteSpace(cs)) { return; } - + if (inCi) { throw new InvalidOperationException( diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/InMemoryPlayerQuestStateStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/InMemoryPlayerQuestStateStoreTests.cs index a741451..3e5d7f6 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/InMemoryPlayerQuestStateStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/InMemoryPlayerQuestStateStoreTests.cs @@ -1,8 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Quests; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/PlayerQuestProgressPersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/PlayerQuestProgressPersistenceIntegrationTests.cs index 3f7398b..b91f607 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/PlayerQuestProgressPersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/PlayerQuestProgressPersistenceIntegrationTests.cs @@ -1,10 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; @@ -105,7 +101,7 @@ public sealed class PlayerQuestProgressPersistenceIntegrationTests(PostgresInteg Assert.False(store.TryGetProgress(PlayerId, questId, out _)); } - var readBackExists = false; + bool readBackExists; await using var secondFactory = new PostgresWebApplicationFactory(); using var secondScope = secondFactory.Services.CreateScope(); var readStore = secondScope.ServiceProvider.GetRequiredService(); diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/PrototypeE7M2QuestCatalogRulesTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/PrototypeE7M2QuestCatalogRulesTests.cs index 6e0f1b7..104ba65 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/PrototypeE7M2QuestCatalogRulesTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/PrototypeE7M2QuestCatalogRulesTests.cs @@ -1,7 +1,5 @@ using NeonSprawl.Server.Game.Encounters; using NeonSprawl.Server.Game.Quests; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/QuestAcceptApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/QuestAcceptApiTests.cs index 10076cd..ee6fcc4 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/QuestAcceptApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/QuestAcceptApiTests.cs @@ -1,16 +1,8 @@ -using System.Net; -using System.Net.Http.Json; -using System.Text; -using System.Text.Json; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionCatalogLoaderTests.cs index 79ee3cc..628372f 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionCatalogLoaderTests.cs @@ -1,19 +1,11 @@ using System.Collections.Frozen; -using System.Net; -using System.Text; using System.Text.Json.Nodes; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Encounters; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Quests; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using NeonSprawl.Server.Tests.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionRegistryTests.cs index b48685c..cc5cc76 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionRegistryTests.cs @@ -1,7 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Quests; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; @@ -11,7 +8,7 @@ public class QuestDefinitionRegistryTests private const string OperatorChainId = "prototype_quest_operator_chain"; public static TheoryData FrozenQuestIds => - new(PrototypeE7M1QuestCatalogRules.ExpectedQuestIds.Order(StringComparer.Ordinal)); + new([.. PrototypeE7M1QuestCatalogRules.ExpectedQuestIds.Order(StringComparer.Ordinal)]); private static QuestDefinitionRegistry CreateRegistryFromRows(IReadOnlyDictionary byId) { diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionsWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionsWorldApiTests.cs index 7ea7e59..a3a510f 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionsWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/QuestDefinitionsWorldApiTests.cs @@ -1,8 +1,4 @@ -using System.Net; -using System.Net.Http.Json; -using System.Text.Json; using NeonSprawl.Server.Game.Quests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/QuestFixtureApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/QuestFixtureApiTests.cs index 3a22039..979ca77 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/QuestFixtureApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/QuestFixtureApiTests.cs @@ -1,17 +1,10 @@ -using System.Net; -using System.Net.Http.Json; -using System.Text; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/QuestObjectiveWiringTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/QuestObjectiveWiringTests.cs index 28d1b73..8564079 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/QuestObjectiveWiringTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/QuestObjectiveWiringTests.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Encounters; @@ -8,9 +7,6 @@ using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/QuestProgressApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/QuestProgressApiTests.cs index b081f91..36ba571 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/QuestProgressApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/QuestProgressApiTests.cs @@ -1,6 +1,3 @@ -using System.Net; -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Encounters; @@ -10,9 +7,6 @@ using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; diff --git a/server/NeonSprawl.Server.Tests/Game/Quests/QuestStateOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Quests/QuestStateOperationsTests.cs index 605cd8f..25cdfed 100644 --- a/server/NeonSprawl.Server.Tests/Game/Quests/QuestStateOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Quests/QuestStateOperationsTests.cs @@ -1,13 +1,9 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Quests; diff --git a/server/NeonSprawl.Server.Tests/Game/Rewards/InMemoryRewardDeliveryStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Rewards/InMemoryRewardDeliveryStoreTests.cs index 8530dbe..4b45f21 100644 --- a/server/NeonSprawl.Server.Tests/Game/Rewards/InMemoryRewardDeliveryStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Rewards/InMemoryRewardDeliveryStoreTests.cs @@ -1,8 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Rewards; diff --git a/server/NeonSprawl.Server.Tests/Game/Rewards/RewardRouterOperationsTests.cs b/server/NeonSprawl.Server.Tests/Game/Rewards/RewardRouterOperationsTests.cs index 7333d49..35a1223 100644 --- a/server/NeonSprawl.Server.Tests/Game/Rewards/RewardRouterOperationsTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Rewards/RewardRouterOperationsTests.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Encounters; using NeonSprawl.Server.Game.Factions; @@ -6,9 +5,6 @@ using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Rewards; diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/ContentBackedSkillLevelCurveTests.cs b/server/NeonSprawl.Server.Tests/Game/Skills/ContentBackedSkillLevelCurveTests.cs index d98f0a7..fdc88cf 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/ContentBackedSkillLevelCurveTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/ContentBackedSkillLevelCurveTests.cs @@ -1,7 +1,3 @@ -using System.Text; -using Microsoft.Extensions.Logging.Abstractions; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Skills; diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/InMemoryPlayerSkillProgressionStoreTests.cs b/server/NeonSprawl.Server.Tests/Game/Skills/InMemoryPlayerSkillProgressionStoreTests.cs index 8b4fe69..b876bc0 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/InMemoryPlayerSkillProgressionStoreTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/InMemoryPlayerSkillProgressionStoreTests.cs @@ -1,6 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Skills; diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/MissionRewardDeniedRegistryWebApplicationFactory.cs b/server/NeonSprawl.Server.Tests/Game/Skills/MissionRewardDeniedRegistryWebApplicationFactory.cs index b4bcd82..54505bf 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/MissionRewardDeniedRegistryWebApplicationFactory.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/MissionRewardDeniedRegistryWebApplicationFactory.cs @@ -2,17 +2,13 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Time.Testing; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Combat; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Mastery; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; -using Npgsql; namespace NeonSprawl.Server.Tests.Game.Skills; @@ -87,19 +83,19 @@ internal sealed class MissionRewardDeniedSkillRegistry : ISkillDefinitionRegistr "salvage", "gather", "Salvage", - new[] { "activity" }); + ["activity"]); private static readonly SkillDefRow Refine = new( "refine", "process", "Refine", - new[] { "activity", "mission_reward", "trainer" }); + ["activity", "mission_reward", "trainer"]); private static readonly SkillDefRow Intrusion = new( "intrusion", "tech", "Intrusion", - new[] { "activity", "mission_reward", "book_or_item" }); + ["activity", "mission_reward", "book_or_item"]); private static readonly IReadOnlyList Ordered = [ diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/MissionRewardSkillXpGrantTests.cs b/server/NeonSprawl.Server.Tests/Game/Skills/MissionRewardSkillXpGrantTests.cs index 2c5788d..047e2fb 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/MissionRewardSkillXpGrantTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/MissionRewardSkillXpGrantTests.cs @@ -1,11 +1,5 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Skills; diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/RefineActivityDeniedRegistryWebApplicationFactory.cs b/server/NeonSprawl.Server.Tests/Game/Skills/RefineActivityDeniedRegistryWebApplicationFactory.cs index 5d46c3e..1bbcf1f 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/RefineActivityDeniedRegistryWebApplicationFactory.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/RefineActivityDeniedRegistryWebApplicationFactory.cs @@ -2,17 +2,13 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Time.Testing; using NeonSprawl.Server.Game.AbilityInput; using NeonSprawl.Server.Game.Combat; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Mastery; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; -using Npgsql; namespace NeonSprawl.Server.Tests.Game.Skills; @@ -87,19 +83,19 @@ internal sealed class RefineActivityDeniedSkillRegistry : ISkillDefinitionRegist "salvage", "gather", "Salvage", - new[] { "activity", "mission_reward" }); + ["activity", "mission_reward"]); private static readonly SkillDefRow RefineNoActivity = new( "refine", "process", "Refine", - new[] { "mission_reward", "trainer" }); + ["mission_reward", "trainer"]); private static readonly SkillDefRow Intrusion = new( "intrusion", "tech", "Intrusion", - new[] { "activity", "mission_reward", "book_or_item" }); + ["activity", "mission_reward", "book_or_item"]); private static readonly IReadOnlyList Ordered = [ diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/RefineActivitySkillXpGrantTests.cs b/server/NeonSprawl.Server.Tests/Game/Skills/RefineActivitySkillXpGrantTests.cs index a2e2e2e..dee46fe 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/RefineActivitySkillXpGrantTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/RefineActivitySkillXpGrantTests.cs @@ -1,11 +1,5 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Skills; diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/SkillCatalogTestPaths.cs b/server/NeonSprawl.Server.Tests/Game/Skills/SkillCatalogTestPaths.cs index 336d1b4..2dd4630 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/SkillCatalogTestPaths.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/SkillCatalogTestPaths.cs @@ -1,4 +1,3 @@ -using NeonSprawl.Server.Game.Skills; namespace NeonSprawl.Server.Tests.Game.Skills; diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionCatalogLoaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionCatalogLoaderTests.cs index d64674d..c75c4f9 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionCatalogLoaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionCatalogLoaderTests.cs @@ -1,11 +1,4 @@ -using System.Net; -using System.Text; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.DependencyInjection; -using NeonSprawl.Server.Tests; -using Microsoft.Extensions.Logging.Abstractions; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Skills; @@ -84,7 +77,7 @@ public class SkillDefinitionCatalogLoaderTests { // Arrange var (_, skillsDir, schemaPath) = CreateTempContentLayout(); - var bad = """ + const string bad = """ { "skills": [ { @@ -110,7 +103,7 @@ public class SkillDefinitionCatalogLoaderTests { // Arrange var (_, skillsDir, schemaPath) = CreateTempContentLayout(); - var singleSalvage = """ + const string singleSalvage = """ { "skills": [ { @@ -139,7 +132,7 @@ public class SkillDefinitionCatalogLoaderTests { // Arrange var (_, skillsDir, schemaPath) = CreateTempContentLayout(); - var twoOnly = """ + const string twoOnly = """ { "skills": [ { diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionRegistryTests.cs b/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionRegistryTests.cs index 2b2a51a..06853d8 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionRegistryTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionRegistryTests.cs @@ -1,10 +1,3 @@ -using System.IO; -using System.Text; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging.Abstractions; -using NeonSprawl.Server.Game.Skills; -using NeonSprawl.Server.Tests; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Skills; @@ -26,7 +19,7 @@ public class SkillDefinitionRegistryTests "intrusion", "tech", "Intrusion", - new[] { "activity", "mission_reward", "book_or_item" }), + ["activity", "mission_reward", "book_or_item"]), }; var registry = CreateRegistryFromRows(rows); // Act @@ -46,7 +39,7 @@ public class SkillDefinitionRegistryTests // Arrange var rows = new Dictionary(StringComparer.Ordinal) { - ["salvage"] = new SkillDefRow("salvage", "gather", "Salvage", new[] { "activity" }), + ["salvage"] = new SkillDefRow("salvage", "gather", "Salvage", ["activity"]), }; var registry = CreateRegistryFromRows(rows); // Act @@ -62,7 +55,7 @@ public class SkillDefinitionRegistryTests // Arrange var rows = new Dictionary(StringComparer.Ordinal) { - ["salvage"] = new SkillDefRow("salvage", "gather", "Salvage", new[] { "activity" }), + ["salvage"] = new SkillDefRow("salvage", "gather", "Salvage", ["activity"]), }; var registry = CreateRegistryFromRows(rows); // Act @@ -78,9 +71,9 @@ public class SkillDefinitionRegistryTests // Arrange var rows = new Dictionary(StringComparer.Ordinal) { - ["salvage"] = new SkillDefRow("salvage", "gather", "Salvage", new[] { "activity", "mission_reward" }), - ["refine"] = new SkillDefRow("refine", "process", "Refine", new[] { "activity" }), - ["intrusion"] = new SkillDefRow("intrusion", "tech", "Intrusion", new[] { "trainer" }), + ["salvage"] = new SkillDefRow("salvage", "gather", "Salvage", ["activity", "mission_reward"]), + ["refine"] = new SkillDefRow("refine", "process", "Refine", ["activity"]), + ["intrusion"] = new SkillDefRow("intrusion", "tech", "Intrusion", ["trainer"]), }; var registry = CreateRegistryFromRows(rows); // Act @@ -105,7 +98,7 @@ public class SkillDefinitionRegistryTests Directory.CreateDirectory(schemaDir); var schemaPath = Path.Combine(schemaDir, "skill-def.schema.json"); File.Copy(SkillCatalogTestPaths.DiscoverRepoSkillDefSchemaPath(), schemaPath, overwrite: true); - var json = """ + const string json = """ { "skills": [ { diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionsWorldApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionsWorldApiTests.cs index 7a2b25f..ea8e44d 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionsWorldApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/SkillDefinitionsWorldApiTests.cs @@ -1,13 +1,11 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Skills; public class SkillDefinitionsWorldApiTests { + private static readonly string[] ExpectedSkillIds = ["intrusion", "refine", "salvage"]; + private static readonly string[] SalvageXpSourceKinds = ["activity", "mission_reward"]; + [Fact] public async Task GetSkillDefinitions_ShouldReturnSchemaV1_WithFrozenTrioInIdOrder() { @@ -23,12 +21,12 @@ public class SkillDefinitionsWorldApiTests Assert.Equal(SkillDefinitionsListResponse.CurrentSchemaVersion, body!.SchemaVersion); Assert.NotNull(body.Skills); var ids = body.Skills.Select(static s => s.Id).ToList(); - Assert.Equal(new[] { "intrusion", "refine", "salvage" }, ids); + Assert.Equal(ExpectedSkillIds, ids); var salvage = body.Skills.Single(s => s.Id == "salvage"); Assert.Equal("Salvage", salvage.DisplayName); Assert.Equal("gather", salvage.Category); - Assert.Equal(new[] { "activity", "mission_reward" }, salvage.AllowedXpSourceKinds); + Assert.Equal(SalvageXpSourceKinds, salvage.AllowedXpSourceKinds); var refine = body.Skills.Single(s => s.Id == "refine"); Assert.Contains("trainer", refine.AllowedXpSourceKinds); diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionGrantApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionGrantApiTests.cs index 3d142c9..3fa090f 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionGrantApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionGrantApiTests.cs @@ -1,9 +1,3 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; -using System.Text.Json; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Skills; @@ -15,7 +9,7 @@ public sealed class SkillProgressionGrantApiTests int schemaVersion, int amount = 50, string sourceKind = "activity") => - new SkillProgressionGrantRequest + new() { SchemaVersion = schemaVersion, SkillId = skillId, diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionGrantPersistenceIntegrationTests.cs b/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionGrantPersistenceIntegrationTests.cs index dec654b..64e7af4 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionGrantPersistenceIntegrationTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionGrantPersistenceIntegrationTests.cs @@ -1,11 +1,5 @@ -using System.Net.Http.Json; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; using NeonSprawl.Server.Tests.Game.PositionState; -using Npgsql; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Skills; diff --git a/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionSnapshotApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionSnapshotApiTests.cs index c2a512b..59529b3 100644 --- a/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionSnapshotApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionSnapshotApiTests.cs @@ -1,8 +1,3 @@ -using System.Linq; -using System.Net; -using System.Net.Http.Json; -using NeonSprawl.Server.Game.Skills; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Skills; diff --git a/server/NeonSprawl.Server.Tests/Game/Targeting/PlayerTargetStateReaderTests.cs b/server/NeonSprawl.Server.Tests/Game/Targeting/PlayerTargetStateReaderTests.cs index bb2d87a..dc3b4ba 100644 --- a/server/NeonSprawl.Server.Tests/Game/Targeting/PlayerTargetStateReaderTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Targeting/PlayerTargetStateReaderTests.cs @@ -1,7 +1,5 @@ using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.Targeting; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Targeting; diff --git a/server/NeonSprawl.Server.Tests/Game/Targeting/TargetingApiTests.cs b/server/NeonSprawl.Server.Tests/Game/Targeting/TargetingApiTests.cs index 9fd1bc5..66be7d5 100644 --- a/server/NeonSprawl.Server.Tests/Game/Targeting/TargetingApiTests.cs +++ b/server/NeonSprawl.Server.Tests/Game/Targeting/TargetingApiTests.cs @@ -1,10 +1,5 @@ -using System.Net; -using System.Net.Http.Json; -using System.Text; using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Npc; using NeonSprawl.Server.Game.Targeting; -using Xunit; namespace NeonSprawl.Server.Tests.Game.Targeting; diff --git a/server/NeonSprawl.Server.Tests/GlobalUsings.cs b/server/NeonSprawl.Server.Tests/GlobalUsings.cs new file mode 100644 index 0000000..f7646f6 --- /dev/null +++ b/server/NeonSprawl.Server.Tests/GlobalUsings.cs @@ -0,0 +1,14 @@ +// Intentional test-project globals (avoid duplicating per-file usings; watch for name clashes with local types). +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.Logging.Abstractions; +global using Microsoft.Extensions.Options; +global using NeonSprawl.Server.Game.Npc; +global using NeonSprawl.Server.Game.Skills; +global using NeonSprawl.Server.Tests.Game.Npc; +global using NeonSprawl.Server.Tests.Game.Skills; +global using Npgsql; +global using System.Net; +global using System.Net.Http.Json; +global using System.Text; +global using System.Text.Json; +global using Xunit; diff --git a/server/NeonSprawl.Server.Tests/InMemoryWebApplicationFactory.cs b/server/NeonSprawl.Server.Tests/InMemoryWebApplicationFactory.cs index e81dc80..ceef833 100644 --- a/server/NeonSprawl.Server.Tests/InMemoryWebApplicationFactory.cs +++ b/server/NeonSprawl.Server.Tests/InMemoryWebApplicationFactory.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Time.Testing; using NeonSprawl.Server.Game.AbilityInput; @@ -16,9 +15,6 @@ using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Mastery; -using NeonSprawl.Server.Game.Npc; -using NeonSprawl.Server.Game.Skills; -using Npgsql; namespace NeonSprawl.Server.Tests; diff --git a/server/NeonSprawl.Server/Game/AbilityInput/InMemoryPlayerHotbarLoadoutStore.cs b/server/NeonSprawl.Server/Game/AbilityInput/InMemoryPlayerHotbarLoadoutStore.cs index 23bdbdf..b5cdecf 100644 --- a/server/NeonSprawl.Server/Game/AbilityInput/InMemoryPlayerHotbarLoadoutStore.cs +++ b/server/NeonSprawl.Server/Game/AbilityInput/InMemoryPlayerHotbarLoadoutStore.cs @@ -49,7 +49,7 @@ public sealed class InMemoryPlayerHotbarLoadoutStore(IOptions Clone(ConcurrentDictionary source) + private static Dictionary Clone(ConcurrentDictionary source) { var copy = new Dictionary(source.Count); foreach (var kv in source) @@ -60,7 +60,7 @@ public sealed class InMemoryPlayerHotbarLoadoutStore(IOptions EmptyBindings() => new Dictionary(); + private static Dictionary EmptyBindings() => []; private static string NormalizePlayerId(string? playerId) { diff --git a/server/NeonSprawl.Server/Game/AbilityInput/PostgresHotbarLoadoutBootstrap.cs b/server/NeonSprawl.Server/Game/AbilityInput/PostgresHotbarLoadoutBootstrap.cs index d64e0c1..3f839e6 100644 --- a/server/NeonSprawl.Server/Game/AbilityInput/PostgresHotbarLoadoutBootstrap.cs +++ b/server/NeonSprawl.Server/Game/AbilityInput/PostgresHotbarLoadoutBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.AbilityInput; diff --git a/server/NeonSprawl.Server/Game/AbilityInput/PostgresPlayerHotbarLoadoutStore.cs b/server/NeonSprawl.Server/Game/AbilityInput/PostgresPlayerHotbarLoadoutStore.cs index 1599521..341b1d2 100644 --- a/server/NeonSprawl.Server/Game/AbilityInput/PostgresPlayerHotbarLoadoutStore.cs +++ b/server/NeonSprawl.Server/Game/AbilityInput/PostgresPlayerHotbarLoadoutStore.cs @@ -66,7 +66,7 @@ public sealed class PostgresPlayerHotbarLoadoutStore(Npgsql.NpgsqlDataSource dat return true; } - private static IReadOnlyDictionary ReadBindings( + private static Dictionary ReadBindings( Npgsql.NpgsqlConnection conn, string playerIdNormalized, Npgsql.NpgsqlTransaction? tx = null) @@ -101,7 +101,7 @@ public sealed class PostgresPlayerHotbarLoadoutStore(Npgsql.NpgsqlDataSource dat return cmd.ExecuteScalar() is not null; } - private static IReadOnlyDictionary EmptyBindings() => new Dictionary(); + private static Dictionary EmptyBindings() => []; private static string NormalizePlayerId(string? playerId) { diff --git a/server/NeonSprawl.Server/Game/Combat/AbilityCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Combat/AbilityCatalogServiceCollectionExtensions.cs index 31673e1..b1774f4 100644 --- a/server/NeonSprawl.Server/Game/Combat/AbilityCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Combat/AbilityCatalogServiceCollectionExtensions.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Combat/AbilityDefinitionCatalogLoader.cs b/server/NeonSprawl.Server/Game/Combat/AbilityDefinitionCatalogLoader.cs index 781c5e9..7b78ac9 100644 --- a/server/NeonSprawl.Server/Game/Combat/AbilityDefinitionCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Combat/AbilityDefinitionCatalogLoader.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; namespace NeonSprawl.Server.Game.Combat; diff --git a/server/NeonSprawl.Server/Game/Combat/AbilityDefinitionRegistry.cs b/server/NeonSprawl.Server/Game/Combat/AbilityDefinitionRegistry.cs index 2bafca8..9a370e0 100644 --- a/server/NeonSprawl.Server/Game/Combat/AbilityDefinitionRegistry.cs +++ b/server/NeonSprawl.Server/Game/Combat/AbilityDefinitionRegistry.cs @@ -41,7 +41,7 @@ public sealed class AbilityDefinitionRegistry(AbilityDefinitionCatalog catalog) /// public IReadOnlyList GetDefinitionsInIdOrder() => _definitionsInIdOrder; - private static IReadOnlyList BuildDefinitionsInIdOrder(AbilityDefinitionCatalog catalog) + private static List BuildDefinitionsInIdOrder(AbilityDefinitionCatalog catalog) { string[] ids = [.. catalog.ById.Keys.OrderBy(k => k, StringComparer.Ordinal)]; var list = new List(ids.Length); diff --git a/server/NeonSprawl.Server/Game/Combat/CombatEntityHealthSnapshot.cs b/server/NeonSprawl.Server/Game/Combat/CombatEntityHealthSnapshot.cs index 4fd0a1f..90a393e 100644 --- a/server/NeonSprawl.Server/Game/Combat/CombatEntityHealthSnapshot.cs +++ b/server/NeonSprawl.Server/Game/Combat/CombatEntityHealthSnapshot.cs @@ -1,10 +1,12 @@ namespace NeonSprawl.Server.Game.Combat; -/// Authoritative HP snapshot for a prototype combat target (NEO-80). -/// Normalized lowercase target id. -/// Catalog max HP for prototype dummies. -/// Current HP after damage; floored at zero. -/// true when is zero. +/// +/// Authoritative HP snapshot for a prototype combat target (NEO-80). +/// is the normalized lowercase target id. +/// is catalog max HP for prototype dummies. +/// is current HP after damage; floored at zero. +/// is true when is zero. +/// public readonly record struct CombatEntityHealthSnapshot( string TargetId, int MaxHp, diff --git a/server/NeonSprawl.Server/Game/Combat/CombatResult.cs b/server/NeonSprawl.Server/Game/Combat/CombatResult.cs index f1a835c..a553532 100644 --- a/server/NeonSprawl.Server/Game/Combat/CombatResult.cs +++ b/server/NeonSprawl.Server/Game/Combat/CombatResult.cs @@ -3,10 +3,10 @@ namespace NeonSprawl.Server.Game.Combat; /// /// Server-internal combat resolution envelope (NEO-81); promoted to wire JSON via cast response extension (NEO-82). /// NEO-84 telemetry hook sites live in . +/// is catalog damage applied on success; zero on deny. +/// is authoritative HP after success; optional on deny (e.g. zero on target_defeated). +/// is true when post-resolve HP is zero on success; false on deny. /// -/// Catalog damage applied on success; zero on deny. -/// Authoritative HP after success; optional on deny (e.g. zero on target_defeated). -/// true when post-resolve HP is zero on success; false on deny. public readonly record struct CombatResult( bool Success, string? ReasonCode, diff --git a/server/NeonSprawl.Server/Game/Combat/PlayerCombatHealthSnapshot.cs b/server/NeonSprawl.Server/Game/Combat/PlayerCombatHealthSnapshot.cs index 5b32379..858b068 100644 --- a/server/NeonSprawl.Server/Game/Combat/PlayerCombatHealthSnapshot.cs +++ b/server/NeonSprawl.Server/Game/Combat/PlayerCombatHealthSnapshot.cs @@ -1,10 +1,12 @@ namespace NeonSprawl.Server.Game.Combat; -/// Authoritative HP snapshot for a session player (NEO-95). -/// Normalized lowercase player id. -/// Prototype session max HP. -/// Current HP after NPC damage; floored at zero. -/// true when is zero. +/// +/// Authoritative HP snapshot for a session player (NEO-95). +/// is the normalized lowercase player id. +/// is prototype session max HP. +/// is current HP after NPC damage; floored at zero. +/// is true when is zero. +/// public readonly record struct PlayerCombatHealthSnapshot( string PlayerId, int MaxHp, diff --git a/server/NeonSprawl.Server/Game/Contracts/ContractCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Contracts/ContractCatalogServiceCollectionExtensions.cs index 813bb8a..500ad93 100644 --- a/server/NeonSprawl.Server/Game/Contracts/ContractCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Contracts/ContractCatalogServiceCollectionExtensions.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Encounters; using NeonSprawl.Server.Game.Factions; diff --git a/server/NeonSprawl.Server/Game/Contracts/ContractTemplateCatalogLoader.cs b/server/NeonSprawl.Server/Game/Contracts/ContractTemplateCatalogLoader.cs index d017909..16ad112 100644 --- a/server/NeonSprawl.Server/Game/Contracts/ContractTemplateCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Contracts/ContractTemplateCatalogLoader.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; using NeonSprawl.Server.Game.Encounters; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Contracts/InMemoryContractOutcomeStore.cs b/server/NeonSprawl.Server/Game/Contracts/InMemoryContractOutcomeStore.cs index 87080aa..6798a0e 100644 --- a/server/NeonSprawl.Server/Game/Contracts/InMemoryContractOutcomeStore.cs +++ b/server/NeonSprawl.Server/Game/Contracts/InMemoryContractOutcomeStore.cs @@ -1,5 +1,4 @@ using System.Collections.Concurrent; -using NeonSprawl.Server.Game.Rewards; namespace NeonSprawl.Server.Game.Contracts; @@ -108,7 +107,7 @@ public sealed class InMemoryContractOutcomeStore(IContractInstanceStore instance query = query.Take(limit.Value); } - return [..query]; + return [.. query]; } /// @@ -159,9 +158,9 @@ public sealed class InMemoryContractOutcomeStore(IContractInstanceStore instance PlayerId = playerId, ContractInstanceId = instanceId, IdempotencyKey = idempotencyKey, - GrantedItems = [..row.GrantedItems], - GrantedSkillXp = [..row.GrantedSkillXp], - GrantedReputation = [..row.GrantedReputation], + GrantedItems = [.. row.GrantedItems], + GrantedSkillXp = [.. row.GrantedSkillXp], + GrantedReputation = [.. row.GrantedReputation], }; return true; } diff --git a/server/NeonSprawl.Server/Game/Contracts/PostgresContractInstanceBootstrap.cs b/server/NeonSprawl.Server/Game/Contracts/PostgresContractInstanceBootstrap.cs index 87fedd1..18c42cb 100644 --- a/server/NeonSprawl.Server/Game/Contracts/PostgresContractInstanceBootstrap.cs +++ b/server/NeonSprawl.Server/Game/Contracts/PostgresContractInstanceBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.Contracts; diff --git a/server/NeonSprawl.Server/Game/Contracts/PostgresContractOutcomeBootstrap.cs b/server/NeonSprawl.Server/Game/Contracts/PostgresContractOutcomeBootstrap.cs index ef6f253..7716afd 100644 --- a/server/NeonSprawl.Server/Game/Contracts/PostgresContractOutcomeBootstrap.cs +++ b/server/NeonSprawl.Server/Game/Contracts/PostgresContractOutcomeBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.Contracts; diff --git a/server/NeonSprawl.Server/Game/Contracts/PostgresContractOutcomeStore.cs b/server/NeonSprawl.Server/Game/Contracts/PostgresContractOutcomeStore.cs index f9bab91..814669e 100644 --- a/server/NeonSprawl.Server/Game/Contracts/PostgresContractOutcomeStore.cs +++ b/server/NeonSprawl.Server/Game/Contracts/PostgresContractOutcomeStore.cs @@ -206,9 +206,9 @@ public sealed class PostgresContractOutcomeStore(Npgsql.NpgsqlDataSource dataSou PlayerId = playerId, ContractInstanceId = instanceId, IdempotencyKey = idempotencyKey, - GrantedItems = [..row.GrantedItems], - GrantedSkillXp = [..row.GrantedSkillXp], - GrantedReputation = [..row.GrantedReputation], + GrantedItems = [.. row.GrantedItems], + GrantedSkillXp = [.. row.GrantedSkillXp], + GrantedReputation = [.. row.GrantedReputation], }; return true; } diff --git a/server/NeonSprawl.Server/Game/Crafting/RecipeCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Crafting/RecipeCatalogServiceCollectionExtensions.cs index 763dc46..ffc4fa6 100644 --- a/server/NeonSprawl.Server/Game/Crafting/RecipeCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Crafting/RecipeCatalogServiceCollectionExtensions.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Crafting/RecipeDefinitionCatalogLoader.cs b/server/NeonSprawl.Server/Game/Crafting/RecipeDefinitionCatalogLoader.cs index 0800c67..b8b223f 100644 --- a/server/NeonSprawl.Server/Game/Crafting/RecipeDefinitionCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Crafting/RecipeDefinitionCatalogLoader.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; namespace NeonSprawl.Server.Game.Crafting; @@ -218,7 +217,7 @@ public static class RecipeDefinitionCatalogLoader return new RecipeDefRow(id, displayName, recipeKind, requiredSkillId, inputs, outputs, requiredSkillLevel, stationTag); } - private static IReadOnlyList ParseIoRows(JsonArray? array) + private static List ParseIoRows(JsonArray? array) { if (array is null) return []; diff --git a/server/NeonSprawl.Server/Game/Crafting/RecipeDefinitionRegistry.cs b/server/NeonSprawl.Server/Game/Crafting/RecipeDefinitionRegistry.cs index 206a400..22e66b3 100644 --- a/server/NeonSprawl.Server/Game/Crafting/RecipeDefinitionRegistry.cs +++ b/server/NeonSprawl.Server/Game/Crafting/RecipeDefinitionRegistry.cs @@ -22,7 +22,7 @@ public sealed class RecipeDefinitionRegistry(RecipeDefinitionCatalog catalog) : /// public IReadOnlyList GetDefinitionsInIdOrder() => _definitionsInIdOrder; - private static IReadOnlyList BuildDefinitionsInIdOrder(RecipeDefinitionCatalog catalog) + private static List BuildDefinitionsInIdOrder(RecipeDefinitionCatalog catalog) { string[] ids = [.. catalog.ById.Keys.OrderBy(k => k, StringComparer.Ordinal)]; var list = new List(ids.Length); diff --git a/server/NeonSprawl.Server/Game/Encounters/EncounterCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Encounters/EncounterCatalogServiceCollectionExtensions.cs index 9a6fbe0..4112434 100644 --- a/server/NeonSprawl.Server/Game/Encounters/EncounterCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Encounters/EncounterCatalogServiceCollectionExtensions.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Encounters/EncounterCombatWiring.cs b/server/NeonSprawl.Server/Game/Encounters/EncounterCombatWiring.cs index b173c07..a1b7fd6 100644 --- a/server/NeonSprawl.Server/Game/Encounters/EncounterCombatWiring.cs +++ b/server/NeonSprawl.Server/Game/Encounters/EncounterCombatWiring.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.Logging; using NeonSprawl.Server.Game.Contracts; using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Items; diff --git a/server/NeonSprawl.Server/Game/Encounters/EncounterCompletionResult.cs b/server/NeonSprawl.Server/Game/Encounters/EncounterCompletionResult.cs index de2b0f4..8bf719e 100644 --- a/server/NeonSprawl.Server/Game/Encounters/EncounterCompletionResult.cs +++ b/server/NeonSprawl.Server/Game/Encounters/EncounterCompletionResult.cs @@ -4,9 +4,9 @@ namespace NeonSprawl.Server.Game.Encounters; /// Server-internal encounter completion resolution envelope (NEO-105). /// Combat wiring promotes via NEO-106; HTTP DTOs via NEO-108. /// NEO-109 telemetry hook sites live in . +/// is item grants on success; empty when denied. +/// is completion payload on success; null when denied. /// -/// Item grants on success; empty when denied. -/// Completion payload on success; null when denied. public readonly record struct EncounterCompletionResult( bool Success, string? ReasonCode, diff --git a/server/NeonSprawl.Server/Game/Encounters/EncounterDefinitionCatalogLoader.cs b/server/NeonSprawl.Server/Game/Encounters/EncounterDefinitionCatalogLoader.cs index 32137f4..427dae8 100644 --- a/server/NeonSprawl.Server/Game/Encounters/EncounterDefinitionCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Encounters/EncounterDefinitionCatalogLoader.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; namespace NeonSprawl.Server.Game.Encounters; @@ -165,7 +164,7 @@ public static class EncounterDefinitionCatalogLoader return new EncounterDefRow(id, displayName, completionCriteriaKind, requiredNpcInstanceIds, rewardTableId); } - private static IReadOnlyList ParseStringArray(JsonArray? array) + private static List ParseStringArray(JsonArray? array) { if (array is null) return []; diff --git a/server/NeonSprawl.Server/Game/Encounters/EncounterDefinitionRegistry.cs b/server/NeonSprawl.Server/Game/Encounters/EncounterDefinitionRegistry.cs index 5e04fb3..ab6a1a2 100644 --- a/server/NeonSprawl.Server/Game/Encounters/EncounterDefinitionRegistry.cs +++ b/server/NeonSprawl.Server/Game/Encounters/EncounterDefinitionRegistry.cs @@ -41,7 +41,7 @@ public sealed class EncounterDefinitionRegistry(EncounterDefinitionCatalog catal /// public IReadOnlyList GetDefinitionsInIdOrder() => _definitionsInIdOrder; - private static IReadOnlyList BuildDefinitionsInIdOrder(EncounterDefinitionCatalog catalog) + private static List BuildDefinitionsInIdOrder(EncounterDefinitionCatalog catalog) { string[] ids = [.. catalog.ById.Keys.OrderBy(k => k, StringComparer.Ordinal)]; var list = new List(ids.Length); diff --git a/server/NeonSprawl.Server/Game/Encounters/InMemoryEncounterCompleteEventStore.cs b/server/NeonSprawl.Server/Game/Encounters/InMemoryEncounterCompleteEventStore.cs index 0f036d8..cb9fca3 100644 --- a/server/NeonSprawl.Server/Game/Encounters/InMemoryEncounterCompleteEventStore.cs +++ b/server/NeonSprawl.Server/Game/Encounters/InMemoryEncounterCompleteEventStore.cs @@ -27,7 +27,7 @@ public sealed class InMemoryEncounterCompleteEventStore : IEncounterCompleteEven eventsByKey[key] = completeEvent with { - GrantedItems = [..completeEvent.GrantedItems], + GrantedItems = [.. completeEvent.GrantedItems], }; return true; } diff --git a/server/NeonSprawl.Server/Game/Encounters/RewardTableDefinitionCatalogLoader.cs b/server/NeonSprawl.Server/Game/Encounters/RewardTableDefinitionCatalogLoader.cs index 9a71202..ceda476 100644 --- a/server/NeonSprawl.Server/Game/Encounters/RewardTableDefinitionCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Encounters/RewardTableDefinitionCatalogLoader.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; namespace NeonSprawl.Server.Game.Encounters; @@ -195,7 +194,7 @@ public static class RewardTableDefinitionCatalogLoader return new RewardTableDefRow(id, displayName, fixedGrants); } - private static IReadOnlyList ParseGrantRows(JsonArray? array) + private static List ParseGrantRows(JsonArray? array) { if (array is null) return []; diff --git a/server/NeonSprawl.Server/Game/Encounters/RewardTableDefinitionRegistry.cs b/server/NeonSprawl.Server/Game/Encounters/RewardTableDefinitionRegistry.cs index a7da70b..257f91d 100644 --- a/server/NeonSprawl.Server/Game/Encounters/RewardTableDefinitionRegistry.cs +++ b/server/NeonSprawl.Server/Game/Encounters/RewardTableDefinitionRegistry.cs @@ -41,7 +41,7 @@ public sealed class RewardTableDefinitionRegistry(RewardTableDefinitionCatalog c /// public IReadOnlyList GetDefinitionsInIdOrder() => _definitionsInIdOrder; - private static IReadOnlyList BuildDefinitionsInIdOrder(RewardTableDefinitionCatalog catalog) + private static List BuildDefinitionsInIdOrder(RewardTableDefinitionCatalog catalog) { string[] ids = [.. catalog.ById.Keys.OrderBy(k => k, StringComparer.Ordinal)]; var list = new List(ids.Length); diff --git a/server/NeonSprawl.Server/Game/Factions/FactionCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Factions/FactionCatalogServiceCollectionExtensions.cs index d9c5255..9b0cecd 100644 --- a/server/NeonSprawl.Server/Game/Factions/FactionCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Factions/FactionCatalogServiceCollectionExtensions.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Factions/FactionDefinitionCatalog.cs b/server/NeonSprawl.Server/Game/Factions/FactionDefinitionCatalog.cs index 5b9088a..139f3ac 100644 --- a/server/NeonSprawl.Server/Game/Factions/FactionDefinitionCatalog.cs +++ b/server/NeonSprawl.Server/Game/Factions/FactionDefinitionCatalog.cs @@ -3,25 +3,19 @@ using System.Collections.ObjectModel; namespace NeonSprawl.Server.Game.Factions; /// In-memory faction catalog loaded at startup (NEO-134). Game code should prefer for lookups. -public sealed class FactionDefinitionCatalog +public sealed class FactionDefinitionCatalog( + string factionsDirectory, + IReadOnlyDictionary byId, + int catalogJsonFileCount) { - public FactionDefinitionCatalog( - string factionsDirectory, - IReadOnlyDictionary byId, - int catalogJsonFileCount) - { - FactionsDirectory = factionsDirectory; - ById = new ReadOnlyDictionary(new Dictionary(byId, StringComparer.Ordinal)); - CatalogJsonFileCount = catalogJsonFileCount; - } - /// Absolute path to the directory that was enumerated for *_factions.json catalogs. - public string FactionsDirectory { get; } + public string FactionsDirectory { get; } = factionsDirectory; - public IReadOnlyDictionary ById { get; } + public IReadOnlyDictionary ById { get; } = + new ReadOnlyDictionary(new Dictionary(byId, StringComparer.Ordinal)); public int DistinctFactionCount => ById.Count; /// Number of *_factions.json files under . - public int CatalogJsonFileCount { get; } + public int CatalogJsonFileCount { get; } = catalogJsonFileCount; } diff --git a/server/NeonSprawl.Server/Game/Factions/FactionDefinitionCatalogLoader.cs b/server/NeonSprawl.Server/Game/Factions/FactionDefinitionCatalogLoader.cs index 6497c6e..d380f67 100644 --- a/server/NeonSprawl.Server/Game/Factions/FactionDefinitionCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Factions/FactionDefinitionCatalogLoader.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; namespace NeonSprawl.Server.Game.Factions; diff --git a/server/NeonSprawl.Server/Game/Factions/FactionStandingApi.cs b/server/NeonSprawl.Server/Game/Factions/FactionStandingApi.cs index 8b60842..1795714 100644 --- a/server/NeonSprawl.Server/Game/Factions/FactionStandingApi.cs +++ b/server/NeonSprawl.Server/Game/Factions/FactionStandingApi.cs @@ -24,9 +24,9 @@ public static class FactionStandingApi FactionStandingSnapshotBuildKind.Success => Results.Json(snapshotResult.Response), FactionStandingSnapshotBuildKind.StoreReadFailed => Results.Problem( + detail: snapshotResult.ReasonCode, statusCode: StatusCodes.Status500InternalServerError, - title: "Faction standing read failed", - detail: snapshotResult.ReasonCode), + title: "Faction standing read failed"), _ => throw new InvalidOperationException($"Unexpected build outcome: {snapshotResult.Kind}"), }; }); diff --git a/server/NeonSprawl.Server/Game/Factions/InMemoryReputationDeltaStore.cs b/server/NeonSprawl.Server/Game/Factions/InMemoryReputationDeltaStore.cs index a33f2e4..c94ca1a 100644 --- a/server/NeonSprawl.Server/Game/Factions/InMemoryReputationDeltaStore.cs +++ b/server/NeonSprawl.Server/Game/Factions/InMemoryReputationDeltaStore.cs @@ -58,7 +58,7 @@ public sealed class InMemoryReputationDeltaStore : IReputationDeltaStore query = query.Take(limit.Value); } - return [..query]; + return [.. query]; } /// diff --git a/server/NeonSprawl.Server/Game/Factions/PostgresPlayerFactionStandingBootstrap.cs b/server/NeonSprawl.Server/Game/Factions/PostgresPlayerFactionStandingBootstrap.cs index cddf10c..17b92ba 100644 --- a/server/NeonSprawl.Server/Game/Factions/PostgresPlayerFactionStandingBootstrap.cs +++ b/server/NeonSprawl.Server/Game/Factions/PostgresPlayerFactionStandingBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.Factions; diff --git a/server/NeonSprawl.Server/Game/Factions/PostgresReputationDeltaBootstrap.cs b/server/NeonSprawl.Server/Game/Factions/PostgresReputationDeltaBootstrap.cs index 92f4b57..6672ac5 100644 --- a/server/NeonSprawl.Server/Game/Factions/PostgresReputationDeltaBootstrap.cs +++ b/server/NeonSprawl.Server/Game/Factions/PostgresReputationDeltaBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.Factions; diff --git a/server/NeonSprawl.Server/Game/Gathering/GatherResult.cs b/server/NeonSprawl.Server/Game/Gathering/GatherResult.cs index 8253a5a..444f852 100644 --- a/server/NeonSprawl.Server/Game/Gathering/GatherResult.cs +++ b/server/NeonSprawl.Server/Game/Gathering/GatherResult.cs @@ -4,10 +4,10 @@ namespace NeonSprawl.Server.Game.Gathering; /// Server-internal gather resolution envelope (NEO-62). May promote to wire JSON when the client needs explicit /// gather payloads; until then prototype verification uses inventory GET + interact response (NEO-63). /// NEO-64 telemetry hook sites live in . +/// is item grants on success; empty when denied. +/// is authoritative capacity after success, or current capacity on depletion deny. +/// is skill XP applied on success; null when denied. /// -/// Item grants on success; empty when denied. -/// Authoritative capacity after success, or current capacity on depletion deny. -/// Skill XP applied on success; null when denied. public readonly record struct GatherResult( bool Success, string? ReasonCode, diff --git a/server/NeonSprawl.Server/Game/Gathering/PostgresResourceNodeInstanceBootstrap.cs b/server/NeonSprawl.Server/Game/Gathering/PostgresResourceNodeInstanceBootstrap.cs index f1fbca1..c427f6a 100644 --- a/server/NeonSprawl.Server/Game/Gathering/PostgresResourceNodeInstanceBootstrap.cs +++ b/server/NeonSprawl.Server/Game/Gathering/PostgresResourceNodeInstanceBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.Gathering; diff --git a/server/NeonSprawl.Server/Game/Gathering/ResourceNodeCatalogLoader.cs b/server/NeonSprawl.Server/Game/Gathering/ResourceNodeCatalogLoader.cs index 7945861..c3f58a8 100644 --- a/server/NeonSprawl.Server/Game/Gathering/ResourceNodeCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Gathering/ResourceNodeCatalogLoader.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; namespace NeonSprawl.Server.Game.Gathering; diff --git a/server/NeonSprawl.Server/Game/Gathering/ResourceNodeCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Gathering/ResourceNodeCatalogServiceCollectionExtensions.cs index 248cb1e..1bafd1c 100644 --- a/server/NeonSprawl.Server/Game/Gathering/ResourceNodeCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Gathering/ResourceNodeCatalogServiceCollectionExtensions.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Gathering/ResourceNodeDefinitionRegistry.cs b/server/NeonSprawl.Server/Game/Gathering/ResourceNodeDefinitionRegistry.cs index 0c41dae..00a06ce 100644 --- a/server/NeonSprawl.Server/Game/Gathering/ResourceNodeDefinitionRegistry.cs +++ b/server/NeonSprawl.Server/Game/Gathering/ResourceNodeDefinitionRegistry.cs @@ -45,8 +45,7 @@ public sealed class ResourceNodeDefinitionRegistry(ResourceNodeCatalog catalog) /// public IReadOnlyList GetDefinitionsInIdOrder() => - catalog.NodesById + [.. catalog.NodesById .OrderBy(kv => kv.Key, StringComparer.Ordinal) - .Select(kv => kv.Value) - .ToList(); + .Select(kv => kv.Value)]; } diff --git a/server/NeonSprawl.Server/Game/Gathering/ResourceNodeInstanceSnapshot.cs b/server/NeonSprawl.Server/Game/Gathering/ResourceNodeInstanceSnapshot.cs index 49ae12f..df73c97 100644 --- a/server/NeonSprawl.Server/Game/Gathering/ResourceNodeInstanceSnapshot.cs +++ b/server/NeonSprawl.Server/Game/Gathering/ResourceNodeInstanceSnapshot.cs @@ -1,6 +1,8 @@ namespace NeonSprawl.Server.Game.Gathering; -/// Server-authoritative remaining gather capacity for one world node instance (NEO-61). -/// Lowercase canonical id (prototype: same as nodeDefId). -/// Successful gathers still allowed before . +/// +/// Server-authoritative remaining gather capacity for one world node instance (NEO-61). +/// is lowercase canonical id (prototype: same as nodeDefId). +/// is successful gathers still allowed before . +/// public readonly record struct ResourceNodeInstanceSnapshot(string InteractableId, int RemainingGathers); diff --git a/server/NeonSprawl.Server/Game/Gigs/CombatDefeatGigXpGrant.cs b/server/NeonSprawl.Server/Game/Gigs/CombatDefeatGigXpGrant.cs index 806b6f2..ddf9fb2 100644 --- a/server/NeonSprawl.Server/Game/Gigs/CombatDefeatGigXpGrant.cs +++ b/server/NeonSprawl.Server/Game/Gigs/CombatDefeatGigXpGrant.cs @@ -19,9 +19,12 @@ public static class CombatDefeatGigXpGrant out _, out _)) { - logger?.LogDebug( - "Combat defeat gig XP grant skipped for player {PlayerId} (store write failed)", - playerId); + if (logger?.IsEnabled(LogLevel.Debug) is true) + { + logger.LogDebug( + "Combat defeat gig XP grant skipped for player {PlayerId} (store write failed)", + playerId); + } } } } diff --git a/server/NeonSprawl.Server/Game/Gigs/PostgresGigProgressionBootstrap.cs b/server/NeonSprawl.Server/Game/Gigs/PostgresGigProgressionBootstrap.cs index 5341f37..1eb5b89 100644 --- a/server/NeonSprawl.Server/Game/Gigs/PostgresGigProgressionBootstrap.cs +++ b/server/NeonSprawl.Server/Game/Gigs/PostgresGigProgressionBootstrap.cs @@ -1,5 +1,3 @@ -using System.Threading; - namespace NeonSprawl.Server.Game.Gigs; /// Applies NEO-44 gig progression table DDL once per process. diff --git a/server/NeonSprawl.Server/Game/Interaction/PrototypeInteractableRegistry.cs b/server/NeonSprawl.Server/Game/Interaction/PrototypeInteractableRegistry.cs index 2fd5f55..84ecec6 100644 --- a/server/NeonSprawl.Server/Game/Interaction/PrototypeInteractableRegistry.cs +++ b/server/NeonSprawl.Server/Game/Interaction/PrototypeInteractableRegistry.cs @@ -1,5 +1,3 @@ -using System.Linq; -using NeonSprawl.Server.Game.PositionState; namespace NeonSprawl.Server.Game.Interaction; @@ -63,7 +61,7 @@ public static class PrototypeInteractableRegistry { InteractableId = kv.Key, Kind = e.Kind, - Anchor = new PositionVector + Anchor = new PositionState.PositionVector { X = e.X, Y = e.Y, @@ -77,8 +75,11 @@ public static class PrototypeInteractableRegistry } } -/// Horizontal reach on X/Z; inclusive boundary. -/// Stable machine category for clients and future rules (NEO-25). +/// +/// Prototype interactable world anchor + reach + kind (NEO-25). +/// is horizontal reach on X/Z; inclusive boundary. +/// is stable machine category for clients and future rules. +/// public readonly record struct PrototypeInteractableEntry( double X, double Y, diff --git a/server/NeonSprawl.Server/Game/Items/ItemCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Items/ItemCatalogServiceCollectionExtensions.cs index 3e27a27..9c85876 100644 --- a/server/NeonSprawl.Server/Game/Items/ItemCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Items/ItemCatalogServiceCollectionExtensions.cs @@ -1,6 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Skills; namespace NeonSprawl.Server.Game.Items; @@ -17,7 +14,7 @@ public static class ItemCatalogServiceCollectionExtensions services.AddSingleton(sp => { var hostEnv = sp.GetRequiredService(); - var opts = sp.GetRequiredService>().Value; + var opts = sp.GetRequiredService>().Value; var logger = sp.GetRequiredService() .CreateLogger("NeonSprawl.Server.Game.Items.ItemCatalog"); diff --git a/server/NeonSprawl.Server/Game/Items/ItemDefinitionCatalogLoader.cs b/server/NeonSprawl.Server/Game/Items/ItemDefinitionCatalogLoader.cs index 78c85d8..dbe1402 100644 --- a/server/NeonSprawl.Server/Game/Items/ItemDefinitionCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Items/ItemDefinitionCatalogLoader.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; namespace NeonSprawl.Server.Game.Items; diff --git a/server/NeonSprawl.Server/Game/Items/PlayerInventoryApi.cs b/server/NeonSprawl.Server/Game/Items/PlayerInventoryApi.cs index a8135a7..3ebe921 100644 --- a/server/NeonSprawl.Server/Game/Items/PlayerInventoryApi.cs +++ b/server/NeonSprawl.Server/Game/Items/PlayerInventoryApi.cs @@ -75,7 +75,7 @@ public static class PlayerInventoryApi EquipmentSlots = MapSlots(snapshot.EquipmentSlots), }; - private static IReadOnlyList MapSlots(InventorySlotState[] slots) + private static InventorySlotStateJson[] MapSlots(InventorySlotState[] slots) { var rows = new InventorySlotStateJson[slots.Length]; for (var i = 0; i < slots.Length; i++) diff --git a/server/NeonSprawl.Server/Game/Items/PlayerInventoryDtos.cs b/server/NeonSprawl.Server/Game/Items/PlayerInventoryDtos.cs index ddd75db..b950452 100644 --- a/server/NeonSprawl.Server/Game/Items/PlayerInventoryDtos.cs +++ b/server/NeonSprawl.Server/Game/Items/PlayerInventoryDtos.cs @@ -30,6 +30,7 @@ public sealed class PlayerInventoryMutationRequest [JsonPropertyName("schemaVersion")] public int SchemaVersion { get; init; } + /// Mutation direction: add or remove (ordinal ignore-case). /// add or remove (ordinal ignore-case). [JsonPropertyName("mutationKind")] public required string MutationKind { get; init; } @@ -52,6 +53,7 @@ public sealed class PlayerInventoryMutationResponse [JsonPropertyName("applied")] public bool Applied { get; init; } + /// Deny reason when is false; null on success. /// null on success; stable snake_case deny codes from on deny. [JsonPropertyName("reasonCode")] public string? ReasonCode { get; init; } diff --git a/server/NeonSprawl.Server/Game/Items/PlayerInventoryMutationWrite.cs b/server/NeonSprawl.Server/Game/Items/PlayerInventoryMutationWrite.cs index bcba549..23b678e 100644 --- a/server/NeonSprawl.Server/Game/Items/PlayerInventoryMutationWrite.cs +++ b/server/NeonSprawl.Server/Game/Items/PlayerInventoryMutationWrite.cs @@ -1,5 +1,7 @@ namespace NeonSprawl.Server.Game.Items; -/// Result of an atomic inventory transform (NEO-54). -/// true to persist ; false to leave storage unchanged. +/// +/// Result of an atomic inventory transform (NEO-54). +/// is true to persist ; false to leave storage unchanged. +/// public readonly record struct PlayerInventoryMutationWrite(bool Write, PlayerInventorySnapshot Value); diff --git a/server/NeonSprawl.Server/Game/Items/PostgresPlayerInventoryBootstrap.cs b/server/NeonSprawl.Server/Game/Items/PostgresPlayerInventoryBootstrap.cs index 1ffa86c..05e8919 100644 --- a/server/NeonSprawl.Server/Game/Items/PostgresPlayerInventoryBootstrap.cs +++ b/server/NeonSprawl.Server/Game/Items/PostgresPlayerInventoryBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.Items; diff --git a/server/NeonSprawl.Server/Game/Mastery/InMemoryPlayerPerkStateStore.cs b/server/NeonSprawl.Server/Game/Mastery/InMemoryPlayerPerkStateStore.cs index 5883dea..b03ae46 100644 --- a/server/NeonSprawl.Server/Game/Mastery/InMemoryPlayerPerkStateStore.cs +++ b/server/NeonSprawl.Server/Game/Mastery/InMemoryPlayerPerkStateStore.cs @@ -202,7 +202,7 @@ public sealed class InMemoryPlayerPerkStateStore(IOptions o { if (!branchPicks.TryGetValue(skillId, out var tiers)) { - tiers = new Dictionary(); + tiers = []; branchPicks[skillId] = tiers; } diff --git a/server/NeonSprawl.Server/Game/Mastery/MasteryCatalog.cs b/server/NeonSprawl.Server/Game/Mastery/MasteryCatalog.cs index 8eb0e88..1dce2f7 100644 --- a/server/NeonSprawl.Server/Game/Mastery/MasteryCatalog.cs +++ b/server/NeonSprawl.Server/Game/Mastery/MasteryCatalog.cs @@ -3,33 +3,27 @@ using System.Collections.ObjectModel; namespace NeonSprawl.Server.Game.Mastery; /// In-memory mastery catalog loaded at startup (NEO-46). Prefer for lookups. -public sealed class MasteryCatalog +public sealed class MasteryCatalog( + string masteryDirectory, + IReadOnlyDictionary tracksBySkillId, + IReadOnlyDictionary perksById, + int catalogJsonFileCount) { - public MasteryCatalog( - string masteryDirectory, - IReadOnlyDictionary tracksBySkillId, - IReadOnlyDictionary perksById, - int catalogJsonFileCount) - { - MasteryDirectory = masteryDirectory; - TracksBySkillId = new ReadOnlyDictionary( - new Dictionary(tracksBySkillId, StringComparer.Ordinal)); - PerksById = new ReadOnlyDictionary( - new Dictionary(perksById, StringComparer.Ordinal)); - CatalogJsonFileCount = catalogJsonFileCount; - } - /// Absolute path to the directory enumerated for *_mastery.json catalogs. - public string MasteryDirectory { get; } + public string MasteryDirectory { get; } = masteryDirectory; - public IReadOnlyDictionary TracksBySkillId { get; } + public IReadOnlyDictionary TracksBySkillId { get; } = + new ReadOnlyDictionary( + new Dictionary(tracksBySkillId, StringComparer.Ordinal)); - public IReadOnlyDictionary PerksById { get; } + public IReadOnlyDictionary PerksById { get; } = + new ReadOnlyDictionary( + new Dictionary(perksById, StringComparer.Ordinal)); public int TrackCount => TracksBySkillId.Count; public int PerkCount => PerksById.Count; /// Number of *_mastery.json files under . - public int CatalogJsonFileCount { get; } + public int CatalogJsonFileCount { get; } = catalogJsonFileCount; } diff --git a/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogLoader.cs b/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogLoader.cs index 63f53d8..8b49a69 100644 --- a/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogLoader.cs @@ -1,7 +1,6 @@ using System.Text; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; namespace NeonSprawl.Server.Game.Mastery; @@ -278,12 +277,15 @@ public static class MasteryCatalogLoader ThrowIfAny(errors); } - logger.LogInformation( - "Loaded mastery catalog from {MasteryDirectory}: {TrackCount} track(s), {PerkCount} perk(s) across {CatalogFileCount} JSON catalog file(s).", - masteryDirectory, - tracksBySkillId.Count, - perksById.Count, - jsonFiles.Length); + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation( + "Loaded mastery catalog from {MasteryDirectory}: {TrackCount} track(s), {PerkCount} perk(s) across {CatalogFileCount} JSON catalog file(s).", + masteryDirectory, + tracksBySkillId.Count, + perksById.Count, + jsonFiles.Length); + } return new MasteryCatalog(masteryDirectory, tracksBySkillId, perksById, jsonFiles.Length); } diff --git a/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogRegistry.cs b/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogRegistry.cs index 38cf143..89b41ec 100644 --- a/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogRegistry.cs +++ b/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogRegistry.cs @@ -30,8 +30,8 @@ public sealed class MasteryCatalogRegistry(MasteryCatalog catalog) : IMasteryCat } public IReadOnlyList GetTracksInSkillIdOrder() => - catalog.TracksBySkillId.Values.OrderBy(t => t.SkillId, StringComparer.Ordinal).ToList(); + [.. catalog.TracksBySkillId.Values.OrderBy(t => t.SkillId, StringComparer.Ordinal)]; public IReadOnlyList GetPerksInIdOrder() => - catalog.PerksById.Values.OrderBy(p => p.Id, StringComparer.Ordinal).ToList(); + [.. catalog.PerksById.Values.OrderBy(p => p.Id, StringComparer.Ordinal)]; } diff --git a/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogServiceCollectionExtensions.cs index f3d95b8..28787d6 100644 --- a/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Mastery/MasteryCatalogServiceCollectionExtensions.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Mastery/PerkStateApi.cs b/server/NeonSprawl.Server/Game/Mastery/PerkStateApi.cs index 0665be3..afab395 100644 --- a/server/NeonSprawl.Server/Game/Mastery/PerkStateApi.cs +++ b/server/NeonSprawl.Server/Game/Mastery/PerkStateApi.cs @@ -93,7 +93,7 @@ public static class PerkStateApi }; } - private static IReadOnlyList MapEvents(IReadOnlyList events) + private static List MapEvents(IReadOnlyList events) { if (events.Count == 0) { diff --git a/server/NeonSprawl.Server/Game/Mastery/PerkStateServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Mastery/PerkStateServiceCollectionExtensions.cs index 1d1aa44..956c9b2 100644 --- a/server/NeonSprawl.Server/Game/Mastery/PerkStateServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Mastery/PerkStateServiceCollectionExtensions.cs @@ -1,5 +1,4 @@ using NeonSprawl.Server.Game.PositionState; -using NeonSprawl.Server.Game.Skills; namespace NeonSprawl.Server.Game.Mastery; diff --git a/server/NeonSprawl.Server/Game/Mastery/PerkStateSnapshot.cs b/server/NeonSprawl.Server/Game/Mastery/PerkStateSnapshot.cs index ecaaf0d..0e7ddea 100644 --- a/server/NeonSprawl.Server/Game/Mastery/PerkStateSnapshot.cs +++ b/server/NeonSprawl.Server/Game/Mastery/PerkStateSnapshot.cs @@ -1,24 +1,18 @@ namespace NeonSprawl.Server.Game.Mastery; /// Read model for one player's perk state (NEO-47). -public sealed class PerkStateSnapshot +public sealed class PerkStateSnapshot( + IReadOnlyDictionary> branchPicksBySkillId, + IReadOnlySet unlockedPerkIds) { public static PerkStateSnapshot Empty { get; } = new( new Dictionary>(StringComparer.Ordinal), new HashSet(StringComparer.Ordinal)); - public PerkStateSnapshot( - IReadOnlyDictionary> branchPicksBySkillId, - IReadOnlySet unlockedPerkIds) - { - BranchPicksBySkillId = branchPicksBySkillId; - UnlockedPerkIds = unlockedPerkIds; - } - /// skillIdtierIndexbranchId. - public IReadOnlyDictionary> BranchPicksBySkillId { get; } + public IReadOnlyDictionary> BranchPicksBySkillId { get; } = branchPicksBySkillId; - public IReadOnlySet UnlockedPerkIds { get; } + public IReadOnlySet UnlockedPerkIds { get; } = unlockedPerkIds; public bool TryGetBranchPick(string skillId, int tierIndex, out string branchId) { diff --git a/server/NeonSprawl.Server/Game/Mastery/PerkUnlockEngine.cs b/server/NeonSprawl.Server/Game/Mastery/PerkUnlockEngine.cs index 400369e..1b81b29 100644 --- a/server/NeonSprawl.Server/Game/Mastery/PerkUnlockEngine.cs +++ b/server/NeonSprawl.Server/Game/Mastery/PerkUnlockEngine.cs @@ -107,7 +107,7 @@ public sealed class PerkUnlockEngine( return new PerkReevaluationOutcome(events, perkStore.GetSnapshot(playerId)); } - private PerkBranchSelectOutcome Deny(PerkStateSnapshot snapshot, string reason) => + private static PerkBranchSelectOutcome Deny(PerkStateSnapshot snapshot, string reason) => new(false, reason, [], snapshot); private int GetSkillLevel(string playerId, string skillId) @@ -237,9 +237,7 @@ public sealed class PerkUnlockEngine( return false; } - events = newIds - .Select(pid => new PerkUnlockEvent(playerId, pid, skillId, tierIndex, branchId, source)) - .ToList(); + events = [.. newIds.Select(pid => new PerkUnlockEvent(playerId, pid, skillId, tierIndex, branchId, source))]; // --- Telemetry hook site (NEO-49): future E9.M1 catalog event `perk_unlock` --- // TODO(E9.M1): catalog emit — once per entry in `events` (idempotent reevaluation produces none). diff --git a/server/NeonSprawl.Server/Game/Mastery/PerkUnlockEvent.cs b/server/NeonSprawl.Server/Game/Mastery/PerkUnlockEvent.cs index 4b4d44b..2e51dba 100644 --- a/server/NeonSprawl.Server/Game/Mastery/PerkUnlockEvent.cs +++ b/server/NeonSprawl.Server/Game/Mastery/PerkUnlockEvent.cs @@ -7,8 +7,10 @@ public enum PerkUnlockSource LevelUp, } -/// Internal event when a perk becomes unlocked (NEO-47). E9.M1 perk_unlock hook site: TryUnlockPerks (NEO-49). -/// Chosen branch when relevant; null for edge cases without a branch context. +/// +/// Internal event when a perk becomes unlocked (NEO-47). E9.M1 perk_unlock hook site: TryUnlockPerks (NEO-49). +/// is chosen branch when relevant; null for edge cases without a branch context. +/// public sealed record PerkUnlockEvent( string PlayerId, string PerkId, diff --git a/server/NeonSprawl.Server/Game/Mastery/PostgresPerkStateBootstrap.cs b/server/NeonSprawl.Server/Game/Mastery/PostgresPerkStateBootstrap.cs index aea17f2..955db5c 100644 --- a/server/NeonSprawl.Server/Game/Mastery/PostgresPerkStateBootstrap.cs +++ b/server/NeonSprawl.Server/Game/Mastery/PostgresPerkStateBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.Mastery; diff --git a/server/NeonSprawl.Server/Game/Mastery/PostgresPlayerPerkStateStore.cs b/server/NeonSprawl.Server/Game/Mastery/PostgresPlayerPerkStateStore.cs index d108260..b692e6f 100644 --- a/server/NeonSprawl.Server/Game/Mastery/PostgresPlayerPerkStateStore.cs +++ b/server/NeonSprawl.Server/Game/Mastery/PostgresPlayerPerkStateStore.cs @@ -51,7 +51,7 @@ public sealed class PostgresPlayerPerkStateStore(Npgsql.NpgsqlDataSource dataSou var branchId = reader.GetString(2); if (!branchPicks.TryGetValue(skillId, out var tiers)) { - tiers = new Dictionary(); + tiers = []; branchPicks[skillId] = tiers; } diff --git a/server/NeonSprawl.Server/Game/Npc/NpcBehaviorCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Npc/NpcBehaviorCatalogServiceCollectionExtensions.cs index 26de6c8..f7bf01b 100644 --- a/server/NeonSprawl.Server/Game/Npc/NpcBehaviorCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Npc/NpcBehaviorCatalogServiceCollectionExtensions.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Combat; using NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Npc/NpcBehaviorDefinitionCatalogLoader.cs b/server/NeonSprawl.Server/Game/Npc/NpcBehaviorDefinitionCatalogLoader.cs index 4838e98..ca6b4e6 100644 --- a/server/NeonSprawl.Server/Game/Npc/NpcBehaviorDefinitionCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Npc/NpcBehaviorDefinitionCatalogLoader.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; namespace NeonSprawl.Server.Game.Npc; diff --git a/server/NeonSprawl.Server/Game/Npc/NpcBehaviorDefinitionRegistry.cs b/server/NeonSprawl.Server/Game/Npc/NpcBehaviorDefinitionRegistry.cs index 9eb6581..4e1f75e 100644 --- a/server/NeonSprawl.Server/Game/Npc/NpcBehaviorDefinitionRegistry.cs +++ b/server/NeonSprawl.Server/Game/Npc/NpcBehaviorDefinitionRegistry.cs @@ -5,7 +5,7 @@ namespace NeonSprawl.Server.Game.Npc; /// Adapter over (NEO-89). public sealed class NpcBehaviorDefinitionRegistry(NpcBehaviorDefinitionCatalog catalog) : INpcBehaviorDefinitionRegistry { - private readonly IReadOnlyList _definitionsInIdOrder = BuildDefinitionsInIdOrder(catalog); + private readonly List _definitionsInIdOrder = BuildDefinitionsInIdOrder(catalog); /// public bool TryGetDefinition(string? behaviorId, [NotNullWhen(true)] out NpcBehaviorDefRow? definition) @@ -41,7 +41,7 @@ public sealed class NpcBehaviorDefinitionRegistry(NpcBehaviorDefinitionCatalog c /// public IReadOnlyList GetDefinitionsInIdOrder() => _definitionsInIdOrder; - private static IReadOnlyList BuildDefinitionsInIdOrder(NpcBehaviorDefinitionCatalog catalog) + private static List BuildDefinitionsInIdOrder(NpcBehaviorDefinitionCatalog catalog) { string[] ids = [.. catalog.ById.Keys.OrderBy(k => k, StringComparer.Ordinal)]; var list = new List(ids.Length); diff --git a/server/NeonSprawl.Server/Game/Npc/NpcRuntimeOperations.cs b/server/NeonSprawl.Server/Game/Npc/NpcRuntimeOperations.cs index 95f15e2..47d69ff 100644 --- a/server/NeonSprawl.Server/Game/Npc/NpcRuntimeOperations.cs +++ b/server/NeonSprawl.Server/Game/Npc/NpcRuntimeOperations.cs @@ -167,7 +167,7 @@ public static class NpcRuntimeOperations return; } - if (!TryHasAggroHolder(npcInstanceId, threatStore, out var aggroHolderPlayerId)) + if (!TryHasAggroHolder(npcInstanceId, threatStore, out _)) { if (snapshot.BehaviorState != NpcBehaviorState.Idle || snapshot.ActiveTelegraph is not null) { @@ -193,16 +193,12 @@ public static class NpcRuntimeOperations // TODO(E9.M1): catalog emit — idle → aggro when aggro holder is set. // Planned payload fields: npcInstanceId, behaviorDefId, fromState (idle), toState (aggro), // phaseStartedUtc, aggroHolderPlayerId. - if (!runtimeStore.TryGet(npcInstanceId, out snapshot)) - { - return; - } } var cursor = windowStart; while (cursor < windowEnd) { - if (!TryHasAggroHolder(npcInstanceId, threatStore, out aggroHolderPlayerId)) + if (!TryHasAggroHolder(npcInstanceId, threatStore, out var aggroHolderPlayerId)) { WriteIdle(runtimeStore, npcInstanceId); // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` --- @@ -212,11 +208,13 @@ public static class NpcRuntimeOperations return; } - if (!runtimeStore.TryGet(npcInstanceId, out snapshot)) + if (!runtimeStore.TryGet(npcInstanceId, out var loopSnapshot)) { return; } + snapshot = loopSnapshot; + var loopCursorBefore = cursor; switch (snapshot.BehaviorState) { @@ -224,61 +222,61 @@ public static class NpcRuntimeOperations return; case NpcBehaviorState.Aggro: - { - var phaseEnd = snapshot.PhaseStartedUtc.AddSeconds(behavior.AttackCooldownSeconds); - if (windowEnd < phaseEnd) { - return; - } + var phaseEnd = snapshot.PhaseStartedUtc.AddSeconds(behavior.AttackCooldownSeconds); + if (windowEnd < phaseEnd) + { + return; + } - cursor = phaseEnd; - var telegraph = CreateTelegraph(npcInstanceId, cursor); - WriteState( - runtimeStore, - npcInstanceId, - NpcBehaviorState.TelegraphWindup, - cursor, - telegraph); - // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` --- - // TODO(E9.M1): catalog emit — aggro → telegraph_windup. - // Planned payload fields: npcInstanceId, behaviorDefId, fromState (aggro), - // toState (telegraph_windup), phaseStartedUtc, aggroHolderPlayerId, telegraphId. - // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `telegraph_fired` --- - // TODO(E9.M1): catalog emit — once per telegraph start (each windup cycle). - // Planned payload fields: npcInstanceId, telegraphId, behaviorDefId, archetypeKind, - // aggroHolderPlayerId, windupStartedUtc, telegraphWindupSeconds. - break; - } + cursor = phaseEnd; + var telegraph = CreateTelegraph(npcInstanceId, cursor); + WriteState( + runtimeStore, + npcInstanceId, + NpcBehaviorState.TelegraphWindup, + cursor, + telegraph); + // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` --- + // TODO(E9.M1): catalog emit — aggro → telegraph_windup. + // Planned payload fields: npcInstanceId, behaviorDefId, fromState (aggro), + // toState (telegraph_windup), phaseStartedUtc, aggroHolderPlayerId, telegraphId. + // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `telegraph_fired` --- + // TODO(E9.M1): catalog emit — once per telegraph start (each windup cycle). + // Planned payload fields: npcInstanceId, telegraphId, behaviorDefId, archetypeKind, + // aggroHolderPlayerId, windupStartedUtc, telegraphWindupSeconds. + break; + } case NpcBehaviorState.TelegraphWindup: - { - var phaseEnd = snapshot.PhaseStartedUtc.AddSeconds(behavior.TelegraphWindupSeconds); - if (windowEnd < phaseEnd) { - return; - } + var phaseEnd = snapshot.PhaseStartedUtc.AddSeconds(behavior.TelegraphWindupSeconds); + if (windowEnd < phaseEnd) + { + return; + } - cursor = phaseEnd; - NpcAttackOperations.TryResolveTelegraphComplete( - npcInstanceId, - aggroHolderPlayerId, - behavior.AttackAbilityId, - abilityRegistry, - positionStore, - playerHealthStore, - threatStore); - WriteState( - runtimeStore, - npcInstanceId, - NpcBehaviorState.Recover, - cursor, - activeTelegraph: null); - // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` --- - // TODO(E9.M1): catalog emit — telegraph_windup → recover (logical attack_execute instant). - // Planned payload fields: npcInstanceId, behaviorDefId, fromState (telegraph_windup), - // toState (recover), phaseStartedUtc, aggroHolderPlayerId, telegraphId (completed windup). - break; - } + cursor = phaseEnd; + NpcAttackOperations.TryResolveTelegraphComplete( + npcInstanceId, + aggroHolderPlayerId, + behavior.AttackAbilityId, + abilityRegistry, + positionStore, + playerHealthStore, + threatStore); + WriteState( + runtimeStore, + npcInstanceId, + NpcBehaviorState.Recover, + cursor, + activeTelegraph: null); + // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` --- + // TODO(E9.M1): catalog emit — telegraph_windup → recover (logical attack_execute instant). + // Planned payload fields: npcInstanceId, behaviorDefId, fromState (telegraph_windup), + // toState (recover), phaseStartedUtc, aggroHolderPlayerId, telegraphId (completed windup). + break; + } case NpcBehaviorState.AttackExecute: // Unreachable in normal windup→recover flow (NEO-93); defensive if execute becomes a visible phase. @@ -303,31 +301,31 @@ public static class NpcRuntimeOperations break; case NpcBehaviorState.Recover: - { - var phaseEnd = snapshot.PhaseStartedUtc.AddSeconds(behavior.AttackCooldownSeconds); - if (windowEnd < phaseEnd) { - return; - } + var phaseEnd = snapshot.PhaseStartedUtc.AddSeconds(behavior.AttackCooldownSeconds); + if (windowEnd < phaseEnd) + { + return; + } - cursor = phaseEnd; - var telegraph = CreateTelegraph(npcInstanceId, cursor); - WriteState( - runtimeStore, - npcInstanceId, - NpcBehaviorState.TelegraphWindup, - cursor, - telegraph); - // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` --- - // TODO(E9.M1): catalog emit — recover → telegraph_windup. - // Planned payload fields: npcInstanceId, behaviorDefId, fromState (recover), - // toState (telegraph_windup), phaseStartedUtc, aggroHolderPlayerId, telegraphId. - // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `telegraph_fired` --- - // TODO(E9.M1): catalog emit — once per telegraph start (each windup cycle). - // Planned payload fields: npcInstanceId, telegraphId, behaviorDefId, archetypeKind, - // aggroHolderPlayerId, windupStartedUtc, telegraphWindupSeconds. - break; - } + cursor = phaseEnd; + var telegraph = CreateTelegraph(npcInstanceId, cursor); + WriteState( + runtimeStore, + npcInstanceId, + NpcBehaviorState.TelegraphWindup, + cursor, + telegraph); + // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` --- + // TODO(E9.M1): catalog emit — recover → telegraph_windup. + // Planned payload fields: npcInstanceId, behaviorDefId, fromState (recover), + // toState (telegraph_windup), phaseStartedUtc, aggroHolderPlayerId, telegraphId. + // --- Telemetry hook site (NEO-96): future E9.M1 catalog event `telegraph_fired` --- + // TODO(E9.M1): catalog emit — once per telegraph start (each windup cycle). + // Planned payload fields: npcInstanceId, telegraphId, behaviorDefId, archetypeKind, + // aggroHolderPlayerId, windupStartedUtc, telegraphWindupSeconds. + break; + } default: return; diff --git a/server/NeonSprawl.Server/Game/Npc/NpcRuntimeStateSnapshot.cs b/server/NeonSprawl.Server/Game/Npc/NpcRuntimeStateSnapshot.cs index 5d89db3..eb6870a 100644 --- a/server/NeonSprawl.Server/Game/Npc/NpcRuntimeStateSnapshot.cs +++ b/server/NeonSprawl.Server/Game/Npc/NpcRuntimeStateSnapshot.cs @@ -1,15 +1,19 @@ namespace NeonSprawl.Server.Game.Npc; -/// Active telegraph row while an NPC is in (NEO-93). -/// Stable id for NEO-94 wire projection. -/// UTC instant when windup phase began. +/// +/// Active telegraph row while an NPC is in (NEO-93). +/// is stable id for NEO-94 wire projection. +/// is UTC instant when windup phase began. +/// public readonly record struct ActiveTelegraphSnapshot(string TelegraphId, DateTimeOffset WindupStartedUtc); -/// Per-NPC runtime behavior state snapshot (NEO-93). -/// Lowercase prototype NPC instance id. -/// Current behavior state. -/// UTC instant when the current phase began. -/// Non-null only during . +/// +/// Per-NPC runtime behavior state snapshot (NEO-93). +/// is lowercase prototype NPC instance id. +/// is current behavior state. +/// is UTC instant when the current phase began. +/// is non-null only during . +/// public readonly record struct NpcRuntimeStateSnapshot( string NpcInstanceId, NpcBehaviorState BehaviorState, diff --git a/server/NeonSprawl.Server/Game/Npc/PrototypeNpcRegistry.cs b/server/NeonSprawl.Server/Game/Npc/PrototypeNpcRegistry.cs index c2c38fa..9214e96 100644 --- a/server/NeonSprawl.Server/Game/Npc/PrototypeNpcRegistry.cs +++ b/server/NeonSprawl.Server/Game/Npc/PrototypeNpcRegistry.cs @@ -61,8 +61,11 @@ public static class PrototypeNpcRegistry } } -/// Frozen behavior catalog id bound to this instance. -/// Horizontal reach on X/Z; inclusive boundary (same as NEO-9). +/// +/// One prototype NPC instance binding + world anchor (NEO-91). +/// is frozen behavior catalog id bound to this instance. +/// is horizontal reach on X/Z; inclusive boundary (same as NEO-9). +/// public readonly record struct PrototypeNpcInstanceEntry( string BehaviorDefId, double X, diff --git a/server/NeonSprawl.Server/Game/Npc/ThreatStateSnapshot.cs b/server/NeonSprawl.Server/Game/Npc/ThreatStateSnapshot.cs index 6d21c01..6b0034c 100644 --- a/server/NeonSprawl.Server/Game/Npc/ThreatStateSnapshot.cs +++ b/server/NeonSprawl.Server/Game/Npc/ThreatStateSnapshot.cs @@ -1,6 +1,8 @@ namespace NeonSprawl.Server.Game.Npc; -/// Per-NPC aggro holder snapshot (NEO-92). -/// Lowercase prototype NPC instance id. -/// Lowercase route player id holding aggro, or when empty. +/// +/// Per-NPC aggro holder snapshot (NEO-92). +/// is lowercase prototype NPC instance id. +/// is lowercase route player id holding aggro, or when empty. +/// public readonly record struct ThreatStateSnapshot(string NpcInstanceId, string? AggroHolderPlayerId); diff --git a/server/NeonSprawl.Server/Game/PositionState/MoveCommandValidation.cs b/server/NeonSprawl.Server/Game/PositionState/MoveCommandValidation.cs index 1cadafa..4d50e3e 100644 --- a/server/NeonSprawl.Server/Game/PositionState/MoveCommandValidation.cs +++ b/server/NeonSprawl.Server/Game/PositionState/MoveCommandValidation.cs @@ -22,7 +22,7 @@ public static class MoveCommandValidation { var dx = to.X - from.X; var dz = to.Z - from.Z; - var horizontal = Math.Sqrt(dx * dx + dz * dz); + var horizontal = Math.Sqrt((dx * dx) + (dz * dz)); if (horizontal > rules.MaxHorizontalStep) { reasonCode = MoveCommandReasonCodes.HorizontalStepExceeded; diff --git a/server/NeonSprawl.Server/Game/PositionState/NpgsqlDataSourceShutdownHostedService.cs b/server/NeonSprawl.Server/Game/PositionState/NpgsqlDataSourceShutdownHostedService.cs index d0d84d7..5aa108a 100644 --- a/server/NeonSprawl.Server/Game/PositionState/NpgsqlDataSourceShutdownHostedService.cs +++ b/server/NeonSprawl.Server/Game/PositionState/NpgsqlDataSourceShutdownHostedService.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.Hosting; using Npgsql; namespace NeonSprawl.Server.Game.PositionState; diff --git a/server/NeonSprawl.Server/Game/PositionState/PostgresPositionBootstrap.cs b/server/NeonSprawl.Server/Game/PositionState/PostgresPositionBootstrap.cs index 47cbf47..f074ac0 100644 --- a/server/NeonSprawl.Server/Game/PositionState/PostgresPositionBootstrap.cs +++ b/server/NeonSprawl.Server/Game/PositionState/PostgresPositionBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.PositionState; diff --git a/server/NeonSprawl.Server/Game/PositionState/PostgresPositionStateStore.cs b/server/NeonSprawl.Server/Game/PositionState/PostgresPositionStateStore.cs index 132fec5..3bab471 100644 --- a/server/NeonSprawl.Server/Game/PositionState/PostgresPositionStateStore.cs +++ b/server/NeonSprawl.Server/Game/PositionState/PostgresPositionStateStore.cs @@ -1,24 +1,8 @@ -using Microsoft.Extensions.Options; - namespace NeonSprawl.Server.Game.PositionState; /// PostgreSQL-backed (NS-17). Player ids are stored normalized: invariant lower + trim for case-insensitive parity with . -public sealed class PostgresPositionStateStore( - Npgsql.NpgsqlDataSource dataSource, - IOptions positionOptions) : IPositionStateStore +public sealed class PostgresPositionStateStore(Npgsql.NpgsqlDataSource dataSource) : IPositionStateStore { - private readonly GamePositionOptions gameOptions = RequireValidOptions(positionOptions.Value); - - private static GamePositionOptions RequireValidOptions(GamePositionOptions options) - { - if (options.DevPlayerId.Trim().Length == 0) - { - throw new InvalidOperationException("Game:DevPlayerId must be non-empty."); - } - - return options; - } - public bool TryGetPosition(string playerId, out PositionSnapshot snapshot) { var norm = NormalizePlayerId(playerId); @@ -69,9 +53,9 @@ public sealed class PostgresPositionStateStore( """, conn); cmd.Parameters.AddWithValue("pid", norm); - cmd.Parameters.AddWithValue("x", x); - cmd.Parameters.AddWithValue("y", y); - cmd.Parameters.AddWithValue("z", z); + cmd.Parameters.AddWithValue(nameof(x), x); + cmd.Parameters.AddWithValue(nameof(y), y); + cmd.Parameters.AddWithValue(nameof(z), z); using var reader = cmd.ExecuteReader(); if (!reader.Read()) { diff --git a/server/NeonSprawl.Server/Game/Quests/PostgresPlayerQuestProgressBootstrap.cs b/server/NeonSprawl.Server/Game/Quests/PostgresPlayerQuestProgressBootstrap.cs index db1cec5..b179c07 100644 --- a/server/NeonSprawl.Server/Game/Quests/PostgresPlayerQuestProgressBootstrap.cs +++ b/server/NeonSprawl.Server/Game/Quests/PostgresPlayerQuestProgressBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.Quests; diff --git a/server/NeonSprawl.Server/Game/Quests/PostgresPlayerQuestStateStore.cs b/server/NeonSprawl.Server/Game/Quests/PostgresPlayerQuestStateStore.cs index f17f315..e6340f2 100644 --- a/server/NeonSprawl.Server/Game/Quests/PostgresPlayerQuestStateStore.cs +++ b/server/NeonSprawl.Server/Game/Quests/PostgresPlayerQuestStateStore.cs @@ -148,23 +148,25 @@ public sealed class PostgresPlayerQuestStateStore(Npgsql.NpgsqlDataSource dataSo return false; } - return TryMutateRow(player, quest, (QuestStepState row, out QuestStepState result) => + MutateRowResult MutateAdvanceStep(QuestStepState row) { if (row.Status != QuestProgressStatus.Active || newStepIndex <= row.CurrentStepIndex) { - result = row; - return false; + return new MutateRowResult(false, row); } - result = new QuestStepState( - row.PlayerId, - row.QuestId, - row.Status, - newStepIndex, - new Dictionary(StringComparer.Ordinal), - row.CompletedAt); - return true; - }, out snapshot); + return new MutateRowResult( + true, + new QuestStepState( + row.PlayerId, + row.QuestId, + row.Status, + newStepIndex, + new Dictionary(StringComparer.Ordinal), + row.CompletedAt)); + } + + return TryMutateRow(player, quest, MutateAdvanceStep, out snapshot); } /// @@ -189,25 +191,30 @@ public sealed class PostgresPlayerQuestStateStore(Npgsql.NpgsqlDataSource dataSo return false; } - return TryMutateRow(player, quest, (QuestStepState row, out QuestStepState result) => + MutateRowResult MutateObjectiveCounter(QuestStepState row) { if (row.Status != QuestProgressStatus.Active) { - result = row; - return false; + return new MutateRowResult(false, row); } - var counters = new Dictionary(row.ObjectiveCounters, StringComparer.Ordinal); + Dictionary counters = row.ObjectiveCounters.ToDictionary( + static pair => pair.Key, + static pair => pair.Value, + StringComparer.Ordinal); counters[objective] = newCount; - result = new QuestStepState( - row.PlayerId, - row.QuestId, - row.Status, - row.CurrentStepIndex, - counters, - row.CompletedAt); - return true; - }, out snapshot); + return new MutateRowResult( + true, + new QuestStepState( + row.PlayerId, + row.QuestId, + row.Status, + row.CurrentStepIndex, + counters, + row.CompletedAt)); + } + + return TryMutateRow(player, quest, MutateObjectiveCounter, out snapshot); } /// @@ -221,23 +228,25 @@ public sealed class PostgresPlayerQuestStateStore(Npgsql.NpgsqlDataSource dataSo return false; } - return TryMutateRow(player, quest, (QuestStepState row, out QuestStepState result) => + MutateRowResult MutateComplete(QuestStepState row) { if (row.Status == QuestProgressStatus.Completed) { - result = row; - return false; + return new MutateRowResult(false, row); } - result = new QuestStepState( - row.PlayerId, - row.QuestId, - QuestProgressStatus.Completed, - row.CurrentStepIndex, - row.ObjectiveCounters, - completedAt); - return true; - }, out snapshot); + return new MutateRowResult( + true, + new QuestStepState( + row.PlayerId, + row.QuestId, + QuestProgressStatus.Completed, + row.CurrentStepIndex, + row.ObjectiveCounters, + completedAt)); + } + + return TryMutateRow(player, quest, MutateComplete, out snapshot); } /// @@ -267,7 +276,7 @@ public sealed class PostgresPlayerQuestStateStore(Npgsql.NpgsqlDataSource dataSo private bool TryMutateRow( string player, string quest, - TryMutateRowDelegate mutator, + Func mutator, out QuestStepState snapshot) { snapshot = null!; @@ -304,16 +313,17 @@ public sealed class PostgresPlayerQuestStateStore(Npgsql.NpgsqlDataSource dataSo current = ReadSnapshot(reader, player, quest); } - if (!mutator(current, out var updated)) + var mutateResult = mutator(current); + if (!mutateResult.Applied) { snapshot = current; tx.Rollback(); return false; } - WriteRow(conn, player, quest, updated, tx); + WriteRow(conn, player, quest, mutateResult.State, tx); tx.Commit(); - snapshot = updated; + snapshot = mutateResult.State; return true; } @@ -401,5 +411,5 @@ public sealed class PostgresPlayerQuestStateStore(Npgsql.NpgsqlDataSource dataSo return cmd.ExecuteScalar() is not null; } - private delegate bool TryMutateRowDelegate(QuestStepState current, out QuestStepState updated); + private readonly record struct MutateRowResult(bool Applied, QuestStepState State); } diff --git a/server/NeonSprawl.Server/Game/Quests/QuestCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Quests/QuestCatalogServiceCollectionExtensions.cs index 0d9e49b..ad1bc76 100644 --- a/server/NeonSprawl.Server/Game/Quests/QuestCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Quests/QuestCatalogServiceCollectionExtensions.cs @@ -1,6 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; using NeonSprawl.Server.Game.Crafting; using NeonSprawl.Server.Game.Encounters; using NeonSprawl.Server.Game.Factions; @@ -21,7 +18,7 @@ public static class QuestCatalogServiceCollectionExtensions services.AddSingleton(sp => { var hostEnv = sp.GetRequiredService(); - var opts = sp.GetRequiredService>().Value; + var opts = sp.GetRequiredService>().Value; var itemCatalog = sp.GetRequiredService(); var recipeCatalog = sp.GetRequiredService(); var encounterCatalog = sp.GetRequiredService(); diff --git a/server/NeonSprawl.Server/Game/Quests/QuestDefinitionCatalogLoader.cs b/server/NeonSprawl.Server/Game/Quests/QuestDefinitionCatalogLoader.cs index b0566b2..5731e6e 100644 --- a/server/NeonSprawl.Server/Game/Quests/QuestDefinitionCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Quests/QuestDefinitionCatalogLoader.cs @@ -2,8 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; -using NeonSprawl.Server.Game.Encounters; using NeonSprawl.Server.Game.Skills; namespace NeonSprawl.Server.Game.Quests; @@ -365,12 +363,12 @@ public static class QuestDefinitionCatalogLoader return rows; } - private static List ParseItemGrantRows(JsonArray? array) + private static List ParseItemGrantRows(JsonArray? array) { if (array is null || array.Count == 0) return []; - var rows = new List(array.Count); + var rows = new List(array.Count); foreach (var node in array) { if (node is not JsonObject grantObj) @@ -378,7 +376,7 @@ public static class QuestDefinitionCatalogLoader var itemId = (grantObj["itemId"] as JsonValue)!.GetValue(); var quantity = (grantObj["quantity"] as JsonValue)!.GetValue(); - rows.Add(new RewardGrantRow(itemId, quantity)); + rows.Add(new Encounters.RewardGrantRow(itemId, quantity)); } return rows; diff --git a/server/NeonSprawl.Server/Game/Quests/QuestDefinitionRegistry.cs b/server/NeonSprawl.Server/Game/Quests/QuestDefinitionRegistry.cs index 6c97d05..f86298b 100644 --- a/server/NeonSprawl.Server/Game/Quests/QuestDefinitionRegistry.cs +++ b/server/NeonSprawl.Server/Game/Quests/QuestDefinitionRegistry.cs @@ -41,7 +41,7 @@ public sealed class QuestDefinitionRegistry(QuestDefinitionCatalog catalog) : IQ /// public IReadOnlyList GetDefinitionsInIdOrder() => _definitionsInIdOrder; - private static IReadOnlyList BuildDefinitionsInIdOrder(QuestDefinitionCatalog catalog) + private static List BuildDefinitionsInIdOrder(QuestDefinitionCatalog catalog) { string[] ids = [.. catalog.ById.Keys.OrderBy(k => k, StringComparer.Ordinal)]; var list = new List(ids.Length); diff --git a/server/NeonSprawl.Server/Game/Quests/QuestObjectiveWiring.cs b/server/NeonSprawl.Server/Game/Quests/QuestObjectiveWiring.cs index f070c09..f9ac60e 100644 --- a/server/NeonSprawl.Server/Game/Quests/QuestObjectiveWiring.cs +++ b/server/NeonSprawl.Server/Game/Quests/QuestObjectiveWiring.cs @@ -83,7 +83,10 @@ public static class QuestObjectiveWiring } catch (Exception ex) { - logger?.LogDebug(ex, "Quest gather wiring skipped for player {PlayerId}", playerId); + if (logger?.IsEnabled(LogLevel.Debug) is true) + { + logger.LogDebug(ex, "Quest gather wiring skipped for player {PlayerId}", playerId); + } } } @@ -156,7 +159,10 @@ public static class QuestObjectiveWiring } catch (Exception ex) { - logger?.LogDebug(ex, "Quest craft wiring skipped for player {PlayerId}", playerId); + if (logger?.IsEnabled(LogLevel.Debug) is true) + { + logger.LogDebug(ex, "Quest craft wiring skipped for player {PlayerId}", playerId); + } } } @@ -227,7 +233,10 @@ public static class QuestObjectiveWiring } catch (Exception ex) { - logger?.LogDebug(ex, "Quest encounter wiring skipped for player {PlayerId}", playerId); + if (logger?.IsEnabled(LogLevel.Debug) is true) + { + logger.LogDebug(ex, "Quest encounter wiring skipped for player {PlayerId}", playerId); + } } } @@ -299,7 +308,10 @@ public static class QuestObjectiveWiring } catch (Exception ex) { - logger?.LogDebug(ex, "Quest progress GET refresh skipped for player {PlayerId}", playerId); + if (logger?.IsEnabled(LogLevel.Debug) is true) + { + logger.LogDebug(ex, "Quest progress GET refresh skipped for player {PlayerId}", playerId); + } } } diff --git a/server/NeonSprawl.Server/Game/Quests/QuestStateOperations.cs b/server/NeonSprawl.Server/Game/Quests/QuestStateOperations.cs index 9d3e019..c3cc606 100644 --- a/server/NeonSprawl.Server/Game/Quests/QuestStateOperations.cs +++ b/server/NeonSprawl.Server/Game/Quests/QuestStateOperations.cs @@ -37,22 +37,22 @@ public static class QuestStateOperations if (!questRegistry.TryNormalizeKnown(questId, out var normalizedQuestId) || !questRegistry.TryGetDefinition(normalizedQuestId, out var definition)) { - return DenyAccept(playerId, questId, QuestStateReasonCodes.UnknownQuest); + return DenyAccept(QuestStateReasonCodes.UnknownQuest); } if (!progressStore.CanWritePlayer(playerId)) { - return DenyAccept(playerId, normalizedQuestId, QuestStateReasonCodes.UnknownPlayer); + return DenyAccept(QuestStateReasonCodes.UnknownPlayer); } if (progressStore.TryGetProgress(playerId, normalizedQuestId, out var existing)) { if (existing.Status == QuestProgressStatus.Completed) { - return DenyAccept(playerId, normalizedQuestId, QuestStateReasonCodes.AlreadyCompleted, existing); + return DenyAccept(QuestStateReasonCodes.AlreadyCompleted, existing); } - return DenyAccept(playerId, normalizedQuestId, QuestStateReasonCodes.AlreadyActive, existing); + return DenyAccept(QuestStateReasonCodes.AlreadyActive, existing); } foreach (var prerequisiteId in definition.PrerequisiteQuestIds) @@ -60,7 +60,7 @@ public static class QuestStateOperations if (!progressStore.TryGetProgress(playerId, prerequisiteId, out var prerequisite) || prerequisite.Status != QuestProgressStatus.Completed) { - return DenyAccept(playerId, normalizedQuestId, QuestStateReasonCodes.PrerequisiteIncomplete); + return DenyAccept(QuestStateReasonCodes.PrerequisiteIncomplete); } } @@ -71,7 +71,7 @@ public static class QuestStateOperations if (!gate.Success) { // Quest-level deny always surfaces faction_gate_blocked (ops may carry unknown_faction for telemetry). - return DenyAccept(playerId, normalizedQuestId, QuestStateReasonCodes.FactionGateBlocked); + return DenyAccept(QuestStateReasonCodes.FactionGateBlocked); } if (progressStore.TryActivate(playerId, normalizedQuestId, out var snapshot)) @@ -303,11 +303,11 @@ public static class QuestStateOperations string playerId, string questId, QuestStepState attemptSnapshot) => - DenyFromProgressSnapshot(attemptSnapshot, QuestStateReasonCodes.AlreadyActive, playerId, questId) + DenyFromProgressSnapshot(attemptSnapshot, QuestStateReasonCodes.AlreadyActive, playerId) ?? (progressStore.TryGetProgress(playerId, questId, out var reread) - ? DenyFromProgressSnapshot(reread, QuestStateReasonCodes.AlreadyActive, playerId, questId) + ? DenyFromProgressSnapshot(reread, QuestStateReasonCodes.AlreadyActive, playerId) : null) - ?? DenyAccept(playerId, questId, QuestStateReasonCodes.UnknownPlayer); + ?? DenyAccept(QuestStateReasonCodes.UnknownPlayer); private static QuestStateOperationResult DenyAdvanceFailure( IPlayerQuestStateStore progressStore, @@ -324,8 +324,7 @@ public static class QuestStateOperations private static QuestStateOperationResult? DenyFromProgressSnapshot( QuestStepState? snapshot, string activeOrIntermediateReasonCode, - string? acceptDenyPlayerId = null, - string? acceptDenyQuestId = null) + string? acceptDenyPlayerId = null) { if (snapshot is null) { @@ -335,14 +334,14 @@ public static class QuestStateOperations if (snapshot.Status == QuestProgressStatus.Completed) { return acceptDenyPlayerId is not null - ? DenyAccept(acceptDenyPlayerId, acceptDenyQuestId ?? string.Empty, QuestStateReasonCodes.AlreadyCompleted, snapshot) + ? DenyAccept(QuestStateReasonCodes.AlreadyCompleted, snapshot) : Deny(QuestStateReasonCodes.AlreadyCompleted, snapshot); } if (snapshot.Status == QuestProgressStatus.Active) { return acceptDenyPlayerId is not null - ? DenyAccept(acceptDenyPlayerId, acceptDenyQuestId ?? string.Empty, activeOrIntermediateReasonCode, snapshot) + ? DenyAccept(activeOrIntermediateReasonCode, snapshot) : Deny(activeOrIntermediateReasonCode, snapshot); } @@ -353,15 +352,12 @@ public static class QuestStateOperations new(Success: true, ReasonCode: null, Snapshot: snapshot); private static QuestStateOperationResult DenyAccept( - string playerId, - string questId, string reasonCode, QuestStepState? snapshot = null) { // --- Telemetry hook site (NEO-121): future E9.M1 catalog event `quest_accept_denied` --- // TODO(E9.M1): catalog emit — reasonCode from QuestStateReasonCodes (unknown_quest, prerequisite_incomplete, etc.). - // Planned payload fields: playerId, questId, reasonCode (caller context threaded for E9.M1 wiring). - // No ingest or ILogger here (comments-only). + // Planned payload fields: playerId, questId, reasonCode (capture at call site when wiring E9.M1). return Deny(reasonCode, snapshot); } diff --git a/server/NeonSprawl.Server/Game/Rewards/InMemoryRewardDeliveryStore.cs b/server/NeonSprawl.Server/Game/Rewards/InMemoryRewardDeliveryStore.cs index 383abf1..41f86fb 100644 --- a/server/NeonSprawl.Server/Game/Rewards/InMemoryRewardDeliveryStore.cs +++ b/server/NeonSprawl.Server/Game/Rewards/InMemoryRewardDeliveryStore.cs @@ -27,9 +27,9 @@ public sealed class InMemoryRewardDeliveryStore : IRewardDeliveryStore eventsByKey[key] = deliveryEvent with { - GrantedItems = [..deliveryEvent.GrantedItems], - GrantedSkillXp = [..deliveryEvent.GrantedSkillXp], - GrantedReputation = [..deliveryEvent.GrantedReputation], + GrantedItems = [.. deliveryEvent.GrantedItems], + GrantedSkillXp = [.. deliveryEvent.GrantedSkillXp], + GrantedReputation = [.. deliveryEvent.GrantedReputation], }; return true; } diff --git a/server/NeonSprawl.Server/Game/Rewards/RewardDeliveryResult.cs b/server/NeonSprawl.Server/Game/Rewards/RewardDeliveryResult.cs index 9d53480..b9da30c 100644 --- a/server/NeonSprawl.Server/Game/Rewards/RewardDeliveryResult.cs +++ b/server/NeonSprawl.Server/Game/Rewards/RewardDeliveryResult.cs @@ -3,11 +3,11 @@ namespace NeonSprawl.Server.Game.Rewards; /// /// Server-internal quest completion reward delivery envelope (NEO-127). /// Quest-state wiring promotes via NEO-128; HTTP DTOs via NEO-129. +/// is item grants on success; empty when denied. +/// is skill XP grants on success; empty when denied. +/// is reputation grants on success; empty when denied. +/// is delivery payload on success; null when denied. /// -/// Item grants on success; empty when denied. -/// Skill XP grants on success; empty when denied. -/// Reputation grants on success; empty when denied. -/// Delivery payload on success; null when denied. public readonly record struct RewardDeliveryResult( bool Success, string? ReasonCode, diff --git a/server/NeonSprawl.Server/Game/Skills/ContentBackedSkillLevelCurve.cs b/server/NeonSprawl.Server/Game/Skills/ContentBackedSkillLevelCurve.cs index d39c630..42919e9 100644 --- a/server/NeonSprawl.Server/Game/Skills/ContentBackedSkillLevelCurve.cs +++ b/server/NeonSprawl.Server/Game/Skills/ContentBackedSkillLevelCurve.cs @@ -150,10 +150,14 @@ public sealed class ContentBackedSkillLevelCurve : ISkillLevelCurve ThrowIfAny(errors); - logger.LogInformation( - "Loaded level curve from {CurvePath} with {LevelCount} thresholds.", - fullCurvePath, - parsedRows.Count); + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation( + "Loaded level curve from {CurvePath} with {LevelCount} thresholds.", + fullCurvePath, + parsedRows.Count); + } + return new ContentBackedSkillLevelCurve(parsedRows); } } diff --git a/server/NeonSprawl.Server/Game/Skills/InMemoryPlayerSkillProgressionStore.cs b/server/NeonSprawl.Server/Game/Skills/InMemoryPlayerSkillProgressionStore.cs index acab145..8acd774 100644 --- a/server/NeonSprawl.Server/Game/Skills/InMemoryPlayerSkillProgressionStore.cs +++ b/server/NeonSprawl.Server/Game/Skills/InMemoryPlayerSkillProgressionStore.cs @@ -9,6 +9,7 @@ public sealed class InMemoryPlayerSkillProgressionStore(IOptions> byPlayer = CreateInitialMap(options.Value); + /// Per-player lock for coherent read/compare/write on inner dictionaries. /// Locks per normalized player id for coherent read/compare/write on inner dictionaries. private readonly ConcurrentDictionary playerLocks = new(StringComparer.OrdinalIgnoreCase); diff --git a/server/NeonSprawl.Server/Game/Skills/PostgresPlayerSkillProgressionStore.cs b/server/NeonSprawl.Server/Game/Skills/PostgresPlayerSkillProgressionStore.cs index 2f10add..f0dc339 100644 --- a/server/NeonSprawl.Server/Game/Skills/PostgresPlayerSkillProgressionStore.cs +++ b/server/NeonSprawl.Server/Game/Skills/PostgresPlayerSkillProgressionStore.cs @@ -148,7 +148,7 @@ public sealed class PostgresPlayerSkillProgressionStore(Npgsql.NpgsqlDataSource tx); upsert.Parameters.AddWithValue("pid", norm); upsert.Parameters.AddWithValue("sid", sid); - upsert.Parameters.AddWithValue("xp", xp); + upsert.Parameters.AddWithValue(nameof(xp), xp); upsert.ExecuteNonQuery(); } @@ -211,7 +211,7 @@ public sealed class PostgresPlayerSkillProgressionStore(Npgsql.NpgsqlDataSource tx); upsert.Parameters.AddWithValue("pid", norm); upsert.Parameters.AddWithValue("sid", sid); - upsert.Parameters.AddWithValue("xp", xp); + upsert.Parameters.AddWithValue(nameof(xp), xp); upsert.ExecuteNonQuery(); } } diff --git a/server/NeonSprawl.Server/Game/Skills/PostgresSkillProgressionBootstrap.cs b/server/NeonSprawl.Server/Game/Skills/PostgresSkillProgressionBootstrap.cs index 3753a37..443d387 100644 --- a/server/NeonSprawl.Server/Game/Skills/PostgresSkillProgressionBootstrap.cs +++ b/server/NeonSprawl.Server/Game/Skills/PostgresSkillProgressionBootstrap.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Skills/SkillCatalogServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Skills/SkillCatalogServiceCollectionExtensions.cs index dcf4d15..a9d9656 100644 --- a/server/NeonSprawl.Server/Game/Skills/SkillCatalogServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Skills/SkillCatalogServiceCollectionExtensions.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; namespace NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Skills/SkillDefinitionCatalog.cs b/server/NeonSprawl.Server/Game/Skills/SkillDefinitionCatalog.cs index 0b0f21a..91db3b1 100644 --- a/server/NeonSprawl.Server/Game/Skills/SkillDefinitionCatalog.cs +++ b/server/NeonSprawl.Server/Game/Skills/SkillDefinitionCatalog.cs @@ -3,25 +3,19 @@ using System.Collections.ObjectModel; namespace NeonSprawl.Server.Game.Skills; /// In-memory skill catalog loaded at startup (NEO-34). Game code should prefer for lookups (NEO-35). -public sealed class SkillDefinitionCatalog +public sealed class SkillDefinitionCatalog( + string skillsDirectory, + IReadOnlyDictionary byId, + int catalogJsonFileCount) { - public SkillDefinitionCatalog( - string skillsDirectory, - IReadOnlyDictionary byId, - int catalogJsonFileCount) - { - SkillsDirectory = skillsDirectory; - ById = new ReadOnlyDictionary(new Dictionary(byId, StringComparer.Ordinal)); - CatalogJsonFileCount = catalogJsonFileCount; - } - /// Absolute path to the directory that was enumerated for *_skills.json catalogs. - public string SkillsDirectory { get; } + public string SkillsDirectory { get; } = skillsDirectory; - public IReadOnlyDictionary ById { get; } + public IReadOnlyDictionary ById { get; } = + new ReadOnlyDictionary(new Dictionary(byId, StringComparer.Ordinal)); public int DistinctSkillCount => ById.Count; /// Number of *_skills.json files under . - public int CatalogJsonFileCount { get; } + public int CatalogJsonFileCount { get; } = catalogJsonFileCount; } diff --git a/server/NeonSprawl.Server/Game/Skills/SkillDefinitionCatalogLoader.cs b/server/NeonSprawl.Server/Game/Skills/SkillDefinitionCatalogLoader.cs index 0e655f6..aebef35 100644 --- a/server/NeonSprawl.Server/Game/Skills/SkillDefinitionCatalogLoader.cs +++ b/server/NeonSprawl.Server/Game/Skills/SkillDefinitionCatalogLoader.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using Json.Schema; -using Microsoft.Extensions.Logging; namespace NeonSprawl.Server.Game.Skills; @@ -111,11 +110,14 @@ public static class SkillDefinitionCatalogLoader ThrowIfAny(errors); } - logger.LogInformation( - "Loaded skill catalog from {SkillsDirectory}: {SkillCount} skill(s) across {CatalogFileCount} JSON catalog file(s).", - skillsDirectory, - rows.Count, - jsonFiles.Length); + if (logger.IsEnabled(LogLevel.Information)) + { + logger.LogInformation( + "Loaded skill catalog from {SkillsDirectory}: {SkillCount} skill(s) across {CatalogFileCount} JSON catalog file(s).", + skillsDirectory, + rows.Count, + jsonFiles.Length); + } return new SkillDefinitionCatalog(skillsDirectory, rows, jsonFiles.Length); } diff --git a/server/NeonSprawl.Server/Game/Skills/SkillProgressionGrantApplyOutcome.cs b/server/NeonSprawl.Server/Game/Skills/SkillProgressionGrantApplyOutcome.cs index 107be9d..77a5728 100644 --- a/server/NeonSprawl.Server/Game/Skills/SkillProgressionGrantApplyOutcome.cs +++ b/server/NeonSprawl.Server/Game/Skills/SkillProgressionGrantApplyOutcome.cs @@ -13,7 +13,10 @@ public enum SkillProgressionGrantApplyKind Granted, } -/// Deny or success JSON envelope; null only when is . +/// +/// Outcome of apply step (NEO-38 / NEO-41 shared path). +/// is deny or success JSON envelope; null only when is . +/// public readonly record struct SkillProgressionGrantApplyOutcome( SkillProgressionGrantApplyKind Kind, SkillProgressionGrantResponse? Response); diff --git a/server/NeonSprawl.Server/Game/Skills/SkillProgressionGrantDtos.cs b/server/NeonSprawl.Server/Game/Skills/SkillProgressionGrantDtos.cs index b853314..b70eb29 100644 --- a/server/NeonSprawl.Server/Game/Skills/SkillProgressionGrantDtos.cs +++ b/server/NeonSprawl.Server/Game/Skills/SkillProgressionGrantDtos.cs @@ -16,6 +16,7 @@ public sealed class SkillProgressionGrantRequest [JsonPropertyName("amount")] public int Amount { get; init; } + /// XP grant source kind (e.g. activity, mission_reward). /// Validated against target skill's allowedXpSourceKinds (ordinal ignore-case). [JsonPropertyName("sourceKind")] public required string SourceKind { get; init; } @@ -32,6 +33,7 @@ public sealed class SkillProgressionGrantResponse [JsonPropertyName("granted")] public bool Granted { get; init; } + /// Stable snake_case deny code when is false. /// Set when is false; stable snake_case values (see README). [JsonPropertyName("reasonCode")] public string? ReasonCode { get; init; } @@ -39,6 +41,7 @@ public sealed class SkillProgressionGrantResponse [JsonPropertyName("progression")] public required SkillProgressionSnapshotResponse Progression { get; init; } + /// Level-up rows for skills that crossed a boundary on this grant. /// Present on success only; empty array when XP changed but level did not. [JsonPropertyName("levelUps")] public required IReadOnlyList LevelUps { get; init; } diff --git a/server/NeonSprawl.Server/Game/Skills/SkillProgressionServiceCollectionExtensions.cs b/server/NeonSprawl.Server/Game/Skills/SkillProgressionServiceCollectionExtensions.cs index b5fb9e1..1aef05d 100644 --- a/server/NeonSprawl.Server/Game/Skills/SkillProgressionServiceCollectionExtensions.cs +++ b/server/NeonSprawl.Server/Game/Skills/SkillProgressionServiceCollectionExtensions.cs @@ -1,5 +1,4 @@ using NeonSprawl.Server.Game.PositionState; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; namespace NeonSprawl.Server.Game.Skills; diff --git a/server/NeonSprawl.Server/Game/Skills/SkillProgressionSnapshotApi.cs b/server/NeonSprawl.Server/Game/Skills/SkillProgressionSnapshotApi.cs index 09c607b..fbc494a 100644 --- a/server/NeonSprawl.Server/Game/Skills/SkillProgressionSnapshotApi.cs +++ b/server/NeonSprawl.Server/Game/Skills/SkillProgressionSnapshotApi.cs @@ -8,6 +8,7 @@ namespace NeonSprawl.Server.Game.Skills; /// public static class SkillProgressionSnapshotApi { + /// Stable deny reason codes for progression grants. /// public const string ReasonUnknownSkill = "unknown_skill"; @@ -58,9 +59,9 @@ public static class SkillProgressionSnapshotApi return outcome.Kind switch { - SkillProgressionGrantApplyKind.Denied => Results.Json(outcome.Response!), + SkillProgressionGrantApplyKind.Denied => Results.Json(outcome.Response), SkillProgressionGrantApplyKind.ProgressionStoreMissing => Results.NotFound(), - SkillProgressionGrantApplyKind.Granted => Results.Json(outcome.Response!), + SkillProgressionGrantApplyKind.Granted => Results.Json(outcome.Response), _ => throw new InvalidOperationException($"Unexpected grant outcome: {outcome.Kind}"), }; }); diff --git a/server/NeonSprawl.Server/Game/Targeting/InMemoryPlayerTargetLockStore.cs b/server/NeonSprawl.Server/Game/Targeting/InMemoryPlayerTargetLockStore.cs index 894de55..254611f 100644 --- a/server/NeonSprawl.Server/Game/Targeting/InMemoryPlayerTargetLockStore.cs +++ b/server/NeonSprawl.Server/Game/Targeting/InMemoryPlayerTargetLockStore.cs @@ -3,7 +3,7 @@ namespace NeonSprawl.Server.Game.Targeting; /// Thread-safe prototype lock store; player keys are trimmed with ordinal case-insensitive lookup (same spirit as position APIs). public sealed class InMemoryPlayerTargetLockStore : IPlayerTargetLockStore { - private readonly object mutex = new(); + private static readonly Lock Mutex = new(); private readonly Dictionary rows = new(StringComparer.OrdinalIgnoreCase); private readonly record struct PlayerLockRow(string? LockIdLowercase, int Sequence); @@ -16,7 +16,7 @@ public sealed class InMemoryPlayerTargetLockStore : IPlayerTargetLockStore return (null, 0); } - lock (mutex) + lock (Mutex) { return rows.TryGetValue(key, out var row) ? (row.LockIdLowercase, row.Sequence) : (null, 0); } @@ -30,7 +30,7 @@ public sealed class InMemoryPlayerTargetLockStore : IPlayerTargetLockStore return (null, 0); } - lock (mutex) + lock (Mutex) { if (!rows.TryGetValue(key, out var prev)) { @@ -58,7 +58,7 @@ public sealed class InMemoryPlayerTargetLockStore : IPlayerTargetLockStore return (null, 0); } - lock (mutex) + lock (Mutex) { var prev = rows.TryGetValue(key, out var r) ? r : new PlayerLockRow(null, 0); diff --git a/server/NeonSprawl.Server/Game/Targeting/TargetingApi.cs b/server/NeonSprawl.Server/Game/Targeting/TargetingApi.cs index 36b33e5..7ad4f0e 100644 --- a/server/NeonSprawl.Server/Game/Targeting/TargetingApi.cs +++ b/server/NeonSprawl.Server/Game/Targeting/TargetingApi.cs @@ -46,8 +46,8 @@ public static class TargetingApi // Clear intent: property omitted or JSON null. if (body.TargetId is null) { - var cleared = locks.ApplyClear(id); - var stateAfter = PlayerTargetStateReader.Build(id, cleared.LockIdLowercase, cleared.Sequence, in snap); + var (clearedLockId, clearedSeq) = locks.ApplyClear(id); + var stateAfter = PlayerTargetStateReader.Build(id, clearedLockId, clearedSeq, in snap); return Results.Json( new TargetSelectResponse { @@ -103,8 +103,8 @@ public static class TargetingApi }); } - var applied = locks.ApplySet(id, lookupKey); - var stateOk = PlayerTargetStateReader.Build(id, applied.LockIdLowercase, applied.Sequence, in effective); + var (appliedLockId, appliedSeq) = locks.ApplySet(id, lookupKey); + var stateOk = PlayerTargetStateReader.Build(id, appliedLockId, appliedSeq, in effective); return Results.Json( new TargetSelectResponse { diff --git a/server/NeonSprawl.Server/Game/World/HorizontalReach.cs b/server/NeonSprawl.Server/Game/World/HorizontalReach.cs index 9d14f3e..20bbbd6 100644 --- a/server/NeonSprawl.Server/Game/World/HorizontalReach.cs +++ b/server/NeonSprawl.Server/Game/World/HorizontalReach.cs @@ -10,7 +10,7 @@ public static class HorizontalReach { var dx = ax - bx; var dz = az - bz; - return Math.Sqrt(dx * dx + dz * dz); + return Math.Sqrt((dx * dx) + (dz * dz)); } /// true when <= radius (boundary inclusive).