Skip to content

Refactor Item API: namespace and builder cleanup#82

Open
k073l wants to merge 8 commits into
ifBars:stablefrom
k073l:refactor/item-builders
Open

Refactor Item API: namespace and builder cleanup#82
k073l wants to merge 8 commits into
ifBars:stablefrom
k073l:refactor/item-builders

Conversation

@k073l
Copy link
Copy Markdown
Collaborator

@k073l k073l commented Jun 4, 2026

Copied existing item classes to their logical namespaces - e.g. QualityItemInstance, QualityItemDefinition and QualityItemDefinitionBuilder into Quality namespace.

Refactored builders - StorableItemDefinitionBuilderBase uses CRTP to preserve fluency of the builder, while allowing for subclassing. This approach reduces code duplication - child definitions of StorableItemDefinition no longer have to define their own .WithBasicInfo(...) and other commmon methods in their specific builders.

Original files are preserved, but marked as Obsolete for compatibility reasons and can be removed in the future release.

I also obsoleted GetItemDefinition in ItemManager, though I'm not sure if that's the best course of action. Some of the types returned from it are marked as Obsolete by this PR, so I figured it's better to make a new method that returns the new ones. Let me know if there's a better way of handling this.

  • Namespace reorganization: moved item types into logical namespaces (S1API.Items.Additive, .Buildable, .Clothing, .Quality, .Storable); legacy flat types preserved and marked [Obsolete] for backward compatibility.
  • Builder refactor: added StorableItemDefinitionBuilderBase (CRTP) to centralize common fluent APIs (.WithBasicInfo, .WithPricing, .WithRequiredRank, etc.) and remove duplication in child builders.
  • Fluent builders: new/updated builders for Additive, Buildable, Clothing, Quality, and Storable items; Build()/BuildInternal() patterns now return strongly-typed wrappers or raw framework defs as appropriate.
  • Item creator utilities: added AdditiveItemCreator, BuildableItemCreator, ClothingItemCreator, QualityItemCreator, and Storable.ItemCreator with CreateBuilder() and CloneFrom(...) helpers.
  • Wrapper types: introduced namespaced wrappers (QualityItemDefinition/Instance, ClothingItemDefinition/Instance, BuildableItemDefinition, StorableItemDefinition) exposing typed properties and CreateInstance overloads.
  • Obsoleted originals: original flat types and creators marked [Obsolete] and left in place for a future removal.
  • ItemManager/API changes: ItemManager.GetItemDefinition marked obsolete; new GetDefinition returns nullable namespaced wrappers. ItemCreator.CreateItem signature cleaned (removed requiresLevelToPurchase).
  • Validation & safety: builders’ Build() implementations now validate IDs and throw ArgumentException for missing/whitespace IDs; null/argument checks added to clone helpers.
  • Clothing builder improvements: ensures native CustomItemUI template exists with registry search/caching and emits controlled warnings for missing required modules.
  • New enums: ClothingSlot, ClothingColor, ClothingApplicationType, BuildSoundType added under appropriate namespaces.
  • Minor: small validation fix related to item ID lookup (commit: "fix(items): validate ID before lookup").
Author Lines Added Lines Removed
k073l 2,300 12

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds namespaced item APIs (Storable, Additive, Buildable, Clothing, Quality): new wrapper types, fluent builders, creator helpers, registry wiring, station-item caching and one-time warnings; marks legacy root-level types obsolete and adds ID/argument validation and ItemManager lookup migration.

Changes

Additive Item API Reorganization

Layer / File(s) Summary
Additive item definition, builder, and creator
S1API/Items/Additive/AdditiveDefinition.cs, S1API/Items/Additive/AdditiveDefinitionBuilder.cs, S1API/Items/Additive/AdditiveItemCreator.cs
New AdditiveDefinition wrapper exposes display material, quality change, yield multiplier, and instant growth; AdditiveDefinitionBuilder adds fluent WithDisplayMaterial and WithEffects, copying/cloning support and Build/BuildInternal; AdditiveItemCreator offers CreateBuilder and CloneFrom overloads with registry/type validation.
Legacy additive API deprecation
S1API/Items/AdditiveDefinition.cs, S1API/Items/AdditiveDefinitionBuilder.cs, S1API/Items/AdditiveItemCreator.cs
Old root-level additive types marked [Obsolete] with migration guidance.

Buildable Item API Reorganization

Layer / File(s) Summary
Buildable item definition, builder, and creator
S1API/Items/Buildable/BuildableItemDefinition.cs, S1API/Items/Buildable/BuildableItemDefinitionBuilder.cs, S1API/Items/Buildable/BuildableItemCreator.cs
New BuildableItemDefinition with BuildSoundType enum and mapped property; BuildableItemDefinitionBuilder with WithBuildSound, cloning, Build/BuildInternal; BuildableItemCreator offers CreateBuilder and CloneFrom overloads with validation.
Legacy buildable API deprecation and ID validation
S1API/Items/BuildableItemCreator.cs, S1API/Items/BuildableItemDefinition.cs, S1API/Items/BuildableItemDefinitionBuilder.cs
Legacy types marked [Obsolete]; legacy builder Build checks _definition.ID and throws ArgumentException when missing.

Clothing Item API Reorganization

Layer / File(s) Summary
Clothing enums and item definition
S1API/Items/Clothing/ClothingApplicationType.cs, S1API/Items/Clothing/ClothingColor.cs, S1API/Items/Clothing/ClothingSlot.cs, S1API/Items/Clothing/ClothingItemDefinition.cs
New Clothing enums and ClothingItemDefinition wrapper expose slot, application type, asset path, colorable flag, default color, and SlotsToBlock with IL2CPP/non-IL2CPP list handling.
Clothing builder with UI template caching
S1API/Items/Clothing/ClothingItemDefinitionBuilder.cs
Fluent builder with defaults, cloning, With* setters, EnsureNativeClothingItemUi() to find/cache native UI templates from registry, and a one-time, reasoned warning mechanism.
Clothing item creator and instance wrapper
S1API/Items/Clothing/ClothingItemCreator.cs, S1API/Items/Clothing/ClothingItemInstance.cs
Creator exposes CreateBuilder and CloneFrom with registry/type validation (null/whitespace guards), instance wrapper maps color and returns typed definition.
Legacy clothing API deprecation
S1API/Items/Clothing*
Root-level clothing types marked [Obsolete] and legacy builders now validate IDs before Build.

Quality Item API Reorganization

Layer / File(s) Summary
Quality item definition, builder, creator, and instance
S1API/Items/Quality/QualityItemDefinition.cs, S1API/Items/Quality/QualityItemDefinitionBuilder.cs, S1API/Items/Quality/QualityItemCreator.cs, S1API/Items/Quality/QualityItemInstance.cs
New Quality namespace types map framework EQuality ↔ Products.Quality, provide CreateInstance overloads, WithDefaultQuality on builder, Build/BuildInternal, creator helpers with cloning and validation, and instance wrapper exposing typed Quality and Definition.
Legacy quality API updates and deprecation
S1API/Items/QualityItemCreator.cs, S1API/Items/QualityItemDefinition.cs, S1API/Items/QualityItemDefinitionBuilder.cs, S1API/Items/QualityItemInstance.cs
Legacy types updated to Products.Quality, marked [Obsolete], and legacy builders now validate IDs before Build.

Storable Item API Reorganization

Layer / File(s) Summary
Storable item definition and base builder infrastructure
S1API/Items/Storable/StorableItemDefinition.cs, S1API/Items/Storable/StorableItemDefinitionBuilder.cs
New StorableItemDefinition wrapper exposes economy and availability properties (BasePurchasePrice, ResellMultiplier, IsUnlocked, RequiresLevelToPurchase, RequiredRank, HasStationItem, StationItemPrefab); generic builder base provides fluent methods for metadata, stack/icon/pricing, equippable, stored/station item handling, demo availability, and required rank.
Storable builder build lifecycle and station-item caching
S1API/Items/Storable/StorableItemDefinitionBuilder.cs
Build validates ID, synchronizes placeholder naming, registers definition, returns wrapper; station-item prefab clone/cache under a hidden DontDestroyOnLoad root with lock protection; one-time chemistry-module warning per prefab instance.
Storable item creator and concrete builder
S1API/Items/Storable/ItemCreator.cs
New Storable.ItemCreator with CreateBuilder, CloneFrom overloads with registry/type validation, CreateItem shortcut for single-call creation, and CreateEquippableBuilder.
Legacy storable API deprecation
S1API/Items/StorableItemDefinition.cs, S1API/Items/StorableItemDefinitionBuilder.cs
Old root-level storable types marked [Obsolete]; legacy builder Build adds ID validation.

Root Items API Consolidation

Layer / File(s) Summary
ItemCreator and ItemManager deprecation and consolidation
S1API/Items/ItemCreator.cs, S1API/Items/ItemManager.cs
Root ItemCreator marked [Obsolete] redirecting to Storable.ItemCreator; removed requiresLevelToPurchase param in favor of requiredRank; ItemManager.GetItemDefinition marked obsolete and new GetDefinition returns ItemDefinition? and wraps registry items into namespaced wrappers; call sites updated to use GetDefinition.

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • ifBars/S1API#79: Overlaps with Storable/Quality wrapper and RequiredRank/clone changes.

Suggested reviewers

  • ifBars

Poem

🐰 New namespaces hop from root to bed,
Builders stitch definitions thread by thread,
Cached station items nestled out of sight,
Old types marked “use new” — migration's right.
🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely summarizes the main refactoring work: reorganizing item classes into namespaces and cleaning up builders, which aligns with the substantial changes across multiple files.
Docstring Coverage ✅ Passed Docstring coverage is 92.31% which is sufficient. The required threshold is 50.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@k073l
Copy link
Copy Markdown
Collaborator Author

k073l commented Jun 4, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot added the enhancement New feature or request label Jun 4, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
S1API/Items/ItemCreator.cs (1)

110-121: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore the legacy CreateItem(... requiresLevelToPurchase ...) overload (and translate it to requiredRank).

S1API/Items/ItemCreator.cs’s obsolete CreateItem overload no longer includes requiresLevelToPurchase, and there’s no backward-compat shim overload present, so precompiled callers will fail to bind to the old method token. Also, RequiresLevelToPurchase is currently driven by requiredRank via StorableItemDefinitionBuilder.WithRequiredRank (null => false, non-null => true), so the compatibility overload must map requiresLevelToPurchase into requiredRank rather than ignoring it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@S1API/Items/ItemCreator.cs` around lines 110 - 121, Add a backward-compatible
overload for CreateItem that accepts the legacy bool requiresLevelToPurchase and
forwards to the existing CreateItem by translating that bool into the nullable
FullRank requiredRank used by the new API; implement CreateItem(..., bool
requiresLevelToPurchase, FullRank? requiredRank = null, ...) so it computes
translatedRequiredRank = requiresLevelToPurchase ? (requiredRank ??
<legacy-default-FullRank>) : null and calls the existing CreateItem(id, name,
description, category, stackLimit, basePurchasePrice, resellMultiplier,
legalStatus, translatedRequiredRank, icon, equippable); ensure you reference the
ItemCreator.CreateItem overload and use
StorableItemDefinitionBuilder.WithRequiredRank semantics (null => no
requirement, non-null => requires level).
🧹 Nitpick comments (3)
S1API/Items/Quality/QualityItemDefinitionBuilder.cs (1)

87-91: ⚡ Quick win

Wrap the method parameter in CreateWrapper instead of builder state.

Line [90] ignores the definition parameter and uses QualityDefinition. Using the passed argument avoids accidental mismatch if base build flow changes.

Proposed fix
 protected override Storable.StorableItemDefinition CreateWrapper(
     S1ItemFramework.StorableItemDefinition definition)
 {
-    return new QualityItemDefinition(QualityDefinition);
+    return new QualityItemDefinition(
+        CrossType.As<S1ItemFramework.QualityItemDefinition>(definition));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@S1API/Items/Quality/QualityItemDefinitionBuilder.cs` around lines 87 - 91,
The CreateWrapper method currently ignores its parameter and uses the builder's
QualityDefinition field; change it to use the incoming
S1ItemFramework.StorableItemDefinition parameter (`definition`) when
constructing the wrapper so the method respects the value provided by the base
build flow (i.e., call new QualityItemDefinition(definition) inside
CreateWrapper instead of referencing QualityDefinition).
S1API/Items/Additive/AdditiveDefinitionBuilder.cs (1)

129-133: ⚡ Quick win

Use the definition argument in CreateWrapper.

This override currently ignores its input and wraps the field-backed instance instead. Wrapping the provided argument keeps behavior aligned with the base contract.

