NEO-149: fix CraftResult and craft API analyzer warnings
Move CraftResult param docs to primary-constructor summaries (RCS1263), use CraftIoAppliedJson[] return and collection expression in MapIoRows, prefer is true for debug log guard (CDT1001), and add MapResponse deny test.pull/190/head
parent
6f735f8643
commit
eb6a4fedde
|
|
@ -5,7 +5,7 @@ meta {
|
||||||
}
|
}
|
||||||
|
|
||||||
docs {
|
docs {
|
||||||
NEO-70 prototype spine: accumulate >=11 scrap_metal_bulk (gather when nodes allow, reuse persisted inventory after dotnet test), refine_scrap_efficient when refined_plate_stock < 2, then make_field_stim_mk0. NEO-118: best-effort quest objective wiring on craft success (active craft_recipe quests). No inventory POST shortcuts for spine materials.
|
NEO-70 prototype spine: accumulate >=11 scrap_metal_bulk (gather when nodes allow, reuse persisted inventory after dotnet test), refine_scrap_efficient when refined_plate_stock < 2, then make_field_stim_mk0. NEO-118: best-effort quest objective wiring on craft success (active craft_recipe quests). Deny envelopes return empty inputsConsumed/outputsGranted arrays. No inventory POST shortcuts for spine materials.
|
||||||
}
|
}
|
||||||
|
|
||||||
script:pre-request {
|
script:pre-request {
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,28 @@ public sealed class PlayerCraftApiTests
|
||||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MapResponse_ShouldReturnEmptyIoArrays_WhenCraftDenied()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var result = new CraftResult(
|
||||||
|
Success: false,
|
||||||
|
ReasonCode: CraftReasonCodes.UnknownRecipe,
|
||||||
|
InputsConsumed: [],
|
||||||
|
OutputsGranted: [],
|
||||||
|
XpGrantSummary: null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = PlayerCraftApi.MapResponse(result);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(response.Success);
|
||||||
|
Assert.Equal(CraftReasonCodes.UnknownRecipe, response.ReasonCode);
|
||||||
|
Assert.Empty(response.InputsConsumed);
|
||||||
|
Assert.Empty(response.OutputsGranted);
|
||||||
|
Assert.Null(response.XpGrantSummary);
|
||||||
|
}
|
||||||
|
|
||||||
private static void SeedStack(InMemoryWebApplicationFactory factory, string itemId, int quantity)
|
private static void SeedStack(InMemoryWebApplicationFactory factory, string itemId, int quantity)
|
||||||
{
|
{
|
||||||
var itemRegistry = factory.Services.GetRequiredService<IItemDefinitionRegistry>();
|
var itemRegistry = factory.Services.GetRequiredService<IItemDefinitionRegistry>();
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ namespace NeonSprawl.Server.Game.Crafting;
|
||||||
/// Server-internal craft resolution envelope (NEO-69); promoted to wire JSON via <see cref="CraftResponse"/> (NEO-70).
|
/// Server-internal craft resolution envelope (NEO-69); promoted to wire JSON via <see cref="CraftResponse"/> (NEO-70).
|
||||||
/// NEO-71 telemetry hook sites live in <see cref="CraftOperations.TryCraft"/> (success path + centralized <c>Deny</c> helper).
|
/// NEO-71 telemetry hook sites live in <see cref="CraftOperations.TryCraft"/> (success path + centralized <c>Deny</c> helper).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="InputsConsumed">Scaled inputs removed on success; empty when denied.</param>
|
|
||||||
/// <param name="OutputsGranted">Scaled outputs added on success; empty when denied.</param>
|
|
||||||
/// <param name="XpGrantSummary">Refine skill XP applied on success; null when denied.</param>
|
|
||||||
public readonly record struct CraftResult(
|
public readonly record struct CraftResult(
|
||||||
bool Success,
|
bool Success,
|
||||||
string? ReasonCode,
|
string? ReasonCode,
|
||||||
|
/// <summary>Scaled inputs removed on success; empty when denied.</summary>
|
||||||
IReadOnlyList<CraftIoApplied> InputsConsumed,
|
IReadOnlyList<CraftIoApplied> InputsConsumed,
|
||||||
|
/// <summary>Scaled outputs added on success; empty when denied.</summary>
|
||||||
IReadOnlyList<CraftIoApplied> OutputsGranted,
|
IReadOnlyList<CraftIoApplied> OutputsGranted,
|
||||||
|
/// <summary>Refine skill XP applied on success; null when denied.</summary>
|
||||||
CraftXpGrantSummary? XpGrantSummary);
|
CraftXpGrantSummary? XpGrantSummary);
|
||||||
|
|
|
||||||
|
|
@ -96,11 +96,11 @@ public static class PlayerCraftApi
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IReadOnlyList<CraftIoAppliedJson> MapIoRows(IReadOnlyList<CraftIoApplied> rows)
|
private static CraftIoAppliedJson[] MapIoRows(IReadOnlyList<CraftIoApplied> rows)
|
||||||
{
|
{
|
||||||
if (rows.Count == 0)
|
if (rows.Count == 0)
|
||||||
{
|
{
|
||||||
return Array.Empty<CraftIoAppliedJson>();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
var mapped = new CraftIoAppliedJson[rows.Count];
|
var mapped = new CraftIoAppliedJson[rows.Count];
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ public static class EncounterCombatWiring
|
||||||
|
|
||||||
if (!completion.Success)
|
if (!completion.Success)
|
||||||
{
|
{
|
||||||
if (logger?.IsEnabled(LogLevel.Debug) == true)
|
if (logger?.IsEnabled(LogLevel.Debug) is true)
|
||||||
{
|
{
|
||||||
logger.LogDebug(
|
logger.LogDebug(
|
||||||
"Encounter completion grant skipped for player {PlayerId} encounter {EncounterId} ({ReasonCode})",
|
"Encounter completion grant skipped for player {PlayerId} encounter {EncounterId} ({ReasonCode})",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue