Skip to content

fix: normalize PacketEvents client version for legacy sessions#5

Merged
ohnodev merged 4 commits intomainfrom
fix/normalize-packetevents-version-for-legacy
Apr 12, 2026
Merged

fix: normalize PacketEvents client version for legacy sessions#5
ohnodev merged 4 commits intomainfrom
fix/normalize-packetevents-version-for-legacy

Conversation

@ohnodev
Copy link
Copy Markdown
Owner

@ohnodev ohnodev commented Apr 12, 2026

Force PacketEvents user version to 26.2 for LegacyLink-marked connections at handshake/config transitions so Reaper movement logic uses modern semantics while wire translation remains 26.1-compatible.

Made-with: Cursor

Summary by CodeRabbit

  • Bug Fixes

    • Improved legacy client compatibility and detection across connection flows.
    • Fixed equipment packet handling so item slots display correctly for legacy clients.
  • New Features

    • Added conditional per-connection version normalization when an optional integration is present.
  • Refactor

    • Consolidated legacy setup into a single initialization path and updated item ID remapping to use a legacy ID table for more reliable translations.

Force PacketEvents user version to 26.2 for LegacyLink-marked connections at handshake/config transitions so Reaper movement logic uses modern semantics while wire translation remains 26.1-compatible.

Made-with: Cursor
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 12, 2026

Warning

Rate limit exceeded

@ohnodev has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 1 minutes and 31 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 1 minutes and 31 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 43fcfc1d-8879-46c9-9371-345a6826735f

📥 Commits

Reviewing files that changed from the base of the PR and between 881ca34 and 5ddc811.

📒 Files selected for processing (5)
  • src/main/java/dev/ohno/legacylink/handler/rewrite/ItemRewriter.java
  • src/main/java/dev/ohno/legacylink/mapping/LegacyItemIdTable.java
  • src/main/java/dev/ohno/legacylink/mixin/HandshakeMixin.java
  • src/main/java/dev/ohno/legacylink/mixin/ItemStackTemplateCodecMixin.java
  • src/main/resources/legacylink.mixins.json
📝 Walkthrough

Walkthrough

Introduces a new PacketEventsVersionBridge that conditionally forces PacketEvents per-user client version to V_26_2 via reflection for legacy connections, and invokes it from existing mixin injection points and legacy setup paths.

Changes

Cohort / File(s) Summary
PacketEvents bridge
src/main/java/dev/ohno/legacylink/integration/PacketEventsVersionBridge.java
New public final class with force26_2IfPresent(Connection) that uses reflection to locate PacketEvents API → protocol manager → user and, if available, sets the user's client version to V_26_2. Handles missing PacketEvents with a one-time debug log and warns on reflection errors including connection remote address.
Mixin integration
src/main/java/dev/ohno/legacylink/mixin/ConfigurationFinishMixin.java, src/main/java/dev/ohno/legacylink/mixin/HandshakeMixin.java
Calls PacketEventsVersionBridge.force26_2IfPresent(connection) after legacy setup/install in configuration-finish and both legacy 26.1 handshake/status handlers (refactored to applyLegacySetup() in HandshakeMixin).
Legacy packet handling
src/main/java/dev/ohno/legacylink/handler/LegacyPacketHandler.java
Added play-phase routing for ClientboundSetEquipmentPacket and implemented remapSetEquipment(ClientboundSetEquipmentPacket) to remap contained ItemStacks via ItemRewriter.remapStack, returning the original packet when no changes occur.
Item ID remapping
src/main/java/dev/ohno/legacylink/handler/rewrite/ItemRewriter.java
Replaced RegistryRemapper usage with LegacyItemIdTable for numeric item-id translation; remap now does a legacy-wire round-trip (toLegacyIdserverItemIdFromLegacyWire) and falls back to Items.STONE if lookup fails. Imports adjusted accordingly.
Registry remapper update
src/main/java/dev/ohno/legacylink/mapping/RegistryRemapper.java
remapItem(int) now canonicalizes via LegacyItemIdTable.toLegacyId(...) then serverItemIdFromLegacyWire(...), removing previous explicit ITEM_REMAP logic and the FALLBACK_ITEM constant; block-state remapping unchanged.

Sequence Diagram(s)

sequenceDiagram
    participant Connection
    participant PacketEventsAPI
    participant ProtocolManager
    participant User

    Connection->>PacketEventsAPI: PacketEvents.getAPI() (reflective)
    PacketEventsAPI->>ProtocolManager: api.getProtocolManager() (reflective)
    ProtocolManager->>User: getUser(protocolManager, connection.channel) (reflective)
    User->>User: setClientVersion(V_26_2) (reflective)
    Note over Connection,User: If any lookup fails or V_26_2 missing → exit silently (debug/warn logs)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 In moonlit code I hop and tune the trace,
I nudge versions gently to the proper place,
With mirrors and care I coax networks to see,
Legacy paws snug in a v2_6_2 tee. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main objective of the pull request: forcing PacketEvents client version to 26.2 for legacy sessions, which is the primary fix mentioned in the PR description and reflected in the new PacketEventsVersionBridge class and its integration points.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/normalize-packetevents-version-for-legacy

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/java/dev/ohno/legacylink/mixin/HandshakeMixin.java (1)

27-50: Extract repeated legacy setup sequence to one helper.

Lines 33-35 and Lines 47-49 duplicate the same sequence. Consider a small private helper to keep ordering consistent across both injection paths.

♻️ Suggested refactor
+    private void legacylink$prepareLegacyConnection() {
+        LegacyTracker.markLegacy(this.connection);
+        LegacyPacketHandler.install(this.connection);
+        PacketEventsVersionBridge.force26_2IfPresent(this.connection);
+    }
+
     `@Inject`(method = "beginLogin", at = `@At`("HEAD"), cancellable = true)
     private void legacylink$acceptLegacyClient(ClientIntentionPacket packet, boolean transfer, CallbackInfo ci) {
         if (packet.protocolVersion() == LegacyLinkConstants.PROTOCOL_26_1) {
@@
-            LegacyTracker.markLegacy(this.connection);
-            LegacyPacketHandler.install(this.connection);
-            PacketEventsVersionBridge.force26_2IfPresent(this.connection);
+            legacylink$prepareLegacyConnection();
@@
     `@Inject`(method = "handleIntention", at = `@At`("HEAD"))
     private void legacylink$markLegacyOnStatusPing(ClientIntentionPacket packet, CallbackInfo ci) {
         if (packet.protocolVersion() == LegacyLinkConstants.PROTOCOL_26_1) {
-            LegacyTracker.markLegacy(this.connection);
-            LegacyPacketHandler.install(this.connection);
-            PacketEventsVersionBridge.force26_2IfPresent(this.connection);
+            legacylink$prepareLegacyConnection();
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/dev/ohno/legacylink/mixin/HandshakeMixin.java` around lines 27
- 50, Extract the repeated legacy setup sequence
(LegacyTracker.markLegacy(this.connection);
LegacyPacketHandler.install(this.connection);
PacketEventsVersionBridge.force26_2IfPresent(this.connection);) into a single
private helper method on HandshakeMixin (e.g., private void
applyLegacySetup(ConnectionType connection) or applyLegacySetup()) and replace
the duplicated blocks in legacylink$acceptLegacyClient and
legacylink$markLegacyOnStatusPing with a call to that helper to ensure ordering
is identical in both injection paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/dev/ohno/legacylink/integration/PacketEventsVersionBridge.java`:
- Around line 38-47: The call to Enum.valueOf((Class<? extends Enum>)
clientVersionClass.asSubclass(Enum.class), "V_26_2") can throw
IllegalArgumentException when the ClientVersion enum lacks V_26_2; add a handler
to catch IllegalArgumentException around the Enum.valueOf invocation in
PacketEventsVersionBridge (the block that computes normalizedVersion and invokes
setClientVersion) and treat it like a missing PacketEvents class: call
logUnavailableOnce() (or otherwise no-op) so the optional PacketEvents
integration doesn't break login/config flow; ensure the catch does not hide real
reflection issues handled by the existing ReflectiveOperationException handler.

---

Nitpick comments:
In `@src/main/java/dev/ohno/legacylink/mixin/HandshakeMixin.java`:
- Around line 27-50: Extract the repeated legacy setup sequence
(LegacyTracker.markLegacy(this.connection);
LegacyPacketHandler.install(this.connection);
PacketEventsVersionBridge.force26_2IfPresent(this.connection);) into a single
private helper method on HandshakeMixin (e.g., private void
applyLegacySetup(ConnectionType connection) or applyLegacySetup()) and replace
the duplicated blocks in legacylink$acceptLegacyClient and
legacylink$markLegacyOnStatusPing with a call to that helper to ensure ordering
is identical in both injection paths.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 75f36bb6-4305-4dbf-8e88-84c9b30fe174

📥 Commits

Reviewing files that changed from the base of the PR and between cc5cdb9 and c379c14.

📒 Files selected for processing (3)
  • src/main/java/dev/ohno/legacylink/integration/PacketEventsVersionBridge.java
  • src/main/java/dev/ohno/legacylink/mixin/ConfigurationFinishMixin.java
  • src/main/java/dev/ohno/legacylink/mixin/HandshakeMixin.java

Canonicalize item remapping through the legacy wire-id table across packet and utility paths, add missing equipment item rewriting, and make PacketEvents version normalization safely no-op when V_26_2 is unavailable while keeping reflection failures visible.

Made-with: Cursor
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/main/java/dev/ohno/legacylink/handler/rewrite/ItemRewriter.java (1)

22-32: Centralize the item-id round-trip in one helper.

remapItemToLegacySafe() and remapItemIdStrict() now inline the same toLegacyId()serverItemIdFromLegacyWire() translation that RegistryRemapper.remapItem() already owns. Calling that helper from both sites would keep this PR’s canonicalization logic in one place and reduce the chance of these paths drifting again.

♻️ Proposed cleanup
 import dev.ohno.legacylink.mapping.LegacyItemIdTable;
+import dev.ohno.legacylink.mapping.RegistryRemapper;
 ...
-        int serverId = Item.getId(item);
-        int legacyWireId = LegacyItemIdTable.toLegacyId(serverId);
-        int canonicalServerId = LegacyItemIdTable.serverItemIdFromLegacyWire(legacyWireId);
+        int canonicalServerId = RegistryRemapper.remapItem(Item.getId(item));
         Item mapped = BuiltInRegistries.ITEM.byId(canonicalServerId);
 ...
-        int legacyWireId = LegacyItemIdTable.toLegacyId(itemId);
-        return LegacyItemIdTable.serverItemIdFromLegacyWire(legacyWireId);
+        return RegistryRemapper.remapItem(itemId);

Also applies to: 72-74

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/dev/ohno/legacylink/handler/rewrite/ItemRewriter.java` around
lines 22 - 32, Replace the duplicated two-step canonicalization
(LegacyItemIdTable.toLegacyId → serverItemIdFromLegacyWire) in
remapItemToLegacySafe with a call to the central helper
RegistryRemapper.remapItem so canonicalization lives in one place; do the same
change for remapItemIdStrict (the other inlined occurrence) and preserve the
existing fallback behavior (return Items.STONE when the remapped item is null).
Ensure you call RegistryRemapper.remapItem(serverId) (or the exact helper
signature) to obtain the canonical server id/item and then keep the
null-check/fallback logic intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main/java/dev/ohno/legacylink/handler/rewrite/ItemRewriter.java`:
- Around line 22-32: Replace the duplicated two-step canonicalization
(LegacyItemIdTable.toLegacyId → serverItemIdFromLegacyWire) in
remapItemToLegacySafe with a call to the central helper
RegistryRemapper.remapItem so canonicalization lives in one place; do the same
change for remapItemIdStrict (the other inlined occurrence) and preserve the
existing fallback behavior (return Items.STONE when the remapped item is null).
Ensure you call RegistryRemapper.remapItem(serverId) (or the exact helper
signature) to obtain the canonical server id/item and then keep the
null-check/fallback logic intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4dcfe419-d7bd-4cdc-b6a2-8e122cfe43a2

📥 Commits

Reviewing files that changed from the base of the PR and between c379c14 and 881ca34.

📒 Files selected for processing (5)
  • src/main/java/dev/ohno/legacylink/handler/LegacyPacketHandler.java
  • src/main/java/dev/ohno/legacylink/handler/rewrite/ItemRewriter.java
  • src/main/java/dev/ohno/legacylink/integration/PacketEventsVersionBridge.java
  • src/main/java/dev/ohno/legacylink/mapping/RegistryRemapper.java
  • src/main/java/dev/ohno/legacylink/mixin/HandshakeMixin.java
✅ Files skipped from review due to trivial changes (2)
  • src/main/java/dev/ohno/legacylink/mixin/HandshakeMixin.java
  • src/main/java/dev/ohno/legacylink/integration/PacketEventsVersionBridge.java

ohnodev added 2 commits April 13, 2026 04:17
Ensure ItemStackTemplate stream codec remaps item ids for legacy sessions so update_advancements icons cannot send out-of-range ids. Also keep status ping path lightweight and collapse non-vanilla namespaces to safe legacy item fallbacks.

Made-with: Cursor
Replace duplicated LegacyItemIdTable round-trip logic in ItemRewriter with RegistryRemapper.remapItem for both remapItemToLegacySafe and remapItemIdStrict while preserving the existing stone fallback.

Made-with: Cursor
@ohnodev ohnodev merged commit 203efb8 into main Apr 12, 2026
1 check passed
@ohnodev ohnodev deleted the fix/normalize-packetevents-version-for-legacy branch April 12, 2026 21:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant