Rework travel api to be POI instead #1173

Open
ferriarnus wants to merge 1 commit from ferriarnus/feat/enderface into dev/1.21.1
ferriarnus commented 2025-10-11 15:05:21 +00:00 (Migrated from github.com)

Description

Change the current travel target api to accept POI instead to generalize the api for the travel anchors and "the enderio".

TODO

  • cleanup
  • Verify api

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.

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

    • Travel and interaction now use in‑world points of interest for anchors and the Enderface, enabling direct activation via right‑click, jump, or crouch.
  • Improvements

    • Rendering pipeline for travel targets updated for better consistency and future extensibility.
    • HUD updated to work seamlessly with the new activation flow.
  • UI

    • Enderface view starts with a 45° pitch; horizontal drag direction adjusted.
    • Enderface marker colours updated to green/dark green to reflect active state.
  • Refactor

    • Migrated legacy travel target system to a unified POI-based framework.
# Description Change the current travel target api to accept POI instead to generalize the api for the travel anchors and "the enderio". <!-- If you're submitting a Draft PR, consider providing a TODO list using checkboxes --> # TODO - [ ] cleanup - [ ] Verify api # 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. <!-- 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 - Travel and interaction now use in‑world points of interest for anchors and the Enderface, enabling direct activation via right‑click, jump, or crouch. - Improvements - Rendering pipeline for travel targets updated for better consistency and future extensibility. - HUD updated to work seamlessly with the new activation flow. - UI - Enderface view starts with a 45° pitch; horizontal drag direction adjusted. - Enderface marker colours updated to green/dark green to reflect active state. - Refactor - Migrated legacy travel target system to a unified POI-based framework. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
coderabbitai[bot] commented 2025-10-11 15:05:47 +00:00 (Migrated from github.com)

Walkthrough

Replaces the TravelTarget API with a new EnderPOI API across the codebase. Introduces EnderPOI interfaces, serializers, types, renderers, events, storage, networking, and service loading. Migrates client and server flows to EnderPOI.onActivation. Updates registries and packets. Removes legacy travel API and related render/event classes.

Changes

Cohort / File(s) Summary
POI API introduction
enderio/.../api/poi/EnderPOI.java, enderio/.../api/poi/EnderPOIApi.java, enderio/.../api/poi/EnderPOISerializer.java, enderio/.../api/poi/EnderPOIType.java, enderio/.../api/poi/POIRenderer.java, enderio/.../api/poi/RegisterEnderPOIRenderersEvent.java, enderio/.../api/poi/package-info.java
Adds EnderPOI core interfaces, codecs, renderer API, registration event, and ServiceLoader API.
Travel API removals
enderio/.../api/travel/TravelTarget.java, enderio/.../api/travel/TravelTargetApi.java, enderio/.../api/travel/TravelTargetType.java, enderio/.../api/travel/TravelRenderer.java, enderio/.../api/travel/RegisterTravelRenderersEvent.java
Removes legacy TravelTarget API, types, renderer, and event.
Client rendering & HUD
enderio/.../client/EnderIOClient.java, enderio/.../client/content/travel/TravelTargetRendering.java, enderio/.../client/content/travel/TravelAnchorRenderer.java, enderio/.../client/content/travel/TravelAnchorHud.java, enderio/.../client/content/enderface/EnderfaceRenderer.java, enderio/.../client/content/enderface/package-info.java, enderio/.../client/content/machines/gui/screen/EnderfaceScreen.java, enderio/.../client/content/travel/TravelClientEventHandler.java
Switches rendering and HUD to EnderPOI/POIRenderer; updates event types and activation flow; adjusts camera input and colours; replaces elevator/teleport logic with POI activation.
Enderface content
enderio/.../content/enderface/EnderfaceBlock.java, enderio/.../content/enderface/EnderfaceBlockEntity.java, enderio/.../content/enderface/EnderfaceTravelTarget.java
Migrates to EnderPOI/EnderPOIApi; adds isActive/onActivation; introduces client screen opening via EnsureSide; updates removal and storage hooks.
Travel Anchor content
enderio/.../content/travel/travel_anchor/AnchorTravelTarget.java, enderio/.../content/travel/travel_anchor/TravelAnchorBlock.java, enderio/.../content/travel/travel_anchor/TravelAnchorBlockEntity.java
Converts Anchor target to EnderPOI with onActivation handling teleport; updates serializer/type and API usage; updates removal/persistence.
Backend handlers & storage
enderio/.../content/travel/TravelHandler.java, enderio/.../content/travel/TravelTargetSavedData.java, enderio/.../foundation/network/ClientPayloadHandler.java, enderio/.../foundation/network/ServerPayloadHandler.java, enderio/.../foundation/network/EIONetwork.java, enderio/.../foundation/network/packets/ClientboundEnderPOIUpdatedPacket.java
Replaces TravelTarget with EnderPOI in handlers, saved data, and networking; introduces new clientbound packet; exposes teleportEvent; updates activation paths.
Registries
enderio/.../api/EnderIORegistries.java, enderio/.../init/EIOTravelTargets.java
Updates registries and deferred registers from TravelTarget* to EnderPOI* equivalents.
Service loader resources
enderio/.../resources/META-INF/services/com.enderio.enderio.api.poi.EnderPOIApi, enderio/.../resources/META-INF/services/com.enderio.enderio.api.travel.TravelTargetApi
Adds EnderPOIApi provider; removes TravelTargetApi provider.
Armory integration
enderio-armory/.../darksteel/upgrades/travel/TravelUpgrade.java
Switches to EnderPOI retrieval and activation in upgrade logic.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Player
  participant Input as Input/Event
  participant Handler as TravelHandler
  participant API as EnderPOIApi
  participant POI as EnderPOI
  participant Server as Server/Level

  Player->>Input: Jump/Crouch/Right-click
  Input->>Handler: Query POI (getEnderPOIs / getElevatorAnchorTarget)
  Handler->>API: getInItemRange / get(...)
  API-->>Handler: Optional<EnderPOI>
  alt POI present
    Handler->>POI: onActivation(level, player)
    alt AnchorTravelTarget
      POI->>Handler: request teleport position
      Handler->>Server: teleportEvent(player, pos)
      Server-->>Player: Teleport and sound
    else Other EnderPOI
      POI-->>Player: Perform POI-specific action (e.g., open screen)
    end
  else No POI
    Input-->>Player: No action / short teleport paths as applicable
  end
sequenceDiagram
  rect rgba(230,240,255,0.5)
  note over Client,Server: Network update of POIs
  participant Server
  participant Net as EIONetwork
  participant Client
  Server->>Net: ClientboundEnderPOIUpdatedPacket
  Net->>Client: Dispatch to ClientPayloadHandler
  Client->>Client: EnderPOIApi.set/remove
  end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Suggested labels

Area-Backend, Type-Enhancement, MC-1.21.1

Poem

A bunny bounds through ports anew,
From travel tales to POI’s view.
With packets packed and codecs neat,
It boops a node—teleport complete!
Renderers hum, the anchors gleam,
I twitch my nose and hop upstream. 🥕

Pre-merge checks and finishing touches

Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description follows the required template structure with sections for Description, TODO, Breaking Changes, and Checklist, but the Breaking Changes section is left empty despite multiple API removals and renames that impact compatibility. Additionally, it could benefit from more detail on design decisions and testing steps to fully explain the refactoring to POI. Please populate the Breaking Changes section with a summary of API interfaces and classes that were removed or renamed, add any relevant design rationale for choosing POI as the abstraction, and include a list of specific tests or scenarios to verify the new POI-based travel functionality.
Docstring Coverage ⚠️ Warning Docstring coverage is 5.05% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Passed checks (1 passed)
Check name Status Explanation
Title Check Passed The title clearly summarises the primary change of the pull request by stating that the travel API has been reworked to use POI instead, which directly aligns with the extensive refactoring and type substitutions documented in the diff. It is concise and focused on the main objective without extraneous detail.
Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

❤️ Share

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

<!-- This is an auto-generated comment: summarize by coderabbit.ai --> <!-- walkthrough_start --> ## Walkthrough Replaces the TravelTarget API with a new EnderPOI API across the codebase. Introduces EnderPOI interfaces, serializers, types, renderers, events, storage, networking, and service loading. Migrates client and server flows to EnderPOI.onActivation. Updates registries and packets. Removes legacy travel API and related render/event classes. ## Changes | Cohort / File(s) | Summary | | --- | --- | | **POI API introduction**<br>`enderio/.../api/poi/EnderPOI.java`, `enderio/.../api/poi/EnderPOIApi.java`, `enderio/.../api/poi/EnderPOISerializer.java`, `enderio/.../api/poi/EnderPOIType.java`, `enderio/.../api/poi/POIRenderer.java`, `enderio/.../api/poi/RegisterEnderPOIRenderersEvent.java`, `enderio/.../api/poi/package-info.java` | Adds EnderPOI core interfaces, codecs, renderer API, registration event, and ServiceLoader API. | | **Travel API removals**<br>`enderio/.../api/travel/TravelTarget.java`, `enderio/.../api/travel/TravelTargetApi.java`, `enderio/.../api/travel/TravelTargetType.java`, `enderio/.../api/travel/TravelRenderer.java`, `enderio/.../api/travel/RegisterTravelRenderersEvent.java` | Removes legacy TravelTarget API, types, renderer, and event. | | **Client rendering & HUD**<br>`enderio/.../client/EnderIOClient.java`, `enderio/.../client/content/travel/TravelTargetRendering.java`, `enderio/.../client/content/travel/TravelAnchorRenderer.java`, `enderio/.../client/content/travel/TravelAnchorHud.java`, `enderio/.../client/content/enderface/EnderfaceRenderer.java`, `enderio/.../client/content/enderface/package-info.java`, `enderio/.../client/content/machines/gui/screen/EnderfaceScreen.java`, `enderio/.../client/content/travel/TravelClientEventHandler.java` | Switches rendering and HUD to EnderPOI/POIRenderer; updates event types and activation flow; adjusts camera input and colours; replaces elevator/teleport logic with POI activation. | | **Enderface content**<br>`enderio/.../content/enderface/EnderfaceBlock.java`, `enderio/.../content/enderface/EnderfaceBlockEntity.java`, `enderio/.../content/enderface/EnderfaceTravelTarget.java` | Migrates to EnderPOI/EnderPOIApi; adds isActive/onActivation; introduces client screen opening via EnsureSide; updates removal and storage hooks. | | **Travel Anchor content**<br>`enderio/.../content/travel/travel_anchor/AnchorTravelTarget.java`, `enderio/.../content/travel/travel_anchor/TravelAnchorBlock.java`, `enderio/.../content/travel/travel_anchor/TravelAnchorBlockEntity.java` | Converts Anchor target to EnderPOI with onActivation handling teleport; updates serializer/type and API usage; updates removal/persistence. | | **Backend handlers & storage**<br>`enderio/.../content/travel/TravelHandler.java`, `enderio/.../content/travel/TravelTargetSavedData.java`, `enderio/.../foundation/network/ClientPayloadHandler.java`, `enderio/.../foundation/network/ServerPayloadHandler.java`, `enderio/.../foundation/network/EIONetwork.java`, `enderio/.../foundation/network/packets/ClientboundEnderPOIUpdatedPacket.java` | Replaces TravelTarget with EnderPOI in handlers, saved data, and networking; introduces new clientbound packet; exposes teleportEvent; updates activation paths. | | **Registries**<br>`enderio/.../api/EnderIORegistries.java`, `enderio/.../init/EIOTravelTargets.java` | Updates registries and deferred registers from TravelTarget* to EnderPOI* equivalents. | | **Service loader resources**<br>`enderio/.../resources/META-INF/services/com.enderio.enderio.api.poi.EnderPOIApi`, `enderio/.../resources/META-INF/services/com.enderio.enderio.api.travel.TravelTargetApi` | Adds EnderPOIApi provider; removes TravelTargetApi provider. | | **Armory integration**<br>`enderio-armory/.../darksteel/upgrades/travel/TravelUpgrade.java` | Switches to EnderPOI retrieval and activation in upgrade logic. | ## Sequence Diagram(s) ```mermaid sequenceDiagram autonumber actor Player participant Input as Input/Event participant Handler as TravelHandler participant API as EnderPOIApi participant POI as EnderPOI participant Server as Server/Level Player->>Input: Jump/Crouch/Right-click Input->>Handler: Query POI (getEnderPOIs / getElevatorAnchorTarget) Handler->>API: getInItemRange / get(...) API-->>Handler: Optional<EnderPOI> alt POI present Handler->>POI: onActivation(level, player) alt AnchorTravelTarget POI->>Handler: request teleport position Handler->>Server: teleportEvent(player, pos) Server-->>Player: Teleport and sound else Other EnderPOI POI-->>Player: Perform POI-specific action (e.g., open screen) end else No POI Input-->>Player: No action / short teleport paths as applicable end ``` ```mermaid sequenceDiagram rect rgba(230,240,255,0.5) note over Client,Server: Network update of POIs participant Server participant Net as EIONetwork participant Client Server->>Net: ClientboundEnderPOIUpdatedPacket Net->>Client: Dispatch to ClientPayloadHandler Client->>Client: EnderPOIApi.set/remove end ``` ## Estimated code review effort 🎯 4 (Complex) | ⏱️ ~75 minutes ## Suggested labels `Area-Backend`, `Type-Enhancement`, `MC-1.21.1` ## Poem > A bunny bounds through ports anew, > From travel tales to POI’s view. > With packets packed and codecs neat, > It boops a node—teleport complete! > Renderers hum, the anchors gleam, > I twitch my nose and hop upstream. 🥕✨ <!-- walkthrough_end --> <!-- pre_merge_checks_walkthrough_start --> ## Pre-merge checks and finishing touches <details> <summary>❌ Failed checks (2 warnings)</summary> | Check name | Status | Explanation | Resolution | | :----------------: | :--------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | ⚠️ Warning | The pull request description follows the required template structure with sections for Description, TODO, Breaking Changes, and Checklist, but the Breaking Changes section is left empty despite multiple API removals and renames that impact compatibility. Additionally, it could benefit from more detail on design decisions and testing steps to fully explain the refactoring to POI. | Please populate the Breaking Changes section with a summary of API interfaces and classes that were removed or renamed, add any relevant design rationale for choosing POI as the abstraction, and include a list of specific tests or scenarios to verify the new POI-based travel functionality. | | Docstring Coverage | ⚠️ Warning | Docstring coverage is 5.05% which is insufficient. The required threshold is 80.00%. | You can run `@coderabbitai generate docstrings` to improve docstring coverage. | </details> <details> <summary>✅ Passed checks (1 passed)</summary> | Check name | Status | Explanation | | :---------: | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Title Check | ✅ Passed | The title clearly summarises the primary change of the pull request by stating that the travel API has been reworked to use POI instead, which directly aligns with the extensive refactoring and type substitutions documented in the diff. It is concise and focused on the main objective without extraneous detail. | </details> <!-- pre_merge_checks_walkthrough_end --> <!-- finishing_touch_checkbox_start --> <details> <summary>✨ Finishing touches</summary> - [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate docstrings <details> <summary>🧪 Generate unit tests (beta)</summary> - [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} --> Create PR with unit tests - [ ] <!-- {"checkboxId": "07f1e7d6-8a8e-4e23-9900-8731c2c87f58", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} --> Post copyable unit tests in a comment </details> </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> <sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub> <!-- tips_end --> <!-- internal state start --> <!-- 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 --> <!-- internal state end -->
github-advanced-security[bot] (Migrated from github.com) reviewed 2025-10-11 15:10:08 +00:00
github-advanced-security[bot] (Migrated from github.com) commented 2025-10-11 15:10:07 +00:00

Implicit narrowing conversion in compound assignment

Implicit cast of source type double to narrower destination type float.

Show more details

## Implicit narrowing conversion in compound assignment Implicit cast of source type double to narrower destination type [float](1). [Show more details](https://github.com/Team-EnderIO/EnderIO/security/code-scanning/191)
coderabbitai[bot] (Migrated from github.com) reviewed 2025-10-11 15:11:54 +00:00
coderabbitai[bot] (Migrated from github.com) left a comment

Actionable comments posted: 7

Caution

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

⚠️ Outside diff range comments (2)
enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)

264-271: Propagate teleport cancellation to the caller.

teleportEvent returns empty when cancelled, but shortTeleport(...) still returns true in that case, which can cause upstream logic (e.g., resource consumption, cooldowns) to behave as if a teleport succeeded.

Apply this change in shortTeleport to return eventPos.isPresent() instead of always true on a computed position:

-            if (player instanceof ServerPlayer serverPlayer) {
+            if (player instanceof ServerPlayer serverPlayer) {
                 Optional<Vec3> eventPos = teleportEvent(player, pos.get());
                 if (eventPos.isPresent()) {
                     player.teleportTo(eventPos.get().x(), eventPos.get().y(), eventPos.get().z());
                     serverPlayer.connection.resetPosition();
                     player.fallDistance = 0;
                     if (player.isInWall()) {
                         player.setPose(Pose.SWIMMING);
                     }
                     player.playNotifySound(SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1F, 1F);
                 } else {
                     player.playNotifySound(SoundEvents.DISPENSER_FAIL, SoundSource.PLAYERS, 1F, 1F);
                 }
-            }
-            return true;
+                return eventPos.isPresent();
+            }
+            return false; // non-server context: no teleport performed

If you prefer to keep client invocation returning true on servers only, return the boolean immediately after event handling and move the outer return true/false accordingly.

enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelTargetRendering.java (1)

82-83: Use value equality, not reference equality, for active target detection.

activeTarget == target may fail if the instances are equal by value but not the same object, causing incorrect highlighting. Use equals.

Apply this diff (fully-qualified to avoid a new import):

-            boolean active = activeTarget == target;
+            boolean active = java.util.Objects.equals(activeTarget, target);
🧹 Nitpick comments (12)
enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOIType.java (1)

5-14: Consider equals/hashCode for proper type identity.

The interface and factory method are well-implemented. The anonymous class captures the toString value efficiently. However, consider whether equals() and hashCode() should be overridden based on the ResourceLocation to ensure proper type identity when used in maps or sets. Currently, the anonymous instances will use reference equality, which may be the intended behaviour if these types are singletons.

If value-based equality is needed (comparing by ResourceLocation rather than reference), apply this diff:

 public interface EnderPOIType<T extends EnderPOI> {
     static <T extends EnderPOI> EnderPOIType<T> simple(final ResourceLocation name) {
         final String toString = name.toString();
         return new EnderPOIType<>() {
             @Override
             public String toString() {
                 return toString;
             }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (this == obj) return true;
+                if (!(obj instanceof EnderPOIType)) return false;
+                return toString.equals(obj.toString());
+            }
+
+            @Override
+            public int hashCode() {
+                return toString.hashCode();
+            }
         };
     }
 }
enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlockEntity.java (1)

61-65: TODO: Implement saving of UI state.

The saveAdditionalSynced method contains a TODO comment indicating that lastUiPitch, lastUiYaw, and lastUiDistance should be saved, but they're not currently persisted. Consider implementing this to maintain UI state across restarts.

enderio/src/main/java/com/enderio/enderio/client/content/enderface/EnderfaceRenderer.java (1)

29-29: Fix spacing around operator.

Missing space before the equality operator: getColor()== null should be getColor() == null.

Apply this diff to fix the spacing:

-        int color = ChatFormatting.GREEN.getColor()== null ? 0xFFFFFF : ChatFormatting.GREEN.getColor();
+        int color = ChatFormatting.GREEN.getColor() == null ? 0xFFFFFF : ChatFormatting.GREEN.getColor();
enderio/src/main/java/com/enderio/enderio/foundation/network/EIONetwork.java (1)

57-58: Update handler method name to align with EnderPOI terminology.

The packet type has been updated to ClientboundEnderPOIUpdatedPacket, but the handler method is still named handleAddTravelTarget. For consistency with the EnderPOI refactor, consider renaming this to handleAddEnderPOI or handleEnderPOIUpdated.

enderio/src/main/java/com/enderio/enderio/foundation/network/ClientPayloadHandler.java (1)

24-29: Consider renaming method to align with EnderPOI terminology.

The method handleAddTravelTarget now handles ClientboundEnderPOIUpdatedPacket but retains the old "TravelTarget" naming. Consider renaming to handleEnderPOIUpdated or handleAddEnderPOI for consistency with the refactored API.

enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (2)

188-204: Add a line‑of‑sight check to avoid selecting POIs through walls (unless intentional).

Current filters use distance and FOV only; without a raycast, POIs can be targeted through solid blocks. If LOS is required, add a clip test from eye to POI center before accepting it. Also consider making the 15° FOV a config.

Would you like me to wire a non‑allocating LOS check using ClipContext between player.eyePosition and target.pos().getCenter() and gate on MISS vs BLOCK?


206-231: Elevator Y bounds are exclusive; consider inclusive checks.

Using >/< excludes POIs exactly at lowerY/upperY. If anchors sit at the range edges, they won’t be found.

Apply this diff if inclusivity is desired:

-                .filter(target -> target.pos().getY() > lowerY && target.pos().getY() < upperY)
+                .filter(target -> target.pos().getY() >= lowerY && target.pos().getY() <= upperY)
enderio/src/main/java/com/enderio/enderio/content/travel/TravelTargetSavedData.java (2)

120-123: Always-dirty SavedData can cause unnecessary saves.

Overriding isDirty() to always return true writes every save cycle. Consider tracking a dirty flag and calling setDirty() on mutations (set/remove), then returning super.isDirty().


75-83: Align packet naming between update and removal
ClientboundEnderPOIUpdatedPacket vs ClientboundTravelTargetRemovedPacket are inconsistent. Rename the removal packet to ClientboundEnderPOIRemovedPacket (and update its imports/references in TravelTargetSavedData.java, ClientPayloadHandler.java, and EIONetwork.java), or add a TODO explaining why the existing name is retained.

enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceTravelTarget.java (1)

40-45: Safer client cast and follow‑up on TODO.

  • Use an instanceof ClientLevel guard before casting to avoid edge‑case ClassCastExceptions.
  • There’s a TODO for packet work; can help stub and wire the interaction packet if needed.

Apply:

-        if (level.isClientSide) {
-            Client.openScreen(level, pos);
-        }
+        if (level.isClientSide) {
+            Client.openScreen(level, pos);
+        }
...
-        public static void openScreen(Level level, BlockPos pos) {
-            Minecraft.getInstance().setScreen(new EnderfaceScreen(pos.immutable(), (ClientLevel) level));
-        }
+        public static void openScreen(Level level, BlockPos pos) {
+            if (!(level instanceof ClientLevel clientLevel)) return;
+            Minecraft.getInstance().setScreen(new EnderfaceScreen(pos.immutable(), clientLevel));
+        }

Happy to draft the client/server packets and handlers for the Enderface interaction.

Also applies to: 77-84

enderio/src/main/java/com/enderio/enderio/content/poi/EnderPOIApiImpl.java (1)

13-38: Return an unmodifiable view from getAll
Replace the live collection with a defensive copy:

-    public Collection<EnderPOI> getAll(Level level) {
-        return TravelTargetSavedData.getTravelData(level).getTravelTargets();
-    }
+    public Collection<EnderPOI> getAll(Level level) {
+        return List.copyOf(TravelTargetSavedData.getTravelData(level).getTravelTargets());
+    }
enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java (1)

80-85: Consider pose fix to avoid 1-tick suffocation like shortTeleport.

In TravelHandler.shortTeleport, after teleport the code sets Pose.SWIMMING when the player is in a wall to avoid a tick of damage. Mirroring that here will improve reliability around tight spaces.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12354a353c and 6014fab4db.

📒 Files selected for processing (39)
  • enderio-armory/src/main/java/com/enderio/armory/common/item/darksteel/upgrades/travel/TravelUpgrade.java (2 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/EnderIORegistries.java (2 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOI.java (1 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOIApi.java (1 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOISerializer.java (1 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOIType.java (1 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/poi/POIRenderer.java (1 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/poi/RegisterEnderPOIRenderersEvent.java (1 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/poi/package-info.java (1 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/travel/RegisterTravelRenderersEvent.java (0 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/travel/TravelRenderer.java (0 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/travel/TravelTarget.java (0 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/travel/TravelTargetApi.java (0 hunks)
  • enderio/src/main/java/com/enderio/enderio/api/travel/TravelTargetType.java (0 hunks)
  • enderio/src/main/java/com/enderio/enderio/client/EnderIOClient.java (2 hunks)
  • enderio/src/main/java/com/enderio/enderio/client/content/enderface/EnderfaceRenderer.java (3 hunks)
  • enderio/src/main/java/com/enderio/enderio/client/content/enderface/package-info.java (1 hunks)
  • enderio/src/main/java/com/enderio/enderio/client/content/machines/gui/screen/EnderfaceScreen.java (2 hunks)
  • enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelAnchorHud.java (2 hunks)
  • enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelAnchorRenderer.java (2 hunks)
  • enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelClientEventHandler.java (6 hunks)
  • enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelTargetRendering.java (3 hunks)
  • enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlock.java (3 hunks)
  • enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlockEntity.java (4 hunks)
  • enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceTravelTarget.java (3 hunks)
  • enderio/src/main/java/com/enderio/enderio/content/poi/EnderPOIApiImpl.java (2 hunks)
  • enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (5 hunks)
  • enderio/src/main/java/com/enderio/enderio/content/travel/TravelStaffItem.java (3 hunks)
  • enderio/src/main/java/com/enderio/enderio/content/travel/TravelTargetSavedData.java (6 hunks)
  • enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java (4 hunks)
  • enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/TravelAnchorBlock.java (2 hunks)
  • enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/TravelAnchorBlockEntity.java (3 hunks)
  • enderio/src/main/java/com/enderio/enderio/foundation/network/ClientPayloadHandler.java (2 hunks)
  • enderio/src/main/java/com/enderio/enderio/foundation/network/EIONetwork.java (2 hunks)
  • enderio/src/main/java/com/enderio/enderio/foundation/network/ServerPayloadHandler.java (3 hunks)
  • enderio/src/main/java/com/enderio/enderio/foundation/network/packets/ClientboundEnderPOIUpdatedPacket.java (1 hunks)
  • enderio/src/main/java/com/enderio/enderio/init/EIOTravelTargets.java (2 hunks)
  • enderio/src/main/resources/META-INF/services/com.enderio.enderio.api.poi.EnderPOIApi (1 hunks)
  • enderio/src/main/resources/META-INF/services/com.enderio.enderio.api.travel.TravelTargetApi (0 hunks)
💤 Files with no reviewable changes (6)
  • enderio/src/main/java/com/enderio/enderio/api/travel/TravelTarget.java
  • enderio/src/main/java/com/enderio/enderio/api/travel/RegisterTravelRenderersEvent.java
  • enderio/src/main/java/com/enderio/enderio/api/travel/TravelTargetApi.java
  • enderio/src/main/java/com/enderio/enderio/api/travel/TravelTargetType.java
  • enderio/src/main/resources/META-INF/services/com.enderio.enderio.api.travel.TravelTargetApi
  • enderio/src/main/java/com/enderio/enderio/api/travel/TravelRenderer.java
🧰 Additional context used
🧬 Code graph analysis (12)
enderio/src/main/java/com/enderio/enderio/client/EnderIOClient.java (1)
enderio/src/main/java/com/enderio/enderio/api/poi/RegisterEnderPOIRenderersEvent.java (1)
  • RegisterEnderPOIRenderersEvent (9-24)
enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelClientEventHandler.java (1)
enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)
  • TravelHandler (39-272)
enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOI.java (1)
enderio/src/main/java/com/enderio/enderio/api/EnderIORegistries.java (2)
  • EnderIORegistries (16-69)
  • Keys (43-68)
enderio/src/main/java/com/enderio/enderio/content/travel/TravelStaffItem.java (1)
enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)
  • TravelHandler (39-272)
enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java (3)
enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)
  • TravelHandler (39-272)
enderio/src/main/java/com/enderio/enderio/init/EIOTravelTargets.java (1)
  • EIOTravelTargets (15-39)
enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceTravelTarget.java (1)
  • Serializer (57-75)
enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlock.java (1)
enderio/src/main/java/com/enderio/enderio/init/EIOBlockEntities.java (1)
  • EIOBlockEntities (61-333)
enderio/src/main/java/com/enderio/enderio/foundation/network/ServerPayloadHandler.java (1)
enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)
  • TravelHandler (39-272)
enderio/src/main/java/com/enderio/enderio/init/EIOTravelTargets.java (3)
enderio/src/main/java/com/enderio/enderio/api/EnderIORegistries.java (1)
  • EnderIORegistries (16-69)
enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceTravelTarget.java (1)
  • Serializer (57-75)
enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java (1)
  • Serializer (105-128)
enderio-armory/src/main/java/com/enderio/armory/common/item/darksteel/upgrades/travel/TravelUpgrade.java (1)
enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)
  • TravelHandler (39-272)
enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceTravelTarget.java (3)
enderio/src/main/java/com/enderio/enderio/client/content/machines/gui/screen/EnderfaceScreen.java (1)
  • EnderfaceScreen (50-543)
enderio/src/main/java/com/enderio/enderio/init/EIOTravelTargets.java (1)
  • EIOTravelTargets (15-39)
enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java (1)
  • Serializer (105-128)
enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelTargetRendering.java (2)
enderio/src/main/java/com/enderio/enderio/api/poi/RegisterEnderPOIRenderersEvent.java (1)
  • RegisterEnderPOIRenderersEvent (9-24)
enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)
  • TravelHandler (39-272)
enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)
enderio/src/main/java/com/enderio/enderio/foundation/tag/EIOTags.java (1)
  • EIOTags (21-203)
Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run Tests
  • GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (37)
enderio/src/main/java/com/enderio/enderio/client/content/machines/gui/screen/EnderfaceScreen.java (2)

67-67: Verify the initial pitch orientation change.

The initial pitch value changed from -45 to 45, reversing the default vertical camera orientation. Ensure this change is intentional and provides the desired user experience when first opening the Enderface screen.


170-172: Improved mouse drag behavior.

The changes enhance the camera controls:

  • Horizontal rotation now moves in the natural direction (yaw increases with rightward mouse movement)
  • Unnecessary float cast removed from pitch clamping

These adjustments improve the intuitiveness of the camera manipulation.

enderio/src/main/java/com/enderio/enderio/client/content/enderface/package-info.java (1)

1-4: Approve package-info.java nullability annotations. net.minecraft.MethodsReturnNonnullByDefault is used extensively across the codebase; no further verification required.

enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlock.java (3)

3-3: LGTM!

The import has been correctly updated from TravelTargetApi to EnderPOIApi as part of the API migration.


20-23: LGTM!

The getRenderShape method is correctly implemented, returning RenderShape.MODEL to ensure the block renders as a 3D model.


33-33: LGTM!

The removal logic has been correctly updated to use the new EnderPOIApi.INSTANCE.removeAt() method, maintaining the same behaviour as before.

enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/TravelAnchorBlock.java (2)

3-3: LGTM!

The import has been correctly updated from TravelTargetApi to EnderPOIApi as part of the API migration.


20-20: LGTM!

The removal logic has been correctly updated to use the new EnderPOIApi.INSTANCE.removeAt() method, maintaining the same behaviour as before.

enderio/src/main/java/com/enderio/enderio/foundation/network/packets/ClientboundEnderPOIUpdatedPacket.java (2)

4-4: LGTM!

The import has been correctly updated from TravelTarget to EnderPOI as part of the API migration.


10-15: LGTM!

The packet has been correctly refactored:

  • Record name updated from ClientboundTravelTargetUpdatedPacket to ClientboundEnderPOIUpdatedPacket
  • Payload type changed from TravelTarget to EnderPOI
  • Packet identifier updated from add_travel_target to add_ender_poi
  • Stream codec correctly references EnderPOI.STREAM_CODEC

All changes are consistent with the API migration.

enderio/src/main/java/com/enderio/enderio/content/travel/TravelStaffItem.java (2)

8-8: LGTM!

The import for EnderPOI is correctly added to support the API migration.


28-28: LGTM!

The import for Optional is correctly added to support the new getEnderPOIs method signature.

enderio/src/main/java/com/enderio/enderio/client/EnderIOClient.java (2)

7-7: LGTM!

The import has been correctly updated from RegisterTravelRenderersEvent to RegisterEnderPOIRenderersEvent as part of the API migration.


392-395: Registry types already use EnderPOIType correctly
Both TRAVEL_ANCHOR_TYPE and ENDERFACE_TYPE register via EnderPOIType::simple, matching the new EnderPOI system.

enderio/src/main/resources/META-INF/services/com.enderio.enderio.api.poi.EnderPOIApi (1)

1-2: EnderPOIApiImpl implementation verified. The class exists in com.enderio.enderio.content.poi and correctly implements EnderPOIApi.

enderio/src/main/java/com/enderio/enderio/api/poi/package-info.java (1)

4-4: Package rename applied consistently
rg search returned no matches for com.enderio.enderio.api.travel—all imports updated to com.enderio.enderio.api.poi.

enderio-armory/src/main/java/com/enderio/armory/common/item/darksteel/upgrades/travel/TravelUpgrade.java (1)

105-118: LGTM! API migration is correct.

The migration from TravelTarget to EnderPOI is properly implemented. The new onActivation method correctly replaces the previous teleportation logic whilst maintaining the same control flow.

enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlockEntity.java (2)

24-24: Verify the sign change for lastUiPitch.

The default value changed from -45 to 45. Ensure this pitch direction change is intentional and doesn't invert the UI camera orientation unexpectedly.


67-80: LGTM! API migration is correct.

The transition from TravelTargetApi to EnderPOIApi is properly implemented in both the getter and setter methods.

enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/TravelAnchorBlockEntity.java (1)

104-117: LGTM! API migration is correct.

The migration from TravelTargetApi to EnderPOIApi maintains the existing logic whilst aligning with the new API surface.

enderio/src/main/java/com/enderio/enderio/api/poi/POIRenderer.java (1)

1-8: LGTM! Clean interface design.

The POIRenderer interface provides a clear contract for rendering EnderPOI instances with appropriate rendering context parameters.

enderio/src/main/java/com/enderio/enderio/foundation/network/ServerPayloadHandler.java (1)

37-57: LGTM! API migration and error handling improved.

The migration to EnderPOIApi and the use of onActivation aligns with the new API design. The change from canBlockTeleport to canTeleport broadens the check to include both item and block teleportation, which is more appropriate for this general handler. The addition of the empty target guard at lines 44-47 improves error handling.

enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelAnchorRenderer.java (1)

36-36: LGTM! Renderer interface migration is correct.

The transition from TravelRenderer to POIRenderer aligns with the API refactor whilst preserving the existing rendering logic.

enderio/src/main/java/com/enderio/enderio/client/content/enderface/EnderfaceRenderer.java (2)

18-18: LGTM! Renderer interface migration is correct.

The transition to POIRenderer aligns with the API refactor.


29-32: LGTM! Colour scheme updated.

The colour changes to GREEN (default) and DARK_GREEN (active) appear intentional and provide visual distinction for the Enderface renderer.

enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOISerializer.java (1)

1-10: LGTM! Serialiser interface renamed and relocated.

The rename from TravelTargetSerializer to EnderPOISerializer and the package relocation from api.travel to api.poi align with the broader API refactor whilst preserving the serialisation contract.

enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelAnchorHud.java (1)

44-89: LGTM!

The method signature correctly updated to accept EnderPOI instead of TravelTarget, and the implementation properly handles the type check for AnchorTravelTarget.

enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelClientEventHandler.java (4)

38-48: LGTM!

The jump and crouch handling correctly migrated to the Optional-based EnderPOI activation pattern, with appropriate cooldown management.


64-70: LGTM!

The empty-click event handler correctly retrieves and activates the EnderPOI, preserving the swing behaviour when activated.


79-83: LGTM!

The block-click event handler correctly retrieves and activates the EnderPOI, setting cancellation result only on successful activation.


92-96: LGTM!

The item-click event handler correctly retrieves and activates the EnderPOI, setting cancellation result only on successful activation.

enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOI.java (1)

19-31: LGTM!

The interface methods are well-defined with clear contracts for position, range, activation status, and activation behaviour.

enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOIApi.java (1)

12-18: LGTM!

The ServiceLoader-based singleton pattern is appropriate for this API, and the method contracts provide a clear and complete interface for EnderPOI management.

enderio/src/main/java/com/enderio/enderio/api/poi/RegisterEnderPOIRenderersEvent.java (1)

15-23: LGTM!

The use of ConcurrentHashMap and returning an immutable copy via Map.copyOf ensures thread safety and prevents external modification of the registry.

enderio/src/main/java/com/enderio/enderio/init/EIOTravelTargets.java (1)

15-33: Registry refactor looks consistent.

Types/serializers now use EnderPOI; helper signature is correct. No issues spotted.

Confirm EIOTravelTargets.register(bus) is invoked during mod init so the registries are created (e.g., in your main mod class).

enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelTargetRendering.java (2)

66-69: Confirm EnderPOIApi iteration matches getEnderPOIs() source to keep identity stable.

activeTarget comes from TravelHandler.getEnderPOIs(player) whereas the loop uses EnderPOIApi.INSTANCE.getAll(level). If these produce distinct instances per tick, identity comparisons will never match. The equals() fix above mitigates this, but please verify both sources produce consistent value objects.


29-38: init() is called in EnderIOClient.clientSetup, ensuring RENDERERS is initialised before use.

**Actionable comments posted: 7** > [!CAUTION] > Some comments are outside the diff and can’t be posted inline due to platform limitations. > > > > <details> > <summary>⚠️ Outside diff range comments (2)</summary><blockquote> > > <details> > <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)</summary><blockquote> > > `264-271`: **Propagate teleport cancellation to the caller.** > > `teleportEvent` returns empty when cancelled, but `shortTeleport(...)` still returns `true` in that case, which can cause upstream logic (e.g., resource consumption, cooldowns) to behave as if a teleport succeeded. > > > Apply this change in `shortTeleport` to return `eventPos.isPresent()` instead of always `true` on a computed position: > > ```diff > - if (player instanceof ServerPlayer serverPlayer) { > + if (player instanceof ServerPlayer serverPlayer) { > Optional<Vec3> eventPos = teleportEvent(player, pos.get()); > if (eventPos.isPresent()) { > player.teleportTo(eventPos.get().x(), eventPos.get().y(), eventPos.get().z()); > serverPlayer.connection.resetPosition(); > player.fallDistance = 0; > if (player.isInWall()) { > player.setPose(Pose.SWIMMING); > } > player.playNotifySound(SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1F, 1F); > } else { > player.playNotifySound(SoundEvents.DISPENSER_FAIL, SoundSource.PLAYERS, 1F, 1F); > } > - } > - return true; > + return eventPos.isPresent(); > + } > + return false; // non-server context: no teleport performed > ``` > > If you prefer to keep client invocation returning `true` on servers only, return the boolean immediately after event handling and move the outer `return true`/`false` accordingly. > > </blockquote></details> > <details> > <summary>enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelTargetRendering.java (1)</summary><blockquote> > > `82-83`: **Use value equality, not reference equality, for active target detection.** > > activeTarget == target may fail if the instances are equal by value but not the same object, causing incorrect highlighting. Use equals. > > Apply this diff (fully-qualified to avoid a new import): > > ```diff > - boolean active = activeTarget == target; > + boolean active = java.util.Objects.equals(activeTarget, target); > ``` > > </blockquote></details> > > </blockquote></details> <details> <summary>🧹 Nitpick comments (12)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOIType.java (1)</summary><blockquote> `5-14`: **Consider equals/hashCode for proper type identity.** The interface and factory method are well-implemented. The anonymous class captures the `toString` value efficiently. However, consider whether `equals()` and `hashCode()` should be overridden based on the `ResourceLocation` to ensure proper type identity when used in maps or sets. Currently, the anonymous instances will use reference equality, which may be the intended behaviour if these types are singletons. If value-based equality is needed (comparing by `ResourceLocation` rather than reference), apply this diff: ```diff public interface EnderPOIType<T extends EnderPOI> { static <T extends EnderPOI> EnderPOIType<T> simple(final ResourceLocation name) { final String toString = name.toString(); return new EnderPOIType<>() { @Override public String toString() { return toString; } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof EnderPOIType)) return false; + return toString.equals(obj.toString()); + } + + @Override + public int hashCode() { + return toString.hashCode(); + } }; } } ``` </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlockEntity.java (1)</summary><blockquote> `61-65`: **TODO: Implement saving of UI state.** The `saveAdditionalSynced` method contains a TODO comment indicating that `lastUiPitch`, `lastUiYaw`, and `lastUiDistance` should be saved, but they're not currently persisted. Consider implementing this to maintain UI state across restarts. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/enderface/EnderfaceRenderer.java (1)</summary><blockquote> `29-29`: **Fix spacing around operator.** Missing space before the equality operator: `getColor()== null` should be `getColor() == null`. Apply this diff to fix the spacing: ```diff - int color = ChatFormatting.GREEN.getColor()== null ? 0xFFFFFF : ChatFormatting.GREEN.getColor(); + int color = ChatFormatting.GREEN.getColor() == null ? 0xFFFFFF : ChatFormatting.GREEN.getColor(); ``` </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/foundation/network/EIONetwork.java (1)</summary><blockquote> `57-58`: **Update handler method name to align with EnderPOI terminology.** The packet type has been updated to `ClientboundEnderPOIUpdatedPacket`, but the handler method is still named `handleAddTravelTarget`. For consistency with the EnderPOI refactor, consider renaming this to `handleAddEnderPOI` or `handleEnderPOIUpdated`. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/foundation/network/ClientPayloadHandler.java (1)</summary><blockquote> `24-29`: **Consider renaming method to align with EnderPOI terminology.** The method `handleAddTravelTarget` now handles `ClientboundEnderPOIUpdatedPacket` but retains the old "TravelTarget" naming. Consider renaming to `handleEnderPOIUpdated` or `handleAddEnderPOI` for consistency with the refactored API. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (2)</summary><blockquote> `188-204`: **Add a line‑of‑sight check to avoid selecting POIs through walls (unless intentional).** Current filters use distance and FOV only; without a raycast, POIs can be targeted through solid blocks. If LOS is required, add a clip test from eye to POI center before accepting it. Also consider making the 15° FOV a config. Would you like me to wire a non‑allocating LOS check using ClipContext between player.eyePosition and target.pos().getCenter() and gate on MISS vs BLOCK? --- `206-231`: **Elevator Y bounds are exclusive; consider inclusive checks.** Using `>`/`<` excludes POIs exactly at `lowerY`/`upperY`. If anchors sit at the range edges, they won’t be found. Apply this diff if inclusivity is desired: ```diff - .filter(target -> target.pos().getY() > lowerY && target.pos().getY() < upperY) + .filter(target -> target.pos().getY() >= lowerY && target.pos().getY() <= upperY) ``` </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelTargetSavedData.java (2)</summary><blockquote> `120-123`: **Always-dirty SavedData can cause unnecessary saves.** Overriding `isDirty()` to always return `true` writes every save cycle. Consider tracking a `dirty` flag and calling `setDirty()` on mutations (set/remove), then returning `super.isDirty()`. --- `75-83`: **Align packet naming between update and removal** `ClientboundEnderPOIUpdatedPacket` vs `ClientboundTravelTargetRemovedPacket` are inconsistent. Rename the removal packet to `ClientboundEnderPOIRemovedPacket` (and update its imports/references in TravelTargetSavedData.java, ClientPayloadHandler.java, and EIONetwork.java), or add a TODO explaining why the existing name is retained. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceTravelTarget.java (1)</summary><blockquote> `40-45`: **Safer client cast and follow‑up on TODO.** - Use an `instanceof ClientLevel` guard before casting to avoid edge‑case `ClassCastException`s. - There’s a TODO for packet work; can help stub and wire the interaction packet if needed. Apply: ```diff - if (level.isClientSide) { - Client.openScreen(level, pos); - } + if (level.isClientSide) { + Client.openScreen(level, pos); + } ... - public static void openScreen(Level level, BlockPos pos) { - Minecraft.getInstance().setScreen(new EnderfaceScreen(pos.immutable(), (ClientLevel) level)); - } + public static void openScreen(Level level, BlockPos pos) { + if (!(level instanceof ClientLevel clientLevel)) return; + Minecraft.getInstance().setScreen(new EnderfaceScreen(pos.immutable(), clientLevel)); + } ``` Happy to draft the client/server packets and handlers for the Enderface interaction. Also applies to: 77-84 </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/poi/EnderPOIApiImpl.java (1)</summary><blockquote> `13-38`: **Return an unmodifiable view from getAll** Replace the live collection with a defensive copy: ```diff - public Collection<EnderPOI> getAll(Level level) { - return TravelTargetSavedData.getTravelData(level).getTravelTargets(); - } + public Collection<EnderPOI> getAll(Level level) { + return List.copyOf(TravelTargetSavedData.getTravelData(level).getTravelTargets()); + } ``` </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java (1)</summary><blockquote> `80-85`: **Consider pose fix to avoid 1-tick suffocation like shortTeleport.** In TravelHandler.shortTeleport, after teleport the code sets Pose.SWIMMING when the player is in a wall to avoid a tick of damage. Mirroring that here will improve reliability around tight spaces. </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 12354a353c406cd077494d5aa11e2b042cb8d453 and 6014fab4db33d09258515482ab260e058d8dd5e3. </details> <details> <summary>📒 Files selected for processing (39)</summary> * `enderio-armory/src/main/java/com/enderio/armory/common/item/darksteel/upgrades/travel/TravelUpgrade.java` (2 hunks) * `enderio/src/main/java/com/enderio/enderio/api/EnderIORegistries.java` (2 hunks) * `enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOI.java` (1 hunks) * `enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOIApi.java` (1 hunks) * `enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOISerializer.java` (1 hunks) * `enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOIType.java` (1 hunks) * `enderio/src/main/java/com/enderio/enderio/api/poi/POIRenderer.java` (1 hunks) * `enderio/src/main/java/com/enderio/enderio/api/poi/RegisterEnderPOIRenderersEvent.java` (1 hunks) * `enderio/src/main/java/com/enderio/enderio/api/poi/package-info.java` (1 hunks) * `enderio/src/main/java/com/enderio/enderio/api/travel/RegisterTravelRenderersEvent.java` (0 hunks) * `enderio/src/main/java/com/enderio/enderio/api/travel/TravelRenderer.java` (0 hunks) * `enderio/src/main/java/com/enderio/enderio/api/travel/TravelTarget.java` (0 hunks) * `enderio/src/main/java/com/enderio/enderio/api/travel/TravelTargetApi.java` (0 hunks) * `enderio/src/main/java/com/enderio/enderio/api/travel/TravelTargetType.java` (0 hunks) * `enderio/src/main/java/com/enderio/enderio/client/EnderIOClient.java` (2 hunks) * `enderio/src/main/java/com/enderio/enderio/client/content/enderface/EnderfaceRenderer.java` (3 hunks) * `enderio/src/main/java/com/enderio/enderio/client/content/enderface/package-info.java` (1 hunks) * `enderio/src/main/java/com/enderio/enderio/client/content/machines/gui/screen/EnderfaceScreen.java` (2 hunks) * `enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelAnchorHud.java` (2 hunks) * `enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelAnchorRenderer.java` (2 hunks) * `enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelClientEventHandler.java` (6 hunks) * `enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelTargetRendering.java` (3 hunks) * `enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlock.java` (3 hunks) * `enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlockEntity.java` (4 hunks) * `enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceTravelTarget.java` (3 hunks) * `enderio/src/main/java/com/enderio/enderio/content/poi/EnderPOIApiImpl.java` (2 hunks) * `enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java` (5 hunks) * `enderio/src/main/java/com/enderio/enderio/content/travel/TravelStaffItem.java` (3 hunks) * `enderio/src/main/java/com/enderio/enderio/content/travel/TravelTargetSavedData.java` (6 hunks) * `enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java` (4 hunks) * `enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/TravelAnchorBlock.java` (2 hunks) * `enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/TravelAnchorBlockEntity.java` (3 hunks) * `enderio/src/main/java/com/enderio/enderio/foundation/network/ClientPayloadHandler.java` (2 hunks) * `enderio/src/main/java/com/enderio/enderio/foundation/network/EIONetwork.java` (2 hunks) * `enderio/src/main/java/com/enderio/enderio/foundation/network/ServerPayloadHandler.java` (3 hunks) * `enderio/src/main/java/com/enderio/enderio/foundation/network/packets/ClientboundEnderPOIUpdatedPacket.java` (1 hunks) * `enderio/src/main/java/com/enderio/enderio/init/EIOTravelTargets.java` (2 hunks) * `enderio/src/main/resources/META-INF/services/com.enderio.enderio.api.poi.EnderPOIApi` (1 hunks) * `enderio/src/main/resources/META-INF/services/com.enderio.enderio.api.travel.TravelTargetApi` (0 hunks) </details> <details> <summary>💤 Files with no reviewable changes (6)</summary> * enderio/src/main/java/com/enderio/enderio/api/travel/TravelTarget.java * enderio/src/main/java/com/enderio/enderio/api/travel/RegisterTravelRenderersEvent.java * enderio/src/main/java/com/enderio/enderio/api/travel/TravelTargetApi.java * enderio/src/main/java/com/enderio/enderio/api/travel/TravelTargetType.java * enderio/src/main/resources/META-INF/services/com.enderio.enderio.api.travel.TravelTargetApi * enderio/src/main/java/com/enderio/enderio/api/travel/TravelRenderer.java </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🧬 Code graph analysis (12)</summary> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/EnderIOClient.java (1)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/poi/RegisterEnderPOIRenderersEvent.java (1)</summary> * `RegisterEnderPOIRenderersEvent` (9-24) </details> </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelClientEventHandler.java (1)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)</summary> * `TravelHandler` (39-272) </details> </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOI.java (1)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/EnderIORegistries.java (2)</summary> * `EnderIORegistries` (16-69) * `Keys` (43-68) </details> </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelStaffItem.java (1)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)</summary> * `TravelHandler` (39-272) </details> </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java (3)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)</summary> * `TravelHandler` (39-272) </details> <details> <summary>enderio/src/main/java/com/enderio/enderio/init/EIOTravelTargets.java (1)</summary> * `EIOTravelTargets` (15-39) </details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceTravelTarget.java (1)</summary> * `Serializer` (57-75) </details> </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlock.java (1)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/init/EIOBlockEntities.java (1)</summary> * `EIOBlockEntities` (61-333) </details> </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/foundation/network/ServerPayloadHandler.java (1)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)</summary> * `TravelHandler` (39-272) </details> </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/init/EIOTravelTargets.java (3)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/EnderIORegistries.java (1)</summary> * `EnderIORegistries` (16-69) </details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceTravelTarget.java (1)</summary> * `Serializer` (57-75) </details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java (1)</summary> * `Serializer` (105-128) </details> </blockquote></details> <details> <summary>enderio-armory/src/main/java/com/enderio/armory/common/item/darksteel/upgrades/travel/TravelUpgrade.java (1)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)</summary> * `TravelHandler` (39-272) </details> </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceTravelTarget.java (3)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/machines/gui/screen/EnderfaceScreen.java (1)</summary> * `EnderfaceScreen` (50-543) </details> <details> <summary>enderio/src/main/java/com/enderio/enderio/init/EIOTravelTargets.java (1)</summary> * `EIOTravelTargets` (15-39) </details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java (1)</summary> * `Serializer` (105-128) </details> </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelTargetRendering.java (2)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/poi/RegisterEnderPOIRenderersEvent.java (1)</summary> * `RegisterEnderPOIRenderersEvent` (9-24) </details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)</summary> * `TravelHandler` (39-272) </details> </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelHandler.java (1)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/foundation/tag/EIOTags.java (1)</summary> * `EIOTags` (21-203) </details> </blockquote></details> </details> </details> <details> <summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)</summary> * GitHub Check: Run Tests * GitHub Check: Analyze (java-kotlin) </details> <details> <summary>🔇 Additional comments (37)</summary><blockquote> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/machines/gui/screen/EnderfaceScreen.java (2)</summary><blockquote> `67-67`: **Verify the initial pitch orientation change.** The initial pitch value changed from -45 to 45, reversing the default vertical camera orientation. Ensure this change is intentional and provides the desired user experience when first opening the Enderface screen. --- `170-172`: **Improved mouse drag behavior.** The changes enhance the camera controls: - Horizontal rotation now moves in the natural direction (yaw increases with rightward mouse movement) - Unnecessary float cast removed from pitch clamping These adjustments improve the intuitiveness of the camera manipulation. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/enderface/package-info.java (1)</summary><blockquote> `1-4`: **Approve package-info.java nullability annotations.** net.minecraft.MethodsReturnNonnullByDefault is used extensively across the codebase; no further verification required. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlock.java (3)</summary><blockquote> `3-3`: **LGTM!** The import has been correctly updated from `TravelTargetApi` to `EnderPOIApi` as part of the API migration. --- `20-23`: **LGTM!** The `getRenderShape` method is correctly implemented, returning `RenderShape.MODEL` to ensure the block renders as a 3D model. --- `33-33`: **LGTM!** The removal logic has been correctly updated to use the new `EnderPOIApi.INSTANCE.removeAt()` method, maintaining the same behaviour as before. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/TravelAnchorBlock.java (2)</summary><blockquote> `3-3`: **LGTM!** The import has been correctly updated from `TravelTargetApi` to `EnderPOIApi` as part of the API migration. --- `20-20`: **LGTM!** The removal logic has been correctly updated to use the new `EnderPOIApi.INSTANCE.removeAt()` method, maintaining the same behaviour as before. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/foundation/network/packets/ClientboundEnderPOIUpdatedPacket.java (2)</summary><blockquote> `4-4`: **LGTM!** The import has been correctly updated from `TravelTarget` to `EnderPOI` as part of the API migration. --- `10-15`: **LGTM!** The packet has been correctly refactored: - Record name updated from `ClientboundTravelTargetUpdatedPacket` to `ClientboundEnderPOIUpdatedPacket` - Payload type changed from `TravelTarget` to `EnderPOI` - Packet identifier updated from `add_travel_target` to `add_ender_poi` - Stream codec correctly references `EnderPOI.STREAM_CODEC` All changes are consistent with the API migration. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/TravelStaffItem.java (2)</summary><blockquote> `8-8`: **LGTM!** The import for `EnderPOI` is correctly added to support the API migration. --- `28-28`: **LGTM!** The import for `Optional` is correctly added to support the new `getEnderPOIs` method signature. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/EnderIOClient.java (2)</summary><blockquote> `7-7`: **LGTM!** The import has been correctly updated from `RegisterTravelRenderersEvent` to `RegisterEnderPOIRenderersEvent` as part of the API migration. --- `392-395`: **Registry types already use EnderPOIType correctly** Both `TRAVEL_ANCHOR_TYPE` and `ENDERFACE_TYPE` register via `EnderPOIType::simple`, matching the new EnderPOI system. </blockquote></details> <details> <summary>enderio/src/main/resources/META-INF/services/com.enderio.enderio.api.poi.EnderPOIApi (1)</summary><blockquote> `1-2`: **EnderPOIApiImpl implementation verified.** The class exists in com.enderio.enderio.content.poi and correctly implements EnderPOIApi. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/poi/package-info.java (1)</summary><blockquote> `4-4`: **Package rename applied consistently** `rg` search returned no matches for `com.enderio.enderio.api.travel`—all imports updated to `com.enderio.enderio.api.poi`. </blockquote></details> <details> <summary>enderio-armory/src/main/java/com/enderio/armory/common/item/darksteel/upgrades/travel/TravelUpgrade.java (1)</summary><blockquote> `105-118`: **LGTM! API migration is correct.** The migration from `TravelTarget` to `EnderPOI` is properly implemented. The new `onActivation` method correctly replaces the previous teleportation logic whilst maintaining the same control flow. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/enderface/EnderfaceBlockEntity.java (2)</summary><blockquote> `24-24`: **Verify the sign change for `lastUiPitch`.** The default value changed from `-45` to `45`. Ensure this pitch direction change is intentional and doesn't invert the UI camera orientation unexpectedly. --- `67-80`: **LGTM! API migration is correct.** The transition from `TravelTargetApi` to `EnderPOIApi` is properly implemented in both the getter and setter methods. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/TravelAnchorBlockEntity.java (1)</summary><blockquote> `104-117`: **LGTM! API migration is correct.** The migration from `TravelTargetApi` to `EnderPOIApi` maintains the existing logic whilst aligning with the new API surface. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/poi/POIRenderer.java (1)</summary><blockquote> `1-8`: **LGTM! Clean interface design.** The `POIRenderer` interface provides a clear contract for rendering `EnderPOI` instances with appropriate rendering context parameters. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/foundation/network/ServerPayloadHandler.java (1)</summary><blockquote> `37-57`: **LGTM! API migration and error handling improved.** The migration to `EnderPOIApi` and the use of `onActivation` aligns with the new API design. The change from `canBlockTeleport` to `canTeleport` broadens the check to include both item and block teleportation, which is more appropriate for this general handler. The addition of the empty target guard at lines 44-47 improves error handling. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelAnchorRenderer.java (1)</summary><blockquote> `36-36`: **LGTM! Renderer interface migration is correct.** The transition from `TravelRenderer` to `POIRenderer` aligns with the API refactor whilst preserving the existing rendering logic. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/enderface/EnderfaceRenderer.java (2)</summary><blockquote> `18-18`: **LGTM! Renderer interface migration is correct.** The transition to `POIRenderer` aligns with the API refactor. --- `29-32`: **LGTM! Colour scheme updated.** The colour changes to GREEN (default) and DARK_GREEN (active) appear intentional and provide visual distinction for the Enderface renderer. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOISerializer.java (1)</summary><blockquote> `1-10`: **LGTM! Serialiser interface renamed and relocated.** The rename from `TravelTargetSerializer` to `EnderPOISerializer` and the package relocation from `api.travel` to `api.poi` align with the broader API refactor whilst preserving the serialisation contract. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelAnchorHud.java (1)</summary><blockquote> `44-89`: **LGTM!** The method signature correctly updated to accept `EnderPOI` instead of `TravelTarget`, and the implementation properly handles the type check for `AnchorTravelTarget`. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelClientEventHandler.java (4)</summary><blockquote> `38-48`: **LGTM!** The jump and crouch handling correctly migrated to the Optional-based EnderPOI activation pattern, with appropriate cooldown management. --- `64-70`: **LGTM!** The empty-click event handler correctly retrieves and activates the EnderPOI, preserving the swing behaviour when activated. --- `79-83`: **LGTM!** The block-click event handler correctly retrieves and activates the EnderPOI, setting cancellation result only on successful activation. --- `92-96`: **LGTM!** The item-click event handler correctly retrieves and activates the EnderPOI, setting cancellation result only on successful activation. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOI.java (1)</summary><blockquote> `19-31`: **LGTM!** The interface methods are well-defined with clear contracts for position, range, activation status, and activation behaviour. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOIApi.java (1)</summary><blockquote> `12-18`: **LGTM!** The ServiceLoader-based singleton pattern is appropriate for this API, and the method contracts provide a clear and complete interface for EnderPOI management. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/api/poi/RegisterEnderPOIRenderersEvent.java (1)</summary><blockquote> `15-23`: **LGTM!** The use of `ConcurrentHashMap` and returning an immutable copy via `Map.copyOf` ensures thread safety and prevents external modification of the registry. </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/init/EIOTravelTargets.java (1)</summary><blockquote> `15-33`: **Registry refactor looks consistent.** Types/serializers now use EnderPOI; helper signature is correct. No issues spotted. Confirm `EIOTravelTargets.register(bus)` is invoked during mod init so the registries are created (e.g., in your main mod class). </blockquote></details> <details> <summary>enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelTargetRendering.java (2)</summary><blockquote> `66-69`: **Confirm EnderPOIApi iteration matches getEnderPOIs() source to keep identity stable.** activeTarget comes from TravelHandler.getEnderPOIs(player) whereas the loop uses EnderPOIApi.INSTANCE.getAll(level). If these produce distinct instances per tick, identity comparisons will never match. The equals() fix above mitigates this, but please verify both sources produce consistent value objects. --- `29-38`: **init() is called in EnderIOClient.clientSetup, ensuring RENDERERS is initialised before use.** </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
coderabbitai[bot] (Migrated from github.com) commented 2025-10-11 15:11:52 +00:00

⚠️ Potential issue | 🟡 Minor

Registry naming inconsistency with EnderPOI refactor.

The registry types have been correctly updated to EnderPOIType<?> and EnderPOISerializer<?>, but the registry field names still use the TRAVEL_TARGET prefix. For consistency with the EnderPOI refactor, consider renaming:

  • TRAVEL_TARGET_TYPESENDER_POI_TYPES
  • TRAVEL_TARGET_SERIALIZERSENDER_POI_SERIALIZERS

The same applies to the registry key names in the Keys class (lines 44-45) and the string literals passed to createKey().

🤖 Prompt for AI Agents
In enderio/src/main/java/com/enderio/enderio/api/EnderIORegistries.java around
lines 18 to 24, the registry field names still use the old TRAVEL_TARGET prefix
even though types were refactored to EnderPOI; rename TRAVEL_TARGET_TYPES →
ENDER_POI_TYPES and TRAVEL_TARGET_SERIALIZERS → ENDER_POI_SERIALIZERS, update
any references/usages to the new names, and in the Keys class (around lines
44-45) rename the corresponding key constants and the string arguments passed to
createKey() to use "ender_poi_types" and "ender_poi_serializers" (or your
project's canonical snake_case), ensuring all call sites and imports are updated
to the new identifiers to keep naming consistent.
_⚠️ Potential issue_ | _🟡 Minor_ **Registry naming inconsistency with EnderPOI refactor.** The registry types have been correctly updated to `EnderPOIType<?>` and `EnderPOISerializer<?>`, but the registry field names still use the `TRAVEL_TARGET` prefix. For consistency with the EnderPOI refactor, consider renaming: - `TRAVEL_TARGET_TYPES` → `ENDER_POI_TYPES` - `TRAVEL_TARGET_SERIALIZERS` → `ENDER_POI_SERIALIZERS` The same applies to the registry key names in the `Keys` class (lines 44-45) and the string literals passed to `createKey()`. <details> <summary>🤖 Prompt for AI Agents</summary> ``` In enderio/src/main/java/com/enderio/enderio/api/EnderIORegistries.java around lines 18 to 24, the registry field names still use the old TRAVEL_TARGET prefix even though types were refactored to EnderPOI; rename TRAVEL_TARGET_TYPES → ENDER_POI_TYPES and TRAVEL_TARGET_SERIALIZERS → ENDER_POI_SERIALIZERS, update any references/usages to the new names, and in the Keys class (around lines 44-45) rename the corresponding key constants and the string arguments passed to createKey() to use "ender_poi_types" and "ender_poi_serializers" (or your project's canonical snake_case), ensuring all call sites and imports are updated to the new identifiers to keep naming consistent. ``` </details> <!-- This is an auto-generated comment by CodeRabbit -->
@ -0,0 +14,4 @@
.dispatch(EnderPOI::serializer, EnderPOISerializer::codec);
StreamCodec<RegistryFriendlyByteBuf, EnderPOI> STREAM_CODEC = ByteBufCodecs
.registry(EnderIORegistries.Keys.TRAVEL_TARGET_SERIALIZERS)
.dispatch(EnderPOI::serializer, EnderPOISerializer::streamCodec);
coderabbitai[bot] (Migrated from github.com) commented 2025-10-11 15:11:52 +00:00

⚠️ Potential issue | 🟡 Minor

Registry naming inconsistency with EnderPOI refactor.

The codecs reference TRAVEL_TARGET_SERIALIZERS which retains the old "TravelTarget" naming. For consistency with the EnderPOI refactor, the registry should be renamed to ENDER_POI_SERIALIZERS (and similarly ENDER_POI_TYPES for the types registry). This naming discrepancy is also present in EnderIORegistries.java.

🤖 Prompt for AI Agents
In enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOI.java around lines
13 to 17, the codec references use the old registry constant
TRAVEL_TARGET_SERIALIZERS; update these to the new ENDER_POI_SERIALIZERS name
(and any related registry constant rename ENDER_POI_TYPES where applicable) to
match the EnderPOI refactor. Also update EnderIORegistries.java to rename the
TRAVEL_TARGET_SERIALIZERS and TRAVEL_TARGET_TYPES constants/keys to
ENDER_POI_SERIALIZERS and ENDER_POI_TYPES respectively, and update any usages
(including ByteBufCodecs.registry(...) calls and byNameCodec() references)
across the codebase to the new names so all registry lookups and codec
dispatches compile and remain consistent.
_⚠️ Potential issue_ | _🟡 Minor_ **Registry naming inconsistency with EnderPOI refactor.** The codecs reference `TRAVEL_TARGET_SERIALIZERS` which retains the old "TravelTarget" naming. For consistency with the EnderPOI refactor, the registry should be renamed to `ENDER_POI_SERIALIZERS` (and similarly `ENDER_POI_TYPES` for the types registry). This naming discrepancy is also present in `EnderIORegistries.java`. <details> <summary>🤖 Prompt for AI Agents</summary> ``` In enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOI.java around lines 13 to 17, the codec references use the old registry constant TRAVEL_TARGET_SERIALIZERS; update these to the new ENDER_POI_SERIALIZERS name (and any related registry constant rename ENDER_POI_TYPES where applicable) to match the EnderPOI refactor. Also update EnderIORegistries.java to rename the TRAVEL_TARGET_SERIALIZERS and TRAVEL_TARGET_TYPES constants/keys to ENDER_POI_SERIALIZERS and ENDER_POI_TYPES respectively, and update any usages (including ByteBufCodecs.registry(...) calls and byNameCodec() references) across the codebase to the new names so all registry lookups and codec dispatches compile and remain consistent. ``` </details> <!-- This is an auto-generated comment by CodeRabbit -->
@ -0,0 +12,4 @@
EnderPOIApi INSTANCE = ServiceLoader.load(EnderPOIApi.class).findFirst().orElseThrow();
Optional<EnderPOI> get(Level level, BlockPos pos);
<T extends EnderPOI> void set(Level level, T travelTarget);
coderabbitai[bot] (Migrated from github.com) commented 2025-10-11 15:11:52 +00:00

⚠️ Potential issue | 🟡 Minor

Update parameter name to match type.

The parameter is named travelTarget but the type is T extends EnderPOI. For consistency, rename the parameter to enderPOI or poi.

Apply this diff:

-    <T extends EnderPOI> void set(Level level, T travelTarget);
+    <T extends EnderPOI> void set(Level level, T enderPOI);
📝 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.

    <T extends EnderPOI> void set(Level level, T enderPOI);
🤖 Prompt for AI Agents
In enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOIApi.java around
line 15 the method parameter is named travelTarget while the generic type is T
extends EnderPOI; rename the parameter to a name matching the type (e.g.,
enderPOI or poi) and update the method signature accordingly so it reads
something like <T extends EnderPOI> void set(Level level, T enderPOI); ensure
the parameter name change is reflected in any implementing classes and usages.
_⚠️ Potential issue_ | _🟡 Minor_ **Update parameter name to match type.** The parameter is named `travelTarget` but the type is `T extends EnderPOI`. For consistency, rename the parameter to `enderPOI` or `poi`. Apply this diff: ```diff - <T extends EnderPOI> void set(Level level, T travelTarget); + <T extends EnderPOI> void set(Level level, T enderPOI); ``` <!-- 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 <T extends EnderPOI> void set(Level level, T enderPOI); ``` </details> <!-- suggestion_end --> <details> <summary>🤖 Prompt for AI Agents</summary> ``` In enderio/src/main/java/com/enderio/enderio/api/poi/EnderPOIApi.java around line 15 the method parameter is named travelTarget while the generic type is T extends EnderPOI; rename the parameter to a name matching the type (e.g., enderPOI or poi) and update the method signature accordingly so it reads something like <T extends EnderPOI> void set(Level level, T enderPOI); ensure the parameter name change is reflected in any implementing classes and usages. ``` </details> <!-- This is an auto-generated comment by CodeRabbit -->
@ -69,3 +68,4 @@
for (EnderPOI target : EnderPOIApi.INSTANCE.getAll(level)) {
double range = itemTeleport ? target.item2BlockRange() : target.block2BlockRange();
double distanceSquared = target.pos().distToCenterSqr(player.position());
if (range * range < distanceSquared || distanceSquared < TravelHandler.MIN_TELEPORTATION_DISTANCE_SQUARED
coderabbitai[bot] (Migrated from github.com) commented 2025-10-11 15:11:53 +00:00

⚠️ Potential issue | 🟠 Major

Null-guard the renderer lookup to avoid NPEs for unregistered types.

If no renderer was registered for a given EnderPOIType, getRenderer(...) returns null and this line will NPE.

Apply this diff:

-        // noinspection unchecked
-        getRenderer((EnderPOIType<T>) target.type()).render(target, levelRender, poseStack, distanceSquared,
-                isActive, partialTick);
+        // noinspection unchecked
+        POIRenderer<T> renderer = (POIRenderer<T>) getRenderer((EnderPOIType<T>) target.type());
+        if (renderer != null) {
+            renderer.render(target, levelRender, poseStack, distanceSquared, isActive, partialTick);
+        }
📝 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 EnderPOI> void render(T target, LevelRenderer levelRender, PoseStack poseStack,
            double distanceSquared, boolean isActive, float partialTick) {
        // noinspection unchecked
        POIRenderer<T> renderer = (POIRenderer<T>) getRenderer((EnderPOIType<T>) target.type());
        if (renderer != null) {
            renderer.render(target, levelRender, poseStack, distanceSquared, isActive, partialTick);
        }
    }
🤖 Prompt for AI Agents
In
enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelTargetRendering.java
around lines 45 to 50, the direct call to getRenderer(...) can return null and
cause an NPE; change the code to assign the result of getRenderer(...) to a
local variable, check if it's null, and if so bail out (return) or skip
rendering (optionally log a warning), otherwise call render on the non-null
renderer with the existing parameters.
_⚠️ Potential issue_ | _🟠 Major_ **Null-guard the renderer lookup to avoid NPEs for unregistered types.** If no renderer was registered for a given EnderPOIType, getRenderer(...) returns null and this line will NPE. Apply this diff: ```diff - // noinspection unchecked - getRenderer((EnderPOIType<T>) target.type()).render(target, levelRender, poseStack, distanceSquared, - isActive, partialTick); + // noinspection unchecked + POIRenderer<T> renderer = (POIRenderer<T>) getRenderer((EnderPOIType<T>) target.type()); + if (renderer != null) { + renderer.render(target, levelRender, poseStack, distanceSquared, isActive, partialTick); + } ``` <!-- 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 EnderPOI> void render(T target, LevelRenderer levelRender, PoseStack poseStack, double distanceSquared, boolean isActive, float partialTick) { // noinspection unchecked POIRenderer<T> renderer = (POIRenderer<T>) getRenderer((EnderPOIType<T>) target.type()); if (renderer != null) { renderer.render(target, levelRender, poseStack, distanceSquared, isActive, partialTick); } } ``` </details> <!-- suggestion_end --> <details> <summary>🤖 Prompt for AI Agents</summary> ``` In enderio/src/main/java/com/enderio/enderio/client/content/travel/TravelTargetRendering.java around lines 45 to 50, the direct call to getRenderer(...) can return null and cause an NPE; change the code to assign the result of getRenderer(...) to a local variable, check if it's null, and if so bail out (return) or skip rendering (optionally log a warning), otherwise call render on the non-null renderer with the existing parameters. ``` </details> <!-- fingerprinting:phantom:medusa:chinchilla --> <!-- This is an auto-generated comment by CodeRabbit -->
coderabbitai[bot] (Migrated from github.com) commented 2025-10-11 15:11:53 +00:00

⚠️ Potential issue | 🔴 Critical

Missing return statement after successful activation.

When onActivation succeeds, the cooldown is applied but the method doesn't return true. This means resources won't be consumed (see line 68-74 in the caller). The method should return true when activation succeeds to ensure resources are properly consumed.

Apply this diff to return true after successful activation:

         } else {
             Optional<EnderPOI> enderPOIs = TravelHandler.getEnderPOIs(player);
             if (enderPOIs.isPresent() && enderPOIs.get().onActivation(level, player)) {
                 player.getCooldowns().addCooldown(item, BaseConfig.COMMON.ITEMS.TRAVELLING_BLINK_DISABLED_TIME.get());
+                return true;
             }
         }
📝 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.

            Optional<EnderPOI> enderPOIs = TravelHandler.getEnderPOIs(player);
            if (enderPOIs.isPresent() && enderPOIs.get().onActivation(level, player)) {
                player.getCooldowns().addCooldown(item, BaseConfig.COMMON.ITEMS.TRAVELLING_BLINK_DISABLED_TIME.get());
                return true;
            }
        }
🤖 Prompt for AI Agents
In enderio/src/main/java/com/enderio/enderio/content/travel/TravelStaffItem.java
around lines 93 to 97, after applying the cooldown when enderPOIs.isPresent() &&
enderPOIs.get().onActivation(level, player) is true, the method currently does
not return true; update the control flow to return true immediately after adding
the cooldown so the caller knows activation succeeded and resources will be
consumed.
_⚠️ Potential issue_ | _🔴 Critical_ **Missing return statement after successful activation.** When `onActivation` succeeds, the cooldown is applied but the method doesn't return `true`. This means resources won't be consumed (see line 68-74 in the caller). The method should return `true` when activation succeeds to ensure resources are properly consumed. Apply this diff to return `true` after successful activation: ```diff } else { Optional<EnderPOI> enderPOIs = TravelHandler.getEnderPOIs(player); if (enderPOIs.isPresent() && enderPOIs.get().onActivation(level, player)) { player.getCooldowns().addCooldown(item, BaseConfig.COMMON.ITEMS.TRAVELLING_BLINK_DISABLED_TIME.get()); + return true; } } ``` <!-- 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 Optional<EnderPOI> enderPOIs = TravelHandler.getEnderPOIs(player); if (enderPOIs.isPresent() && enderPOIs.get().onActivation(level, player)) { player.getCooldowns().addCooldown(item, BaseConfig.COMMON.ITEMS.TRAVELLING_BLINK_DISABLED_TIME.get()); return true; } } ``` </details> <!-- suggestion_end --> <details> <summary>🤖 Prompt for AI Agents</summary> ``` In enderio/src/main/java/com/enderio/enderio/content/travel/TravelStaffItem.java around lines 93 to 97, after applying the cooldown when enderPOIs.isPresent() && enderPOIs.get().onActivation(level, player) is true, the method currently does not return true; update the control flow to return true immediately after adding the cooldown so the caller knows activation succeeded and resources will be consumed. ``` </details> <!-- This is an auto-generated comment by CodeRabbit -->
coderabbitai[bot] (Migrated from github.com) commented 2025-10-11 15:11:53 +00:00

🛠️ Refactor suggestion | 🟠 Major

Make deserialisation tolerant to bad data to avoid world-load crashes.

EnderPOI.CODEC.decode(...).getOrThrow() will crash on malformed or legacy entries. Prefer resultOrPartial to log and skip invalid entries.

Example:

private EnderPOI loadTarget(HolderLookup.Provider lookupProvider, Tag tag) {
    var ctx = lookupProvider.createSerializationContext(NbtOps.INSTANCE);
    return EnderPOI.CODEC.decode(ctx, tag)
        .result()
        .map(com.mojang.datafixers.util.Pair::getFirst)
        .orElse(null);
}

// And in loadNBT:
targets.stream()
    .map(t -> loadTarget(lookupProvider, (CompoundTag) t))
    .filter(Objects::nonNull)
    .forEach(target -> travelTargets.put(target.pos(), target));

This avoids hard failures and drops corrupt entries with a log (add one if desired).

🤖 Prompt for AI Agents
In
enderio/src/main/java/com/enderio/enderio/content/travel/TravelTargetSavedData.java
around lines 114-118, the current loadTarget call uses
EnderPOI.CODEC.decode(...).getOrThrow(), which will crash on malformed or legacy
data; change it to use the safe decode result (result() or resultOrPartial) and
map the Pair to its first value, returning null when decoding fails, and update
the caller (loadNBT) to filter out nulls before inserting into travelTargets so
corrupt entries are skipped; optionally log the decoding error in the
resultOrPartial consumer for diagnostics.
_🛠️ Refactor suggestion_ | _🟠 Major_ **Make deserialisation tolerant to bad data to avoid world-load crashes.** `EnderPOI.CODEC.decode(...).getOrThrow()` will crash on malformed or legacy entries. Prefer `resultOrPartial` to log and skip invalid entries. Example: ```java private EnderPOI loadTarget(HolderLookup.Provider lookupProvider, Tag tag) { var ctx = lookupProvider.createSerializationContext(NbtOps.INSTANCE); return EnderPOI.CODEC.decode(ctx, tag) .result() .map(com.mojang.datafixers.util.Pair::getFirst) .orElse(null); } // And in loadNBT: targets.stream() .map(t -> loadTarget(lookupProvider, (CompoundTag) t)) .filter(Objects::nonNull) .forEach(target -> travelTargets.put(target.pos(), target)); ``` This avoids hard failures and drops corrupt entries with a log (add one if desired). <details> <summary>🤖 Prompt for AI Agents</summary> ``` In enderio/src/main/java/com/enderio/enderio/content/travel/TravelTargetSavedData.java around lines 114-118, the current loadTarget call uses EnderPOI.CODEC.decode(...).getOrThrow(), which will crash on malformed or legacy data; change it to use the safe decode result (result() or resultOrPartial) and map the Pair to its first value, returning null when decoding fails, and update the caller (loadNBT) to filter out nulls before inserting into travelTargets so corrupt entries are skipped; optionally log the decoding error in the resultOrPartial consumer for diagnostics. ``` </details> <!-- fingerprinting:phantom:medusa:chinchilla --> <!-- This is an auto-generated comment by CodeRabbit -->
coderabbitai[bot] (Migrated from github.com) commented 2025-10-11 15:11:53 +00:00

⚠️ Potential issue | 🔴 Critical

Fire teleport event server-side only; gate client packet send on client without event.

EntityTeleportEvent should not be posted on the client. Currently Line 78 calls TravelHandler.teleportEvent(...) before the server/client check, which can trigger client-side handlers, desync logic, and suppress the server request if “cancelled” on client. Move event posting into the server branch and send the request unconditionally on client.

Apply this diff:

-        teleportPosition = TravelHandler.teleportEvent(player, teleportPosition).orElse(null);
-        if (teleportPosition != null) {
-            if (player instanceof ServerPlayer serverPlayer) {
-                player.teleportTo(teleportPosition.x(), teleportPosition.y(), teleportPosition.z());
-                // Stop "moved too quickly" warnings
-                serverPlayer.connection.resetPosition();
-                player.playNotifySound(SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 0.75F, 1F);
-            } else {
-                PacketDistributor.sendToServer(new ServerboundRequestTravelPacket(this.pos()));
-            }
-
-            player.resetFallDistance();
-            return true;
-        }
-        return false;
+        if (player instanceof ServerPlayer serverPlayer) {
+            var eventPos = TravelHandler.teleportEvent(player, teleportPosition);
+            if (eventPos.isEmpty()) {
+                player.playNotifySound(SoundEvents.DISPENSER_FAIL, SoundSource.PLAYERS, 0.75F, 1F);
+                return false;
+            }
+            Vec3 finalPos = eventPos.get();
+            player.teleportTo(finalPos.x(), finalPos.y(), finalPos.z());
+            // Stop "moved too quickly" warnings
+            serverPlayer.connection.resetPosition();
+            player.playNotifySound(SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 0.75F, 1F);
+            player.resetFallDistance();
+            return true;
+        } else {
+            PacketDistributor.sendToServer(new ServerboundRequestTravelPacket(this.pos()));
+            // Server will validate and perform the teleport.
+            return true;
+        }
🤖 Prompt for AI Agents
In
enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java
around lines 69 to 93, the teleport event is currently fired before checking
whether the player is server-side, which can post EntityTeleportEvent on the
client and allow client-side cancellation to suppress the server request; move
the TravelHandler.teleportEvent(...) call inside the serverPlayer branch so the
event is only posted server-side, and in the client branch always send
PacketDistributor.sendToServer(new ServerboundRequestTravelPacket(this.pos()))
without invoking the event; ensure the server branch still respects the event's
optional result (skip teleport if empty) and that fall distance reset, sound,
and connection.resetPosition() run only after a successful server-side
event/teleport result.
_⚠️ Potential issue_ | _🔴 Critical_ **Fire teleport event server-side only; gate client packet send on client without event.** EntityTeleportEvent should not be posted on the client. Currently Line 78 calls TravelHandler.teleportEvent(...) before the server/client check, which can trigger client-side handlers, desync logic, and suppress the server request if “cancelled” on client. Move event posting into the server branch and send the request unconditionally on client. Apply this diff: ```diff - teleportPosition = TravelHandler.teleportEvent(player, teleportPosition).orElse(null); - if (teleportPosition != null) { - if (player instanceof ServerPlayer serverPlayer) { - player.teleportTo(teleportPosition.x(), teleportPosition.y(), teleportPosition.z()); - // Stop "moved too quickly" warnings - serverPlayer.connection.resetPosition(); - player.playNotifySound(SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 0.75F, 1F); - } else { - PacketDistributor.sendToServer(new ServerboundRequestTravelPacket(this.pos())); - } - - player.resetFallDistance(); - return true; - } - return false; + if (player instanceof ServerPlayer serverPlayer) { + var eventPos = TravelHandler.teleportEvent(player, teleportPosition); + if (eventPos.isEmpty()) { + player.playNotifySound(SoundEvents.DISPENSER_FAIL, SoundSource.PLAYERS, 0.75F, 1F); + return false; + } + Vec3 finalPos = eventPos.get(); + player.teleportTo(finalPos.x(), finalPos.y(), finalPos.z()); + // Stop "moved too quickly" warnings + serverPlayer.connection.resetPosition(); + player.playNotifySound(SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 0.75F, 1F); + player.resetFallDistance(); + return true; + } else { + PacketDistributor.sendToServer(new ServerboundRequestTravelPacket(this.pos())); + // Server will validate and perform the teleport. + return true; + } ``` <details> <summary>🤖 Prompt for AI Agents</summary> ``` In enderio/src/main/java/com/enderio/enderio/content/travel/travel_anchor/AnchorTravelTarget.java around lines 69 to 93, the teleport event is currently fired before checking whether the player is server-side, which can post EntityTeleportEvent on the client and allow client-side cancellation to suppress the server request; move the TravelHandler.teleportEvent(...) call inside the serverPlayer branch so the event is only posted server-side, and in the client branch always send PacketDistributor.sendToServer(new ServerboundRequestTravelPacket(this.pos())) without invoking the event; ensure the server branch still respects the event's optional result (skip teleport if empty) and that fall distance reset, sound, and connection.resetPosition() run only after a successful server-side event/teleport result. ``` </details> <!-- fingerprinting:phantom:medusa:chinchilla --> <!-- This is an auto-generated comment by CodeRabbit -->
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin ferriarnus/feat/enderface:ferriarnus/feat/enderface
git switch ferriarnus/feat/enderface

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch dev/1.21.1
git merge --no-ff ferriarnus/feat/enderface
git switch ferriarnus/feat/enderface
git rebase dev/1.21.1
git switch dev/1.21.1
git merge --ff-only ferriarnus/feat/enderface
git switch ferriarnus/feat/enderface
git rebase dev/1.21.1
git switch dev/1.21.1
git merge --no-ff ferriarnus/feat/enderface
git switch dev/1.21.1
git merge --squash ferriarnus/feat/enderface
git switch dev/1.21.1
git merge --ff-only ferriarnus/feat/enderface
git switch dev/1.21.1
git merge ferriarnus/feat/enderface
git push origin dev/1.21.1
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#1173
No description provided.