Suggested diff
 protected override Storable.StorableItemDefinition CreateWrapper(
     S1ItemFramework.StorableItemDefinition definition)
 {
-    return new AdditiveDefinition(AdditiveDefinition);
+    var additiveDefinition = CrossType.As<S1ItemFramework.AdditiveDefinition>(definition);
+    return new AdditiveDefinition(additiveDefinition);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@S1API/Items/Additive/AdditiveDefinitionBuilder.cs` around lines 129 - 133,
The CreateWrapper override currently ignores its input parameter and uses the
field-backed AdditiveDefinition; update CreateWrapper to construct and return
the wrapper using the provided parameter (i.e. call the AdditiveDefinition
constructor with the method parameter `definition` rather than the field) so the
override honors the base contract and wraps the passed-in
S1ItemFramework.StorableItemDefinition.
S1API/Items/ItemManager.cs (1)

78-124: ⚡ Quick win

Use GetDefinition internally so non-obsolete APIs stop routing through legacy wrappers.

You added the new resolver here, but Line 211 and Line 258 still call GetItemDefinition. That keeps UnregisterItem/GetAllItemDefinitions on the deprecated path and returns legacy wrapper types from a non-obsolete API surface.

Targeted follow-up diff
-            ItemDefinition definition = GetItemDefinition(itemID);
+            ItemDefinition? definition = GetDefinition(itemID);
             if (definition == null)
             {
                 return false;
             }

             RemoveFromRuntimeCleanupQueue(definition.S1ItemDefinition, definition.ID);
             S1Registry.Instance.RemoveFromRegistry(definition.S1ItemDefinition);
-            return GetItemDefinition(itemID) == null;
+            return GetDefinition(itemID) == null;
...
-                var wrappedItem = GetItemDefinition(itemId);
+                var wrappedItem = GetDefinition(itemId);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@S1API/Items/ItemManager.cs` around lines 78 - 124, GetDefinition was
introduced to return the new item-definition types but some callers
(specifically UnregisterItem and GetAllItemDefinitions) still call the legacy
GetItemDefinition, causing deprecated wrappers to be returned; update those
callers to call GetDefinition instead so UnregisterItem and
GetAllItemDefinitions (and any other places at the noted call sites) use the new
resolver and return the non-obsolete types, ensuring you replace uses of
GetItemDefinition with GetDefinition in the methods that currently route through
the legacy path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@S1API/Items/Additive/AdditiveDefinitionBuilder.cs`:
- Around line 84-95: In WithEffects (AdditiveDefinitionBuilder.WithEffects)
clamp the instantGrowth argument to the documented 0..1 range before persisting
it: compute a clampedInstant = MathF.Clamp(instantGrowth, 0f, 1f) (or Math.Clamp
if preferred) and pass clampedInstant into AutoPropertySetter.TrySet for
AdditiveDefinition.InstantGrowth; leave the existing warning/log behavior
unchanged and only change the value being set.

In `@S1API/Items/Additive/AdditiveItemCreator.cs`:
- Around line 34-39: In CloneFrom(string sourceItemId) validate sourceItemId for
null or whitespace before calling S1Registry.GetItem: if
string.IsNullOrWhiteSpace(sourceItemId) throw new
ArgumentException("sourceItemId must be provided", nameof(sourceItemId)); then
proceed to call S1Registry.GetItem and keep the existing not-found
ArgumentException; this ensures CloneFrom returns a deterministic argument error
for bad input and still throws the existing error when the registry lookup
fails.

In `@S1API/Items/Buildable/BuildableItemCreator.cs`:
- Around line 87-88: Update the example to use the new namespaced lookup API:
replace the call to ItemManager.GetItemDefinition(...) with
ItemManager.GetDefinition(...), so the sample that shows var originalRack =
ItemManager.GetItemDefinition("StorageRack-1x0.5") as BuildableItemDefinition
uses ItemManager.GetDefinition("StorageRack-1x0.5") instead; ensure the rest of
the example still references BuildableItemCreator.CloneFrom and casts to
S1API.Items.Buildable.BuildableItemDefinition (or uses a safe null check) to
avoid failed casts/nulls.

In `@S1API/Items/Buildable/BuildableItemDefinitionBuilder.cs`:
- Around line 59-61: The WithBuildSound method is using the legacy
Items.BuildSoundType; change its parameter to the new namespaced enum
S1API.Items.Buildable.BuildSoundType in the
BuildableItemDefinitionBuilder.WithBuildSound signature and update the cast
inside the method to cast from S1API.Items.Buildable.BuildSoundType to
S1ItemFramework.BuildableItemDefinition.EBuildSoundType (keeping
BuildableDefinition.BuildSoundType assignment as-is) so the new builder API no
longer leaks the deprecated root enum.

In `@S1API/Items/BuildableItemDefinitionBuilder.cs`:
- Line 194: In BuildableItemDefinitionBuilder replace the nullable ID check to
reject whitespace-only strings: change the guard that checks _definition.ID from
string.IsNullOrEmpty(...) to string.IsNullOrWhiteSpace(...); also ensure the
exception type reflects invalid argument (use ArgumentException with
nameof(_definition.ID)) so whitespace-only IDs are rejected at the same check
point.

In `@S1API/Items/Clothing/ClothingItemCreator.cs`:
- Around line 60-67: In CloneFrom (ClothingItemCreator.cs) add a guard at the
start to validate sourceItemId (use string.IsNullOrWhiteSpace) and fail early:
if the input is null/empty/whitespace, log a clear error via Logger.Error
mentioning the invalid sourceItemId and return null before calling
S1.Registry.GetItem; keep the existing behavior for registry-miss unchanged.

In `@S1API/Items/Clothing/ClothingItemDefinitionBuilder.cs`:
- Around line 156-169: The public API for WithBlockedSlots currently accepts
Clothing.ClothingColor[] but immediately casts to S1Clothing.EClothingSlot;
change the parameter to accept the correct slot type (e.g., ClothingSlot[] or
the internal S1Clothing.EClothingSlot array type you want exposed) so callers
use the intended slot enum, and update both branches that assign
ClothingDefinition.SlotsToBlock (the IL2CPPMELON branch creating
Il2CppCollections.List<S1Clothing.EClothingSlot> and the non-IL2CPPMELON branch
creating List<S1Clothing.EClothingSlot>) to add items from the new parameter
without mismatched casts; ensure method signature WithBlockedSlots(...) and any
casting code that adds to ClothingDefinition.SlotsToBlock are updated
consistently.

In `@S1API/Items/ClothingItemDefinitionBuilder.cs`:
- Line 242: The current validation in ClothingItemDefinitionBuilder checks only
for null or empty ID using string.IsNullOrEmpty(_definition.ID); update this to
reject whitespace-only IDs by using string.IsNullOrWhiteSpace and throw an
ArgumentException (not ArgumentNullException) when the ID is
null/empty/whitespace; locate the check around the _definition.ID validation and
replace the condition and exception accordingly so invalid whitespace IDs are
rejected.

In `@S1API/Items/Quality/QualityItemCreator.cs`:
- Around line 35-41: In CloneFrom, validate the sourceItemId parameter for null
or whitespace before calling S1Registry.GetItem: check
string.IsNullOrWhiteSpace(sourceItemId) and throw an ArgumentException (or
ArgumentNullException) referencing nameof(sourceItemId) if invalid, then proceed
to call S1Registry.GetItem(sourceItemId) and keep the existing not-found
exception behavior for when the registry returns null.

In `@S1API/Items/QualityItemDefinitionBuilder.cs`:
- Line 278: The current check in QualityItemDefinitionBuilder that does "if
(string.IsNullOrEmpty(_definition.ID)) throw new
ArgumentNullException(nameof(_definition.ID));" conflates null and empty; update
the validation in the builder (where _definition.ID is validated) to first test
for null and throw ArgumentNullException(nameof(_definition.ID)) and then test
for empty (e.g., _definition.ID == string.Empty or _definition.ID.Length == 0)
and throw new ArgumentException("ID cannot be empty", nameof(_definition.ID));
so callers can distinguish null vs. present-but-empty IDs.

In `@S1API/Items/Storable/StorableItemDefinitionBuilder.cs`:
- Around line 373-394: The Build() method in StorableItemDefinitionBuilder
validates Definition.ID but throws ArgumentNullException with Definition.ID
(which may be null/empty); change this to throw an InvalidOperationException
instead with a clear message (e.g., "Cannot build item definition: ID is
required.") while keeping the existing Logger.Error call; update the exception
construction in Build() (and any similar validation in the class) to use
InvalidOperationException and include a descriptive message rather than passing
Definition.ID as the parameter name.

---

Outside diff comments:
In `@S1API/Items/ItemCreator.cs`:
- Around line 110-121: Add a backward-compatible overload for CreateItem that
accepts the legacy bool requiresLevelToPurchase and forwards to the existing
CreateItem by translating that bool into the nullable FullRank requiredRank used
by the new API; implement CreateItem(..., bool requiresLevelToPurchase,
FullRank? requiredRank = null, ...) so it computes translatedRequiredRank =
requiresLevelToPurchase ? (requiredRank ?? <legacy-default-FullRank>) : null and
calls the existing CreateItem(id, name, description, category, stackLimit,
basePurchasePrice, resellMultiplier, legalStatus, translatedRequiredRank, icon,
equippable); ensure you reference the ItemCreator.CreateItem overload and use
StorableItemDefinitionBuilder.WithRequiredRank semantics (null => no
requirement, non-null => requires level).

---

Nitpick comments:
In `@S1API/Items/Additive/AdditiveDefinitionBuilder.cs`:
- Around line 129-133: The CreateWrapper override currently ignores its input
parameter and uses the field-backed AdditiveDefinition; update CreateWrapper to
construct and return the wrapper using the provided parameter (i.e. call the
AdditiveDefinition constructor with the method parameter `definition` rather
than the field) so the override honors the base contract and wraps the passed-in
S1ItemFramework.StorableItemDefinition.

In `@S1API/Items/ItemManager.cs`:
- Around line 78-124: GetDefinition was introduced to return the new
item-definition types but some callers (specifically UnregisterItem and
GetAllItemDefinitions) still call the legacy GetItemDefinition, causing
deprecated wrappers to be returned; update those callers to call GetDefinition
instead so UnregisterItem and GetAllItemDefinitions (and any other places at the
noted call sites) use the new resolver and return the non-obsolete types,
ensuring you replace uses of GetItemDefinition with GetDefinition in the methods
that currently route through the legacy path.

In `@S1API/Items/Quality/QualityItemDefinitionBuilder.cs`:
- Around line 87-91: The CreateWrapper method currently ignores its parameter
and uses the builder's QualityDefinition field; change it to use the incoming
S1ItemFramework.StorableItemDefinition parameter (`definition`) when
constructing the wrapper so the method respects the value provided by the base
build flow (i.e., call new QualityItemDefinition(definition) inside
CreateWrapper instead of referencing QualityDefinition).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2d1f6f12-da60-4ca7-b523-f590521b1174

📥 Commits

Reviewing files that changed from the base of the PR and between f6dfcfc and 477f459.

📒 Files selected for processing (41)
  • S1API/Items/Additive/AdditiveDefinition.cs
  • S1API/Items/Additive/AdditiveDefinitionBuilder.cs
  • S1API/Items/Additive/AdditiveItemCreator.cs
  • S1API/Items/AdditiveDefinition.cs
  • S1API/Items/AdditiveDefinitionBuilder.cs
  • S1API/Items/AdditiveItemCreator.cs
  • S1API/Items/Buildable/BuildableItemCreator.cs
  • S1API/Items/Buildable/BuildableItemDefinition.cs
  • S1API/Items/Buildable/BuildableItemDefinitionBuilder.cs
  • S1API/Items/BuildableItemCreator.cs
  • S1API/Items/BuildableItemDefinition.cs
  • S1API/Items/BuildableItemDefinitionBuilder.cs
  • S1API/Items/Clothing/ClothingApplicationType.cs
  • S1API/Items/Clothing/ClothingColor.cs
  • S1API/Items/Clothing/ClothingItemCreator.cs
  • S1API/Items/Clothing/ClothingItemDefinition.cs
  • S1API/Items/Clothing/ClothingItemDefinitionBuilder.cs
  • S1API/Items/Clothing/ClothingItemInstance.cs
  • S1API/Items/Clothing/ClothingSlot.cs
  • S1API/Items/ClothingApplicationType.cs
  • S1API/Items/ClothingColor.cs
  • S1API/Items/ClothingItemCreator.cs
  • S1API/Items/ClothingItemDefinition.cs
  • S1API/Items/ClothingItemDefinitionBuilder.cs
  • S1API/Items/ClothingItemInstance.cs
  • S1API/Items/ClothingSlot.cs
  • S1API/Items/ItemCreator.cs
  • S1API/Items/ItemManager.cs
  • S1API/Items/Quality/QualityItemCreator.cs
  • S1API/Items/Quality/QualityItemDefinition.cs
  • S1API/Items/Quality/QualityItemDefinitionBuilder.cs
  • S1API/Items/Quality/QualityItemInstance.cs
  • S1API/Items/QualityItemCreator.cs
  • S1API/Items/QualityItemDefinition.cs
  • S1API/Items/QualityItemDefinitionBuilder.cs
  • S1API/Items/QualityItemInstance.cs
  • S1API/Items/Storable/ItemCreator.cs
  • S1API/Items/Storable/StorableItemDefinition.cs
  • S1API/Items/Storable/StorableItemDefinitionBuilder.cs
  • S1API/Items/StorableItemDefinition.cs
  • S1API/Items/StorableItemDefinitionBuilder.cs

Comment thread S1API/Items/Additive/AdditiveDefinitionBuilder.cs
Comment thread S1API/Items/Additive/AdditiveItemCreator.cs
Comment thread S1API/Items/Buildable/BuildableItemCreator.cs Outdated
Comment thread S1API/Items/Buildable/BuildableItemDefinitionBuilder.cs Outdated
Comment thread S1API/Items/BuildableItemDefinitionBuilder.cs Outdated
Comment on lines +156 to +169
public ClothingItemDefinitionBuilder WithBlockedSlots(params Clothing.ClothingColor[] slots)
{
#if (IL2CPPMELON)
ClothingDefinition.SlotsToBlock = new Il2CppCollections.List<S1Clothing.EClothingSlot>();
foreach (var slot in slots)
{
ClothingDefinition.SlotsToBlock.Add((S1Clothing.EClothingSlot)slot);
}
#else
ClothingDefinition.SlotsToBlock = new List<S1Clothing.EClothingSlot>();
foreach (var slot in slots)
{
ClothingDefinition.SlotsToBlock.Add((S1Clothing.EClothingSlot)slot);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use ClothingSlot in WithBlockedSlots API.

Line 156 takes Clothing.ClothingColor[], but Lines 162/168 cast to EClothingSlot. This exposes the wrong public contract and makes normal slot usage awkward/error-prone.

Proposed fix
-        public ClothingItemDefinitionBuilder WithBlockedSlots(params Clothing.ClothingColor[] slots)
+        public ClothingItemDefinitionBuilder WithBlockedSlots(params Clothing.ClothingSlot[] slots)
         {
 `#if` (IL2CPPMELON)
             ClothingDefinition.SlotsToBlock = new Il2CppCollections.List<S1Clothing.EClothingSlot>();
             foreach (var slot in slots)
             {
                 ClothingDefinition.SlotsToBlock.Add((S1Clothing.EClothingSlot)slot);
             }
 `#else`
             ClothingDefinition.SlotsToBlock = new List<S1Clothing.EClothingSlot>();
             foreach (var slot in slots)
             {
                 ClothingDefinition.SlotsToBlock.Add((S1Clothing.EClothingSlot)slot);
             }
 `#endif`
             return this;
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public ClothingItemDefinitionBuilder WithBlockedSlots(params Clothing.ClothingColor[] slots)
{
#if (IL2CPPMELON)
ClothingDefinition.SlotsToBlock = new Il2CppCollections.List<S1Clothing.EClothingSlot>();
foreach (var slot in slots)
{
ClothingDefinition.SlotsToBlock.Add((S1Clothing.EClothingSlot)slot);
}
#else
ClothingDefinition.SlotsToBlock = new List<S1Clothing.EClothingSlot>();
foreach (var slot in slots)
{
ClothingDefinition.SlotsToBlock.Add((S1Clothing.EClothingSlot)slot);
}
public ClothingItemDefinitionBuilder WithBlockedSlots(params Clothing.ClothingSlot[] slots)
{
`#if` (IL2CPPMELON)
ClothingDefinition.SlotsToBlock = new Il2CppCollections.List<S1Clothing.EClothingSlot>();
foreach (var slot in slots)
{
ClothingDefinition.SlotsToBlock.Add((S1Clothing.EClothingSlot)slot);
}
`#else`
ClothingDefinition.SlotsToBlock = new List<S1Clothing.EClothingSlot>();
foreach (var slot in slots)
{
ClothingDefinition.SlotsToBlock.Add((S1Clothing.EClothingSlot)slot);
}
`#endif`
return this;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@S1API/Items/Clothing/ClothingItemDefinitionBuilder.cs` around lines 156 -
169, The public API for WithBlockedSlots currently accepts
Clothing.ClothingColor[] but immediately casts to S1Clothing.EClothingSlot;
change the parameter to accept the correct slot type (e.g., ClothingSlot[] or
the internal S1Clothing.EClothingSlot array type you want exposed) so callers
use the intended slot enum, and update both branches that assign
ClothingDefinition.SlotsToBlock (the IL2CPPMELON branch creating
Il2CppCollections.List<S1Clothing.EClothingSlot> and the non-IL2CPPMELON branch
creating List<S1Clothing.EClothingSlot>) to add items from the new parameter
without mismatched casts; ensure method signature WithBlockedSlots(...) and any
casting code that adds to ClothingDefinition.SlotsToBlock are updated
consistently.

Comment thread S1API/Items/ClothingItemDefinitionBuilder.cs Outdated
Comment thread S1API/Items/Quality/QualityItemCreator.cs
/// <returns>A wrapper around the created storable item definition.</returns>
public QualityItemDefinition Build()
{
if (string.IsNullOrEmpty(_definition.ID)) throw new ArgumentNullException(nameof(_definition.ID));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the correct exception type for empty IDs.

Line [278] throws ArgumentNullException for both null and empty. Empty should throw ArgumentException so callers can distinguish invalid-but-present values.

Proposed fix
- if (string.IsNullOrEmpty(_definition.ID)) throw new ArgumentNullException(nameof(_definition.ID));
+ if (_definition.ID == null)
+     throw new ArgumentNullException(nameof(_definition.ID));
+ if (_definition.ID.Length == 0)
+     throw new ArgumentException("Item ID cannot be empty.", nameof(_definition.ID));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@S1API/Items/QualityItemDefinitionBuilder.cs` at line 278, The current check
in QualityItemDefinitionBuilder that does "if
(string.IsNullOrEmpty(_definition.ID)) throw new
ArgumentNullException(nameof(_definition.ID));" conflates null and empty; update
the validation in the builder (where _definition.ID is validated) to first test
for null and throw ArgumentNullException(nameof(_definition.ID)) and then test
for empty (e.g., _definition.ID == string.Empty or _definition.ID.Length == 0)
and throw new ArgumentException("ID cannot be empty", nameof(_definition.ID));
so callers can distinguish null vs. present-but-empty IDs.

Comment thread S1API/Items/Storable/StorableItemDefinitionBuilder.cs
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@S1API/Items/ItemManager.cs`:
- Line 258: GetAllItemDefinitions() currently routes through GetDefinition which
returns namespaced wrapper types and breaks callers that expect legacy root
wrapper types; restore the legacy contract by having GetAllItemDefinitions()
call the legacy wrapper method GetItemDefinition (or iterate and call
GetItemDefinition for each id) so its results remain the old root wrapper type,
or alternatively mark GetAllItemDefinitions() [Obsolete] and introduce a new
method (e.g., GetAllNamespacedItemDefinitions) that delegates to GetDefinition;
update callers/tests accordingly and ensure method signatures and return types
match the legacy root wrapper type to avoid runtime downcast failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 321a214a-d1b0-40f9-87eb-0048130dfa40

📥 Commits

Reviewing files that changed from the base of the PR and between 477f459 and 2b3efd0.

📒 Files selected for processing (13)
  • S1API/Items/Additive/AdditiveDefinitionBuilder.cs
  • S1API/Items/Additive/AdditiveItemCreator.cs
  • S1API/Items/Buildable/BuildableItemCreator.cs
  • S1API/Items/Buildable/BuildableItemDefinitionBuilder.cs
  • S1API/Items/BuildableItemDefinitionBuilder.cs
  • S1API/Items/Clothing/ClothingItemCreator.cs
  • S1API/Items/ClothingItemDefinitionBuilder.cs
  • S1API/Items/ItemManager.cs
  • S1API/Items/Quality/QualityItemCreator.cs
  • S1API/Items/QualityItemDefinitionBuilder.cs
  • S1API/Items/Storable/ItemCreator.cs
  • S1API/Items/Storable/StorableItemDefinitionBuilder.cs
  • S1API/Items/StorableItemDefinitionBuilder.cs
🚧 Files skipped from review as they are similar to previous changes (8)
  • S1API/Items/StorableItemDefinitionBuilder.cs
  • S1API/Items/Buildable/BuildableItemDefinitionBuilder.cs
  • S1API/Items/Quality/QualityItemCreator.cs
  • S1API/Items/Additive/AdditiveItemCreator.cs
  • S1API/Items/Clothing/ClothingItemCreator.cs
  • S1API/Items/Storable/ItemCreator.cs
  • S1API/Items/Buildable/BuildableItemCreator.cs
  • S1API/Items/Storable/StorableItemDefinitionBuilder.cs


// Use GetItemDefinition to properly wrap the item with the correct type
var wrappedItem = GetItemDefinition(itemId);
var wrappedItem = GetDefinition(itemId);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve GetAllItemDefinitions() legacy wrapper contract.

GetAllItemDefinitions() is still non-obsolete, but it now routes through GetDefinition, which returns namespaced wrapper types. Existing consumers that downcast results to legacy root wrapper types can break at runtime. Keep this method on legacy wrapping (GetItemDefinition) or mark it obsolete and introduce a new method for namespaced wrappers.

Proposed minimal compatibility fix
-                // Use GetItemDefinition to properly wrap the item with the correct type
-                var wrappedItem = GetDefinition(itemId);
+                // Keep legacy contract for this non-obsolete API.
+#pragma warning disable CS0618
+                var wrappedItem = GetItemDefinition(itemId);
+#pragma warning restore CS0618
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@S1API/Items/ItemManager.cs` at line 258, GetAllItemDefinitions() currently
routes through GetDefinition which returns namespaced wrapper types and breaks
callers that expect legacy root wrapper types; restore the legacy contract by
having GetAllItemDefinitions() call the legacy wrapper method GetItemDefinition
(or iterate and call GetItemDefinition for each id) so its results remain the
old root wrapper type, or alternatively mark GetAllItemDefinitions() [Obsolete]
and introduce a new method (e.g., GetAllNamespacedItemDefinitions) that
delegates to GetDefinition; update callers/tests accordingly and ensure method
signatures and return types match the legacy root wrapper type to avoid runtime
downcast failures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant