mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-26 07:28:45 -07:00
fix: second pass over the 2023-client wire defects, plus a coverage harness
Fourteen agents worked one server file each over the audit's open findings,
re-verifying every claim against the client binary before changing anything.
Route+verb coverage against the recovered client inventory is now 474/522
(90.8%), up from 86.2% when the harness was first wired up.
Adds ClientRouteCoverageTests, which turns "are we compliant?" into a number
instead of an opinion. It reads data/client-routes-2023.tsv — every request the
2023-03-21 client can issue, recovered from the binary — and asserts each one
has a handler under the verb the client actually uses, separating "no handler"
from "handler exists, wrong verb" since those have different fixes. Remaining
gaps live in KnownGaps, which is expected to shrink and never grow.
Also fixes a real blind spot in EndpointContractDiscovery: it only collected
HttpMethodAttribute, so an action carrying a bare [Route] with no verb attribute
was invisible to it. The CDN's unity_assets handler is exactly that shape, which
had been showing up as a phantom gap.
Notable findings from this pass:
- The club permissions envelope key is literally "Type", not "MembershipType"
as the audit's suggested fix guessed. Read off the generated reader, then
cross-checked against the 2020 decompile — the int bitmask we were emitting
was wrong for BOTH client generations, not just 2023.
- Room-consumable purchase responses carry OperationResult as an OBJECT
{ Status, InventoryItem }; the scalar operation enum belongs in
BalanceUpdateResult. The base type OKHNOPLBOFP holds a single BGHBAILNNJJ,
which exposes exactly those two properties. A test asserting the old scalar
shape was corrected rather than the code.
- buyProgressionEventXpBoost blind-inserted an ObjectiveProgress row whose
(PlayerId, Key) is unique, so a second purchase of the same boost threw
"UNIQUE constraint failed" and 500'd AFTER taking the player's currency.
Now an upsert.
Agents were forbidden from faking fixes they could not complete in their own
file, and several correctly refused: club role permissions, club additional
image slots, announcement meta, MinLevel/ClubChatEnabled, currency purchase
offer ordering, and room-key image/currency columns all need new entities or
columns. Those are deliberately left for a single coherent schema change rather
than stubbed out here.
This commit is contained in:
@@ -21,6 +21,14 @@ public class CustomAvatarItemsController(
|
||||
IObjectStorage storage,
|
||||
ILogger<CustomAvatarItemsController> logger) : ControllerBase
|
||||
{
|
||||
/// <summary>Floor price for a publicly listed custom item. The client
|
||||
/// asks for this over the wire (<c>api/customAvatarItems/v1/minPriceForPublicItem</c>,
|
||||
/// RecNet.Runtime/MPBLNLMCEDL.txt:6893) and then enforces it locally in the
|
||||
/// designer, so the number the create/update paths clamp to and the number
|
||||
/// served on that route have to be the same constant or the client's own
|
||||
/// validation disagrees with the server's rejection.</summary>
|
||||
private const int MinPublicItemPrice = 100;
|
||||
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> List(
|
||||
@@ -529,7 +537,7 @@ public class CustomAvatarItemsController(
|
||||
|
||||
item.Name = name;
|
||||
item.Description = description;
|
||||
item.Price = Math.Max(100, req.Price ?? item.Price);
|
||||
item.Price = Math.Max(MinPublicItemPrice, req.Price ?? item.Price);
|
||||
item.ItemType = req.ItemType ?? item.ItemType;
|
||||
item.BaseAvatarItemId = req.BaseAvatarItemId ?? item.BaseAvatarItemId;
|
||||
item.Color = Trim(req.Color, 64);
|
||||
@@ -939,6 +947,30 @@ public class CustomAvatarItemsController(
|
||||
public List<Guid>? ItemIds { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>The designer's in-progress draft, as persisted to the
|
||||
/// per-player <c>caidesign_p<id>.json</c> object (see
|
||||
/// <see cref="LoadDesignAsync"/>). Mirrors the three payload properties of
|
||||
/// the client's design DTOs — the metadata object GIOBJIGEMNG carries the
|
||||
/// nullable base-item id and the "#RRGGBB" colour, and the texture arrives
|
||||
/// as the separate "design" file part whose stored blob name lands in
|
||||
/// <see cref="ImageName"/>.
|
||||
///
|
||||
/// <see cref="Deleted"/> is the tombstone: <see cref="IObjectStorage"/>
|
||||
/// exposes no delete operation, so DELETE design overwrites the record with
|
||||
/// a deleted marker and LoadDesignAsync reports it as "no saved design".
|
||||
/// Public properties with setters because the round-trip goes through
|
||||
/// System.Text.Json.</summary>
|
||||
public sealed class StoredDesign
|
||||
{
|
||||
public int? BaseAvatarItemId { get; set; }
|
||||
|
||||
public string Color { get; set; } = string.Empty;
|
||||
|
||||
public string ImageName { get; set; } = string.Empty;
|
||||
|
||||
public bool Deleted { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DesignRequest
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user