Skip to content

Inventory click refactor#489

Merged
Tides merged 11 commits into1.21.xfrom
inventory-click-refactor
Jun 29, 2025
Merged

Inventory click refactor#489
Tides merged 11 commits into1.21.xfrom
inventory-click-refactor

Conversation

@Tides
Copy link
Member

@Tides Tides commented Jun 28, 2025

Summary by CodeRabbit

  • New Features

    • Added support for hashed item stacks and component hash comparison, enabling more robust inventory validation and synchronization.
    • Introduced new click types for inventory interactions, allowing for more detailed handling of user actions.
    • Implemented new inventory click event handling logic, including support for pickup, swap, throw, quick craft, and pickup all actions.
    • Added player input tracking and asynchronous player disconnection with a reason.
  • Improvements

    • Centralized and standardized numeric argument parsing, including support for min/max value bounds.
    • Enhanced container click event data to provide more detailed context about inventory interactions.
    • Improved inventory data component storage with hash-based comparison features.
    • Updated inventory packet handling for more accurate synchronization between client and server.
  • Bug Fixes

    • Improved synchronization of inventory state by validating and correcting mismatches using hashed item stack comparisons.
  • Chores

    • Upgraded dependencies to the latest Microsoft.Extensions packages and added System.IO.Hashing.
  • Refactor

    • Simplified inventory packet handling by removing mode-specific logic in favor of hash-based validation.
    • Converted several classes and interfaces to records and partial classes for consistency and maintainability.
  • Removals

    • Removed obsolete slot property and NBT serialization methods from item stack handling.

@github-actions github-actions bot added api Relates to Obsidian.API commands Relates to Obsidian.Commands nbt Relates to Obsidian.Nbt plugins Relates to plugins source-generation Relates to Obsidian.SourceGenerators tests Relates to Obsidian.Tests labels Jun 28, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jun 28, 2025

Walkthrough

This update introduces a generic base class for numeric argument parsers, centralizing min/max bound logic and serialization. It adds hashed item stack support with new interfaces and classes, updates inventory event and packet handling to use hashed items and new click types, and revises inventory and player interfaces for improved input and disconnection handling. Inventory click handling is refactored into a dedicated partial event handler with detailed logic per click type.

Changes

File(s) / Area Change Summary
Obsidian.API/Commands/ArgumentParsers/NumericArgumentParsers.cs Refactored all numeric argument parsers to inherit from a new generic base class with min/max bounds and serialization; introduced NumberFlags enum.
Obsidian.API/Events/ContainerClickEventArgs.cs Replaced direct Item property with computed property; added click metadata (container ID, slot, button, state, click type); updated constructor.
Obsidian.API/Inventory/DataComponents/BlockPredicatesDataComponent.cs Added WriteHashed method placeholder.
Obsidian.API/Inventory/DataComponents/ComponentBuilder.cs Updated serialization/deserialization lambdas for list components to use explicit signatures instead of method groups.
Obsidian.API/Inventory/DataComponents/DataComponentsStorage.cs Changed to record class; added hashed component storage, indexer, and hash comparison methods.
Obsidian.API/Inventory/ItemStack.cs Changed to record class; removed Slot property and all custom equality members.
Obsidian.API/_Enums/ClickType.cs Added new ClickType enum for inventory actions.
Obsidian.API/_Interfaces/IHashedItemStack.cs Added new interface for hashed item stack operations and metadata.
Obsidian.API/_Interfaces/INetStreamReader.cs Added ReadHashedItemStack method.
Obsidian.API/_Interfaces/IPlayer.cs Added Input property and DisconnectAsync method.
Obsidian/Entities/Player.Helpers.cs Removed direct setting of Slot on item during inventory load.
Obsidian/Entities/Player.cs Added Input property, overrode Sneaking, and added DisconnectAsync.
Obsidian/Events/MainEventHandler.Inventory.cs New file: Implements inventory click event handling logic for all click types including pickup, swap, throw, quick craft, and pickup all.
Obsidian/Events/MainEventHandler.cs Changed to partial class; switched container copy logic to index-based iteration.
Obsidian/HashedItemStack.cs New class: Implements IHashedItemStack, provides hash-based item comparison using CRC32 of serialized components.
Obsidian/Net/NetworkBuffer.Reading.cs Added ReadHashedItemStack method; minor formatting fixes.
Obsidian/Net/NetworkBuffer.Writing.cs Minor formatting (added blank line).
Obsidian/Net/Packets/Play/Clientbound/ContainerSetContentPacket.cs Changed constructor parameter from byte windowId to int containerId.
Obsidian/Net/Packets/Play/Serverbound/ContainerClickPacket.cs Replaced mode-specific logic with hash-based validation and event dispatch; changed to use ClickType and IHashedItemStack; removed old enum and methods.
Obsidian/Obsidian.csproj Upgraded Microsoft.Extensions.* packages; added System.IO.Hashing dependency.
Obsidian/Utilities/Extensions.Nbt.cs Removed ItemStack.ToNbt extension method.
Obsidian.API/Events/ContainerEventArgs.cs Made Container property non-required; added constructor parameter with null check.
Obsidian.API/Events/ContainerClosedEventArgs.cs Added BaseContainer parameter to constructor and base call.
Obsidian/Net/Packets/Play/Serverbound/ContainerClosePacket.cs Changed event args construction to pass container via constructor instead of property initializer.

Sequence Diagram(s)

Inventory Click Handling (New Flow)

sequenceDiagram
    participant Client
    participant Server
    participant MainEventHandler
    participant Player
    participant Container

    Client->>Server: Send ContainerClickPacket (with ClickType, HashedItems)
    Server->>MainEventHandler: OnInventoryClick(args)
    MainEventHandler->>Player: Validate carried item vs container slot (hash compare)
    alt mismatch
        MainEventHandler->>Client: Send ContainerSetSlotPacket (resync)
    else match
        MainEventHandler->>Container: Apply changes (based on ClickType)
        MainEventHandler->>Player: Update inventory/carried item
        MainEventHandler->>Client: (If needed) Send ContainerSetContentPacket
    end
Loading

Hashed Item Stack Comparison

sequenceDiagram
    participant HashedItemStack
    participant ItemStack

    HashedItemStack->>ItemStack: For each component, serialize and hash
    HashedItemStack->>HashedItemStack: Compare hashes
    alt all hashes match
        HashedItemStack-->>Caller: Return true
    else any mismatch
        HashedItemStack-->>Caller: Return false
    end
Loading

Possibly related PRs

  • ObsidianMC/Obsidian#488: Refactors argument parsers, including the introduction of a generic base class for numeric parsers and updates to parser IDs, directly relating to this PR's numeric parser changes.

Poem

A rabbit hopped through code so neat,
Numeric bounds now can't be beat!
Hashed stacks compare, events align,
Click types and packets all combine.
With input, drag, and thrown delight—
Inventory's future's looking bright!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 351c9ed and d1f6e47.

📒 Files selected for processing (4)
  • Obsidian.API/Events/ContainerClickEventArgs.cs (1 hunks)
  • Obsidian.API/Events/ContainerClosedEventArgs.cs (1 hunks)
  • Obsidian.API/Events/ContainerEventArgs.cs (1 hunks)
  • Obsidian/Net/Packets/Play/Serverbound/ContainerClosePacket.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Obsidian.API/Events/ContainerEventArgs.cs
  • Obsidian.API/Events/ContainerClickEventArgs.cs
🧰 Additional context used
🧬 Code Graph Analysis (1)
Obsidian/Net/Packets/Play/Serverbound/ContainerClosePacket.cs (1)
Obsidian.API/Events/ContainerClosedEventArgs.cs (2)
  • ContainerClosedEventArgs (2-11)
  • ContainerClosedEventArgs (6-8)
🔇 Additional comments (2)
Obsidian/Net/Packets/Play/Serverbound/ContainerClosePacket.cs (1)

15-15: ContainerClosePacket: null-forgiving operator is safe here

The check if (ContainerId == 0) return; guarantees we only reach the close logic for a window the server previously opened via OpenInventoryAsync (which sets OpenedContainer). Since OpenedContainer is only cleared once the close event fires, it cannot be null in this branch. No additional null-check is required.

Obsidian.API/Events/ContainerClosedEventArgs.cs (1)

6-8: Excellent refactor for improved type safety.

Moving the container parameter to the constructor enforces non-null initialization and prevents the container from being uninitialized. This is a solid improvement over property-based initialization.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment
  • Commit Unit Tests in branch inventory-click-refactor

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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: 20

♻️ Duplicate comments (40)
Obsidian/Assets/item_components.json (40)

2034-2037: Same concern as 1626-1629 – please confirm property support.


2131-2154: Same metadata gap as the black harness (1706-1729).


2729-2732: See earlier carpet shearing comment.


2826-2849: Same harness-metadata issue raised for black harness.


5158-5168: Same attribute-modifier duplication concern as 3297-3306.


5686-5689: See earlier carpet shearing comment.


5766-5789: Same harness-metadata issue raised for black harness.


7581-7591: Attribute-modifier ID duplication (see 3297-3306).


9548-9552: See horse-armour shearing comment (7140-7144).


9951-9954: See earlier carpet shearing comment.


10031-10054: Same harness-metadata issue raised for black harness.


10214-10217: See earlier carpet shearing comment.


10294-10317: Same harness-metadata issue raised for black harness.


11329-11333: See horse-armour shearing comment (7140-7144).


12325-12329: See horse-armour shearing comment (7140-7144).


12514-12517: See earlier carpet shearing comment.


12594-12617: Same harness-metadata issue raised for black harness.


12777-12780: See earlier carpet shearing comment.


12857-12880: Same harness-metadata issue raised for black harness.


13120-13123: See earlier carpet shearing comment.


13200-13223: Same harness-metadata issue raised for black harness.


13494-13497: See earlier carpet shearing comment.


13574-13597: Same harness-metadata issue raised for black harness.


16220-16223: See earlier carpet shearing comment.


16300-16323: Same harness-metadata issue raised for black harness.


17129-17139: Attribute-modifier ID duplication (see 3297-3306).


17267-17270: See earlier carpet shearing comment.


17347-17370: Same harness-metadata issue raised for black harness.


17535-17545: Attribute-modifier ID duplication (see 3297-3306).


18612-18615: See earlier carpet shearing comment.


18692-18715: Same harness-metadata issue raised for black harness.


19290-19293: See earlier carpet shearing comment.


19370-19393: Same harness-metadata issue raised for black harness.


20634-20644: Attribute-modifier ID duplication (see 3297-3306).


24836-24839: See earlier carpet shearing comment.


24916-24939: Same harness-metadata issue raised for black harness.


25123-25133: Attribute-modifier ID duplication (see 3297-3306).


25635-25638: See earlier carpet shearing comment.


25715-25738: Same harness-metadata issue raised for black harness.


25839-25849: Attribute-modifier ID duplication (see 3297-3306).

🧹 Nitpick comments (16)
Obsidian.API/Inventory/DataComponents/BlockPredicatesDataComponent.cs (1)

14-14: Consider documenting the incomplete implementation.

The WriteHashed method throws NotImplementedException, which could cause runtime issues if called. Consider adding documentation or a TODO comment to indicate this is a placeholder during the hashed item stack refactoring.

-    public void WriteHashed(INetStreamWriter writer) => throw new NotImplementedException();
+    // TODO: Implement hashed serialization for block predicates
+    public void WriteHashed(INetStreamWriter writer) => throw new NotImplementedException();
Obsidian/Net/Packets/Play/Serverbound/PlayerCommandPacket.cs (1)

1-1: Remove unused using directive.

The Microsoft.Extensions.Logging using directive is added but no logging calls are present in the code.

-using Microsoft.Extensions.Logging;
Obsidian/Net/Packets/Play/Serverbound/PlayerInputPacket.cs (1)

15-31: Consider thread safety for concurrent input updates.

The packet handling logic is correct, but consider potential race conditions if multiple input packets are processed concurrently for the same player.

The sneaking state change detection and broadcasting logic properly:

  • Captures the previous sneaking state
  • Updates player input
  • Broadcasts SetEntityDataPacket to other players when sneaking changes
  • Correctly excludes the player themselves using player.EntityId

Consider adding synchronization if player input can be updated concurrently:

public override ValueTask HandleAsync(IServer server, IPlayer player)
{
+    lock (player) // or use a more granular lock
+    {
        var wasSneaking = player.Sneaking;
        player.Input = this.Flags;
        
        if (player.Sneaking != wasSneaking)
        {
            player.World.PacketBroadcaster.QueuePacketToWorld(player.World, new SetEntityDataPacket
            {
                EntityId = player.EntityId,
                Entity = player
            }, player.EntityId);
        }
+    }
    
    return default;
}
Obsidian.API/Commands/ArgumentParsers/EntityArgumentParser.cs (1)

10-15: TODO implementation needed for production readiness.

The TryParseArgument method is currently stubbed and always returns false. This means entity parsing for commands like @p, @a, @e, @r selectors and entity names will not work.

Would you like me to help implement the entity parsing logic or create an issue to track this implementation?

Obsidian/Utilities/Extensions.Nbt.Chat.cs (1)

174-178: Appropriate use of NotImplementedException for incomplete features.

The explicit exceptions for unimplemented hover content types are better than silent failures. These clearly indicate areas that need implementation.

Would you like me to help implement the missing HoverItemContent and HoverEntityComponent serialization logic?

Obsidian/HashedItemStack.cs (1)

18-43: Consider dynamic buffer sizing for large components.

The implementation is solid with proper ArrayPool usage and CRC32 hashing. However, the fixed 256-byte buffer size might be insufficient for large data components.

Consider implementing dynamic buffer sizing:

-        var sharedBuffer = ArrayPool<byte>.Shared.Rent(256);
+        var bufferSize = Math.Max(256, EstimateComponentSize(type));
+        var sharedBuffer = ArrayPool<byte>.Shared.Rent(bufferSize);

Or handle buffer overflow scenarios gracefully by catching exceptions and retrying with a larger buffer.

Obsidian.API/_Types/BaseArgumentParser.cs (1)

5-5: Track TODO for async parsing support.

The TODO comment indicates that async parsing support may be needed in the future. This could be important for parsers that need to perform I/O operations (e.g., database lookups, external API calls).

Would you like me to create an issue to track the implementation of async TryParseArgument methods?

Obsidian.SourceGenerators/Registry/RegistryGenerator.cs (1)

17-18: Remove commented debugger code.

Commented debugging code should be removed before merging to production.

     public void Initialize(IncrementalGeneratorInitializationContext ctx)
     {
-        //if (!Debugger.IsAttached)
-        //    Debugger.Launch();
-
         var jsonFiles = ctx.AdditionalTextsProvider
Obsidian.API/Events/ContainerClickEventArgs.cs (1)

26-26: Consider adding validation for the required properties.

The required property pattern is implemented correctly. However, consider adding validation to ensure ClickedSlot is within valid bounds for the container size.

+private bool IsValidSlot => ClickedSlot >= 0 && ClickedSlot < Container.Size;

Also applies to: 28-31, 33-33, 35-35

Obsidian/Assets/tags.json (4)

2348-2354: Minor nit: keep tag names & contents consistent

Consider renaming either this tag or the previous one so that “dry vegetation” and “sand” are mutually exclusive, or refactor per the previous comment.
Otherwise LGTM.


3072-3081: Empty dialog tags ship as dead code

Both dialog/pause_screen_additions and dialog/quick_actions are empty arrays.
If that’s intentional, 👍. If they’re placeholders, consider omitting them to avoid bloating the tag file or add a _todo comment.


3464-3492: followable_friendly_mobs gets big – consider splitting

This tag is starting to become a kitchen-sink list (29 entries).
Long flat arrays are hard to maintain; think about factoring by behaviour (e.g. followable_friendly_mobs/land, /air, /rideable) and composing with # references.


4640-4674: Harness & tempt-item tags – good, but enforce colour ordering

Great to see the colour-complete harness list.
For future diffs, sticking to alphabetical (or dye-order) sorting reduces conflict churn, but that’s just a style hint.

Obsidian/Assets/recipes.json (1)

15488-15502: Adding a craftable saddle may break vanilla balance

Vanilla intentionally makes saddles non-craftable. Introducing this recipe alters progression and loot-table value.
If that’s intentional, gate it behind a datapack toggle or config flag; otherwise consider removing.

Obsidian/Assets/item_components.json (2)

1706-1729: Harness definition is missing core item metadata

The newly-added harness items have no minecraft:creative_category, minecraft:icon, or minecraft:render_offsets. They will not appear in creative inventory and may render incorrectly in hand.
Consider cloning the saddle definition and trimming unneeded fields instead of copying the minimal template.


3297-3306: Attribute-modifier ID re-use may stack unintentionally

"id": "minecraft:waypoint_transmit_range_hide" is re-used across multiple head items.
If two pieces are worn simultaneously (e.g., carved pumpkin + mob head via armour stand tricks) the engine may merge rather than treat them separately.
Generate per-item UUID-like IDs to be safe.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ac8459 and 09dd3ea.

📒 Files selected for processing (71)
  • Obsidian.API/Commands/ArgumentParsers/BooleanArgumentParser.cs (1 hunks)
  • Obsidian.API/Commands/ArgumentParsers/EntityArgumentParser.cs (1 hunks)
  • Obsidian.API/Commands/ArgumentParsers/LocationArgumentParser.cs (1 hunks)
  • Obsidian.API/Commands/ArgumentParsers/MinecraftTimeArgumentParser.cs (2 hunks)
  • Obsidian.API/Commands/ArgumentParsers/NumericArgumentParsers.Helpers.cs (1 hunks)
  • Obsidian.API/Commands/ArgumentParsers/NumericArgumentParsers.cs (1 hunks)
  • Obsidian.API/Commands/ArgumentParsers/PlayerArgumentParser.cs (1 hunks)
  • Obsidian.API/Commands/ArgumentParsers/StringArgumentParser.cs (1 hunks)
  • Obsidian.API/Events/ContainerClickEventArgs.cs (1 hunks)
  • Obsidian.API/Inventory/DataComponents/BlockPredicatesDataComponent.cs (1 hunks)
  • Obsidian.API/Inventory/DataComponents/ComponentBuilder.cs (2 hunks)
  • Obsidian.API/Inventory/DataComponents/DataComponentsStorage.cs (1 hunks)
  • Obsidian.API/Inventory/ItemStack.cs (1 hunks)
  • Obsidian.API/Obsidian.API.csproj (2 hunks)
  • Obsidian.API/Plugins/IPluginRegistry.cs (1 hunks)
  • Obsidian.API/_Attributes/ArgumentParserAttribute.cs (1 hunks)
  • Obsidian.API/_Enums/ClickType.cs (1 hunks)
  • Obsidian.API/_Enums/EntityType.cs (2 hunks)
  • Obsidian.API/_Enums/PlayerInput.cs (1 hunks)
  • Obsidian.API/_Enums/ProtocolVersion.cs (1 hunks)
  • Obsidian.API/_Interfaces/IHashedItemStack.cs (1 hunks)
  • Obsidian.API/_Interfaces/INetStreamReader.cs (1 hunks)
  • Obsidian.API/_Interfaces/IPlayer.cs (2 hunks)
  • Obsidian.API/_Types/BaseArgumentParser.cs (1 hunks)
  • Obsidian.API/_Types/HexColor.cs (1 hunks)
  • Obsidian.API/_Types/MinecraftTime.cs (2 hunks)
  • Obsidian.Nbt/Obsidian.Nbt.csproj (1 hunks)
  • Obsidian.Nbt/RawNbtWriter.Primitives.cs (2 hunks)
  • Obsidian.Nbt/RawNbtWriter.cs (4 hunks)
  • Obsidian.SourceGenerators/Obsidian.SourceGenerators.csproj (1 hunks)
  • Obsidian.SourceGenerators/Registry/EntityGenerator.cs (0 hunks)
  • Obsidian.SourceGenerators/Registry/Models/Assets.cs (1 hunks)
  • Obsidian.SourceGenerators/Registry/RegistryGenerator.cs (1 hunks)
  • Obsidian.Tests/Commands.cs (1 hunks)
  • Obsidian.Tests/Nbt.cs (1 hunks)
  • Obsidian/Assets/command_parsers.json (1 hunks)
  • Obsidian/Assets/item_components.json (49 hunks)
  • Obsidian/Assets/packets.json (7 hunks)
  • Obsidian/Assets/recipes.json (67 hunks)
  • Obsidian/Assets/tags.json (9 hunks)
  • Obsidian/Commands/CommandNode.cs (3 hunks)
  • Obsidian/Commands/CommandNodeType.cs (1 hunks)
  • Obsidian/Commands/Framework/CommandHandler.cs (3 hunks)
  • Obsidian/Commands/Modules/MainCommandModule.cs (2 hunks)
  • Obsidian/Commands/Parsers/CommandParser.cs (0 hunks)
  • Obsidian/Commands/Parsers/EntityCommandParser.cs (0 hunks)
  • Obsidian/Commands/Parsers/MinecraftTimeParser.cs (0 hunks)
  • Obsidian/Commands/Parsers/NumberCommandParsers.cs (0 hunks)
  • Obsidian/Commands/Parsers/StringCommandParser.cs (0 hunks)
  • Obsidian/Entities/Entity.cs (2 hunks)
  • Obsidian/Entities/Player.Helpers.cs (0 hunks)
  • Obsidian/Entities/Player.cs (3 hunks)
  • Obsidian/Events/MainEventHandler.Inventory.cs (1 hunks)
  • Obsidian/Events/MainEventHandler.cs (2 hunks)
  • Obsidian/HashedItemStack.cs (1 hunks)
  • Obsidian/Net/ClientHandlers/ConfigurationClientHandler.cs (0 hunks)
  • Obsidian/Net/ClientHandlers/PlayClientHandler.cs (2 hunks)
  • Obsidian/Net/NetworkBuffer.Reading.cs (6 hunks)
  • Obsidian/Net/NetworkBuffer.Writing.cs (3 hunks)
  • Obsidian/Net/NetworkBuffer.cs (1 hunks)
  • Obsidian/Net/Packets/Play/Clientbound/ContainerSetContentPacket.cs (1 hunks)
  • Obsidian/Net/Packets/Play/Serverbound/ContainerClickPacket.cs (4 hunks)
  • Obsidian/Net/Packets/Play/Serverbound/PlayerCommandPacket.cs (4 hunks)
  • Obsidian/Net/Packets/Play/Serverbound/PlayerInputPacket.cs (1 hunks)
  • Obsidian/Obsidian.csproj (1 hunks)
  • Obsidian/Plugins/PluginRegistry.cs (1 hunks)
  • Obsidian/Registries/CommandsRegistry.cs (2 hunks)
  • Obsidian/Server.cs (1 hunks)
  • Obsidian/Utilities/Extensions.Nbt.Chat.cs (4 hunks)
  • Obsidian/Utilities/Extensions.Nbt.cs (0 hunks)
  • Obsidian/Utilities/Extensions.cs (1 hunks)
💤 Files with no reviewable changes (9)
  • Obsidian/Net/ClientHandlers/ConfigurationClientHandler.cs
  • Obsidian.SourceGenerators/Registry/EntityGenerator.cs
  • Obsidian/Entities/Player.Helpers.cs
  • Obsidian/Commands/Parsers/MinecraftTimeParser.cs
  • Obsidian/Utilities/Extensions.Nbt.cs
  • Obsidian/Commands/Parsers/CommandParser.cs
  • Obsidian/Commands/Parsers/StringCommandParser.cs
  • Obsidian/Commands/Parsers/NumberCommandParsers.cs
  • Obsidian/Commands/Parsers/EntityCommandParser.cs
🧰 Additional context used
🧬 Code Graph Analysis (14)
Obsidian.Tests/Commands.cs (1)
Obsidian/Commands/Framework/CommandParser.cs (3)
  • CommandParser (5-88)
  • IsCommandQualified (9-19)
  • SplitQualifiedString (21-87)
Obsidian.API/Commands/ArgumentParsers/NumericArgumentParsers.Helpers.cs (1)
Obsidian.API/Commands/ArgumentParsers/NumericArgumentParsers.cs (2)
  • NumericArgumentParser (5-48)
  • NumericArgumentParser (17-26)
Obsidian.API/_Interfaces/INetStreamReader.cs (1)
Obsidian/Net/NetworkBuffer.Reading.cs (1)
  • IHashedItemStack (121-149)
Obsidian/Net/NetworkBuffer.cs (3)
Obsidian.Nbt/RawNbtWriter.cs (1)
  • Span (275-275)
Obsidian.API/_Interfaces/INetStream.cs (3)
  • Span (7-7)
  • Span (9-9)
  • Span (11-11)
Obsidian/WorldData/RegionFile.cs (1)
  • offset (344-352)
Obsidian/Commands/Modules/MainCommandModule.cs (2)
Obsidian.API/_Types/HexColor.cs (4)
  • HexColor (11-14)
  • HexColor (16-19)
  • HexColor (21-23)
  • HexColor (25-28)
Obsidian/Utilities/Extensions.Nbt.Chat.cs (1)
  • ChatMessage (86-132)
Obsidian.API/_Interfaces/IPlayer.cs (2)
Obsidian/Entities/Player.cs (16)
  • ValueTask (175-207)
  • ValueTask (209-219)
  • ValueTask (221-245)
  • ValueTask (247-262)
  • ValueTask (264-290)
  • ValueTask (292-293)
  • ValueTask (295-296)
  • ValueTask (298-299)
  • ValueTask (301-327)
  • ValueTask (329-329)
  • ValueTask (330-330)
  • ValueTask (381-396)
  • ValueTask (428-435)
  • ValueTask (437-444)
  • ValueTask (446-462)
  • ValueTask (464-474)
Obsidian.API/_Types/ChatMessage.cs (16)
  • ChatMessage (60-60)
  • ChatMessage (68-68)
  • ChatMessage (76-79)
  • ChatMessage (81-91)
  • ChatMessage (93-103)
  • ChatMessage (112-115)
  • ChatMessage (125-129)
  • ChatMessage (139-143)
  • ChatMessage (171-177)
  • ChatMessage (179-185)
  • ChatMessage (188-194)
  • ChatMessage (196-202)
  • ChatMessage (204-212)
  • ChatMessage (214-225)
  • ChatMessage (227-239)
  • ChatMessage (241-252)
Obsidian.API/Inventory/DataComponents/ComponentBuilder.cs (3)
Obsidian.API/_Interfaces/INetStreamWriter.cs (3)
  • WriteLengthPrefixedArray (54-54)
  • WriteLengthPrefixedArray (56-56)
  • WriteItemStack (35-35)
Obsidian.API/_Interfaces/INetStreamReader.cs (2)
  • List (35-35)
  • ItemStack (66-66)
Obsidian/Net/NetworkBuffer.Reading.cs (1)
  • List (398-407)
Obsidian/Events/MainEventHandler.cs (2)
Obsidian/Events/MainEventHandler.Inventory.cs (1)
  • MainEventHandler (7-242)
Obsidian.API/_Types/MinecraftEventHandler.cs (1)
  • MinecraftEventHandler (2-2)
Obsidian.API/Inventory/ItemStack.cs (4)
Obsidian.API/_Interfaces/IPlayer.cs (2)
  • ItemStack (124-124)
  • ItemStack (125-125)
Obsidian/Entities/Player.cs (2)
  • ItemStack (172-172)
  • ItemStack (173-173)
Obsidian.API/_Interfaces/INetStreamReader.cs (1)
  • ItemStack (66-66)
Obsidian/Utilities/Extensions.Nbt.cs (1)
  • ItemStack (23-31)
Obsidian/Entities/Player.cs (3)
Obsidian/Entities/Player.Helpers.cs (1)
  • Player (12-416)
Obsidian/Client.cs (8)
  • Player (411-414)
  • ValueTask (163-185)
  • ValueTask (228-243)
  • ValueTask (245-261)
  • ValueTask (301-313)
  • ValueTask (386-398)
  • Client (23-415)
  • Client (139-161)
Obsidian.API/_Interfaces/IPlayer.cs (10)
  • ValueTask (60-60)
  • ValueTask (61-61)
  • ValueTask (62-62)
  • ValueTask (63-63)
  • ValueTask (64-64)
  • ValueTask (65-65)
  • ValueTask (66-66)
  • ValueTask (67-67)
  • ValueTask (68-68)
  • ValueTask (86-86)
Obsidian/Net/Packets/Play/Serverbound/PlayerInputPacket.cs (2)
Obsidian/Services/PacketBroadcaster.cs (1)
  • PacketBroadcaster (9-115)
Obsidian/Entities/Entity.cs (1)
  • Entity (7-436)
Obsidian.API/_Interfaces/IHashedItemStack.cs (6)
Obsidian.API/_Interfaces/INetStreamReader.cs (3)
  • IHashedItemStack (67-67)
  • List (35-35)
  • ItemStack (66-66)
Obsidian/Net/NetworkBuffer.Reading.cs (2)
  • IHashedItemStack (121-149)
  • List (398-407)
Obsidian/HashedItemStack.cs (1)
  • Compare (18-43)
Obsidian.API/_Interfaces/IPlayer.cs (2)
  • ItemStack (124-124)
  • ItemStack (125-125)
Obsidian/Entities/Player.cs (2)
  • ItemStack (172-172)
  • ItemStack (173-173)
Obsidian.API/Inventory/ItemStack.cs (1)
  • ItemStack (25-31)
Obsidian/Entities/Entity.cs (2)
Obsidian/Entities/Player.cs (16)
  • ValueTask (175-207)
  • ValueTask (209-219)
  • ValueTask (221-245)
  • ValueTask (247-262)
  • ValueTask (264-290)
  • ValueTask (292-293)
  • ValueTask (295-296)
  • ValueTask (298-299)
  • ValueTask (301-327)
  • ValueTask (329-329)
  • ValueTask (330-330)
  • ValueTask (381-396)
  • ValueTask (428-435)
  • ValueTask (437-444)
  • ValueTask (446-462)
  • ValueTask (464-474)
Obsidian/WorldData/World.cs (2)
  • World (15-889)
  • World (88-95)
Obsidian.API/Events/ContainerClickEventArgs.cs (2)
Obsidian.API/Containers/BaseContainer.cs (5)
  • ItemStack (64-64)
  • ItemStack (140-140)
  • BaseContainer (6-130)
  • BaseContainer (22-22)
  • BaseContainer (24-29)
Obsidian.API/Containers/Container.cs (3)
  • Container (5-88)
  • Container (22-22)
  • Container (24-32)
🔇 Additional comments (112)
Obsidian.Nbt/Obsidian.Nbt.csproj (1)

24-26: LGTM! Good addition for performance optimization.

The CommunityToolkit.HighPerformance dependency will enable efficient buffer management for NBT operations as mentioned in the summary.

Obsidian.API/_Attributes/ArgumentParserAttribute.cs (1)

1-7: Well-designed attribute implementation.

The ArgumentParserAttribute is correctly implemented with appropriate AttributeUsage configuration and follows C# attribute conventions.

Obsidian.API/_Enums/ClickType.cs (1)

1-12: Comprehensive and well-structured enum.

The ClickType enum appropriately covers the various inventory click operations and follows good enum design practices with explicit int typing.

Obsidian.API/_Enums/ProtocolVersion.cs (1)

76-79: Correct protocol version addition.

The new v1_21_6 protocol version follows the established naming and numbering conventions properly.

Obsidian.Tests/Commands.cs (1)

28-28: LGTM! Proper namespace qualification.

The fully qualified CommandParser usage correctly addresses potential namespace conflicts from the command parser refactoring. The test functionality remains unchanged while being more explicit about which parser class is being used.

Also applies to: 31-31

Obsidian.API/Commands/ArgumentParsers/NumericArgumentParsers.Helpers.cs (1)

1-2: LGTM! Consistent with command parser refactoring.

The namespace change to Obsidian.API.Commands.ArgumentParsers and class rename to NumericArgumentParser<TNumber> aligns with the broader architectural refactoring. The helper methods correctly handle type-specific serialization of numeric bounds using appropriate conversion methods.

Obsidian/Net/NetworkBuffer.cs (1)

59-59: LGTM! Unnecessary cast removal.

Removing the explicit int casts for offset and size is correct since these fields are already declared as int type. This improves readability without affecting functionality.

Also applies to: 64-64

Obsidian/Utilities/Extensions.cs (1)

56-57: LGTM! Enhanced entity type specificity.

Replacing EntityType.Potion with the more specific EntityType.SplashPotion and EntityType.LingeringPotion improves classification granularity. Both potion types are correctly classified as non-living entities.

Obsidian.API/_Interfaces/INetStreamReader.cs (1)

67-67: LGTM! Proper interface extension for hashed item stacks.

The ReadHashedItemStack() method declaration correctly extends the interface to support the new hashed item stack functionality. The nullable return type and naming convention are consistent with other optional reading methods in the interface.

Obsidian.SourceGenerators/Registry/Models/Assets.cs (1)

17-18: LGTM! Clean formatting improvement.

The parameter list split improves readability without affecting functionality.

Obsidian/Commands/CommandNodeType.cs (1)

15-15: LGTM! Proper flag enum addition.

The new IsRestricted flag correctly follows the powers of 2 pattern and supports the enhanced command node state representation.

Obsidian.SourceGenerators/Obsidian.SourceGenerators.csproj (1)

15-20: All package versions are current and secure

The updates in Obsidian.SourceGenerators/Obsidian.SourceGenerators.csproj (lines 15–20) use the latest stable releases and have no known security vulnerabilities:

  • Microsoft.CodeAnalysis.CSharp 4.14.0 – latest
  • Microsoft.CodeAnalysis.Analyzers 4.14.0 – latest
  • Microsoft.Bcl.AsyncInterfaces 9.0.6 – latest
  • System.Text.Encodings.Web 9.0.6 – latest
  • System.Text.Json 9.0.6 – latest
  • System.IO.Pipelines 9.0.6 – latest

No action required.

Obsidian/Obsidian.csproj (1)

53-56: All dependencies are up-to-date and secure.

  • Microsoft.Extensions.DependencyInjection 9.0.6
  • Microsoft.Extensions.Hosting.Abstractions 9.0.6
  • Microsoft.Extensions.Logging 9.0.6
  • Microsoft.Extensions.Logging.Abstractions 9.0.6
  • System.IO.Hashing 9.0.5

These are the latest stable releases and no known security vulnerabilities have been reported.

Obsidian/Net/NetworkBuffer.Writing.cs (1)

414-414: Minor formatting adjustment.

Added blank line for code readability.

Obsidian/Server.cs (1)

47-47: Protocol version update looks good.

The update from v1_21_5 to v1_21_6 aligns with the protocol enhancements mentioned in the PR summary, including new packets and features.

Obsidian.API/Obsidian.API.csproj (2)

44-44: Good addition of command parser asset.

The command_parsers.json asset file supports the new command argument parsing system mentioned in the PR summary.


77-81: Dependency updates look appropriate.

The addition of CommunityToolkit.HighPerformance and the minor version updates to Microsoft.Extensions packages support the performance optimizations and new features in this refactor.

Obsidian.API/_Interfaces/IPlayer.cs (2)

12-12: Well-designed addition for player input tracking.

The PlayerInput Input property provides a clean way to track player input state using the new flag-based enum. This enhances the interface capabilities for handling player interactions.


60-60: Good addition for enhanced disconnect messaging.

The DisconnectAsync(ChatMessage reason) method complements the existing KickAsync methods and provides richer disconnect messaging capabilities using the ChatMessage type.

Obsidian.API/_Enums/PlayerInput.cs (1)

1-12: Excellent enum design for player input flags.

The PlayerInput enum is well-designed with:

  • Correct [Flags] attribute for bitwise operations
  • Efficient byte underlying type for network transmission
  • Proper power-of-2 values for bit manipulation
  • Comprehensive coverage of player input actions
  • Clear, consistent naming

This provides an efficient way to represent multiple simultaneous player inputs in a single byte.

Obsidian/Net/Packets/Play/Clientbound/ContainerSetContentPacket.cs (1)

6-9: LGTM! Type consistency improvement.

The change from byte windowId to int containerId aligns the container identifier type with the integer-based container IDs used elsewhere in the codebase, such as in ContainerClickEventArgs. The serialization logic using WriteVarInt already supports integer values, so this change is backward compatible.

Obsidian.API/Inventory/ItemStack.cs (1)

6-6: LGTM! Appropriate use of record type.

Converting ItemStack to a record class is an excellent choice for this value type. Records provide automatic value-based equality implementations, which aligns perfectly with the hash-based validation and synchronization improvements mentioned in the PR objectives.

Obsidian/Assets/command_parsers.json (1)

1-59: command_parsers.json – validation passed

  • JSON syntax is valid.
  • All 57 parser mappings have unique IDs (57 total, 57 unique).
  • Naming conventions are consistent.
Obsidian/Plugins/PluginRegistry.cs (1)

81-83: LGTM! Improved parser registration pattern.

The changes align well with the new parser architecture:

  • Using BaseArgumentParser<T> provides better type safety than generic constraints
  • The TryAddArgumentParser method suggests a defensive approach to prevent duplicate parser registrations, which is appropriate for a plugin registry
Obsidian/Commands/Modules/MainCommandModule.cs (3)

71-71: LGTM! Improved separation of content and styling.

Removing inline color codes from the text and using structured ChatMessage properties improves maintainability and reduces the risk of formatting errors.


81-82: LGTM! Consistent use of explicit color properties.

The change from inline color codes to the explicit Color = HexColor.Gold property provides better structure and type safety for chat message formatting.


88-93: LGTM! Well-structured chat message composition.

The refactored approach using ChatMessage.Simple() and explicit color properties creates a cleaner, more maintainable structure for building complex chat messages. The separation of the description text with its own color styling is particularly well done.

Obsidian.API/Plugins/IPluginRegistry.cs (1)

6-6: LGTM: Interface signature improvement enhances type safety.

The change from a generic constraint to an explicit BaseArgumentParser<T> parameter makes the interface more type-safe and aligns with the broader parser refactoring. This explicit typing provides clearer expectations for implementers.

Obsidian/Events/MainEventHandler.cs (2)

7-7: LGTM: Partial class conversion enables modular organization.

Converting to a partial class allows the MainEventHandler to be split across multiple files, which improves code organization. This aligns with the new MainEventHandler.Inventory.cs file mentioned in the relevant code snippets.


289-294: LGTM: Index-based iteration improves slot handling precision.

The change from foreach to a for loop with explicit slot indexing provides better control over item positioning in containers. This change supports the new inventory click handling system that requires precise slot management.

Obsidian.API/Commands/ArgumentParsers/LocationArgumentParser.cs (1)

3-4: LGTM: Parser refactoring aligns with new attribute-driven architecture.

The addition of the [ArgumentParser("minecraft:vec3")] attribute and partial class declaration follows the new standardized parser pattern. This enables source generation of parser metadata while maintaining the existing parsing logic. The Minecraft identifier correctly matches the vec3 command parser type.

Obsidian.API/Commands/ArgumentParsers/PlayerArgumentParser.cs (1)

3-4: LGTM: Consistent parser refactoring maintains functionality.

The [ArgumentParser("minecraft:game_profile")] attribute and partial class conversion follows the same pattern as other parsers in this refactoring. The identifier correctly matches Minecraft's game profile parser type, and the existing parsing logic is preserved.

Obsidian/Entities/Player.cs (4)

43-43: LGTM: PlayerInput property enables comprehensive input tracking.

The addition of the PlayerInput property provides a centralized way to track player input states using flag-based enumeration, which is efficient and extensible.


45-55: LGTM: Sneaking property override integrates well with input system.

The override correctly uses bitwise operations to manage the sneak flag within the PlayerInput property. The implementation properly sets and clears the PlayerInput.Sneak flag while maintaining the existing Sneaking property interface.


627-627: LGTM: DisconnectAsync method provides clean delegation.

The method correctly forwards the disconnect call to the client's DisconnectAsync method, providing a convenient API on the Player class while maintaining proper separation of concerns.


145-145: Verify if constructor change is intentional.

The constructor line is marked as changed but appears identical to what would be expected. Please confirm if this represents a formatting change or if there are non-visible modifications.

Obsidian.Nbt/RawNbtWriter.Primitives.cs (3)

1-4: LGTM! Proper dependencies added for high-performance buffer operations.

The new using directives align with the buffer management enhancements using ArrayPool<byte> and CommunityToolkit.HighPerformance.


171-171: Good defensive programming practice.

Adding the Reserve call before copying data prevents buffer overflows and ensures adequate capacity.


178-191: Excellent buffer management implementation.

The Reserve method provides:

  • Proper input validation with Debug.Assert
  • Efficient resizing using ArrayPool<byte>.Shared.Resize
  • Smart growth strategy (doubling capacity)
  • Public access for preemptive buffer management

The implementation follows .NET performance best practices for buffer operations.

Obsidian.API/Inventory/DataComponents/ComponentBuilder.cs (3)

143-144: Good refactoring to explicit lambda expressions.

Converting from method group references to explicit lambdas makes the delegate signatures clearer and aligns with the hashed item stack serialization improvements mentioned in the PR.


147-148: Consistent pattern applied.

The same lambda expression pattern ensures consistency across all item stack components.


209-209: Pattern completion for Container component.

Applying the same explicit lambda pattern maintains consistency with the other item stack components.

Obsidian/Commands/CommandNode.cs (5)

12-12: Good architectural improvement.

Changing from CommandParser? to BaseArgumentParser? provides a more flexible and generic parser system, aligning with the new argument parser framework.


18-18: Enhanced suggestion support.

The new SuggestionType property enables command suggestion metadata, improving the command system's usability.


24-24: Cleaner serialization using helper method.

Using WriteLengthPrefixedArray is more readable and maintainable than manual loop serialization.


28-28: Critical bug fix in redirect serialization.

Writing the node's own Index instead of iterating over children is the correct behavior for redirect serialization according to the Command Data protocol.


41-44: Proper conditional suggestion serialization.

The conditional serialization of SuggestionType when the HasSuggestions flag is set follows the protocol specification correctly.

Obsidian.API/_Types/HexColor.cs (1)

33-48: HexColor Code Verification Complete

All hex values in Obsidian.API/_Types/HexColor.cs have been checked against the standard Minecraft color definitions and match expected RGB equivalents. The switch to hex-string constructors and the updated naming align with conventions and are correct.

• File verified: Obsidian.API/_Types/HexColor.cs
• Result: All color codes match expected values.

Refactoring approved—no further action needed.

Obsidian/Net/Packets/Play/Serverbound/PlayerCommandPacket.cs (3)

14-14: Good refactoring to improve clarity.

Renaming from EAction to PlayerCommand provides better semantic meaning and aligns with the architectural separation where sneaking commands are moved to PlayerInputPacket.

Also applies to: 22-22


67-79: Appropriate separation of concerns.

The removal of StartSneaking and StopSneaking from the enum aligns with the introduction of PlayerInputPacket for handling input state, creating a cleaner separation between command actions and input flags.


32-57: Switch statement correctly updated.

All cases properly use the new PlayerCommand enum values, maintaining the same functionality while improving code clarity.

Obsidian.Nbt/RawNbtWriter.cs (3)

26-26: LGTM! Constructors correctly use the new buffer size.

The constructors properly use the updated InitialBufferSize constant.

Also applies to: 36-36


76-82: Conditional root tag logic is correct and consistent

The early-return for List root types in RawNbtWriter.WriteCompoundStart matches the implementation in NbtWriterStream.WriteCompoundStart, ensuring that list elements do not write a tag header. No changes are required.

• Confirmed in Obsidian.Nbt/RawNbtWriter.cs WriteCompoundStart (lines 76–82)
• Behavior mirrors Obsidian.Nbt/NbtWriterStream.cs WriteCompoundStart


8-8: Buffer resizing via doubling strategy ensures amortized performance

The Reserve(int capacity) implementation in Obsidian.Nbt/RawNbtWriter.Primitives.cs uses ArrayPool<byte>.Shared.Resize(ref data, newCapacity) with a doubling-growth strategy (and falls back to the exact required size if that’s larger). While dropping the initial buffer from 4096→256 bytes does mean a few more resizes for very large NBT payloads, the amortized cost remains constant and impact in real‐world usage will be negligible. No changes needed.

Obsidian/Net/Packets/Play/Serverbound/PlayerInputPacket.cs (1)

10-13: LGTM! Proper packet deserialization.

The Populate method correctly reads the byte value and casts it to the PlayerInput enum.

Obsidian.API/Commands/ArgumentParsers/BooleanArgumentParser.cs (1)

1-19: LGTM! Well-implemented boolean argument parser.

The implementation demonstrates good practices:

  • Proper use of [ArgumentParser] attribute with brigadier identifier
  • Primary constructor with default value support via chained constructor
  • Correct use of bool.TryParse for argument parsing
  • Proper serialization pattern calling base.Write() before writing value

The sealed partial class design aligns with the broader argument parser refactoring mentioned in the AI summary.

Obsidian/Registries/CommandsRegistry.cs (2)

2-2: LGTM! Updated import for new argument parser namespace.

The import correctly references the new Obsidian.API.Commands.ArgumentParsers namespace.


78-87: Audit negative integer acceptance for ‘brigadier:integer’ and ‘brigadier:long’

The switch in Obsidian/Registries/CommandsRegistry.cs (lines 78–87) now uses UnsignedIntArgumentParser and UnsignedLongArgumentParser, which will reject negative values. Please verify that none of your registered commands rely on negative integer or long inputs (e.g., block coordinates, relative offsets, time adjustments). If some commands do need to accept negatives, revert those cases to a signed parser or add explicit branches.

• File: Obsidian/Registries/CommandsRegistry.cs (lines 78–87) – “brigadier:integer” and “brigadier:long” mappings

Obsidian/Net/NetworkBuffer.Reading.cs (2)

30-30: LGTM! Minor formatting improvements.

The formatting adjustments in various methods improve code consistency.

Also applies to: 231-231, 260-260, 420-420


105-107: LGTM! Code reorganization without functional changes.

The repositioning of component reading variables doesn't change the functionality but improves code organization.

Obsidian.API/Commands/ArgumentParsers/MinecraftTimeArgumentParser.cs (4)

3-4: LGTM! Attribute-based parser identification implemented correctly.

The [ArgumentParser("minecraft:time")] attribute and sealed partial class declaration align well with the new argument parser framework using source generation.


6-6: LGTM! Min property with sensible default.

The Min property with default value 0 provides a configurable minimum tick value, which is reasonable for time validation.


40-45: LGTM! Proper minimum validation implemented.

The minimum validation logic correctly rejects parsed time values below the threshold and resets the result appropriately before returning false.


49-54: LGTM! Serialization follows established pattern.

The Write method correctly calls the base implementation and serializes the Min property, maintaining consistency with other argument parsers.

Obsidian.API/_Interfaces/IHashedItemStack.cs (1)

4-17: Well-designed interface for hashed item stack abstraction.

The interface provides a clean abstraction for hashed item stacks with appropriate properties and comparison functionality. The property names and types are clear and consistent with the item stack domain.

Obsidian.API/Inventory/DataComponents/DataComponentsStorage.cs (5)

4-4: Good design choice using record class.

Converting to abstract record class is appropriate for value-type semantics and provides better immutability patterns for component storage.


7-7: LGTM! Clean separation of hashed and regular component storage.

The separate hashedStorage dictionary appropriately maintains the hashed components distinct from the regular component storage.


13-13: LGTM! Proper indexer implementation.

The indexer provides clean access to components by type using the internal storage dictionary.


17-28: Excellent documentation and clear method purpose.

The documentation clearly explains that hashes are client-provided and used only for server-side comparison, which is crucial for understanding the security and validation model.


30-31: LGTM! Efficient hash comparison method.

The CompareComponentHash method provides efficient hash-based comparison using TryGetValue for optimal performance.

Obsidian/Net/ClientHandlers/PlayClientHandler.cs (3)

80-82: LGTM! New PlayerInputPacket handling added correctly.

The new case for PlayerInputPacket (ID 42) follows the established pattern and integrates properly with the existing packet handling framework.


83-88: LGTM! Packet ID shifts handled correctly.

The RecipeBookSeenRecipePacket and RenameItemPacket cases have been properly updated to their new IDs (46 and 47).


12-18: Packet ID consistency confirmed

All packet mappings in PlayClientHandler.cs align with the serverbound Play definitions in Obsidian/Assets/packets.json—no discrepancies found.

Obsidian/Entities/Entity.cs (4)

47-58: Good design choice making entity properties virtual.

Making these boolean properties virtual enables proper polymorphism and allows derived classes like Player to override behavior (e.g., Sneaking property). This supports the new player input system mentioned in the summary.


50-50: LGTM! MovementFlags property virtualization supports inheritance.

Making MovementFlags virtual aligns with the other state properties and enables derived classes to customize movement behavior.


227-227: LGTM! RemoveAsync method virtualization enables custom cleanup.

Making RemoveAsync virtual allows derived entities to implement custom removal logic while maintaining the default world entity destruction behavior.


229-229: LGTM! GenerateBitmask virtualization supports entity-specific flags.

Making GenerateBitmask virtual enables derived entities to customize their metadata bitmask generation, which is essential for entity-specific behaviors.

Obsidian.API/Commands/ArgumentParsers/EntityArgumentParser.cs (3)

3-8: LGTM! Well-structured parser with proper defaults.

The class structure, attribute decoration, and constructor design follow the new argument parser pattern correctly. The default constructor with SingleEntityOrPlayer provides sensible defaults.


17-23: LGTM! Correct network serialization.

The Write method properly calls the base implementation and correctly serializes the EntityFilter enum as a signed byte for network protocol compliance.


25-29: LGTM! Appropriate enum design.

The EntityFilter enum with sbyte backing type and meaningful values aligns well with Minecraft protocol requirements.

Obsidian.Tests/Nbt.cs (2)

13-105: LGTM! Comprehensive NBT reading test activated.

The ReadBigTest method provides thorough validation of NBT deserialization across various tag types, nested compounds, lists, and arrays. The test assertions are well-structured and validate both data integrity and structure correctness.


108-181: LGTM! Well-designed round-trip test.

The WriteBigTest method creates a complex NBT structure and validates it by reading it back, ensuring write/read symmetry. The use of MemoryStream and calling ReadBigTest for validation is an excellent testing pattern.

Obsidian.API/_Types/MinecraftTime.cs (3)

10-15: LGTM! Proper day-to-time conversions.

The mathematical relationships are correct: 1 day = 24000 ticks = 1200 seconds. This ensures all time properties are synchronized when creating from a day value.


17-22: LGTM! Correct second-to-time conversions.

The conversions properly calculate ticks (second * 20) and days (second / 1200), maintaining consistency across all time representations.


24-29: LGTM! Accurate tick-to-time conversions.

The tick-based conversions correctly derive seconds (tick / 20) and days (tick / 24000), ensuring complete time synchronization.

Obsidian/Utilities/Extensions.Nbt.Chat.cs (3)

33-45: LGTM! Improved streaming list serialization.

The change from creating intermediate list objects to streaming serialization improves performance and memory usage. The loop structure correctly handles compound writing for each extra item.


167-167: LGTM! Correct snake_case naming convention.

The change from "hoverEvent" to "hover_event" aligns with Minecraft protocol standards for NBT tag naming.


182-182: LGTM! Consistent snake_case naming.

The change from "clickEvent" to "click_event" maintains naming consistency with the protocol.

Obsidian/HashedItemStack.cs (2)

7-16: LGTM! Clean class structure and constructor.

The class properly implements IHashedItemStack with clear property initialization. The primary constructor with default count parameter is well-designed.


24-40: LGTM! Proper resource management and hash comparison.

The ArrayPool usage is correct with proper return, and the CRC32 hashing provides efficient component comparison. The early return on hash mismatch optimizes performance.

Obsidian/Commands/Framework/CommandHandler.cs (1)

30-36: Add null checks and validate generic arguments count.

The parser initialization logic assumes BaseType is not null and has at least one generic argument. This could throw exceptions if these assumptions don't hold.

Apply this diff to add defensive checks:

 var parsers = typeof(StringArgumentParser).Assembly.GetTypes()
     .Where(type => typeof(BaseArgumentParser).IsAssignableFrom(type) && !type.IsAbstract)
-    .Where(type => type.BaseType?.IsGenericType is true && type.BaseType.GetGenericArguments().Length != 0)
+    .Where(type => type.BaseType?.IsGenericType is true && type.BaseType.GetGenericArguments().Length > 0)
     .Select(x => (Activator.CreateInstance(x) as BaseArgumentParser)!);

 _argumentParsers = parsers.OrderBy(x => x.Id)
-    .ToDictionary(x => x.GetType().BaseType!.GetGenericArguments().First(), x => x);
+    .ToDictionary(x => x.GetType().BaseType!.GetGenericArguments()[0], x => x);

Additionally, consider logging a warning if any parser types are skipped due to missing generic arguments.

Likely an incorrect or invalid review comment.

Obsidian/Events/MainEventHandler.Inventory.cs (3)

50-51: LGTM! Early return optimization.

Good defensive check to avoid unnecessary processing when the carried item is null or already at max stack size.


162-162: Verify if thrown items should glow.

All thrown items are set to glow. Is this intentional for gameplay mechanics or debugging?

If this is not intended, remove the glowing effect:

                 EntityId = Server.GetNextEntityId(),
                 Item = removedItem,
-                Glowing = true,
                 World = player.World,
                 Position = loc

222-222: Hotbar slot offset is correct

Verified that PlayerHotbarStart in Obsidian.API/Containers/Container.cs is defined as 36, so button + 36 correctly maps to the player’s hotbar slots.

• Container.cs:

private const int PlayerHotbarStart = 36;
private const int PlayerHotbarEnd   = PlayerHotbarStart + 8;

• MainEventHandler.Inventory.cs (line 222):

var localSlot = button + PlayerHotbarStart; // 36

Consider replacing the magic number 36 with the PlayerHotbarStart constant for clarity.

Obsidian.API/Commands/ArgumentParsers/StringArgumentParser.cs (1)

3-4: LGTM! Consistent attribute usage.

The [ArgumentParser] attributes correctly specify the brigadier/minecraft identifiers for both parser classes, aligning with the new source generation pattern.

Also applies to: 24-25

Obsidian.API/Events/ContainerClickEventArgs.cs (2)

13-13: LGTM!

The logic for determining player inventory based on ContainerId == 0 aligns with the documented behavior.


15-21: LGTM!

Comprehensive documentation and proper implementation of the required property pattern.

Obsidian/Assets/tags.json (6)

1150-1161: Verify block list completeness for happy ghast avoidance

The avoidance list looks sane, but you might also want to include self–igniting hazards the entity meets frequently in the Nether such as lava, campfire or fire_pit blocks (if they exist in your dataset) to avoid edge-case damage loops.
Please double-check the intended design spec.


2355-2362: Naming is accurate, but double-check client sound hooks

Just a reminder: make sure the client/engine side actually hooks the happy-ghast “dried_ghast” ambient sounds to soul_sand / soul_soil, otherwise this new tag will be a no-op.


3380-3385: First‐class harness capability registered

Tag correctly links minecraft:happy_ghast to the new harness mechanic.
Nothing to change.


3428-3438: Happy ghast added to underwater-dismount group

Good catch – avoids rare soft-lock situations when riding entities underwater.
No issues spotted.


3454-3461: Fall-damage immunity tag updated

Appending happy_ghast makes sense and is consistent with vanilla ghast.
No action required.


4716-4718: Horse food: adding plain carrot ✅

minecraft:carrot was missing and is required for parity with Java breeding rules.
Change looks correct.

Obsidian/Net/Packets/Play/Serverbound/ContainerClickPacket.cs (1)

52-67: LGTM!

The deserialization logic is well-implemented with proper capacity initialization for the dictionary.

Obsidian/Assets/recipes.json (1)

9760-9768: Confirm that “~” is a legal key character

The shaped recipe (lead?) swaps S/# for ~. While the spec only forbids space, JSON patchers occasionally mis-parse tildes in pattern strings. Double-check in-game loading or switch to a safer ASCII letter.

Obsidian/Assets/packets.json (1)

170-177: Verify CustomClickAction packet in multiple states

The CustomClickAction packet appears in both Configuration state (packet ID 8) and Play state (packet ID 65). While this is valid in the Minecraft protocol, please confirm this duplication is intentional.

Also applies to: 1562-1569

Obsidian/Assets/item_components.json (6)

1626-1629: Verify engine support for can_be_sheared / shearing_sound on carpets

Carpet items have never exposed these two properties in vanilla Bedrock. Double-check that the runtime actually consumes them; otherwise they’ll be silently ignored and create dead config.


7140-7144: Confirm can_be_sheared is valid on horse-armour equippables

Horse armour has no precedent for being sheared. Ensure the property is recognised; otherwise strip it to avoid parser warnings.


10497-10511: Spawn-egg translation key differs from vanilla pattern

Vanilla uses "item.minecraft.xyz_spawn_egg.name" in language files.
Ensure localisation entry matches or the name will show as the raw key.


14814-14828: Validate jukebox_playable sound event

Ensure the sound event "minecraft:tears" exists in the new sounds.json; otherwise the disc will play silence and log an error.


20017-20021: Saddle: verify shearing_sound route

Saddles are equippable on several entities; confirm that adding a shearing path does not collide with existing “unequip” logic or break dispenser behaviour.


25208-25210: Wolf armour: confirm can_be_sheared validity

The wolf armour item historically uses item.wolf_armor.unequip; ensure the engine triggers this when armour is removed, not via actual shearing.

Copy link

@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: 3

♻️ Duplicate comments (6)
Obsidian.API/Commands/ArgumentParsers/NumericArgumentParsers.cs (4)

37-47: Critical: Incomplete type handling in WriteNumbers method remains unresolved.

The WriteNumbers method still only handles 4 of the 10+ numeric types supported by the parser implementations. This will cause serialization to fail silently for byte, sbyte, short, ushort, uint, ulong, and decimal types.

Add support for all missing numeric types:

 private void WriteNumbers(INetStreamWriter writer)
 {
     if (NumberType == typeof(int))
         this.WriteAsInt(writer);
+    else if (NumberType == typeof(byte))
+        this.WriteAsByte(writer);
+    else if (NumberType == typeof(sbyte))
+        this.WriteAsSByte(writer);
+    else if (NumberType == typeof(short))
+        this.WriteAsShort(writer);
+    else if (NumberType == typeof(ushort))
+        this.WriteAsUShort(writer);
+    else if (NumberType == typeof(uint))
+        this.WriteAsUInt(writer);
     else if (NumberType == typeof(double))
         this.WriteAsDouble(writer);
     else if (NumberType == typeof(float))
         this.WriteAsSingle(writer);
     else if (NumberType == typeof(long))
         this.WriteAsLong(writer);
+    else if (NumberType == typeof(ulong))
+        this.WriteAsULong(writer);
+    else if (NumberType == typeof(decimal))
+        this.WriteAsDecimal(writer);
 }

50-108: Critical: Multiple parsers share the same brigadier identifier causing registration conflicts.

Six different parser classes use [ArgumentParser("brigadier:integer")], which will result in only one being registered while the others are silently ignored at runtime.

Assign unique brigadier identifiers to each parser type:

-[ArgumentParser("brigadier:integer")]
+[ArgumentParser("brigadier:int")]
 public sealed partial class SignedIntArgumentParser : NumericArgumentParser<int>

-[ArgumentParser("brigadier:integer")]
+[ArgumentParser("brigadier:byte")]
 public sealed partial class UnsignedByteArgumentParser : NumericArgumentParser<byte>

-[ArgumentParser("brigadier:integer")]
+[ArgumentParser("brigadier:sbyte")]
 public sealed partial class SignedByteArgumentParser : NumericArgumentParser<sbyte>

-[ArgumentParser("brigadier:integer")]
+[ArgumentParser("brigadier:short")]
 public sealed partial class SignedShortArgumentParser : NumericArgumentParser<short>

-[ArgumentParser("brigadier:integer")]
+[ArgumentParser("brigadier:ushort")]
 public sealed partial class UnsignedShortArgumentParser : NumericArgumentParser<ushort>

-[ArgumentParser("brigadier:integer")]
+[ArgumentParser("brigadier:uint")]
 public sealed partial class UnsignedIntArgumentParser : NumericArgumentParser<uint>

110-128: Critical: Duplicate brigadier identifier for long parsers causing registration conflict.

Both signed and unsigned long parsers use the same "brigadier:long" identifier, which will cause a registration collision.

Use distinct identifiers for signed vs unsigned long:

 [ArgumentParser("brigadier:long")]
 public sealed partial class SignedLongArgumentParser : NumericArgumentParser<long>

-[ArgumentParser("brigadier:long")]
+[ArgumentParser("brigadier:ulong")]
 public sealed partial class UnsignedLongArgumentParser : NumericArgumentParser<ulong>

150-151: Questionable: DecimalArgumentParser using "brigadier:double" identifier.

While better than the previous "brigadier:integer", using "brigadier:double" for a decimal parser may be semantically incorrect since decimal and double have different precision and behavior characteristics.

Consider using a more appropriate identifier:

-[ArgumentParser("brigadier:double")]
+[ArgumentParser("brigadier:decimal")]
 public sealed partial class DecimalArgumentParser : NumericArgumentParser<decimal>
Obsidian/Net/Packets/Play/Serverbound/ContainerClickPacket.cs (2)

81-93: Still using incorrect item for carried slot synchronization.

The synchronization packet is still sending clickedItem instead of this.CarriedItem for slot -1. This is the same issue identified in previous reviews and can cause client-server desynchronization.

             await player.Client.QueuePacketAsync(new ContainerSetSlotPacket
             {
                 ContainerId = this.ContainerId,
                 Slot = -1,
-                SlotData = clickedItem,
+                SlotData = this.CarriedItem,
                 StateId = 0,//State id is ignored if slot is set to -1
             });

114-119: Still using incorrect carried item in container sync packet.

The CarriedItem property in the sync packet should be this.CarriedItem (the actual item the player is carrying), not clickedItem. This is the same issue from previous reviews.

             await player.Client.QueuePacketAsync(new ContainerSetContentPacket(this.ContainerId, container.ToList())
             {
                 StateId = this.StateId,
-                CarriedItem = clickedItem
+                CarriedItem = this.CarriedItem
             });
🧹 Nitpick comments (2)
Obsidian/Net/Packets/Play/Serverbound/ContainerClickPacket.cs (1)

95-108: Consider extracting inventory validation logic.

The inventory validation logic is well-structured but could benefit from being extracted into a separate method for better maintainability and testability.

+    private Dictionary<short, IHashedItemStack> ValidateInventoryChanges(IContainer container)
+    {
+        var invalidItems = new Dictionary<short, IHashedItemStack>();
+        foreach (var (changedSlot, hashedItem) in this.ChangedSlots)
+        {
+            var checkedItem = container[changedSlot];
+
+            if (hashedItem == null)
+            {
+                container.RemoveItem(changedSlot);
+                continue;
+            }
+
+            if (!hashedItem.Compare(checkedItem))
+                invalidItems.Add(changedSlot, hashedItem);
+        }
+        return invalidItems;
+    }

Then use it in the main method:

-        var invalidItems = new Dictionary<short, IHashedItemStack>();
-        foreach (var (changedSlot, hashedItem) in this.ChangedSlots)
-        {
-            var checkedItem = container[changedSlot];
-
-            if(hashedItem == null)
-            {
-                container.RemoveItem(changedSlot);
-                continue;
-            }
-
-            if (!hashedItem.Compare(checkedItem))
-                invalidItems.Add(changedSlot, hashedItem);
-        }
+        var invalidItems = ValidateInventoryChanges(container);
Obsidian/Events/MainEventHandler.Inventory.cs (1)

162-162: Remove glowing effect from thrown items.

Thrown items don't typically glow in Minecraft. This appears to be unintentional.

-                Glowing = true,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09dd3ea and 7cd70bd.

📒 Files selected for processing (6)
  • Obsidian.API/Commands/ArgumentParsers/NumericArgumentParsers.cs (1 hunks)
  • Obsidian.API/Events/ContainerClickEventArgs.cs (1 hunks)
  • Obsidian.API/Events/ContainerEventArgs.cs (1 hunks)
  • Obsidian/Events/MainEventHandler.Inventory.cs (1 hunks)
  • Obsidian/Net/NetworkBuffer.Writing.cs (2 hunks)
  • Obsidian/Net/Packets/Play/Serverbound/ContainerClickPacket.cs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Obsidian/Net/NetworkBuffer.Writing.cs
  • Obsidian.API/Events/ContainerClickEventArgs.cs
🔇 Additional comments (7)
Obsidian.API/Commands/ArgumentParsers/NumericArgumentParsers.cs (2)

5-26: Good: Well-designed generic base class with proper constraints and flag management.

The generic base class effectively consolidates common numeric parser functionality with appropriate type constraints and flag-based min/max value tracking.


160-166: Fixed: NumberFlags enum now has explicit flag values.

The explicit values for HasMinValue = 1 and HasMaxValue = 2 ensure proper bitwise operations for the flags enum.

Obsidian/Net/Packets/Play/Serverbound/ContainerClickPacket.cs (4)

39-39: Good refactor to use ClickType enum.

The change from Mode to ClickType aligns well with the overall refactor objectives and improves code clarity.


42-42: Good fix for the nullable reference type issue.

The initialization to an empty dictionary properly addresses the previous concern about using default!.


121-129: Good refactor of event dispatch.

The event dispatch has been properly updated to use the new ContainerClickEventArgs structure with the required properties.


58-67: ✅ Deserialization methods verified

Both ReadVarInt<TEnum>() and ReadHashedItemStack() are declared in INetStreamReader and implemented in NetworkBuffer.Reading. No further changes needed.

Obsidian/Events/MainEventHandler.Inventory.cs (1)

60-60: No action needed: ItemStack uses value-based equality

The ItemStack type is declared as a C# record class (public sealed record class ItemStack …, IEquatable<ItemStack>), which the compiler synthesizes with value-based ==, !=, and Equals implementations. The existing checks

if (item is null || item != carriedItem)

correctly compare item equality by value, so no change is required.

@Tides Tides merged commit 7c8b5ce into 1.21.x Jun 29, 2025
3 checks passed
@Tides Tides deleted the inventory-click-refactor branch June 29, 2025 20:14
@coderabbitai coderabbitai bot mentioned this pull request Aug 30, 2025
@coderabbitai coderabbitai bot mentioned this pull request Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Relates to Obsidian.API commands Relates to Obsidian.Commands nbt Relates to Obsidian.Nbt plugins Relates to plugins source-generation Relates to Obsidian.SourceGenerators tests Relates to Obsidian.Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant