[8.0] Conduit block rewrite #1025

Merged
Rover656 merged 44 commits from feat/conduit-rewrite into dev/1.21.1 2025-05-06 21:11:05 +00:00
Rover656 commented 2025-03-07 20:21:32 +00:00 (Migrated from github.com)

Description

Replaces #958 which had a nasty commit history and became difficult to rebase.

TODO

  • Add the ability to open filter GUIs from the conduit screen (and go back).
  • Address any newly introduced TODOs.
  • Many other things, I'm very busy so will keep updating this list as I trawl through.

Breaking Changes

List any breaking changes in this section, such as: changed/removed APIs, changed or removed items/blocks or modifications to recipes and gameplay mechanics.

Major API breaks for mods that add or interact with conduits.
Has supporting logic for loading existing conduit bundles, but it is not saved in a backward-compatible format (i.e. 7.2 cannot be safely downgraded from)

Checklist

  • My code follows the style guidelines of this project (.editorconfig, most IDEs will use this for you).
  • I have made corresponding changes to the documentation.
  • My changes are ready for review from a contributor.

Summary by CodeRabbit

  • New Features

    • Introduced advanced conduit API for improved flexibility and extensibility, including new interfaces for bundles, connections, and screen types.
    • Added new GUI components for conduits, such as dynamic tooltips, enhanced button widgets, and improved screen layout management.
    • Implemented refined filter APIs for items, fluids, and entities, supporting more granular filtering and menu interactions.
    • Enhanced visual effects for conduit bundles, including custom hit and destruction particles.
  • Improvements

    • Refined enum and method naming for clarity and consistency across the API.
    • Improved tooltip localisation and display for dye colours and toggle buttons.
    • Streamlined conduit registration, network, and data management, with new registries and deprecation of legacy systems.
    • Updated redstone control and sensitivity handling for more precise behaviour.
  • Bug Fixes

    • Fixed tooltip synchronisation issues on toggle buttons.
    • Improved tooltip suppression logic for overlays in GUIs.
  • Removals/Deprecations

    • Removed legacy and redundant interfaces/classes, including old filter abstractions and deprecated conduit data structures.
    • Deprecated or removed obsolete registry keys and data types.
  • Refactor

    • Refactored package structure for better modularity and maintainability.
    • Simplified slot creation in menus to enable easier customisation.
  • Chores

    • Updated build configuration and dependency management for enhanced compatibility and formatting.
  • Style

    • Improved code formatting and readability in various components and language files.
  • Documentation

    • Enhanced documentation and annotations for experimental and deprecated features.
# Description Replaces #958 which had a nasty commit history and became difficult to rebase. <!-- If you're submitting a Draft PR, consider providing a TODO list using checkboxes --> # TODO - [x] Add the ability to open filter GUIs from the conduit screen (and go back). - [x] Address any newly introduced TODOs. - [x] Many other things, I'm very busy so will keep updating this list as I trawl through. # Breaking Changes List any breaking changes in this section, such as: changed/removed APIs, changed or removed items/blocks or modifications to recipes and gameplay mechanics. Major API breaks for mods that add or interact with conduits. Has supporting logic for loading existing conduit bundles, but it is not saved in a backward-compatible format (i.e. 7.2 cannot be safely downgraded from) <!-- For drafts, fill this in as you go; if you are leaving draft, make sure these are all complete. --> # Checklist - [ ] My code follows the style guidelines of this project (.editorconfig, most IDEs will use this for you). - [ ] I have made corresponding changes to the documentation. - [ ] My changes are ready for review from a contributor. <!-- Thanks to: https://embeddedartistry.com/blog/2017/08/04/a-github-pull-request-template-for-your-projects/ for the building blocks of this template --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced advanced conduit API for improved flexibility and extensibility, including new interfaces for bundles, connections, and screen types. - Added new GUI components for conduits, such as dynamic tooltips, enhanced button widgets, and improved screen layout management. - Implemented refined filter APIs for items, fluids, and entities, supporting more granular filtering and menu interactions. - Enhanced visual effects for conduit bundles, including custom hit and destruction particles. - **Improvements** - Refined enum and method naming for clarity and consistency across the API. - Improved tooltip localisation and display for dye colours and toggle buttons. - Streamlined conduit registration, network, and data management, with new registries and deprecation of legacy systems. - Updated redstone control and sensitivity handling for more precise behaviour. - **Bug Fixes** - Fixed tooltip synchronisation issues on toggle buttons. - Improved tooltip suppression logic for overlays in GUIs. - **Removals/Deprecations** - Removed legacy and redundant interfaces/classes, including old filter abstractions and deprecated conduit data structures. - Deprecated or removed obsolete registry keys and data types. - **Refactor** - Refactored package structure for better modularity and maintainability. - Simplified slot creation in menus to enable easier customisation. - **Chores** - Updated build configuration and dependency management for enhanced compatibility and formatting. - **Style** - Improved code formatting and readability in various components and language files. - **Documentation** - Enhanced documentation and annotations for experimental and deprecated features. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Rover656 commented 2025-03-11 00:22:23 +00:00 (Migrated from github.com)

@coderabbitai summary

@coderabbitai summary
coderabbitai[bot] commented 2025-03-11 00:22:28 +00:00 (Migrated from github.com)
Actions performed

Summary regeneration triggered.

<!-- This is an auto-generated reply by CodeRabbit --> <details> <summary>:white_check_mark: Actions performed</summary> Summary regeneration triggered. </details>
coderabbitai[bot] commented 2025-03-11 00:22:33 +00:00 (Migrated from github.com)

Walkthrough

This update introduces a substantial refactor and expansion of the conduit API and client systems. It adds new interfaces, records, enums, and classes for conduit bundles, connections, menus, models, and tickers, while deprecating or removing legacy types. Numerous package reorganisations and method signature changes improve type flexibility and modularity. The client setup is updated to register new model modifiers and screen types, and visual/particle effects for conduit bundles are enhanced. Several filtering interfaces are replaced or consolidated, and new filter APIs are introduced for items, fluids, and entities. Miscellaneous improvements include tooltip handling, slot creation customisation, and dependency updates.

Changes

File(s) / Path(s) Change Summary
enderio-conduits/api/, enderio-conduits/api/bundle/, enderio-conduits/api/connection/, enderio-conduits/api/network/, enderio-conduits/api/model/, enderio-conduits/api/screen/, enderio-conduits/api/ticker/ Major API refactor: new interfaces, records, enums, and classes for conduit bundles, connections, node data, menus, models, and tickers; deprecation/removal of legacy types; package reorganisations; enhanced type parameters and modularity.
enderio-conduits/client/ Added ConduitBundleExtension for particle effects; updated ConduitClientSetup to register new model modifiers, screen types, and client extensions; import and registration logic updated.
enderio-conduits/common/conduit/block/common/conduit/bundle/ Refactored imports to new package structure for conduit bundle block entities.
enderio-conduits-modded/src/main/java/com/enderio/modconduits/mods/mekanism/, enderio-conduits-modded/src/main/java/com/enderio/modconduits/mods/refinedstorage/ Updated imports and method signatures to match new conduit API and package structure.
enderio-base/api/filter/ Introduced new filter interfaces: ItemFilter, FluidFilter, FilterMenuProvider; removed legacy interfaces (ResourceFilter, ItemStackFilter, FluidStackFilter); refined EntityFilter methods.
enderio-base/api/misc/RedstoneControl.java Added isRedstoneSensitive property to enum, updated constants and constructor, added getter.
enderio-base/client/gui/widget/DyeColorPickerWidget.java, enderio-base/common/lang/EIOEnumLang.java Improved dye colour tooltip support and added translation map for dye colours.
enderio-base/common/lang/EIOLang.java Formatting changes and removal of unused component declarations.
enderio-base/common/blockentity/Wrenchable.java, enderio-base/common/item/tool/YetaWrenchItem.java Refactored wrench interaction to use UseOnContext; removed legacy method usage.
endercore/client/gui/widgets/ Added new IconButton class; removed legacy ToggleImageButton; improved tooltip and toggle logic in related widgets.
endercore/common/menu/BaseEnderMenu.java Refactored slot creation to use overridable factory methods for inventory and armour slots.
endercore/common/util/TooltipUtil.java Changed return type of style method to MutableComponent.
endercore/common/blockentity/EnderBlockEntity.java Removed deferred change notification logic and simplified capability cache logic.
build.gradle.kts, enderio-conduits/build.gradle.kts Updated Spotless/Cleanthat plugin version; added Jade dependency by property.
Miscellaneous (various files) Parameter renaming for clarity, import updates, formatting, and minor logic improvements.

Sequence Diagram(s)

sequenceDiagram
    participant Game as Game Engine
    participant Bundle as ConduitBundle
    participant Conduit as Conduit
    participant Node as ConduitNode
    participant Menu as ConduitMenuDataAccess
    participant Screen as ConduitScreenType

    Game->>Bundle: Add/Remove conduit
    Bundle->>Conduit: Validate addition/removal
    Bundle->>Node: Update node data/config
    Node->>Conduit: Query connection/config
    Game->>Menu: Open conduit menu
    Menu->>Screen: Provide config and extra data
    Screen->>Menu: Update config via modifier
  • Team-EnderIO/EnderIO#1035: Updates to BaseEnumPickerWidget for scrolling and ordinal usage, related to tooltip and value management changes in this PR.

Suggested labels

P-0-High

Poem

In tunnels deep where conduits run,
The rabbits code—refactor begun!
New bundles, nodes, and menus bright,
Models, filters, widgets—what a sight!
With particles and tooltips too,
This warren’s code feels fresh and new.
🐇

Finishing Touches
  • 📝 Generate Docstrings

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
🪧 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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 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.
<!-- This is an auto-generated comment: summarize by coderabbit.ai --> <!-- walkthrough_start --> ## Walkthrough This update introduces a substantial refactor and expansion of the conduit API and client systems. It adds new interfaces, records, enums, and classes for conduit bundles, connections, menus, models, and tickers, while deprecating or removing legacy types. Numerous package reorganisations and method signature changes improve type flexibility and modularity. The client setup is updated to register new model modifiers and screen types, and visual/particle effects for conduit bundles are enhanced. Several filtering interfaces are replaced or consolidated, and new filter APIs are introduced for items, fluids, and entities. Miscellaneous improvements include tooltip handling, slot creation customisation, and dependency updates. ## Changes | File(s) / Path(s) | Change Summary | |-------------------------------------------------------------------------------------------------------------|---------------| | `enderio-conduits/api/`, `enderio-conduits/api/bundle/`, `enderio-conduits/api/connection/`, `enderio-conduits/api/network/`, `enderio-conduits/api/model/`, `enderio-conduits/api/screen/`, `enderio-conduits/api/ticker/` | Major API refactor: new interfaces, records, enums, and classes for conduit bundles, connections, node data, menus, models, and tickers; deprecation/removal of legacy types; package reorganisations; enhanced type parameters and modularity. | | `enderio-conduits/client/` | Added `ConduitBundleExtension` for particle effects; updated `ConduitClientSetup` to register new model modifiers, screen types, and client extensions; import and registration logic updated. | | `enderio-conduits/common/conduit/block/` → `common/conduit/bundle/` | Refactored imports to new package structure for conduit bundle block entities. | | `enderio-conduits-modded/src/main/java/com/enderio/modconduits/mods/mekanism/`, `enderio-conduits-modded/src/main/java/com/enderio/modconduits/mods/refinedstorage/` | Updated imports and method signatures to match new conduit API and package structure. | | `enderio-base/api/filter/` | Introduced new filter interfaces: `ItemFilter`, `FluidFilter`, `FilterMenuProvider`; removed legacy interfaces (`ResourceFilter`, `ItemStackFilter`, `FluidStackFilter`); refined `EntityFilter` methods. | | `enderio-base/api/misc/RedstoneControl.java` | Added `isRedstoneSensitive` property to enum, updated constants and constructor, added getter. | | `enderio-base/client/gui/widget/DyeColorPickerWidget.java`, `enderio-base/common/lang/EIOEnumLang.java` | Improved dye colour tooltip support and added translation map for dye colours. | | `enderio-base/common/lang/EIOLang.java` | Formatting changes and removal of unused component declarations. | | `enderio-base/common/blockentity/Wrenchable.java`, `enderio-base/common/item/tool/YetaWrenchItem.java` | Refactored wrench interaction to use `UseOnContext`; removed legacy method usage. | | `endercore/client/gui/widgets/` | Added new `IconButton` class; removed legacy `ToggleImageButton`; improved tooltip and toggle logic in related widgets. | | `endercore/common/menu/BaseEnderMenu.java` | Refactored slot creation to use overridable factory methods for inventory and armour slots. | | `endercore/common/util/TooltipUtil.java` | Changed return type of `style` method to `MutableComponent`. | | `endercore/common/blockentity/EnderBlockEntity.java` | Removed deferred change notification logic and simplified capability cache logic. | | `build.gradle.kts`, `enderio-conduits/build.gradle.kts` | Updated Spotless/Cleanthat plugin version; added Jade dependency by property. | | Miscellaneous (various files) | Parameter renaming for clarity, import updates, formatting, and minor logic improvements. | ## Sequence Diagram(s) ```mermaid sequenceDiagram participant Game as Game Engine participant Bundle as ConduitBundle participant Conduit as Conduit participant Node as ConduitNode participant Menu as ConduitMenuDataAccess participant Screen as ConduitScreenType Game->>Bundle: Add/Remove conduit Bundle->>Conduit: Validate addition/removal Bundle->>Node: Update node data/config Node->>Conduit: Query connection/config Game->>Menu: Open conduit menu Menu->>Screen: Provide config and extra data Screen->>Menu: Update config via modifier ``` ## Possibly related PRs - [Team-EnderIO/EnderIO#1035](https://github.com/Team-EnderIO/EnderIO/pull/1035): Updates to `BaseEnumPickerWidget` for scrolling and ordinal usage, related to tooltip and value management changes in this PR. ## Suggested labels `P-0-High` ## Poem > In tunnels deep where conduits run, > The rabbits code—refactor begun! > New bundles, nodes, and menus bright, > Models, filters, widgets—what a sight! > With particles and tooltips too, > This warren’s code feels fresh and new. > 🐇✨ <!-- walkthrough_end --> <!-- internal state start --> <!-- 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 --> <!-- internal state end --> <!-- finishing_touch_checkbox_start --> <details open="true"> <summary>✨ Finishing Touches</summary> - [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings </details> <!-- finishing_touch_checkbox_end --> <!-- tips_start --> --- 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. <details> <summary>❤️ Share</summary> - [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai) - [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai) - [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai) - [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code) </details> <details> <summary>🪧 Tips</summary> ### Chat There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Team-EnderIO/EnderIO&utm_content=1025): - Review comments: Directly reply to a review comment made by CodeRabbit. Example: - `I pushed a fix in commit <commit_id>, please review it.` - `Generate unit testing code for this file.` - `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 generate unit testing code for this file.` - `@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 generate unit testing code.` - `@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](https://www.coderabbit.ai/contact-us/support) 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](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR. - `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in 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](https://docs.coderabbit.ai/guides/configure-coderabbit) 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](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit. - Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback. - Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements. </details> <!-- tips_end -->
Rover656 commented 2025-03-11 00:40:44 +00:00 (Migrated from github.com)

@coderabbitai review

@coderabbitai review
coderabbitai[bot] commented 2025-03-11 00:40:50 +00:00 (Migrated from github.com)
Actions performed

Review triggered.

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.

<!-- This is an auto-generated reply by CodeRabbit --> <details> <summary>:white_check_mark: Actions performed</summary> Review triggered. > 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. </details>
coderabbitai[bot] (Migrated from github.com) reviewed 2025-03-11 01:02:09 +00:00
coderabbitai[bot] (Migrated from github.com) left a comment

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

🛑 Comments failed to post (28)
enderio-conduits/src/main/java/com/enderio/conduits/integration/jade/package-info.java (1)

4-4: 🛠️ Refactor suggestion

Updated Package Declaration

The package declaration has been adjusted to reflect the new organisational structure, moving the file into com.enderio.conduits.integration.jade as intended by this refactor. Please ensure that all related modules, documentation, and references are updated accordingly to maintain consistency across the codebase.

enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/type/item/ItemConduitNodeData.java (1)

18-22: 🛠️ Refactor suggestion

Consider limiting or validating the map entries.

By using Codec.unboundedMap(Direction.CODEC, Codec.INT), there is no explicit upper bound on map size. Realistically, only 6 entries are needed (one per Direction). You might consider using an enum-based map (e.g. EnumMap<Direction, Integer>) or validating the map during decoding to ensure data doesn't exceed expected sizes.

enderio-conduits/src/main/java/com/enderio/conduits/client/model/conduit/modifier/RedstoneConduitModelModifier.java (1)

14-14: 🛠️ Refactor suggestion

Add type checking before casting.

This direct cast assumes the conduit is a RedstoneConduit type. If a different conduit type is passed, this would throw a ClassCastException. Consider adding a type check before casting:

- RedstoneConduit redstoneConduit = (RedstoneConduit) conduit.value();
+ if (!(conduit.value() instanceof RedstoneConduit)) {
+     return null; // Or a default texture
+ }
+ RedstoneConduit redstoneConduit = (RedstoneConduit) conduit.value();
📝 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.

        if (!(conduit.value() instanceof RedstoneConduit)) {
            return null; // Or a default texture
        }
        RedstoneConduit redstoneConduit = (RedstoneConduit) conduit.value();
enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/graph/ConduitGraphContext.java (2)

109-113: 🛠️ Refactor suggestion

Review: Encoding Context via Codec

The encodeContext method utilises encodeStart(...).getOrThrow() to perform serialization. While this approach ensures immediate feedback by throwing on error, it might be beneficial to consider more graceful error handling in future iterations, especially if codec failures are expected to occur under normal operation.


131-146: 🛠️ Refactor suggestion

Review: Robustness in loadNetworkContext Parsing

The private static loadNetworkContext method has been refactored to use the wildcard type for Conduit<?, ?> and includes critical null checks via Objects.requireNonNull. However, the repeated use of getOrThrow() (also noted in the TODO comment) indicates that error handling could be made more robust and flexible. Consider revisiting this approach to gracefully manage potential codec parsing failures.

enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/graph/ConduitConnectionHost.java (2)

12-12: ⚠️ Potential issue

Address TODO comment before finalising PR

This TODO comment indicates uncertainty about whether this should be an interface or a concrete class. As interfaces are part of your public API contract (even if not marked as public API), changing this later could be disruptive. Consider resolving this architectural decision before merging.


20-22: 💡 Verification agent

🧩 Analysis chain

Verify error handling for connection configuration operations

The interface doesn't specify how errors should be handled when getting or setting connection configurations. Consider documenting what happens with invalid directions or null configuration values. Should implementers throw exceptions or handle errors gracefully?


🏁 Script executed:

#!/bin/bash
# Search for implementations of these methods to understand how errors are handled

echo "Searching for implementations of getConnectionConfig and setConnectionConfig..."
rg -A 5 -B 5 "getConnectionConfig\(Direction" --type java
rg -A 5 -B 5 "setConnectionConfig\(Direction" --type java

Length of output: 14470


Update: Document Explicit Exception Contracts for Connection Configuration Methods

The investigation shows that implementations consistently handle error conditions by throwing exceptions (e.g. an IllegalStateException when the connection host is missing, or an IllegalArgumentException as documented in the API). However, the interface in ConduitConnectionHost.java does not explicitly specify the expected behaviour for invalid directions or null configuration values.

  • Please update the method documentation (Javadoc) to explicitly state:
    • That an IllegalArgumentException (or the appropriate exception) will be thrown if an invalid direction is provided.
    • What behaviour is expected if a null configuration value is passed to setConnectionConfig.
  • This clearer contract will help implementers ensure consistent error handling and improve the API’s usability.
enderio-conduits/src/main/java/com/enderio/conduits/api/screen/RegisterConduitScreenTypesEvent.java (1)

13-15: 💡 Verification agent

🧩 Analysis chain

Consider handling duplicate registrations.

The current implementation silently overwrites existing screen types for a conduit type. Depending on the intended behavior, you might want to log a warning or throw an exception when a duplicate registration occurs.


🏁 Script executed:

#!/bin/bash
# Check if there are any existing usages of this event that might be affected by this behavior
rg -m 5 -A 3 "RegisterConduitScreenTypesEvent" --type java

Length of output: 3204


Duplicate Registration Handling Required

The current implementation of the register method in
enderio-conduits/src/main/java/com/enderio/conduits/api/screen/RegisterConduitScreenTypesEvent.java
silently overwrites any prior registration for a given conduit type. Given that the event is subsequently used in methods such as the one in ConduitClientSetup.java to register screen types, it would be prudent to explicitly handle duplicate registrations. For example, you might want to add a check to verify if a registration already exists and then log a warning or throw an exception before overwriting.

A suggested approach:

public void register(ConduitType<? extends Conduit<?, ?>> conduitType, ConduitScreenType<?> screenType) {
    if(screenTypes.containsKey(conduitType)) {
         // Optionally log a warning or throw an exception to flag duplicate registration.
         // For instance:
         // throw new IllegalArgumentException("Duplicate registration for conduit type: " + conduitType);
         // Or alternatively:
         // Logger.warn("Duplicate registration for conduit type: " + conduitType + ". Overwriting existing screen type.");
    }
    screenTypes.put(conduitType, screenType);
}

This change would ensure that accidental duplicate registrations do not lead to silent overwrites and make debugging registration issues easier.

enderio-conduits/src/main/java/com/enderio/conduits/client/model/conduit/bundle/ConduitBundleRenderState.java (2)

92-94: ⚠️ Potential issue

Potential null pointer exception in isConnectionEndpoint

This method assumes that conduitConnections.get(side) will never return null, but there's no guarantee of this. Consider adding a null check or using getOrDefault() as done in the getConnectedConduits method.

public boolean isConnectionEndpoint(Direction side) {
-    return !conduitConnections.get(side).isEmpty();
+    var connections = conduitConnections.get(side);
+    return connections != null && !connections.isEmpty();
}
📝 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.

    public boolean isConnectionEndpoint(Direction side) {
        var connections = conduitConnections.get(side);
        return connections != null && !connections.isEmpty();
    }

96-98: ⚠️ Potential issue

Missing null checks in getConnectionState

Similar to the issue above, this method may throw NullPointerExceptions if either conduitConnections.get(side) or the inner map's get returns null.

public ConduitConnectionRenderState getConnectionState(Direction side, Holder<Conduit<?, ?>> conduit) {
-    return conduitConnections.get(side).get(conduit);
+    Map<Holder<Conduit<?, ?>>, ConduitConnectionRenderState> sideConnections = conduitConnections.get(side);
+    return sideConnections != null ? sideConnections.get(conduit) : null;
}
📝 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.

    public ConduitConnectionRenderState getConnectionState(Direction side, Holder<Conduit<?, ?>> conduit) {
        Map<Holder<Conduit<?, ?>>, ConduitConnectionRenderState> sideConnections = conduitConnections.get(side);
        return sideConnections != null ? sideConnections.get(conduit) : null;
    }
enderio-conduits/src/main/java/com/enderio/conduits/client/gui/ConduitSelectionButton.java (1)

47-48: 🛠️ Refactor suggestion

Reference check vs. logical equality.
Using conduit != currentConduit.get() is a valid reference check, but consider whether a logical comparison (e.g., .equals()) might be more appropriate if multiple Holder<Conduit<?, ?>> instances could refer to the same underlying conduit.

enderio-conduits/src/main/java/com/enderio/conduits/api/network/node/legacy/ConduitData.java (1)

24-25: 🛠️ Refactor suggestion

Revisit parameter usage in withClientChanges.
This method currently ignores the guiData parameter, raising doubts about its relevance. Consider removing the parameter if truly unneeded, or implement the intended logic if appropriate.

enderio-conduits/src/main/java/com/enderio/conduits/api/ticker/IOAwareConduitTicker.java (2)

44-56: 🛠️ Refactor suggestion

Avoid creating duplicate connection objects for send/receive.

Calling createConnection(...) twice for the same node and side is wasteful if both canSend(...) and canReceive(...) return true. Refactor to create a single connection object, then add it to both sender and receiver lists if needed.

- if (canSend(node, config)) {
-     var connection = createConnection(level, node, side);
-     if (connection != null) {
-         senders.get(config.sendColor()).add(connection);
-     }
- }
-
- if (canReceive(node, config)) {
-     var connection = createConnection(level, node, side);
-     if (connection != null) {
-         receivers.get(config.receiveColor()).add(connection);
-     }
- }
+ var canSend = canSend(node, config);
+ var canReceive = canReceive(node, config);
+ if (canSend || canReceive) {
+     var connection = createConnection(level, node, side);
+     if (connection != null) {
+         if (canSend) {
+             senders.get(config.sendColor()).add(connection);
+         }
+         if (canReceive) {
+             receivers.get(config.receiveColor()).add(connection);
+         }
+     }
+ }
📝 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.

                    var canSend = canSend(node, config);
                    var canReceive = canReceive(node, config);
                    if (canSend || canReceive) {
                        var connection = createConnection(level, node, side);
                        if (connection != null) {
                            if (canSend) {
                                senders.get(config.sendColor()).add(connection);
                            }
                            if (canReceive) {
                                receivers.get(config.receiveColor()).add(connection);
                            }
                        }
                    }

129-130: 💡 Verification agent

🧩 Analysis chain

Check for a potentially null inventory reference.

node.getInventory(side) could potentially return null, causing a NullPointerException if callers use inventory() without checking. Confirm that this is safe or add a null check to avoid unexpected runtime errors.


🏁 Script executed:

#!/bin/bash
# Description: Search the codebase for usage of inventory() to confirm if null checks are in place.
fd -e java --exec rg --context 5 'inventory\(\)'

Length of output: 2774


Attention: Potential Null-Reference Risk in Inventory Access

The method implementation for inventory() simply returns node.getInventory(side) without any null-check. Our codebase usage—such as in:

  • var inventory = receiver.inventory();
  • Subsequent calls like inventory.getStackInSlot(...)

—suggests that callers assume the return value will never be null. This could be risky if node.getInventory(side) can indeed return null, as it would lead to a NullPointerException at runtime.

Please either:

  • Confirm that node.getInventory(side) is guaranteed never to return null (for example, via a non-null invariant or appropriate annotations/documentation), or
  • Add an explicit null-check within the inventory() method (or at all call sites) to handle a potential null value safely.
enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/legacy/DynamicConnectionState.java (1)

53-63: 🛠️ Refactor suggestion

Handle the STUB or remove the redundant code
The provided parameters (level, pos, direction, type) are not used, and the method simply returns a fixed DynamicConnectionState. Consider implementing the intended logic or removing this STUB.

- // STUB
- return new DynamicConnectionState(false, DyeColor.GREEN, true, DyeColor.GREEN, RedstoneControl.NEVER_ACTIVE,
-     DyeColor.RED, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY);
+Conduit.ConduitConnectionData defaultConnection = type.value().getDefaultConnection(level, pos, direction);
+return new DynamicConnectionState(
+    defaultConnection.isInsert(),
+    DyeColor.GREEN,
+    defaultConnection.isExtract(),
+    DyeColor.GREEN,
+    defaultConnection.control(),
+    DyeColor.RED,
+    ItemStack.EMPTY,
+    ItemStack.EMPTY,
+    ItemStack.EMPTY
+);
📝 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.

            Holder<Conduit<?, ?>> type) {
                Conduit.ConduitConnectionData defaultConnection = type.value().getDefaultConnection(level, pos, direction);
                return new DynamicConnectionState(
                    defaultConnection.isInsert(),
                    DyeColor.GREEN,
                    defaultConnection.isExtract(),
                    DyeColor.GREEN,
                    defaultConnection.control(),
                    DyeColor.RED,
                    ItemStack.EMPTY,
                    ItemStack.EMPTY,
                    ItemStack.EMPTY
                );
            }
enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/type/item/ItemConduit.java (1)

109-128: ⚠️ Potential issue

Safeguard against null legacy side config.
When retrieving legacy data, there's a risk oldSideConfig might be null if the map lacks entries for certain sides. Dereferencing it could result in a null pointer exception.

To address this, consider a null check as shown below:

- var oldSideConfig = legacyData.get(side);
- node.setConnectionConfig(side,
-     currentConfig.withIsRoundRobin(oldSideConfig.isRoundRobin)
-                  .withIsSelfFeed(oldSideConfig.isSelfFeed)
-                  .withPriority(oldSideConfig.priority));
+ var oldSideConfig = legacyData.get(side);
+ if (oldSideConfig != null) {
+     node.setConnectionConfig(side,
+         currentConfig.withIsRoundRobin(oldSideConfig.isRoundRobin)
+                      .withIsSelfFeed(oldSideConfig.isSelfFeed)
+                      .withPriority(oldSideConfig.priority));
+ }
📝 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.

    @Override
    public void copyLegacyData(ConduitNode node, ConduitDataAccessor legacyDataAccessor) {
        var legacyData = legacyDataAccessor.getData(ConduitTypes.Data.ITEM.get());
        if (legacyData == null) {
            return;
        }

        // Copy connection config
        for (Direction side : Direction.values()) {
            if (node.isConnectedTo(side)) {
                var oldSideConfig = legacyData.get(side);
                var currentConfig = node.getConnectionConfig(side, ItemConduitConnectionConfig.TYPE);

                if (oldSideConfig != null) {
                    node.setConnectionConfig(side,
                        currentConfig.withIsRoundRobin(oldSideConfig.isRoundRobin)
                                     .withIsSelfFeed(oldSideConfig.isSelfFeed)
                                     .withPriority(oldSideConfig.priority));
                }
            }
        }
    }
enderio-conduits/src/main/java/com/enderio/conduits/client/gui/screen/types/FluidConduitScreenType.java (2)

111-122: 🛠️ Refactor suggestion

Handle invalid resource locations when retrieving locked fluid.
A malformed or missing fluid identifier could throw an exception.

Consider adding a try/catch block:

- return BuiltInRegistries.FLUID.get(ResourceLocation.parse(tag.getString("LockedFluid")));
+ try {
+     return BuiltInRegistries.FLUID.get(ResourceLocation.parse(tag.getString("LockedFluid")));
+ } catch (Exception e) {
+     // Log and gracefully handle invalid fluid name
+     return Fluids.EMPTY;
+ }
📝 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.

    private Fluid getLockedFluid(ConduitMenuDataAccess<FluidConduitConnectionConfig> dataAccess) {
        var tag = dataAccess.getExtraGuiData();
        if (tag == null) {
            return Fluids.EMPTY;
        }

        if (!tag.contains("LockedFluid")) {
            return Fluids.EMPTY;
        }

        try {
            return BuiltInRegistries.FLUID.get(ResourceLocation.parse(tag.getString("LockedFluid")));
        } catch (Exception e) {
            // Log and gracefully handle invalid fluid name
            return Fluids.EMPTY;
        }
    }

124-193: 🛠️ Refactor suggestion

Confirm fluid supplier reliability.
Ensure currentFluid.get() is never null. If null is possible, add a safeguard check to prevent potential NullPointerExceptions.

Example adjustment:

- if (!currentFluid.get().isSame(Fluids.EMPTY)) {
+ var fluid = currentFluid.get();
+ if (fluid != null && !fluid.isSame(Fluids.EMPTY)) {
+     // ...
+ }
📝 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.

    private static class FluidWidget extends AbstractWidget {
        private static final ResourceLocation WIDGET_TEXTURE = EnderIO.loc("textures/gui/fluidbackground.png");

        private final Runnable onPress;
        private final Supplier<Fluid> currentFluid;

        FluidWidget(int x, int y, Supplier<Fluid> fluid, Runnable onPress) {
            super(x, y, 14, 14, Component.empty());
            this.onPress = onPress;
            this.currentFluid = fluid;
        }

        @Override
        public void updateWidgetNarration(NarrationElementOutput pNarrationElementOutput) {
        }

        @Override
        public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
            if (isHoveredOrFocused()) {
                MutableComponent tooltip = ConduitLang.FLUID_CONDUIT_CHANGE_FLUID1.copy();
                tooltip.append("\n").append(ConduitLang.FLUID_CONDUIT_CHANGE_FLUID2);
                var fluid = currentFluid.get();
                if (fluid != null && !fluid.isSame(Fluids.EMPTY)) {
                    tooltip.append("\n")
                           .append(TooltipUtil.withArgs(ConduitLang.FLUID_CONDUIT_CHANGE_FLUID3,
                                   fluid.getFluidType().getDescription()));
                }
                setTooltip(Tooltip.create(TooltipUtil.style(tooltip)));
            }

            RenderSystem.enableBlend();
            RenderSystem.defaultBlendFunc();
            RenderSystem.enableDepthTest();
            guiGraphics.blit(WIDGET_TEXTURE, getX(), getY(), 0, 0, this.width, this.height);
            if (currentFluid.get().isSame(Fluids.EMPTY)) {
                return;
            }

            IClientFluidTypeExtensions props = IClientFluidTypeExtensions.of(currentFluid.get());
            ResourceLocation still = props.getStillTexture();
            AbstractTexture texture = Minecraft.getInstance()
                    .getTextureManager()
                    .getTexture(TextureAtlas.LOCATION_BLOCKS);
            if (texture instanceof TextureAtlas atlas) {
                TextureAtlasSprite sprite = atlas.getSprite(still);

                int color = props.getTintColor();
                RenderSystem.setShaderColor(FastColor.ARGB32.red(color) / 255.0F,
                        FastColor.ARGB32.green(color) / 255.0F, FastColor.ARGB32.blue(color) / 255.0F,
                        FastColor.ARGB32.alpha(color) / 255.0F);
                RenderSystem.enableBlend();

                int atlasWidth = (int) (sprite.contents().width() / (sprite.getU1() - sprite.getU0()));
                int atlasHeight = (int) (sprite.contents().height() / (sprite.getV1() - sprite.getV0()));

                guiGraphics.blit(TextureAtlas.LOCATION_BLOCKS, getX() + 1, getY() + 1, 0, sprite.getU0() * atlasWidth,
                        sprite.getV0() * atlasHeight, 12, 12, atlasWidth, atlasHeight);

                RenderSystem.setShaderColor(1, 1, 1, 1);
            }

            RenderSystem.disableBlend();
            RenderSystem.disableDepthTest();
        }

        @Override
        public void onClick(double pMouseX, double pMouseY) {
            onPress.run();
        }
    }
}
enderio-conduits/src/main/java/com/enderio/conduits/common/network/ConduitCommonPayloadHandler.java (1)

6-22: ⚠️ Potential issue

Review of ConduitCommonPayloadHandler implementation

The singleton implementation looks good, but there appears to be a potential issue with the permissions check in the handler method. Currently, only spectator players can update the connection configuration, which seems counterintuitive - spectators typically shouldn't be able to modify game state.

Consider the following fix:

-                if (context.player().isSpectator() && context.player().containerMenu instanceof ConduitMenu menu) {
+                if (!context.player().isSpectator() && context.player().containerMenu instanceof ConduitMenu menu) {
                     menu.setConnectionConfig(packet.connectionConfig());
                 }

Also, consider adding validation for the packet data and error logging for debugging purposes.

📝 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.

public class ConduitCommonPayloadHandler {
    private static final ConduitCommonPayloadHandler INSTANCE = new ConduitCommonPayloadHandler();

    public void handle(SetConduitConnectionConfigPacket packet, IPayloadContext context) {
        context.enqueueWork(() -> {
            if (packet.containerId() == context.player().containerMenu.containerId) {
-                if (context.player().isSpectator() && context.player().containerMenu instanceof ConduitMenu menu) {
+                if (!context.player().isSpectator() && context.player().containerMenu instanceof ConduitMenu menu) {
                     menu.setConnectionConfig(packet.connectionConfig());
                 }
            }
        });
    }

    public static ConduitCommonPayloadHandler getInstance() {
        return INSTANCE;
    }
}
enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/bundle/ConduitBlockEvent.java (1)

36-43: 🛠️ Refactor suggestion

Review spectator usage.
Allowing spectators to open conduit GUIs can be a design choice, but it may inadvertently disclose system internals. Please confirm that this aligns with your gameplay or security requirements.

enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/type/fluid/FluidConduitTicker.java (1)

28-29: ⚠️ Potential issue

Possible naming confusion leading to incorrect fluid flow.
The parameter receiver is drained, while senders are used for insertion. This may invert the intuitive usage of "receiver" and "sender". If the intention is to push fluid into “receiver”, rename these parameters or reverse the logic to avoid confusion about which side is actually providing fluid.

- private int doFluidTransfer(FluidStack fluid, Connection receiver, List<Connection> senders) {
-     FluidStack extractedFluid = receiver.fluidHandler().drain(fluid, IFluidHandler.FluidAction.SIMULATE);
-     ...
-     FluidStack transferredFluid = FluidUtil.tryFluidTransfer(insert.fluidHandler(), receiver.fluidHandler(), fluid, true);
+ private int doFluidTransfer(FluidStack fluid, Connection supplier, List<Connection> consumers) {
+     FluidStack extractedFluid = supplier.fluidHandler().drain(fluid, IFluidHandler.FluidAction.SIMULATE);
+     ...
+     FluidStack transferredFluid = FluidUtil.tryFluidTransfer(consumer.fluidHandler(), supplier.fluidHandler(), fluid, true);

Also applies to: 56-57

enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/ConduitBlockItem.java (1)

133-135: 🛠️ Refactor suggestion

Potential ClassCastException risk.

Casting o2 to (T) may cause a runtime error if they do not share the same type. Consider verifying compatibility or adding a defensive check to ensure correctness.

 private static <T extends Conduit<T, ?>> int compareConduitTo(Conduit<T, ?> o1, Conduit<?, ?> o2) {
-    return o1.compareTo((T) o2);
+    if (o2.getClass().isAssignableFrom(o1.getClass())) {
+        return o1.compareTo((T) o2);
+    } else {
+        // Fallback logic or safe handling
+        return 0;
+    }
 }
📝 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.

    private static <T extends Conduit<T, ?>> int compareConduitTo(Conduit<T, ?> o1, Conduit<?, ?> o2) {
        if (o2.getClass().isAssignableFrom(o1.getClass())) {
            return o1.compareTo((T) o2);
        } else {
            // Fallback logic or safe handling
            return 0;
        }
    }
enderio-conduits/src/main/java/com/enderio/conduits/api/ConduitType.java (1)

34-40: 🛠️ Refactor suggestion

Check all call sites for the updated method signatures.
These methods now accept a more flexible type parameter T extends Conduit<T, ?>. Confirm that all code referencing these factory or builder methods has been updated to avoid compile-time errors.

enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/type/redstone/RedstoneConduit.java (1)

99-105: ⚠️ Potential issue

isItemValid uses stack.getCapability(...) instanceof ...
getCapability returns a LazyOptional, so direct instanceof checks typically fail at runtime. Ensure the code resolves the capability instance first.

enderio-conduits/src/main/java/com/enderio/conduits/client/gui/screen/types/ConduitScreenTypes.java (1)

23-29: 🛠️ Refactor suggestion

Add null check in get method

The get method doesn't verify if the SCREEN_TYPES map has been initialized or if the lookup returns null. This could lead to unexpected NullPointerExceptions.

     @EnsureSide(EnsureSide.Side.CLIENT)
     @Nullable
     public static <T extends Conduit<T, U>, U extends ConnectionConfig> ConduitScreenType<U> get(
             ConduitType<T> conduitType) {
+        if (SCREEN_TYPES == null) {
+            return null;
+        }
         // noinspection unchecked
         return (ConduitScreenType<U>) SCREEN_TYPES.get(conduitType);
     }
📝 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.

    @EnsureSide(EnsureSide.Side.CLIENT)
    @Nullable
    public static <T extends Conduit<T, U>, U extends ConnectionConfig> ConduitScreenType<U> get(
            ConduitType<T> conduitType) {
        if (SCREEN_TYPES == null) {
            return null;
        }
        // noinspection unchecked
        return (ConduitScreenType<U>) SCREEN_TYPES.get(conduitType);
    }
enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/type/fluid/FluidConduit.java (1)

33-34: ⚠️ Potential issue

Evaluate fallback scenario for multi-fluid.
If the conduit is multi-fluid, canConnectConduits() returns true without further checks. Ensure this does not allow unintended fluid mixing in the network.

Do you need a fallback check to disallow mixing incompatible fluids?

enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/menu/ConduitMenu.java (1)

85-103: 💡 Verification agent

Verification inconclusive

Verify buffer decoding for potential errors.
Decoding from the buffer can throw runtime exceptions if the data is malformed or from a mismatched mod version. Including minimal error handling or fallback logic could protect against unexpected data corruption and prevent crashes.

Please run a quick search throughout the codebase to confirm if any buffer decoding exceptions are caught or handled:


🏁 Script executed:

#!/bin/bash
rg -A 5 "decode(buf)"

Length of output: 23


Buffer Decoding Error Handling Required

It has been confirmed that the buffer decoding in the constructor of ConduitMenu (lines 85–103) is unguarded—that is, there is no try-catch or other form of error handling in place for the Conduit.STREAM_CODEC.decode(buf) call. Without such safeguards, a malformed buffer or a version mismatch could indeed result in runtime exceptions and potentially crash the application.

Please consider adding minimal error handling or fallback logic at this stage. A potential solution could involve wrapping the decode call in a try-catch block to handle any exceptions gracefully, thereby ensuring the UI remains stable even in the event of data corruption.

Affected file:
enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/menu/ConduitMenu.java (lines 85–103)

enderio-conduits/src/main/java/com/enderio/conduits/api/Conduit.java (1)

196-198: 🛠️ Refactor suggestion

Inform users about item inventory size changes on conduit upgrades.
A note is present regarding item loss. It might be beneficial to present an in-game warning if the user tries to transition from a larger inventory conduit to a smaller one.

> [!CAUTION] > Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings. <details> <summary>🛑 Comments failed to post (28)</summary><blockquote> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/integration/jade/package-info.java (1)</summary><blockquote> 4-4: _🛠️ Refactor suggestion_ **Updated Package Declaration** The package declaration has been adjusted to reflect the new organisational structure, moving the file into `com.enderio.conduits.integration.jade` as intended by this refactor. Please ensure that all related modules, documentation, and references are updated accordingly to maintain consistency across the codebase. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/type/item/ItemConduitNodeData.java (1)</summary><blockquote> 18-22: _🛠️ Refactor suggestion_ **Consider limiting or validating the map entries.** By using `Codec.unboundedMap(Direction.CODEC, Codec.INT)`, there is no explicit upper bound on map size. Realistically, only 6 entries are needed (one per `Direction`). You might consider using an enum-based map (e.g. `EnumMap<Direction, Integer>`) or validating the map during decoding to ensure data doesn't exceed expected sizes. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/client/model/conduit/modifier/RedstoneConduitModelModifier.java (1)</summary><blockquote> 14-14: _🛠️ Refactor suggestion_ **Add type checking before casting.** This direct cast assumes the conduit is a RedstoneConduit type. If a different conduit type is passed, this would throw a ClassCastException. Consider adding a type check before casting: ```diff - RedstoneConduit redstoneConduit = (RedstoneConduit) conduit.value(); + if (!(conduit.value() instanceof RedstoneConduit)) { + return null; // Or a default texture + } + RedstoneConduit redstoneConduit = (RedstoneConduit) conduit.value(); ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion if (!(conduit.value() instanceof RedstoneConduit)) { return null; // Or a default texture } RedstoneConduit redstoneConduit = (RedstoneConduit) conduit.value(); ````` </details> <!-- suggestion_end --> </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/graph/ConduitGraphContext.java (2)</summary><blockquote> 109-113: _🛠️ Refactor suggestion_ **Review: Encoding Context via Codec** The `encodeContext` method utilises `encodeStart(...).getOrThrow()` to perform serialization. While this approach ensures immediate feedback by throwing on error, it might be beneficial to consider more graceful error handling in future iterations, especially if codec failures are expected to occur under normal operation. --- 131-146: _🛠️ Refactor suggestion_ **Review: Robustness in loadNetworkContext Parsing** The private static `loadNetworkContext` method has been refactored to use the wildcard type for `Conduit<?, ?>` and includes critical null checks via `Objects.requireNonNull`. However, the repeated use of `getOrThrow()` (also noted in the TODO comment) indicates that error handling could be made more robust and flexible. Consider revisiting this approach to gracefully manage potential codec parsing failures. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/graph/ConduitConnectionHost.java (2)</summary><blockquote> 12-12: _⚠️ Potential issue_ **Address TODO comment before finalising PR** This TODO comment indicates uncertainty about whether this should be an interface or a concrete class. As interfaces are part of your public API contract (even if not marked as public API), changing this later could be disruptive. Consider resolving this architectural decision before merging. --- 20-22: _💡 Verification agent_ <details> <summary>🧩 Analysis chain</summary> **Verify error handling for connection configuration operations** The interface doesn't specify how errors should be handled when getting or setting connection configurations. Consider documenting what happens with invalid directions or null configuration values. Should implementers throw exceptions or handle errors gracefully? --- 🏁 Script executed: ```shell #!/bin/bash # Search for implementations of these methods to understand how errors are handled echo "Searching for implementations of getConnectionConfig and setConnectionConfig..." rg -A 5 -B 5 "getConnectionConfig\(Direction" --type java rg -A 5 -B 5 "setConnectionConfig\(Direction" --type java ``` Length of output: 14470 --- </details> **Update: Document Explicit Exception Contracts for Connection Configuration Methods** The investigation shows that implementations consistently handle error conditions by throwing exceptions (e.g. an IllegalStateException when the connection host is missing, or an IllegalArgumentException as documented in the API). However, the interface in *ConduitConnectionHost.java* does not explicitly specify the expected behaviour for invalid directions or null configuration values. - Please update the method documentation (Javadoc) to explicitly state: - That an IllegalArgumentException (or the appropriate exception) will be thrown if an invalid direction is provided. - What behaviour is expected if a null configuration value is passed to setConnectionConfig. - This clearer contract will help implementers ensure consistent error handling and improve the API’s usability. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/api/screen/RegisterConduitScreenTypesEvent.java (1)</summary><blockquote> 13-15: _💡 Verification agent_ <details> <summary>🧩 Analysis chain</summary> **Consider handling duplicate registrations.** The current implementation silently overwrites existing screen types for a conduit type. Depending on the intended behavior, you might want to log a warning or throw an exception when a duplicate registration occurs. --- 🏁 Script executed: ```shell #!/bin/bash # Check if there are any existing usages of this event that might be affected by this behavior rg -m 5 -A 3 "RegisterConduitScreenTypesEvent" --type java ``` Length of output: 3204 --- </details> **Duplicate Registration Handling Required** The current implementation of the register method in `enderio-conduits/src/main/java/com/enderio/conduits/api/screen/RegisterConduitScreenTypesEvent.java` silently overwrites any prior registration for a given conduit type. Given that the event is subsequently used in methods such as the one in `ConduitClientSetup.java` to register screen types, it would be prudent to explicitly handle duplicate registrations. For example, you might want to add a check to verify if a registration already exists and then log a warning or throw an exception before overwriting. A suggested approach: ```java public void register(ConduitType<? extends Conduit<?, ?>> conduitType, ConduitScreenType<?> screenType) { if(screenTypes.containsKey(conduitType)) { // Optionally log a warning or throw an exception to flag duplicate registration. // For instance: // throw new IllegalArgumentException("Duplicate registration for conduit type: " + conduitType); // Or alternatively: // Logger.warn("Duplicate registration for conduit type: " + conduitType + ". Overwriting existing screen type."); } screenTypes.put(conduitType, screenType); } ``` This change would ensure that accidental duplicate registrations do not lead to silent overwrites and make debugging registration issues easier. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/client/model/conduit/bundle/ConduitBundleRenderState.java (2)</summary><blockquote> 92-94: _⚠️ Potential issue_ **Potential null pointer exception in isConnectionEndpoint** This method assumes that `conduitConnections.get(side)` will never return null, but there's no guarantee of this. Consider adding a null check or using getOrDefault() as done in the `getConnectedConduits` method. ```diff public boolean isConnectionEndpoint(Direction side) { - return !conduitConnections.get(side).isEmpty(); + var connections = conduitConnections.get(side); + return connections != null && !connections.isEmpty(); } ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion public boolean isConnectionEndpoint(Direction side) { var connections = conduitConnections.get(side); return connections != null && !connections.isEmpty(); } ````` </details> <!-- suggestion_end --> --- 96-98: _⚠️ Potential issue_ **Missing null checks in getConnectionState** Similar to the issue above, this method may throw NullPointerExceptions if either `conduitConnections.get(side)` or the inner map's get returns null. ```diff public ConduitConnectionRenderState getConnectionState(Direction side, Holder<Conduit<?, ?>> conduit) { - return conduitConnections.get(side).get(conduit); + Map<Holder<Conduit<?, ?>>, ConduitConnectionRenderState> sideConnections = conduitConnections.get(side); + return sideConnections != null ? sideConnections.get(conduit) : null; } ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion public ConduitConnectionRenderState getConnectionState(Direction side, Holder<Conduit<?, ?>> conduit) { Map<Holder<Conduit<?, ?>>, ConduitConnectionRenderState> sideConnections = conduitConnections.get(side); return sideConnections != null ? sideConnections.get(conduit) : null; } ````` </details> <!-- suggestion_end --> </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/client/gui/ConduitSelectionButton.java (1)</summary><blockquote> 47-48: _🛠️ Refactor suggestion_ **Reference check vs. logical equality.** Using `conduit != currentConduit.get()` is a valid reference check, but consider whether a logical comparison (e.g., `.equals()`) might be more appropriate if multiple `Holder<Conduit<?, ?>>` instances could refer to the same underlying conduit. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/api/network/node/legacy/ConduitData.java (1)</summary><blockquote> 24-25: _🛠️ Refactor suggestion_ **Revisit parameter usage in withClientChanges.** This method currently ignores the `guiData` parameter, raising doubts about its relevance. Consider removing the parameter if truly unneeded, or implement the intended logic if appropriate. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/api/ticker/IOAwareConduitTicker.java (2)</summary><blockquote> 44-56: _🛠️ Refactor suggestion_ **Avoid creating duplicate connection objects for send/receive.** Calling `createConnection(...)` twice for the same node and side is wasteful if both `canSend(...)` and `canReceive(...)` return true. Refactor to create a single connection object, then add it to both sender and receiver lists if needed. ```diff - if (canSend(node, config)) { - var connection = createConnection(level, node, side); - if (connection != null) { - senders.get(config.sendColor()).add(connection); - } - } - - if (canReceive(node, config)) { - var connection = createConnection(level, node, side); - if (connection != null) { - receivers.get(config.receiveColor()).add(connection); - } - } + var canSend = canSend(node, config); + var canReceive = canReceive(node, config); + if (canSend || canReceive) { + var connection = createConnection(level, node, side); + if (connection != null) { + if (canSend) { + senders.get(config.sendColor()).add(connection); + } + if (canReceive) { + receivers.get(config.receiveColor()).add(connection); + } + } + } ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion var canSend = canSend(node, config); var canReceive = canReceive(node, config); if (canSend || canReceive) { var connection = createConnection(level, node, side); if (connection != null) { if (canSend) { senders.get(config.sendColor()).add(connection); } if (canReceive) { receivers.get(config.receiveColor()).add(connection); } } } ````` </details> <!-- suggestion_end --> --- 129-130: _💡 Verification agent_ <details> <summary>🧩 Analysis chain</summary> **Check for a potentially null inventory reference.** `node.getInventory(side)` could potentially return `null`, causing a NullPointerException if callers use `inventory()` without checking. Confirm that this is safe or add a null check to avoid unexpected runtime errors. --- 🏁 Script executed: ```shell #!/bin/bash # Description: Search the codebase for usage of inventory() to confirm if null checks are in place. fd -e java --exec rg --context 5 'inventory\(\)' ``` Length of output: 2774 --- </details> **Attention: Potential Null-Reference Risk in Inventory Access** The method implementation for `inventory()` simply returns `node.getInventory(side)` without any null-check. Our codebase usage—such as in: - `var inventory = receiver.inventory();` - Subsequent calls like `inventory.getStackInSlot(...)` —suggests that callers assume the return value will never be null. This could be risky if `node.getInventory(side)` can indeed return null, as it would lead to a NullPointerException at runtime. Please either: - Confirm that `node.getInventory(side)` is guaranteed never to return null (for example, via a non-null invariant or appropriate annotations/documentation), or - Add an explicit null-check within the `inventory()` method (or at all call sites) to handle a potential null value safely. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/legacy/DynamicConnectionState.java (1)</summary><blockquote> 53-63: _🛠️ Refactor suggestion_ **Handle the STUB or remove the redundant code** The provided parameters (`level`, `pos`, `direction`, `type`) are not used, and the method simply returns a fixed `DynamicConnectionState`. Consider implementing the intended logic or removing this STUB. ```diff - // STUB - return new DynamicConnectionState(false, DyeColor.GREEN, true, DyeColor.GREEN, RedstoneControl.NEVER_ACTIVE, - DyeColor.RED, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY); +Conduit.ConduitConnectionData defaultConnection = type.value().getDefaultConnection(level, pos, direction); +return new DynamicConnectionState( + defaultConnection.isInsert(), + DyeColor.GREEN, + defaultConnection.isExtract(), + DyeColor.GREEN, + defaultConnection.control(), + DyeColor.RED, + ItemStack.EMPTY, + ItemStack.EMPTY, + ItemStack.EMPTY +); ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion Holder<Conduit<?, ?>> type) { Conduit.ConduitConnectionData defaultConnection = type.value().getDefaultConnection(level, pos, direction); return new DynamicConnectionState( defaultConnection.isInsert(), DyeColor.GREEN, defaultConnection.isExtract(), DyeColor.GREEN, defaultConnection.control(), DyeColor.RED, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY ); } ````` </details> <!-- suggestion_end --> </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/type/item/ItemConduit.java (1)</summary><blockquote> 109-128: _⚠️ Potential issue_ **Safeguard against null legacy side config.** When retrieving legacy data, there's a risk `oldSideConfig` might be null if the map lacks entries for certain sides. Dereferencing it could result in a null pointer exception. To address this, consider a null check as shown below: ```diff - var oldSideConfig = legacyData.get(side); - node.setConnectionConfig(side, - currentConfig.withIsRoundRobin(oldSideConfig.isRoundRobin) - .withIsSelfFeed(oldSideConfig.isSelfFeed) - .withPriority(oldSideConfig.priority)); + var oldSideConfig = legacyData.get(side); + if (oldSideConfig != null) { + node.setConnectionConfig(side, + currentConfig.withIsRoundRobin(oldSideConfig.isRoundRobin) + .withIsSelfFeed(oldSideConfig.isSelfFeed) + .withPriority(oldSideConfig.priority)); + } ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion @Override public void copyLegacyData(ConduitNode node, ConduitDataAccessor legacyDataAccessor) { var legacyData = legacyDataAccessor.getData(ConduitTypes.Data.ITEM.get()); if (legacyData == null) { return; } // Copy connection config for (Direction side : Direction.values()) { if (node.isConnectedTo(side)) { var oldSideConfig = legacyData.get(side); var currentConfig = node.getConnectionConfig(side, ItemConduitConnectionConfig.TYPE); if (oldSideConfig != null) { node.setConnectionConfig(side, currentConfig.withIsRoundRobin(oldSideConfig.isRoundRobin) .withIsSelfFeed(oldSideConfig.isSelfFeed) .withPriority(oldSideConfig.priority)); } } } } ````` </details> <!-- suggestion_end --> </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/client/gui/screen/types/FluidConduitScreenType.java (2)</summary><blockquote> 111-122: _🛠️ Refactor suggestion_ **Handle invalid resource locations when retrieving locked fluid.** A malformed or missing fluid identifier could throw an exception. Consider adding a try/catch block: ```diff - return BuiltInRegistries.FLUID.get(ResourceLocation.parse(tag.getString("LockedFluid"))); + try { + return BuiltInRegistries.FLUID.get(ResourceLocation.parse(tag.getString("LockedFluid"))); + } catch (Exception e) { + // Log and gracefully handle invalid fluid name + return Fluids.EMPTY; + } ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion private Fluid getLockedFluid(ConduitMenuDataAccess<FluidConduitConnectionConfig> dataAccess) { var tag = dataAccess.getExtraGuiData(); if (tag == null) { return Fluids.EMPTY; } if (!tag.contains("LockedFluid")) { return Fluids.EMPTY; } try { return BuiltInRegistries.FLUID.get(ResourceLocation.parse(tag.getString("LockedFluid"))); } catch (Exception e) { // Log and gracefully handle invalid fluid name return Fluids.EMPTY; } } ````` </details> <!-- suggestion_end --> --- 124-193: _🛠️ Refactor suggestion_ **Confirm fluid supplier reliability.** Ensure `currentFluid.get()` is never null. If null is possible, add a safeguard check to prevent potential NullPointerExceptions. Example adjustment: ```diff - if (!currentFluid.get().isSame(Fluids.EMPTY)) { + var fluid = currentFluid.get(); + if (fluid != null && !fluid.isSame(Fluids.EMPTY)) { + // ... + } ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion private static class FluidWidget extends AbstractWidget { private static final ResourceLocation WIDGET_TEXTURE = EnderIO.loc("textures/gui/fluidbackground.png"); private final Runnable onPress; private final Supplier<Fluid> currentFluid; FluidWidget(int x, int y, Supplier<Fluid> fluid, Runnable onPress) { super(x, y, 14, 14, Component.empty()); this.onPress = onPress; this.currentFluid = fluid; } @Override public void updateWidgetNarration(NarrationElementOutput pNarrationElementOutput) { } @Override public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { if (isHoveredOrFocused()) { MutableComponent tooltip = ConduitLang.FLUID_CONDUIT_CHANGE_FLUID1.copy(); tooltip.append("\n").append(ConduitLang.FLUID_CONDUIT_CHANGE_FLUID2); var fluid = currentFluid.get(); if (fluid != null && !fluid.isSame(Fluids.EMPTY)) { tooltip.append("\n") .append(TooltipUtil.withArgs(ConduitLang.FLUID_CONDUIT_CHANGE_FLUID3, fluid.getFluidType().getDescription())); } setTooltip(Tooltip.create(TooltipUtil.style(tooltip))); } RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); RenderSystem.enableDepthTest(); guiGraphics.blit(WIDGET_TEXTURE, getX(), getY(), 0, 0, this.width, this.height); if (currentFluid.get().isSame(Fluids.EMPTY)) { return; } IClientFluidTypeExtensions props = IClientFluidTypeExtensions.of(currentFluid.get()); ResourceLocation still = props.getStillTexture(); AbstractTexture texture = Minecraft.getInstance() .getTextureManager() .getTexture(TextureAtlas.LOCATION_BLOCKS); if (texture instanceof TextureAtlas atlas) { TextureAtlasSprite sprite = atlas.getSprite(still); int color = props.getTintColor(); RenderSystem.setShaderColor(FastColor.ARGB32.red(color) / 255.0F, FastColor.ARGB32.green(color) / 255.0F, FastColor.ARGB32.blue(color) / 255.0F, FastColor.ARGB32.alpha(color) / 255.0F); RenderSystem.enableBlend(); int atlasWidth = (int) (sprite.contents().width() / (sprite.getU1() - sprite.getU0())); int atlasHeight = (int) (sprite.contents().height() / (sprite.getV1() - sprite.getV0())); guiGraphics.blit(TextureAtlas.LOCATION_BLOCKS, getX() + 1, getY() + 1, 0, sprite.getU0() * atlasWidth, sprite.getV0() * atlasHeight, 12, 12, atlasWidth, atlasHeight); RenderSystem.setShaderColor(1, 1, 1, 1); } RenderSystem.disableBlend(); RenderSystem.disableDepthTest(); } @Override public void onClick(double pMouseX, double pMouseY) { onPress.run(); } } } ````` </details> <!-- suggestion_end --> </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/network/ConduitCommonPayloadHandler.java (1)</summary><blockquote> 6-22: _⚠️ Potential issue_ **Review of ConduitCommonPayloadHandler implementation** The singleton implementation looks good, but there appears to be a potential issue with the permissions check in the handler method. Currently, only spectator players can update the connection configuration, which seems counterintuitive - spectators typically shouldn't be able to modify game state. Consider the following fix: ```diff - if (context.player().isSpectator() && context.player().containerMenu instanceof ConduitMenu menu) { + if (!context.player().isSpectator() && context.player().containerMenu instanceof ConduitMenu menu) { menu.setConnectionConfig(packet.connectionConfig()); } ``` Also, consider adding validation for the packet data and error logging for debugging purposes. <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion public class ConduitCommonPayloadHandler { private static final ConduitCommonPayloadHandler INSTANCE = new ConduitCommonPayloadHandler(); public void handle(SetConduitConnectionConfigPacket packet, IPayloadContext context) { context.enqueueWork(() -> { if (packet.containerId() == context.player().containerMenu.containerId) { - if (context.player().isSpectator() && context.player().containerMenu instanceof ConduitMenu menu) { + if (!context.player().isSpectator() && context.player().containerMenu instanceof ConduitMenu menu) { menu.setConnectionConfig(packet.connectionConfig()); } } }); } public static ConduitCommonPayloadHandler getInstance() { return INSTANCE; } } ````` </details> <!-- suggestion_end --> </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/bundle/ConduitBlockEvent.java (1)</summary><blockquote> 36-43: _🛠️ Refactor suggestion_ **Review spectator usage.** Allowing spectators to open conduit GUIs can be a design choice, but it may inadvertently disclose system internals. Please confirm that this aligns with your gameplay or security requirements. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/type/fluid/FluidConduitTicker.java (1)</summary><blockquote> 28-29: _⚠️ Potential issue_ **Possible naming confusion leading to incorrect fluid flow.** The parameter `receiver` is drained, while `senders` are used for insertion. This may invert the intuitive usage of "receiver" and "sender". If the intention is to push fluid into “receiver”, rename these parameters or reverse the logic to avoid confusion about which side is actually providing fluid. ```diff - private int doFluidTransfer(FluidStack fluid, Connection receiver, List<Connection> senders) { - FluidStack extractedFluid = receiver.fluidHandler().drain(fluid, IFluidHandler.FluidAction.SIMULATE); - ... - FluidStack transferredFluid = FluidUtil.tryFluidTransfer(insert.fluidHandler(), receiver.fluidHandler(), fluid, true); + private int doFluidTransfer(FluidStack fluid, Connection supplier, List<Connection> consumers) { + FluidStack extractedFluid = supplier.fluidHandler().drain(fluid, IFluidHandler.FluidAction.SIMULATE); + ... + FluidStack transferredFluid = FluidUtil.tryFluidTransfer(consumer.fluidHandler(), supplier.fluidHandler(), fluid, true); ``` Also applies to: 56-57 </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/ConduitBlockItem.java (1)</summary><blockquote> 133-135: _🛠️ Refactor suggestion_ **Potential ClassCastException risk.** Casting `o2` to `(T)` may cause a runtime error if they do not share the same type. Consider verifying compatibility or adding a defensive check to ensure correctness. ```diff private static <T extends Conduit<T, ?>> int compareConduitTo(Conduit<T, ?> o1, Conduit<?, ?> o2) { - return o1.compareTo((T) o2); + if (o2.getClass().isAssignableFrom(o1.getClass())) { + return o1.compareTo((T) o2); + } else { + // Fallback logic or safe handling + return 0; + } } ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion private static <T extends Conduit<T, ?>> int compareConduitTo(Conduit<T, ?> o1, Conduit<?, ?> o2) { if (o2.getClass().isAssignableFrom(o1.getClass())) { return o1.compareTo((T) o2); } else { // Fallback logic or safe handling return 0; } } ````` </details> <!-- suggestion_end --> </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/api/ConduitType.java (1)</summary><blockquote> 34-40: _🛠️ Refactor suggestion_ **Check all call sites for the updated method signatures.** These methods now accept a more flexible type parameter `T extends Conduit<T, ?>`. Confirm that all code referencing these factory or builder methods has been updated to avoid compile-time errors. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/type/redstone/RedstoneConduit.java (1)</summary><blockquote> 99-105: _⚠️ Potential issue_ **`isItemValid` uses `stack.getCapability(...) instanceof ...`** `getCapability` returns a `LazyOptional`, so direct `instanceof` checks typically fail at runtime. Ensure the code resolves the capability instance first. </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/client/gui/screen/types/ConduitScreenTypes.java (1)</summary><blockquote> 23-29: _🛠️ Refactor suggestion_ **Add null check in get method** The `get` method doesn't verify if the `SCREEN_TYPES` map has been initialized or if the lookup returns null. This could lead to unexpected NullPointerExceptions. ```diff @EnsureSide(EnsureSide.Side.CLIENT) @Nullable public static <T extends Conduit<T, U>, U extends ConnectionConfig> ConduitScreenType<U> get( ConduitType<T> conduitType) { + if (SCREEN_TYPES == null) { + return null; + } // noinspection unchecked return (ConduitScreenType<U>) SCREEN_TYPES.get(conduitType); } ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **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. `````suggestion @EnsureSide(EnsureSide.Side.CLIENT) @Nullable public static <T extends Conduit<T, U>, U extends ConnectionConfig> ConduitScreenType<U> get( ConduitType<T> conduitType) { if (SCREEN_TYPES == null) { return null; } // noinspection unchecked return (ConduitScreenType<U>) SCREEN_TYPES.get(conduitType); } ````` </details> <!-- suggestion_end --> </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/type/fluid/FluidConduit.java (1)</summary><blockquote> 33-34: _⚠️ Potential issue_ **Evaluate fallback scenario for multi-fluid.** If the conduit is multi-fluid, `canConnectConduits()` returns `true` without further checks. Ensure this does not allow unintended fluid mixing in the network. Do you need a fallback check to disallow mixing incompatible fluids? </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/menu/ConduitMenu.java (1)</summary><blockquote> 85-103: _💡 Verification agent_ <details> <summary>❓ Verification inconclusive</summary> **Verify buffer decoding for potential errors.** Decoding from the buffer can throw runtime exceptions if the data is malformed or from a mismatched mod version. Including minimal error handling or fallback logic could protect against unexpected data corruption and prevent crashes. Please run a quick search throughout the codebase to confirm if any buffer decoding exceptions are caught or handled: --- 🏁 Script executed: ```shell #!/bin/bash rg -A 5 "decode(buf)" ``` Length of output: 23 --- </details> **Buffer Decoding Error Handling Required** It has been confirmed that the buffer decoding in the constructor of `ConduitMenu` (lines 85–103) is unguarded—that is, there is no try-catch or other form of error handling in place for the `Conduit.STREAM_CODEC.decode(buf)` call. Without such safeguards, a malformed buffer or a version mismatch could indeed result in runtime exceptions and potentially crash the application. Please consider adding minimal error handling or fallback logic at this stage. A potential solution could involve wrapping the decode call in a try-catch block to handle any exceptions gracefully, thereby ensuring the UI remains stable even in the event of data corruption. Affected file: • `enderio-conduits/src/main/java/com/enderio/conduits/common/conduit/menu/ConduitMenu.java` (lines 85–103) </blockquote></details> <details> <summary>enderio-conduits/src/main/java/com/enderio/conduits/api/Conduit.java (1)</summary><blockquote> 196-198: _🛠️ Refactor suggestion_ **Inform users about item inventory size changes on conduit upgrades.** A note is present regarding item loss. It might be beneficial to present an in-game warning if the user tries to transition from a larger inventory conduit to a smaller one. </blockquote></details> </blockquote></details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
justliliandev (Migrated from github.com) reviewed 2025-03-17 22:06:45 +00:00
justliliandev (Migrated from github.com) left a comment

there are some nice improvements there, well done

there are some nice improvements there, well done
justliliandev (Migrated from github.com) commented 2025-03-17 20:26:52 +00:00

I think this should be final?

I think this should be final?
justliliandev (Migrated from github.com) commented 2025-03-17 20:28:22 +00:00

replace this comment with either ensure annotation or the UseOnly Annotation
also both constructors are identical, is that itended?

replace this comment with either ensure annotation or the UseOnly Annotation also both constructors are identical, is that itended?
justliliandev (Migrated from github.com) commented 2025-03-17 20:34:22 +00:00

i think this should be reference equality

i think this should be reference equality
justliliandev (Migrated from github.com) commented 2025-03-17 20:38:36 +00:00

why is this checking hasCustomBackDestination? it will always be true and is already checked by AbstractFilterMenu#clickMenuButton

why is this checking hasCustomBackDestination? it will always be true and is already checked by AbstractFilterMenu#clickMenuButton
@ -0,0 +23,4 @@
*/
@ApiStatus.Experimental
@ApiStatus.AvailableSince("8.0.0")
public interface ConduitBundle {
justliliandev (Migrated from github.com) commented 2025-03-17 21:01:35 +00:00

is there a reason that conduit additions/removals/queries are exposed as api, was there a request for this?

is there a reason that conduit additions/removals/queries are exposed as api, was there a request for this?
@ -0,0 +8,4 @@
@ApiStatus.Experimental
public record ConnectionConfigType<T extends ConnectionConfig>(MapCodec<T> codec,
StreamCodec<RegistryFriendlyByteBuf, T> streamCodec, Supplier<T> defaultSupplier) {
justliliandev (Migrated from github.com) commented 2025-03-17 21:07:48 +00:00

rename defaultSupplier to factory if you want

rename defaultSupplier to factory if you want
@ -0,0 +35,4 @@
ConduitMenuDataAccess<U> dataAccess);
/**
* Already projected into gui space (guiLeft & guiRight in Screen), so only local transformations required.
justliliandev (Migrated from github.com) commented 2025-03-17 21:12:49 +00:00
     * Already projected into gui space (guiLeft & guiTop in Screen), so only local transformations required.
```suggestion * Already projected into gui space (guiLeft & guiTop in Screen), so only local transformations required. ```
@ -0,0 +296,4 @@
public boolean isCustomRenderer() {
return false;
}
justliliandev (Migrated from github.com) commented 2025-03-17 21:26:27 +00:00

dual-color redstone control? Not questioning or something, just interested in knowing more.

dual-color redstone control? Not questioning or something, just interested in knowing more.
@ -0,0 +15,4 @@
* A11Y tools for conduit block behaviours.
*/
@EventBusSubscriber(/* value = Dist.CLIENT, */modid = EnderIOConduits.MODULE_MOD_ID, bus = EventBusSubscriber.Bus.GAME)
public class ConduitA11yManager {
justliliandev (Migrated from github.com) commented 2025-03-17 21:33:46 +00:00

what will this be doing in the future?

what will this be doing in the future?
Rover656 (Migrated from github.com) reviewed 2025-03-18 16:54:17 +00:00
Rover656 (Migrated from github.com) commented 2025-03-18 16:54:16 +00:00

Yep that's right, thanks

Yep that's right, thanks
Rover656 (Migrated from github.com) reviewed 2025-03-18 16:54:49 +00:00
Rover656 (Migrated from github.com) commented 2025-03-18 16:54:49 +00:00

UseOnly is a good idea - and yes normally both constructors are identical, but they can have different overloads (i.e. client menu uses a buffer to load extra data while server menu reads from the BE)

UseOnly is a good idea - and yes normally both constructors are identical, but they can have different overloads (i.e. client menu uses a buffer to load extra data while server menu reads from the BE)
Rover656 (Migrated from github.com) reviewed 2025-03-18 16:55:46 +00:00
@ -0,0 +23,4 @@
*/
@ApiStatus.Experimental
@ApiStatus.AvailableSince("8.0.0")
public interface ConduitBundle {
Rover656 (Migrated from github.com) commented 2025-03-18 16:55:46 +00:00

The developer of Pipe Connector was looking for better ways to interact with the conduit bundles. I think they are useful utilities to expose

The developer of [Pipe Connector](https://www.curseforge.com/minecraft/mc-mods/pipe-connector) was looking for better ways to interact with the conduit bundles. I think they are useful utilities to expose
Rover656 (Migrated from github.com) reviewed 2025-03-18 16:56:23 +00:00
@ -0,0 +296,4 @@
public boolean isCustomRenderer() {
return false;
}
Rover656 (Migrated from github.com) commented 2025-03-18 16:56:23 +00:00

Redstone control for both insertion and extraction independently has been requested - while we're now in a position where this can be implemented from a technical standpoint, work needs to be done to render both colours well.

Redstone control for both insertion and extraction independently has been requested - while we're now in a position where this can be implemented from a technical standpoint, work needs to be done to render both colours well.
Rover656 (Migrated from github.com) reviewed 2025-03-18 16:57:01 +00:00
@ -0,0 +15,4 @@
* A11Y tools for conduit block behaviours.
*/
@EventBusSubscriber(/* value = Dist.CLIENT, */modid = EnderIOConduits.MODULE_MOD_ID, bus = EventBusSubscriber.Bus.GAME)
public class ConduitA11yManager {
Rover656 (Migrated from github.com) commented 2025-03-18 16:57:01 +00:00

The intent is to make placing conduits easier by expanding the bounding box of the block when holding a conduit already present in the bundle, so users don't have to struggle with aiming for the tiny conduit square.

Still needs work however, so I've left it commented for now.

The intent is to make placing conduits easier by expanding the bounding box of the block when holding a conduit already present in the bundle, so users don't have to struggle with aiming for the tiny conduit square. Still needs work however, so I've left it commented for now.
Rover656 commented 2025-03-18 16:57:24 +00:00 (Migrated from github.com)

there are some nice improvements there, well done

Thanks for the review :) I hope to continue working on this PR when Uni chills out a bit :)
I hope you are well!

> there are some nice improvements there, well done Thanks for the review :) I hope to continue working on this PR when Uni chills out a bit :) I hope you are well!
coderabbitai[bot] (Migrated from github.com) reviewed 2025-05-06 21:00:23 +00:00
coderabbitai[bot] (Migrated from github.com) left a comment

Actionable comments posted: 1

🔭 Outside diff range comments (1)
enderio-base/src/main/java/com/enderio/EnderIOBase.java (1)

7-26: ⚠️ Potential issue

Import order needs to be fixed.

The pipeline failure indicates that the import order doesn't comply with the project's formatting requirements.

Run the command suggested in the error message to fix this:

./gradlew :enderio-base:spotlessApply
🧹 Nitpick comments (2)
endercore/src/main/java/com/enderio/core/common/menu/BaseEnderMenu.java (1)

69-75: Consider adding Javadoc to the factory methods.

These factory methods provide a good extension point for subclasses. It would be helpful to add Javadoc comments explaining their purpose, parameters, and how they can be overridden by subclasses to customize slot creation.

+    /**
+     * Creates a slot for the player inventory.
+     * Override this method to provide custom inventory slots.
+     *
+     * @param inventory The player's inventory
+     * @param slot The slot index
+     * @param x The x position
+     * @param y The y position
+     * @return A new inventory slot
+     */
     protected Slot createPlayerInventorySlot(Inventory inventory, int slot, int x, int y) {
         return new Slot(inventory, slot, x, y);
     }

+    /**
+     * Creates an armor slot for the player inventory.
+     * Override this method to provide custom armor slots.
+     *
+     * @param inventory The player's inventory
+     * @param slot The slot index
+     * @param x The x position 
+     * @param y The y position
+     * @param slotType The equipment slot type
+     * @return A new armor slot
+     */
     protected ArmorSlot createPlayerArmorSlot(Inventory inventory, int slot, int x, int y, EquipmentSlot slotType) {
         return new ArmorSlot(inventory, slot, x, y, slotType);
     }
enderio-base/src/main/java/com/enderio/base/api/filter/FilterMenuProvider.java (1)

9-9: Consider addressing the TODO comment before finalising

This TODO comment indicates that the interface name might not be finalised. Consider resolving this before the final release to ensure API stability.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0a7b37d70dedfbb014c5a153aed4ca11e070c968 and 232cfa188d.

Files ignored due to path filters (21)
  • enderio-base/src/generated/resources/assets/enderio/lang/en_us.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/assets/enderio/models/item/advanced_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/assets/enderio/models/item/basic_fluid_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/assets/enderio/models/item/basic_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/assets/enderio/models/item/basic_soul_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/assets/enderio/models/item/big_advanced_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/assets/enderio/models/item/big_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/advanced_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/basic_fluid_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/basic_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/basic_soul_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/erase_advanced_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/erase_basic_fluid_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/erase_basic_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/recipe/advanced_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/recipe/basic_fluid_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/recipe/basic_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/recipe/basic_soul_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/recipe/erase_advanced_item_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/recipe/erase_basic_fluid_filter.json is excluded by !**/generated/**
  • enderio-base/src/generated/resources/data/enderio/recipe/erase_basic_item_filter.json is excluded by !**/generated/**
📒 Files selected for processing (23)
  • build.gradle.kts (1 hunks)
  • endercore/src/main/java/com/enderio/core/client/gui/screen/EnderContainerScreen.java (3 hunks)
  • endercore/src/main/java/com/enderio/core/client/gui/widgets/BaseEnumPickerWidget.java (1 hunks)
  • endercore/src/main/java/com/enderio/core/client/gui/widgets/IconButton.java (1 hunks)
  • endercore/src/main/java/com/enderio/core/client/gui/widgets/ToggleIconButton.java (1 hunks)
  • endercore/src/main/java/com/enderio/core/client/gui/widgets/ToggleImageButton.java (0 hunks)
  • endercore/src/main/java/com/enderio/core/client/icon/EnumIconMap.java (1 hunks)
  • endercore/src/main/java/com/enderio/core/common/blockentity/EnderBlockEntity.java (1 hunks)
  • endercore/src/main/java/com/enderio/core/common/menu/BaseBlockEntityMenu.java (1 hunks)
  • endercore/src/main/java/com/enderio/core/common/menu/BaseEnderMenu.java (1 hunks)
  • endercore/src/main/java/com/enderio/core/common/network/CoreNetwork.java (1 hunks)
  • endercore/src/main/java/com/enderio/core/common/util/TooltipUtil.java (1 hunks)
  • enderio-armory/src/main/java/com/enderio/armory/common/init/ArmoryNetwork.java (1 hunks)
  • enderio-base/src/main/java/com/enderio/EnderIOBase.java (2 hunks)
  • enderio-base/src/main/java/com/enderio/base/api/attachment/StoredEntityData.java (1 hunks)
  • enderio-base/src/main/java/com/enderio/base/api/filter/EntityFilter.java (1 hunks)
  • enderio-base/src/main/java/com/enderio/base/api/filter/FilterMenuProvider.java (1 hunks)
  • enderio-base/src/main/java/com/enderio/base/api/filter/FluidFilter.java (1 hunks)
  • enderio-base/src/main/java/com/enderio/base/api/filter/FluidStackFilter.java (0 hunks)
  • enderio-base/src/main/java/com/enderio/base/api/filter/ItemFilter.java (1 hunks)
  • enderio-base/src/main/java/com/enderio/base/api/filter/ItemStackFilter.java (0 hunks)
  • enderio-base/src/main/java/com/enderio/base/api/filter/ResourceFilter.java (0 hunks)
  • enderio-base/src/main/java/com/enderio/base/api/misc/RedstoneControl.java (2 hunks)
💤 Files with no reviewable changes (4)
  • enderio-base/src/main/java/com/enderio/base/api/filter/ResourceFilter.java
  • enderio-base/src/main/java/com/enderio/base/api/filter/ItemStackFilter.java
  • enderio-base/src/main/java/com/enderio/base/api/filter/FluidStackFilter.java
  • endercore/src/main/java/com/enderio/core/client/gui/widgets/ToggleImageButton.java
Files skipped from review due to trivial changes (2)
  • endercore/src/main/java/com/enderio/core/client/icon/EnumIconMap.java
  • enderio-base/src/main/java/com/enderio/base/api/filter/ItemFilter.java
🚧 Files skipped from review as they are similar to previous changes (7)
  • build.gradle.kts
  • endercore/src/main/java/com/enderio/core/client/gui/widgets/BaseEnumPickerWidget.java
  • endercore/src/main/java/com/enderio/core/common/menu/BaseBlockEntityMenu.java
  • endercore/src/main/java/com/enderio/core/client/gui/widgets/ToggleIconButton.java
  • endercore/src/main/java/com/enderio/core/common/blockentity/EnderBlockEntity.java
  • enderio-base/src/main/java/com/enderio/base/api/misc/RedstoneControl.java
  • endercore/src/main/java/com/enderio/core/client/gui/screen/EnderContainerScreen.java
🧰 Additional context used
🧬 Code Graph Analysis (1)
enderio-base/src/main/java/com/enderio/EnderIOBase.java (2)
enderio-base/src/main/java/com/enderio/base/common/filter/item/ItemFilterSlot.java (1)
  • ItemFilterSlot (9-35)
enderio-base/src/main/java/com/enderio/base/common/filter/fluid/FluidFilterSlot.java (1)
  • FluidFilterSlot (13-36)
🪛 GitHub Actions: Verify Build
enderio-base/src/main/java/com/enderio/EnderIOBase.java

[error] 1-1: Spotless formatting check failed. Import order and formatting violations detected. Run './gradlew :enderio-base:spotlessApply' to fix.

enderio-base/src/main/java/com/enderio/base/api/attachment/StoredEntityData.java

[error] 1-1: Spotless formatting check failed. Import order and formatting violations detected. Run './gradlew :enderio-base:spotlessApply' to fix.

🔇 Additional comments (11)
enderio-armory/src/main/java/com/enderio/armory/common/init/ArmoryNetwork.java (1)

25-25: API usage updated correctly

The code has been updated to use the simplified registrar method that only takes the protocol version rather than namespace and protocol version. This aligns with similar changes throughout the codebase and maintains consistency with the network API usage pattern.

endercore/src/main/java/com/enderio/core/common/network/CoreNetwork.java (1)

17-17: API usage updated correctly

The change simplifies the payload registrar acquisition by directly passing the protocol version instead of using the chained approach with module ID and .versioned(). This matches the pattern used in other network initialisation classes and makes the code more consistent across the codebase.

enderio-base/src/main/java/com/enderio/EnderIOBase.java (1)

7-7: Import paths have been updated to reflect package reorganisation.

The changes to import paths for ItemFilterSlot and FluidFilterSlot align with the broader refactoring of filter interfaces into dedicated packages based on filter type. This improves code organisation by grouping related filter components together.

Also applies to: 26-26

endercore/src/main/java/com/enderio/core/common/menu/BaseEnderMenu.java (3)

51-52: Good refactoring to use factory methods for slot creation.

This change improves extensibility by delegating slot creation to a dedicated method rather than direct instantiation. This allows subclasses to override the method to customize slot creation without altering the inventory layout logic.


59-59: Consistent use of the factory method pattern here.

The refactoring continues by applying the same factory method pattern to hotbar slots, maintaining consistency across the codebase.


65-65: Good implementation of factory method for armor slots.

Using the factory method pattern for armor slots completes the refactoring consistently. This makes the code more maintainable and allows subclasses to provide custom armor slot implementations.

endercore/src/main/java/com/enderio/core/common/util/TooltipUtil.java (1)

14-14: Improved type safety with MutableComponent return type.

Good change! Refining the return type from Component to MutableComponent provides better type safety and makes method chaining more intuitive. This accurately reflects that the method always returns a mutable component that can be further modified.

enderio-base/src/main/java/com/enderio/base/api/filter/FluidFilter.java (1)

1-17: Well-designed fluid filtering interface

This newly introduced interface provides a clean, explicit contract for fluid filtering. The method signature allows for contextual filtering by accepting a target fluid handler and returns the filtered stack (potentially with a different amount) rather than just a boolean result. This is a more powerful approach than the previous predicate-based design.

The documentation clearly explains how to use the interface, particularly noting the return of FluidStack#EMPTY to indicate that nothing should be transferred.

enderio-base/src/main/java/com/enderio/base/api/filter/FilterMenuProvider.java (1)

10-14: Clear interface definition for filter menu interaction

This new interface provides a standardised way to open filter-related menus with a clean, concise method signature. The inclusion of a goBackRunnable parameter is particularly useful for managing menu navigation flows.

The experimental annotation appropriately indicates that this API might evolve further.

enderio-base/src/main/java/com/enderio/base/api/attachment/StoredEntityData.java (1)

46-64: Effective implementation of optional entity data serialisation

The OPTIONAL_STREAM_CODEC provides a robust mechanism for efficiently serialising and deserialising optional StoredEntityData. The implementation correctly uses a boolean flag to indicate data presence and delegates to the existing STREAM_CODEC when needed.

This addition aligns well with the enhanced filter API's support for optional entity data handling.

However, there's a pipeline failure related to Spotless formatting issues. You should run the suggested command to fix these:

./gradlew :enderio-base:spotlessApply
enderio-base/src/main/java/com/enderio/base/api/filter/EntityFilter.java (1)

3-10: Improved entity filtering with specialised methods

This refactoring enhances the EntityFilter interface by providing distinct test methods for different entity-related types. This approach is more precise than the previous generic entity predicate, allowing for more flexible and powerful filtering capabilities.

The addition of test(StoredEntityData) is particularly valuable as it enables filtering of serialised entity data without requiring a live entity instance.

**Actionable comments posted: 1** <details> <summary>🔭 Outside diff range comments (1)</summary><blockquote> <details> <summary>enderio-base/src/main/java/com/enderio/EnderIOBase.java (1)</summary><blockquote> `7-26`: _⚠️ Potential issue_ **Import order needs to be fixed.** The pipeline failure indicates that the import order doesn't comply with the project's formatting requirements. Run the command suggested in the error message to fix this: ``` ./gradlew :enderio-base:spotlessApply ``` </blockquote></details> </blockquote></details> <details> <summary>🧹 Nitpick comments (2)</summary><blockquote> <details> <summary>endercore/src/main/java/com/enderio/core/common/menu/BaseEnderMenu.java (1)</summary><blockquote> `69-75`: **Consider adding Javadoc to the factory methods.** These factory methods provide a good extension point for subclasses. It would be helpful to add Javadoc comments explaining their purpose, parameters, and how they can be overridden by subclasses to customize slot creation. ```diff + /** + * Creates a slot for the player inventory. + * Override this method to provide custom inventory slots. + * + * @param inventory The player's inventory + * @param slot The slot index + * @param x The x position + * @param y The y position + * @return A new inventory slot + */ protected Slot createPlayerInventorySlot(Inventory inventory, int slot, int x, int y) { return new Slot(inventory, slot, x, y); } + /** + * Creates an armor slot for the player inventory. + * Override this method to provide custom armor slots. + * + * @param inventory The player's inventory + * @param slot The slot index + * @param x The x position + * @param y The y position + * @param slotType The equipment slot type + * @return A new armor slot + */ protected ArmorSlot createPlayerArmorSlot(Inventory inventory, int slot, int x, int y, EquipmentSlot slotType) { return new ArmorSlot(inventory, slot, x, y, slotType); } ``` </blockquote></details> <details> <summary>enderio-base/src/main/java/com/enderio/base/api/filter/FilterMenuProvider.java (1)</summary><blockquote> `9-9`: **Consider addressing the TODO comment before finalising** This TODO comment indicates that the interface name might not be finalised. Consider resolving this before the final release to ensure API stability. </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used: CodeRabbit UI** **Review profile: CHILL** **Plan: Pro** <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 0a7b37d70dedfbb014c5a153aed4ca11e070c968 and 232cfa188d513cd7bf4665f6c05aa56d713d6a6c. </details> <details> <summary>⛔ Files ignored due to path filters (21)</summary> * `enderio-base/src/generated/resources/assets/enderio/lang/en_us.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/assets/enderio/models/item/advanced_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/assets/enderio/models/item/basic_fluid_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/assets/enderio/models/item/basic_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/assets/enderio/models/item/basic_soul_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/assets/enderio/models/item/big_advanced_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/assets/enderio/models/item/big_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/advanced_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/basic_fluid_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/basic_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/basic_soul_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/erase_advanced_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/erase_basic_fluid_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/advancement/recipes/misc/erase_basic_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/recipe/advanced_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/recipe/basic_fluid_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/recipe/basic_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/recipe/basic_soul_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/recipe/erase_advanced_item_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/recipe/erase_basic_fluid_filter.json` is excluded by `!**/generated/**` * `enderio-base/src/generated/resources/data/enderio/recipe/erase_basic_item_filter.json` is excluded by `!**/generated/**` </details> <details> <summary>📒 Files selected for processing (23)</summary> * `build.gradle.kts` (1 hunks) * `endercore/src/main/java/com/enderio/core/client/gui/screen/EnderContainerScreen.java` (3 hunks) * `endercore/src/main/java/com/enderio/core/client/gui/widgets/BaseEnumPickerWidget.java` (1 hunks) * `endercore/src/main/java/com/enderio/core/client/gui/widgets/IconButton.java` (1 hunks) * `endercore/src/main/java/com/enderio/core/client/gui/widgets/ToggleIconButton.java` (1 hunks) * `endercore/src/main/java/com/enderio/core/client/gui/widgets/ToggleImageButton.java` (0 hunks) * `endercore/src/main/java/com/enderio/core/client/icon/EnumIconMap.java` (1 hunks) * `endercore/src/main/java/com/enderio/core/common/blockentity/EnderBlockEntity.java` (1 hunks) * `endercore/src/main/java/com/enderio/core/common/menu/BaseBlockEntityMenu.java` (1 hunks) * `endercore/src/main/java/com/enderio/core/common/menu/BaseEnderMenu.java` (1 hunks) * `endercore/src/main/java/com/enderio/core/common/network/CoreNetwork.java` (1 hunks) * `endercore/src/main/java/com/enderio/core/common/util/TooltipUtil.java` (1 hunks) * `enderio-armory/src/main/java/com/enderio/armory/common/init/ArmoryNetwork.java` (1 hunks) * `enderio-base/src/main/java/com/enderio/EnderIOBase.java` (2 hunks) * `enderio-base/src/main/java/com/enderio/base/api/attachment/StoredEntityData.java` (1 hunks) * `enderio-base/src/main/java/com/enderio/base/api/filter/EntityFilter.java` (1 hunks) * `enderio-base/src/main/java/com/enderio/base/api/filter/FilterMenuProvider.java` (1 hunks) * `enderio-base/src/main/java/com/enderio/base/api/filter/FluidFilter.java` (1 hunks) * `enderio-base/src/main/java/com/enderio/base/api/filter/FluidStackFilter.java` (0 hunks) * `enderio-base/src/main/java/com/enderio/base/api/filter/ItemFilter.java` (1 hunks) * `enderio-base/src/main/java/com/enderio/base/api/filter/ItemStackFilter.java` (0 hunks) * `enderio-base/src/main/java/com/enderio/base/api/filter/ResourceFilter.java` (0 hunks) * `enderio-base/src/main/java/com/enderio/base/api/misc/RedstoneControl.java` (2 hunks) </details> <details> <summary>💤 Files with no reviewable changes (4)</summary> * enderio-base/src/main/java/com/enderio/base/api/filter/ResourceFilter.java * enderio-base/src/main/java/com/enderio/base/api/filter/ItemStackFilter.java * enderio-base/src/main/java/com/enderio/base/api/filter/FluidStackFilter.java * endercore/src/main/java/com/enderio/core/client/gui/widgets/ToggleImageButton.java </details> <details> <summary>✅ Files skipped from review due to trivial changes (2)</summary> * endercore/src/main/java/com/enderio/core/client/icon/EnumIconMap.java * enderio-base/src/main/java/com/enderio/base/api/filter/ItemFilter.java </details> <details> <summary>🚧 Files skipped from review as they are similar to previous changes (7)</summary> * build.gradle.kts * endercore/src/main/java/com/enderio/core/client/gui/widgets/BaseEnumPickerWidget.java * endercore/src/main/java/com/enderio/core/common/menu/BaseBlockEntityMenu.java * endercore/src/main/java/com/enderio/core/client/gui/widgets/ToggleIconButton.java * endercore/src/main/java/com/enderio/core/common/blockentity/EnderBlockEntity.java * enderio-base/src/main/java/com/enderio/base/api/misc/RedstoneControl.java * endercore/src/main/java/com/enderio/core/client/gui/screen/EnderContainerScreen.java </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🧬 Code Graph Analysis (1)</summary> <details> <summary>enderio-base/src/main/java/com/enderio/EnderIOBase.java (2)</summary><blockquote> <details> <summary>enderio-base/src/main/java/com/enderio/base/common/filter/item/ItemFilterSlot.java (1)</summary> * `ItemFilterSlot` (9-35) </details> <details> <summary>enderio-base/src/main/java/com/enderio/base/common/filter/fluid/FluidFilterSlot.java (1)</summary> * `FluidFilterSlot` (13-36) </details> </blockquote></details> </details><details> <summary>🪛 GitHub Actions: Verify Build</summary> <details> <summary>enderio-base/src/main/java/com/enderio/EnderIOBase.java</summary> [error] 1-1: Spotless formatting check failed. Import order and formatting violations detected. Run './gradlew :enderio-base:spotlessApply' to fix. </details> <details> <summary>enderio-base/src/main/java/com/enderio/base/api/attachment/StoredEntityData.java</summary> [error] 1-1: Spotless formatting check failed. Import order and formatting violations detected. Run './gradlew :enderio-base:spotlessApply' to fix. </details> </details> </details> <details> <summary>🔇 Additional comments (11)</summary><blockquote> <details> <summary>enderio-armory/src/main/java/com/enderio/armory/common/init/ArmoryNetwork.java (1)</summary> `25-25`: **API usage updated correctly** The code has been updated to use the simplified `registrar` method that only takes the protocol version rather than namespace and protocol version. This aligns with similar changes throughout the codebase and maintains consistency with the network API usage pattern. </details> <details> <summary>endercore/src/main/java/com/enderio/core/common/network/CoreNetwork.java (1)</summary> `17-17`: **API usage updated correctly** The change simplifies the payload registrar acquisition by directly passing the protocol version instead of using the chained approach with module ID and `.versioned()`. This matches the pattern used in other network initialisation classes and makes the code more consistent across the codebase. </details> <details> <summary>enderio-base/src/main/java/com/enderio/EnderIOBase.java (1)</summary> `7-7`: **Import paths have been updated to reflect package reorganisation.** The changes to import paths for `ItemFilterSlot` and `FluidFilterSlot` align with the broader refactoring of filter interfaces into dedicated packages based on filter type. This improves code organisation by grouping related filter components together. Also applies to: 26-26 </details> <details> <summary>endercore/src/main/java/com/enderio/core/common/menu/BaseEnderMenu.java (3)</summary> `51-52`: **Good refactoring to use factory methods for slot creation.** This change improves extensibility by delegating slot creation to a dedicated method rather than direct instantiation. This allows subclasses to override the method to customize slot creation without altering the inventory layout logic. --- `59-59`: **Consistent use of the factory method pattern here.** The refactoring continues by applying the same factory method pattern to hotbar slots, maintaining consistency across the codebase. --- `65-65`: **Good implementation of factory method for armor slots.** Using the factory method pattern for armor slots completes the refactoring consistently. This makes the code more maintainable and allows subclasses to provide custom armor slot implementations. </details> <details> <summary>endercore/src/main/java/com/enderio/core/common/util/TooltipUtil.java (1)</summary> `14-14`: **Improved type safety with MutableComponent return type.** Good change! Refining the return type from `Component` to `MutableComponent` provides better type safety and makes method chaining more intuitive. This accurately reflects that the method always returns a mutable component that can be further modified. </details> <details> <summary>enderio-base/src/main/java/com/enderio/base/api/filter/FluidFilter.java (1)</summary> `1-17`: **Well-designed fluid filtering interface** This newly introduced interface provides a clean, explicit contract for fluid filtering. The method signature allows for contextual filtering by accepting a target fluid handler and returns the filtered stack (potentially with a different amount) rather than just a boolean result. This is a more powerful approach than the previous predicate-based design. The documentation clearly explains how to use the interface, particularly noting the return of `FluidStack#EMPTY` to indicate that nothing should be transferred. </details> <details> <summary>enderio-base/src/main/java/com/enderio/base/api/filter/FilterMenuProvider.java (1)</summary> `10-14`: **Clear interface definition for filter menu interaction** This new interface provides a standardised way to open filter-related menus with a clean, concise method signature. The inclusion of a `goBackRunnable` parameter is particularly useful for managing menu navigation flows. The experimental annotation appropriately indicates that this API might evolve further. </details> <details> <summary>enderio-base/src/main/java/com/enderio/base/api/attachment/StoredEntityData.java (1)</summary> `46-64`: **Effective implementation of optional entity data serialisation** The `OPTIONAL_STREAM_CODEC` provides a robust mechanism for efficiently serialising and deserialising optional `StoredEntityData`. The implementation correctly uses a boolean flag to indicate data presence and delegates to the existing `STREAM_CODEC` when needed. This addition aligns well with the enhanced filter API's support for optional entity data handling. However, there's a pipeline failure related to Spotless formatting issues. You should run the suggested command to fix these: ``` ./gradlew :enderio-base:spotlessApply ``` </details> <details> <summary>enderio-base/src/main/java/com/enderio/base/api/filter/EntityFilter.java (1)</summary> `3-10`: **Improved entity filtering with specialised methods** This refactoring enhances the `EntityFilter` interface by providing distinct test methods for different entity-related types. This approach is more precise than the previous generic entity predicate, allowing for more flexible and powerful filtering capabilities. The addition of `test(StoredEntityData)` is particularly valuable as it enables filtering of serialised entity data without requiring a live entity instance. </details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
@ -0,0 +37,4 @@
protected void updateWidgetNarration(NarrationElementOutput pNarrationElementOutput) {
}
}
coderabbitai[bot] (Migrated from github.com) commented 2025-05-06 21:00:23 +00:00

🛠️ Refactor suggestion

Well-implemented IconButton class with minor accessibility improvement needed.

The IconButton class is a clean implementation of a button with an icon sprite. The design is straightforward, using composition with a Runnable for the action and proper constructor parameters. One improvement could be made:

The updateWidgetNarration method is empty, which could impact screen reader accessibility. Consider implementing narration support:

@Override
protected void updateWidgetNarration(NarrationElementOutput pNarrationElementOutput) {
+    if (getTooltip() != null && getTooltip().getMessage() != null) {
+        pNarrationElementOutput.add(NarratedElementType.TITLE, getTooltip().getMessage());
+    } else {
+        pNarrationElementOutput.add(NarratedElementType.TITLE, Component.translatable("narration.button.icon"));
+    }
}
_🛠️ Refactor suggestion_ **Well-implemented IconButton class with minor accessibility improvement needed.** The IconButton class is a clean implementation of a button with an icon sprite. The design is straightforward, using composition with a Runnable for the action and proper constructor parameters. One improvement could be made: The `updateWidgetNarration` method is empty, which could impact screen reader accessibility. Consider implementing narration support: ```diff @Override protected void updateWidgetNarration(NarrationElementOutput pNarrationElementOutput) { + if (getTooltip() != null && getTooltip().getMessage() != null) { + pNarrationElementOutput.add(NarratedElementType.TITLE, getTooltip().getMessage()); + } else { + pNarrationElementOutput.add(NarratedElementType.TITLE, Component.translatable("narration.button.icon")); + } } ``` <!-- This is an auto-generated comment by CodeRabbit -->
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Team-EnderIO/EnderIO#1025
No description provided.