Skip to content

Dev v1.1.2#13

Merged
3add merged 53 commits into
mainfrom
dev
May 19, 2026
Merged

Dev v1.1.2#13
3add merged 53 commits into
mainfrom
dev

Conversation

@3add
Copy link
Copy Markdown
Owner

@3add 3add commented May 19, 2026

Summary by CodeRabbit

  • New Features

    • Field-based property system for inspecting/modifying entity and packet fields by name; new section expressions to construct fake entities and entity metadata.
    • Update checker that can notify eligible players on join.
  • Refactor

    • Player skin handling now operates on Player instances; large reorganization of expression/field APIs and package relocations.
    • Many legacy fake-entity/property expressions removed or consolidated.
  • Documentation

    • Added English localization, config update-checker settings, and README SkBee formatting fixes.

Review Change Stack

3add and others added 30 commits May 15, 2026 23:41
…LogUtil throughout the project replacing slf4j
…cket and ExprPacketField)

fix: description for ExprPacketField and SecExprNewPacket to show the available fields
add: buildServer task
refactor: rename PacketDefinitionRegistry, MainPacketDefinitions and SkBeePacketDefinitions
refactor: make use of lambda
…ny syntax collisions and looks a lot better in code)
refactor: Definition based classes for a more abstract and expandable approach

This did a lot and I cba to write it all out, look at the changes if you're interested nerd
Clarified the relationship between PacketEventsSK and SkBee in the README.
Added note about SkBee requirement for element registration.
Add clarification about entity pose requirement.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 48f73c35-900c-4180-9b85-8cf31957920d

📥 Commits

Reviewing files that changed from the base of the PR and between b656e1e and c97aea2.

📒 Files selected for processing (2)
  • src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/BaseMetaFieldRegistrar.java
  • src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java

📝 Walkthrough

Walkthrough

Adds a schema-driven field/constructor registry system; migrates packet/meta/fake-entity construction and expressions to it; refactors ConversionUtil, PlayerSkinManager, and logging; updates build/config/docs/lang; relocates packet API packages; and adds a Modrinth-based UpdateChecker with join notifications.

Changes

Core schema and registries

Layer / File(s) Summary
Registry framework and primitives
src/main/java/.../api/util/field/*
Adds BaseFieldRegistry, InheritingFieldRegistry, FieldSchema, FieldAccessor, FieldRegistrar, ConstructionContext to support schema-driven construction and field access.
Packet field registry & registrars
src/main/java/.../element/general/field/packet/*
Adds PacketFieldRegistry singleton and client/server/SkBee registrars to declare packet field schemas and constructors for packet wrappers.
Meta field registry & registrars
src/main/java/.../element/general/field/meta/*
Adds MetaFieldRegistry and registrars (Base, Display, Interaction, Item, Living) with constructors and consumers for EntityMeta types.
Fake-entity field registry & registrars
src/main/java/.../element/entity/field/*
Adds FakeEntityFieldRegistry, FakeBaseEntityFieldRegistrar, FakePlayerEntityFieldRegistrar to register WrapperEntity/WrapperPlayer fields and construction logic.
Section migrations
src/main/java/.../element/general/section/*, src/main/java/.../element/entity/section/*
SecExprNewPacket, SecExprNewMeta, SecExprNewFakeEntity now validate and construct using FieldSchema and ConstructionContext.
Expression migrations
src/main/java/.../element/general/expression/prop/*, src/main/java/.../element/entity/expression/prop/*
ExprPacketField, ExprMetaField, ExprFakeEntityField updated/added to query FieldSchema/FieldAccessor for get/change and dynamic descriptions.
Conversion utilities
src/main/java/.../api/util/ConversionUtil.java
Expanded conversions (locations, quaternions, timespans, billboards, item-display transforms) with null guards used by registrars and constructors.

API, packages, removals

Layer / File(s) Summary
API relocations
src/main/java/dev/threeadd/packeteventssk/api/general/packet/*
Relocates PacketSendOrReceiveEvent/Listener and PacketTypeRegistry to .api.general.packet and updates imports across the plugin.
Removals
many src/main/java/.../element/** files
Removes PacketConstructorRegistry, SkBeePacketRegistrations, UserManager, EntityMetaPropertyExpression base, and numerous legacy ExprFake*/ExprFakeMeta* files as the registry-driven approach replaces them.

Skins and simple elements

Layer / File(s) Summary
Player skin refactor
src/main/java/dev/threeadd/packeteventssk/api/simple/PlayerSkinManager.java
Switches to Player-based API for global and per-viewer skins; re-registers profile per viewer and updates respawn/teleport/packet flow.
Simple effects
src/main/java/dev/threeadd/packeteventssk/element/simple/*
EffDisplayedSkin refactored to call new PlayerSkinManager APIs; package imports updated.

Logging, loader, build, config, updates

Layer / File(s) Summary
Logging & loader
src/main/java/dev/threeadd/packeteventssk/api/util/LogUtil.java, src/main/java/dev/threeadd/packeteventssk/AddonLoader.java
Adds LogUtil and replaces SLF4J/Adventure logging in AddonLoader, finalizes registration, logs element counts, and throws on element load failure.
Build, README, config, lang
build.gradle.kts, README.md, src/main/resources/config.yml, src/main/resources/lang/english.lang
Bumps project version/deps, repository ordering, fixes README SkBee section formatting, adds update-checker config keys and english.lang entries.
Update checker
src/main/java/dev/threeadd/packeteventssk/update/*
Adds UpdateChecker and ModrinthVersion to fetch Modrinth releases; JoinUpdateListener notifies permitted players on join; UpdateChecker hooked from plugin lifecycle.

Sequence Diagram(s)

sequenceDiagram
  participant Sec as SkriptSection
  participant Reg as PacketFieldRegistry
  participant Schema as FieldSchema
  participant Ctx as ConstructionContext
  participant Packet as PacketWrapper
  Sec->>Reg: getSchema(packetType)
  Reg-->>Schema: returns FieldSchema(accessors, constructor)
  Sec->>Ctx: assemble values map
  Schema->>Packet: constructor.apply(Ctx)
  Packet-->>Sec: constructed packet instance
Loading
sequenceDiagram
  participant Sec as SkriptSection
  participant Reg as MetaFieldRegistry
  participant Schema as FieldSchema
  participant Ctx as ConstructionContext
  participant Meta as EntityMeta
  Sec->>Reg: getSchema(entityType)
  Reg-->>Schema: return FieldSchema(accessors, constructor)
  Sec->>Ctx: assemble values map
  Schema->>Meta: constructor.apply(Ctx)
  Meta-->>Sec: constructed meta
Loading

Estimated code review effort: 🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs:

  • 3add/PacketEventsSK#13 — Overlapping edits to README/build, AddonLoader/LogUtil, and update-checker additions.

"A rabbit fixed the schema plot,
Fields sprouted neatly, one by lot. 🐰
Packets, metas, skins aligned,
Logs now sing with MiniMessage kind. ✨
Hop, test, release — a tidy bind."

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 19, 2026

Qodana for JVM

8 new problems were found

Inspection name Severity Problems
Constant values 🔶 Warning 5
Nullability and data flow problems 🔶 Warning 3
View the detailed Qodana report

To be able to view the detailed Qodana report, you can either:

To get *.log files or any other Qodana artifacts, run the action with upload-result option set to true,
so that the action will upload the files as the job artifacts:

      - name: 'Qodana Scan'
        uses: JetBrains/qodana-action@v2025.3.2
        with:
          upload-result: true
Contact Qodana team

Contact us at qodana-support@jetbrains.com

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR bumps PacketEventsSK to v1.1.2, adds a Modrinth-based update checker, and performs a sizable refactor of “packet/meta/fake entity field” handling by introducing a schema/accessor registry system that replaces many specialized expressions/sections with generic “field” access.

Changes:

  • Add an update-checker (config + Modrinth API integration + join notifications).
  • Introduce a generic field registry framework (FieldSchema/FieldAccessor/ConstructionContext) and use it for packets, entity meta, and fake entities.
  • Restructure several packages and remove legacy registries/expressions in favor of the new field system; update build + docs accordingly.

Reviewed changes

Copilot reviewed 108 out of 109 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/main/resources/lang/english.lang Adds/updates language keys for newly introduced types.
src/main/resources/config.yml Bumps version header and adds update-checker configuration section.
src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java New Modrinth update check logic (sync/async) and console logging.
src/main/java/dev/threeadd/packeteventssk/update/ModrinthVersion.java New Modrinth version JSON wrapper and supported-version checks.
src/main/java/dev/threeadd/packeteventssk/update/JoinUpdateListener.java Notifies privileged players on join when an update is available.
src/main/java/dev/threeadd/packeteventssk/PacketEventsSK.java Switches logging to LogUtil, wires metrics + update checker, removes UserManager registration.
src/main/java/dev/threeadd/packeteventssk/metrics/MetricsLoader.java Moves MetricsLoader into a dedicated metrics package.
src/main/java/dev/threeadd/packeteventssk/element/simple/SimpleElementRegistration.java Updates imports to new effect package naming.
src/main/java/dev/threeadd/packeteventssk/element/simple/effect/EffGlow.java Package rename to ...simple.effect.
src/main/java/dev/threeadd/packeteventssk/element/simple/effect/EffDisplayedSkin.java Package rename + adjusts PlayerSkinManager API usage and simplifies viewer handling.
src/main/java/dev/threeadd/packeteventssk/element/general/Types.java Updates/extends type registrations (interaction hand) and refactors some patterns/strings.
src/main/java/dev/threeadd/packeteventssk/element/general/section/SecExprNewPacket.java Reworks new-packet section to use packet field schemas/accessors + auto-doc generation.
src/main/java/dev/threeadd/packeteventssk/element/general/GeneralElementRegistration.java Registers new packet/meta field registries and new expressions/sections.
src/main/java/dev/threeadd/packeteventssk/element/general/field/packet/SkBeePacketFieldRegistrar.java Adds SkBee-dependent packet field registration (NBT).
src/main/java/dev/threeadd/packeteventssk/element/general/field/packet/ServerBoundPacketFieldRegistrar.java Adds serverbound packet schemas/accessors and constructors.
src/main/java/dev/threeadd/packeteventssk/element/general/field/packet/PacketFieldRegistry.java Introduces packet field registry singleton and registrar list.
src/main/java/dev/threeadd/packeteventssk/element/general/field/packet/ClientBoundPacketFieldRegistrar.java Adds clientbound packet schemas/accessors and constructors.
src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/MetaFieldRegistry.java Introduces inheriting meta field registry keyed by entity type.
src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/LivingMetaFieldRegistrar.java Adds (currently incomplete) living-entity meta field schema.
src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/ItemMetaFieldRegistrar.java Adds item-entity meta field schema and constructor.
src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/InteractionMetaFieldRegistrar.java Adds interaction-entity meta field schema and constructor.
src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/BaseMetaFieldRegistrar.java Adds base entity meta field schema + conditional pose field.
src/main/java/dev/threeadd/packeteventssk/element/general/expression/prop/ExprPlayerSkin.java Package rename to new expression namespace.
src/main/java/dev/threeadd/packeteventssk/element/general/expression/prop/ExprPacketPacketType.java Package rename to new expression namespace.
src/main/java/dev/threeadd/packeteventssk/element/general/expression/prop/ExprPacketField.java Migrates packet-field expression to schema/accessor system + improves docs and change typing.
src/main/java/dev/threeadd/packeteventssk/element/general/expression/prop/ExprMetaField.java New generic meta-field expression built on meta field registry.
src/main/java/dev/threeadd/packeteventssk/element/general/expression/prop/ExprEntityId.java Package rename to new expression namespace.
src/main/java/dev/threeadd/packeteventssk/element/general/expression/ExprSkinFromValue.java Package rename to new expression namespace.
src/main/java/dev/threeadd/packeteventssk/element/general/event/EvtPacketSendOrReceive.java Updates imports + changes syntax to require literal packet type (%*packettype%).
src/main/java/dev/threeadd/packeteventssk/element/general/effect/EffFetchSkin.java Updates syntax patterns (adds optional “fetch” and “named/with name”).
src/main/java/dev/threeadd/packeteventssk/element/general/effect/EffCancelPacket.java Updates PacketSendOrReceiveEvent import path.
src/main/java/dev/threeadd/packeteventssk/element/entity/sections/EffSecCreateFakeEntity.java Removes legacy fake-entity creation effect section.
src/main/java/dev/threeadd/packeteventssk/element/entity/section/SecExprNewFakeEntity.java New fake-entity constructor section built on fake-entity field schemas/accessors.
src/main/java/dev/threeadd/packeteventssk/element/entity/field/FakePlayerEntityFieldRegistrar.java Adds player fake-entity schema (skin/name + constructor).
src/main/java/dev/threeadd/packeteventssk/element/entity/field/FakeEntityFieldRegistry.java Introduces inheriting fake-entity field registry.
src/main/java/dev/threeadd/packeteventssk/element/entity/field/FakeBaseEntityFieldRegistrar.java Adds base fake-entity fields (viewers/location/meta/id/uuid) + constructor.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/player/ExprFakePlayerEntitySkin.java Removes legacy fake-player skin property expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/living/ExprFakeLivingEntityMetaHealth.java Removes legacy fake living-meta health expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/item/ExprFakeItemMetaItem.java Removes legacy dropped-item meta item expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/interaction/ExprFakeInterationMetaHeightOrWidth.java Removes legacy interaction meta width/height expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/text/ExprFakeTextDisplayMetaTextShadowed.java Removes legacy text-display shadowed expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/text/ExprFakeTextDisplayMetaText.java Removes legacy text-display text expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/text/ExprFakeTextDisplayMetaBackGroundColor.java Removes legacy text-display background color expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/item/ExprFakeItemDisplayMetaItem.java Removes legacy item-display item expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/ExprFakeDisplayMetaViewRange.java Removes legacy display view-range expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/ExprFakeDisplayMetaTranslation.java Removes legacy display translation expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/ExprFakeDisplayMetaTransformationInterpolationDuration.java Removes legacy display transform interpolation duration expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/ExprFakeDisplayMetaTeleportInterpolationDuration.java Removes legacy display teleport interpolation duration expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/ExprFakeDisplayMetaScale.java Removes legacy display scale expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/ExprFakeDisplayMetaLeftOrRightRotation.java Removes legacy display rotation expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/ExprFakeDisplayMetaInterpolationDelay.java Removes legacy display interpolation delay expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/ExprFakeDisplayMetaHeightOrWidth.java Removes legacy display height/width expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/ExprFakeDisplayMetaBillboard.java Removes legacy display billboard expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/display/block/ExprFakeBlockDisplayMetaBlock.java Removes legacy block-display block-data expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaSwimming.java Removes legacy base-meta swimming expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaSprinting.java Removes legacy base-meta sprinting expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaSneaking.java Removes legacy base-meta sneaking expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaSilent.java Removes legacy base-meta silent expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaPose.java Removes legacy base-meta pose expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaInvisible.java Removes legacy base-meta invisible expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaGravity.java Removes legacy base-meta gravity expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaGlowing.java Removes legacy base-meta glowing expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaFrozenTime.java Removes legacy base-meta frozen-time expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaFire.java Removes legacy base-meta fire expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaElytra.java Removes legacy base-meta elytra expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaCustomNameVisible.java Removes legacy base-meta custom-name-visible expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaCustomName.java Removes legacy base-meta custom-name expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/meta/base/ExprFakeMetaAirTime.java Removes legacy base-meta air-time expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/ExprFakeEntityViewers.java Removes legacy fake-entity viewers property expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/ExprFakeEntityUuid.java Removes legacy fake-entity uuid property expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/ExprFakeEntityType.java Removes legacy fake-entity type property expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/ExprFakeEntityMeta.java Removes legacy fake-entity meta property expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/ExprFakeEntityLocation.java Removes legacy fake-entity location property expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expressions/prop/ExprFakeEntityId.java Removes legacy fake-entity id property expression.
src/main/java/dev/threeadd/packeteventssk/element/entity/expression/prop/living/ExprFakeLivingEntityAttribute.java Package rename to new expression namespace.
src/main/java/dev/threeadd/packeteventssk/element/entity/expression/prop/ExprVisibleFakeEntities.java Package rename to new expression namespace.
src/main/java/dev/threeadd/packeteventssk/element/entity/expression/prop/ExprFakeEntityField.java New generic fake-entity field expression built on fake-entity field registry.
src/main/java/dev/threeadd/packeteventssk/element/entity/expression/ExprFakeEntityFromUuid.java Package rename to new expression namespace.
src/main/java/dev/threeadd/packeteventssk/element/entity/expression/ExprFakeEntityFromId.java Package rename to new expression namespace.
src/main/java/dev/threeadd/packeteventssk/element/entity/expression/ExprFakeEntityEventValue.java Package rename to new expression namespace.
src/main/java/dev/threeadd/packeteventssk/element/entity/expression/ExprFakeEntitiesAll.java Package rename to new expression namespace.
src/main/java/dev/threeadd/packeteventssk/element/entity/EntityElementRegistration.java Registers fake-entity field registry; replaces removed legacy sections/expressions with new ones.
src/main/java/dev/threeadd/packeteventssk/element/entity/effect/EffTeleportFakeEntity.java Adjusts syntax pattern spacing for fake-entity wording.
src/main/java/dev/threeadd/packeteventssk/element/entity/effect/EffSpawnFakeEntity.java Adjusts syntax pattern spacing for fake-entity wording.
src/main/java/dev/threeadd/packeteventssk/element/entity/effect/EffRideFakeEntity.java Adjusts syntax patterns spacing for fake-entity wording.
src/main/java/dev/threeadd/packeteventssk/element/entity/effect/EffKillFakeEntity.java Adjusts syntax pattern spacing for fake-entity wording.
src/main/java/dev/threeadd/packeteventssk/config/Configurable.java Adds config keys for update checker enabled/async.
src/main/java/dev/threeadd/packeteventssk/config/Config.java Removes slf4j logger usage and changes config-update failure behavior to throw.
src/main/java/dev/threeadd/packeteventssk/api/util/LogUtil.java New centralized console/player messaging utility (MiniMessage + prefix).
src/main/java/dev/threeadd/packeteventssk/api/util/field/InheritingFieldRegistry.java New inheriting registry implementation for type hierarchies.
src/main/java/dev/threeadd/packeteventssk/api/util/field/FieldSchema.java New field schema record with field lookup and readable-doc rendering.
src/main/java/dev/threeadd/packeteventssk/api/util/field/FieldRegistrar.java New registrar interface for registry population.
src/main/java/dev/threeadd/packeteventssk/api/util/field/FieldAccessor.java New accessor record with aliases + getter/setter.
src/main/java/dev/threeadd/packeteventssk/api/util/field/ConstructionContext.java New context type for constructing objects from schema arguments.
src/main/java/dev/threeadd/packeteventssk/api/util/field/BaseFieldRegistry.java New base registry + builder and registrar workflow.
src/main/java/dev/threeadd/packeteventssk/api/util/ConversionUtil.java Expands conversion helpers (timespan, billboard/transform enums, locations) with null-handling.
src/main/java/dev/threeadd/packeteventssk/api/general/UserManager.java Removed legacy PacketEvents user caching listener.
src/main/java/dev/threeadd/packeteventssk/api/general/SkBeePacketRegistrations.java Removed legacy SkBee packet-registration hook.
src/main/java/dev/threeadd/packeteventssk/api/general/PacketConstructorRegistry.java Removed legacy packet constructor/field registry.
src/main/java/dev/threeadd/packeteventssk/api/general/packet/PacketTypeRegistry.java Moves PacketTypeRegistry into api.general.packet and cleans imports.
src/main/java/dev/threeadd/packeteventssk/api/general/packet/PacketSendOrReceiveListener.java Moves listener into api.general.packet.
src/main/java/dev/threeadd/packeteventssk/api/general/packet/PacketSendOrReceiveEvent.java Moves event into api.general.packet.
src/main/java/dev/threeadd/packeteventssk/api/entity/EntityMetaPropertyExpression.java Removes legacy meta-property expression base class.
src/main/java/dev/threeadd/packeteventssk/AddonLoader.java Switches to LogUtil, changes Registration settings, and adds element-count logging.
README.md Updates SkBee section and clarifies optional addon-provided types.
build.gradle.kts Bumps version/deps, tweaks repositories, and adds a local “buildServer” copy task.
Comments suppressed due to low confidence (2)

src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java:88

  • If getLatestVersionFromModrinth() returns null, latestReleaseFuture is cancelled and updateVersionFuture is never completed/cancelled (because thenApply won’t run for a cancelled future). That can leave callers waiting forever. Ensure the returned future always completes (e.g., completeExceptionally, or complete with a sentinel/Optional and handle it explicitly).
    src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java:102
  • getLatestVersionFromModrinth() opens a stream/reader without closing it, and uses URL#openStream() without timeouts. This can leak resources and hang startup on slow networks. Use try-with-resources and an HttpURLConnection (or HttpClient) with connect/read timeouts, and handle an empty JSON array safely before elements.get(0).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/main/java/dev/threeadd/packeteventssk/api/util/field/BaseFieldRegistry.java Outdated
Comment thread src/main/java/dev/threeadd/packeteventssk/AddonLoader.java Outdated
Comment thread src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java
Comment thread src/main/resources/config.yml
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: 5

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

🟠 Major comments (18)
src/main/java/dev/threeadd/packeteventssk/api/util/ConversionUtil.java-52-55 (1)

52-55: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Using getFirst() world is incorrect for multi-world servers.

com.github.retrooper.packetevents.protocol.world.Location doesn't carry world information, so defaulting to the first world will produce wrong results on any multi-world server. If world context is unavailable from the PE Location, callers need to supply it explicitly or this method should require a World parameter.

Suggested signature change
-public static Location toBukkitLocation(com.github.retrooper.packeteventssk.protocol.world.Location location) {
+public static Location toBukkitLocation(com.github.retrooper.packetevents.protocol.world.Location location, World world) {
     if (location == null) return null;
-    return new Location(Bukkit.getWorlds().getFirst(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+    return new Location(world, location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/api/util/ConversionUtil.java`
around lines 52 - 55, The toBukkitLocation method in ConversionUtil uses
Bukkit.getWorlds().getFirst() which breaks multi-world servers because
com.github.retrooper.packetevents.protocol.world.Location has no world info;
change the API to require the caller to supply the target World (e.g., replace
or overload public static Location toBukkitLocation(...location) with public
static Location toBukkitLocation(World world,
com.github.retrooper.packetevents.protocol.world.Location location)), remove the
getFirst() call, construct the Bukkit Location using the provided World, and
update all call sites to pass the correct World (or add an overload that
delegates to the new method and mark the no-world signature deprecated).
src/main/java/dev/threeadd/packeteventssk/api/simple/PlayerSkinManager.java-89-89 (1)

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

Debug logging uses ERROR level instead of DEBUG/TRACE.

This line logs routine operational data (target and viewer names) at ERROR level. This will pollute error logs during normal operation and may trigger monitoring alerts for non-error conditions. Use log.debug() or log.trace() for diagnostic output.

Proposed fix
-        log.error("target: {}, viewers: {}", target.getName(), viewers.stream().map(Player::getName).toList());
+        log.debug("target: {}, viewers: {}", target.getName(), viewers.stream().map(Player::getName).toList());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/api/simple/PlayerSkinManager.java`
at line 89, In PlayerSkinManager replace the routine diagnostic log call that
currently uses log.error(...) (the line logging "target: {}, viewers: {}" with
target.getName() and viewers.stream().map(Player::getName).toList()) with a
debug or trace level call (e.g., log.debug(...)/log.trace(...)) and wrap it with
a log.isDebugEnabled()/isTraceEnabled() guard or use a parameterized/debug
lambda-style logger to avoid the viewer stream allocation when debug is
disabled.
src/main/java/dev/threeadd/packeteventssk/api/simple/PlayerSkinManager.java-158-165 (1)

158-165: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Potential race condition: packet sent before async teleport completes.

teleportAsync() returns a CompletableFuture, but the START_LOADING_CHUNKS packet is sent immediately after without awaiting completion. This may cause the packet to arrive before the player is teleported, leading to inconsistent client state.

Proposed fix using thenRun
-        player.teleportAsync(player.getLocation()); // replaces WrapperPlayServerPlayerPositionAndLook cause it's advertised as buggy if done using the packet
-
-        WrapperPlayServerChangeGameState startLoadingChunksPacket = new WrapperPlayServerChangeGameState(
-                Reason.START_LOADING_CHUNKS,
-                0.0f);
-        PacketEvents.getAPI().getPlayerManager().sendPacket(player, startLoadingChunksPacket);
+        player.teleportAsync(player.getLocation()).thenRun(() -> {
+            WrapperPlayServerChangeGameState startLoadingChunksPacket = new WrapperPlayServerChangeGameState(
+                    Reason.START_LOADING_CHUNKS,
+                    0.0f);
+            PacketEvents.getAPI().getPlayerManager().sendPacket(player, startLoadingChunksPacket);
+        });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/api/simple/PlayerSkinManager.java`
around lines 158 - 165, teleportAsync returns a CompletableFuture and the
START_LOADING_CHUNKS packet is currently sent immediately afterward, creating a
race; change the flow so the START_LOADING_CHUNKS packet
(WrapperPlayServerChangeGameState with Reason.START_LOADING_CHUNKS) is only sent
after player.teleportAsync(player.getLocation()) completes by chaining the
future (e.g., player.teleportAsync(...).thenRun(() ->
PacketEvents.getAPI().getPlayerManager().sendPacket(player,
startLoadingChunksPacket))) and handle errors on the future (e.g.,
exceptionally/logging) to avoid swallowing exceptions.
src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java-80-88 (1)

80-88: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

updateVersionFuture never completes if latestReleaseFuture is cancelled.

When latestReleaseFuture.cancel(true) is called (after the fix above), the thenApply callback won't execute, leaving updateVersionFuture in an incomplete state. Callers awaiting this future will hang indefinitely.

Use whenComplete or handle instead to ensure updateVersionFuture is always resolved.

Suggested fix using handle()
-            latestReleaseFuture.thenApply(version -> {
-                if (version.getUpdateVersion().compareTo(PLUGIN_VERSION) <= 0) {
-                    updateVersionFuture.cancel(true);
+            latestReleaseFuture.handle((version, throwable) -> {
+                if (throwable != null || version == null) {
+                    updateVersionFuture.completeExceptionally(
+                        throwable != null ? throwable : new RuntimeException("Failed to fetch version"));
+                } else if (version.getUpdateVersion().compareTo(PLUGIN_VERSION) <= 0) {
+                    updateVersionFuture.completeExceptionally(new RuntimeException("Already up to date"));
                 } else {
                     CURRENT_UPDATE_VERSION = version;
                     updateVersionFuture.complete(CURRENT_UPDATE_VERSION);
                 }
                 return true;
             });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java` around
lines 80 - 88, The callback on latestReleaseFuture uses thenApply so if
latestReleaseFuture is cancelled the lambda never runs and updateVersionFuture
remains unresolved; change the chaining to use handle or whenComplete on
latestReleaseFuture (referencing latestReleaseFuture.thenApply(...) currently)
and in that handler always complete or cancel updateVersionFuture
(updateVersionFuture.complete(...), updateVersionFuture.cancel(...), or
updateVersionFuture.completeExceptionally(...)) depending on whether the
incoming result is null/exceptional or the version is older (compare using
version.getUpdateVersion().compareTo(PLUGIN_VERSION)), and still set
CURRENT_UPDATE_VERSION when appropriate so callers never hang.
src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java-94-103 (1)

94-103: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Resource leak: BufferedReader is never closed.

The BufferedReader wrapping the URL stream is never closed, leaking the underlying socket connection. Use try-with-resources.

Suggested fix
     private static ModrinthVersion getLatestVersionFromModrinth() {
         try {
             URL url = new URI("https://api.modrinth.com/v2/project/CmkvxP9q/version").toURL();
-            BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
-            JsonArray elements = new Gson().fromJson(reader, JsonArray.class);
-            JsonElement latestVersion = elements.get(0);
-            return new ModrinthVersion(latestVersion);
+            try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
+                JsonArray elements = new Gson().fromJson(reader, JsonArray.class);
+                JsonElement latestVersion = elements.get(0);
+                return new ModrinthVersion(latestVersion);
+            }
         } catch (IOException | URISyntaxException e) {
             LogUtil.error("Checking for updates failed");
         }
         return null;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java` around
lines 94 - 103, The BufferedReader created in UpdateChecker (the block that
builds URL url, BufferedReader reader, reads JsonArray elements and returns new
ModrinthVersion) is never closed; wrap the URL.openStream()/BufferedReader in a
try-with-resources so the stream and reader are automatically closed (e.g., use
try (BufferedReader reader = new BufferedReader(new
InputStreamReader(url.openStream()))) { ... }) and move the JSON
parsing/ModrinthVersion construction inside that try, keeping the existing catch
for IOException | URISyntaxException and returning null on failure.
src/main/java/dev/threeadd/packeteventssk/element/entity/section/SecExprNewFakeEntity.java-163-165 (1)

163-165: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid returning [null] from the expression getter.

Line 164 wraps a nullable result directly. When creation fails, this returns an array containing null instead of no value, which can break downstream handling.

Proposed fix
     `@Override`
     protected WrapperEntity `@Nullable` [] get(Event event) {
-        return new WrapperEntity[]{createEntity(event)};
+        WrapperEntity entity = createEntity(event);
+        return entity == null ? null : new WrapperEntity[]{entity};
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/dev/threeadd/packeteventssk/element/entity/section/SecExprNewFakeEntity.java`
around lines 163 - 165, The getter SecExprNewFakeEntity.get(Event event)
currently returns new WrapperEntity[]{createEntity(event)} which can yield an
array containing a null element when createEntity(event) fails; change the
method to call createEntity(event), check the result, and return either a
single-element array containing the non-null WrapperEntity or an empty array (no
elements) when createEntity returns null so downstream code never receives
[null]; update the implementation around get(Event) and the createEntity call
accordingly.
src/main/java/dev/threeadd/packeteventssk/element/entity/expression/prop/ExprFakeEntityField.java-141-153 (1)

141-153: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Tighten array compatibility before invoking field setters.

On Line 144, any array is accepted for any expected array type. That can push incompatible arrays into the setter and trigger runtime type failures.

Proposed fix
-            if (!isCompatible && expected.isArray() && newValue.getClass().isArray()) {
-                isCompatible = true;
-            }
+            if (!isCompatible && expected.isArray() && newValue.getClass().isArray()) {
+                Class<?> componentType = expected.getComponentType();
+                int len = Array.getLength(newValue);
+                boolean componentsCompatible = true;
+                for (int i = 0; i < len; i++) {
+                    Object element = Array.get(newValue, i);
+                    if (element != null && !componentType.isInstance(element)) {
+                        componentsCompatible = false;
+                        break;
+                    }
+                }
+                isCompatible = componentsCompatible;
+            }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/dev/threeadd/packeteventssk/element/entity/expression/prop/ExprFakeEntityField.java`
around lines 141 - 153, The code in ExprFakeEntityField currently treats any
array as compatible whenever expected.isArray(), which can still pass
incompatible element types to targetField.setter(); tighten the check by, when
expected.isArray() && newValue.getClass().isArray(), comparing the component
types: obtain expected.getComponentType() and
newValue.getClass().getComponentType() and require the new component type to be
assignable to the expected component type (taking into account
primitive<->wrapper differences if necessary) before setting; only call
((BiConsumer<WrapperEntity, Object>) targetField.setter()).accept(entity,
newValue) if that component-type compatibility check passes, otherwise log the
same Skript.warning and continue.
build.gradle.kts-16-16 (1)

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

Remove hardcoded developer-specific path.

The serverLocation contains an absolute Windows path with a specific username. This breaks build portability for other developers and should not be committed to the repository.

Consider one of these solutions:

  • Move to gradle.properties (add to .gitignore)
  • Use a relative path with a sensible default
  • Make it configurable with clear documentation
🔧 Suggested fix using gradle.properties

In build.gradle.kts, change to:

-val serverLocation = "C:/Users/jaspe/Desktop/Servers/packetSKTestServer/plugins"
+val serverLocation: String by project

Then create a gradle.properties file (add to .gitignore):

serverLocation=C:/Users/jaspe/Desktop/Servers/packetSKTestServer/plugins

Add to .gitignore:

gradle.properties

And provide a gradle.properties.example:

# Copy this file to gradle.properties and configure your server path
serverLocation=path/to/your/server/plugins
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build.gradle.kts` at line 16, The build currently hardcodes a
developer-specific absolute path in the serverLocation variable in
build.gradle.kts; replace this by reading a configurable property (e.g.,
project.findProperty("serverLocation") or System.getenv("SERVER_LOCATION")) with
a sensible relative-path default (like "./plugins") to preserve portability,
then move the developer-specific value into a local gradle.properties (and add
gradle.properties to .gitignore) and provide a gradle.properties.example with a
placeholder path; update any references to serverLocation in build.gradle.kts to
use the new property lookup.
src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/DisplayMetaFieldRegistrar.java-82-84 (1)

82-84: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Shadow strength field is wired to the wrong setter.

Line 83 maps "display shadow strength" to setShadowRadius(...) instead of setShadowStrength(...), so writes hit the wrong property.

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

In
`@src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/DisplayMetaFieldRegistrar.java`
around lines 82 - 84, The display shadow strength field is wired to the wrong
setter: in DisplayMetaFieldRegistrar the mapping using
AbstractDisplayMeta::getShadowStrength currently calls
meta.setShadowRadius(newNum.floatValue()); change that call to
meta.setShadowStrength(newNum.floatValue()) so the "display shadow strength"
field reads via getShadowStrength and writes to setShadowStrength (ensure the
method name matches the AbstractDisplayMeta API).
src/main/java/dev/threeadd/packeteventssk/api/util/field/BaseFieldRegistry.java-46-47 (1)

46-47: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard against empty field-name varargs to avoid runtime crashes.

Line 47 and Line 53 dereference names[0] without validating input. Calling either method with no names throws ArrayIndexOutOfBoundsException during registration.

Proposed fix
 public <V> Builder<T> requiredField(Class<V> expectedType, Function<T, V> getter, `@Nullable` BiConsumer<T, V> setter, String... names) {
+    if (names.length == 0) {
+        throw new IllegalArgumentException("At least one field name is required");
+    }
     accessors.add(new FieldAccessor<>(names[0], Arrays.copyOfRange(names, 1, names.length), expectedType, false, (Function<BaseType, V>) getter, (BiConsumer<BaseType, V>) setter));
     return this;
 }
@@
 public <V> Builder<T> optionalField(Class<V> expectedType, Function<T, V> getter, `@Nullable` BiConsumer<T, V> setter, String... names) {
+    if (names.length == 0) {
+        throw new IllegalArgumentException("At least one field name is required");
+    }
     accessors.add(new FieldAccessor<>(names[0], Arrays.copyOfRange(names, 1, names.length), expectedType, true, (Function<BaseType, V>) getter, (BiConsumer<BaseType, V>) setter));
     return this;
 }

Also applies to: 52-53

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

In
`@src/main/java/dev/threeadd/packeteventssk/api/util/field/BaseFieldRegistry.java`
around lines 46 - 47, The Builder<T> methods (requiredField and the similar
optionalField overload) currently dereference names[0] without validation
causing ArrayIndexOutOfBoundsException when called with no names; add an input
guard at the start of each method to check that names is non-null and
names.length>0 and throw an IllegalArgumentException (with a clear message like
"field names must contain at least one name") if the check fails so the call
site gets a clear error instead of an OOB exception; update both
requiredField(...) and optionalField(...) in class BaseFieldRegistry.Builder to
perform this validation before constructing the new FieldAccessor.
src/main/java/dev/threeadd/packeteventssk/api/util/field/InheritingFieldRegistry.java-20-29 (1)

20-29: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Protect parent-chain traversal from cycles.

getSchema has no cycle detection. If getParentKey ever forms a cycle, this loop never terminates and can hang the server thread.

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

In
`@src/main/java/dev/threeadd/packeteventssk/api/util/field/InheritingFieldRegistry.java`
around lines 20 - 29, In InheritingFieldRegistry, getSchema(K key) currently
follows the parent chain via getParentKey with no cycle detection; add cycle
protection by tracking visited keys (e.g., a HashSet<K> visited) as you walk the
chain in getSchema and stop if a key is encountered twice—on detection either
return null or throw a specific exception/log an error to avoid an infinite
loop; ensure you still call super.getSchema for each current key and update
visited before advancing to getParentKey.
src/main/java/dev/threeadd/packeteventssk/api/util/field/InheritingFieldRegistry.java-68-83 (1)

68-83: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Child accessors cannot override inherited ones with current merge order.

Parent accessors are added before child accessors, and lookup returns the first match. A child field with the same name/alias is effectively ignored.

Proposed fix
- mergedAccessors.addAll(parentSchema.accessors());
+ mergedAccessors.addAll(parentSchema.accessors());
@@
- mergedAccessors.addAll(this.accessors);
+ // ensure child definitions override parent by removing conflicting inherited entries
+ mergedAccessors.removeIf(parent ->
+         this.accessors.stream().anyMatch(child -> child.matches(parent.name())));
+ mergedAccessors.addAll(this.accessors);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/dev/threeadd/packeteventssk/api/util/field/InheritingFieldRegistry.java`
around lines 68 - 83, The merge currently appends parent accessors before child
accessors so children cannot override parents; change InheritingFieldRegistry's
merge logic (the mergedAccessors construction that uses classToTypeMap,
REGISTRY, FieldSchema, this.accessors, constructor) to start with the child's
accessors and then add parent accessors only when they do not conflict with any
child accessor (compare accessor identity by field name and aliases), i.e.,
build a set of child accessor names/aliases from this.accessors, add those first
to mergedAccessors, then iterate parentSchema.accessors() and add each parent
accessor only if none of its names/aliases exist in the child set, then put the
new FieldSchema into REGISTRY.
src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/LivingMetaFieldRegistrar.java-23-24 (1)

23-24: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid truncating health values to integers.

Line 23 and Line 39 use intValue(), which drops fractional health values. This can produce incorrect state when scripts pass decimal health.

Suggested fix
-                        (meta, newNum) -> meta.setHealth(newNum.intValue()),
+                        (meta, newNum) -> meta.setHealth(newNum.floatValue()),
...
-            meta.setHealth(health.intValue());
+            meta.setHealth(health.floatValue());

Also applies to: 37-40

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

In
`@src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/LivingMetaFieldRegistrar.java`
around lines 23 - 24, The health field registration in LivingMetaFieldRegistrar
is truncating fractional health by calling newNum.intValue(); update the lambda
handlers that call meta.setHealth(newNum.intValue()) (and the similar occurrence
around lines 37–40) to use the appropriate floating conversion (e.g.,
newNum.doubleValue() or newNum.floatValue()) so decimals are preserved and
ensure meta.setHealth is called with the matching double/float type; adjust any
method signature or cast if necessary to accept the floating type.
src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/InteractionMetaFieldRegistrar.java-20-24 (1)

20-24: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve numeric precision for interaction dimensions.

Line 20, Line 24, Line 36, and Line 41 coerce Number to int, which truncates fractional width/height values. This silently changes user input and metadata behavior.

Suggested fix
-                        (meta, newNum) -> meta.setWidth(newNum.intValue()),
+                        (meta, newNum) -> meta.setWidth(newNum.floatValue()),
...
-                        (meta, newNum) -> meta.setHeight(newNum.intValue()),
+                        (meta, newNum) -> meta.setHeight(newNum.floatValue()),
...
-                        meta.setWidth(width.intValue());
+                        meta.setWidth(width.floatValue());
...
-                        meta.setHeight(height.intValue());
+                        meta.setHeight(height.floatValue());

Also applies to: 34-42

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

In
`@src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/InteractionMetaFieldRegistrar.java`
around lines 20 - 24, The registrar currently truncates fractional interaction
dimensions by calling newNum.intValue() in the optionalField(Number.class,
InteractionMeta::getWidth, (meta, newNum) -> meta.setWidth(newNum.intValue()),
"interaction width") and the analogous height lambda; update these to preserve
precision by using newNum.doubleValue() (i.e. (meta, newNum) ->
meta.setWidth(newNum.doubleValue()) and -> meta.setHeight(newNum.doubleValue()))
and update InteractionMeta's getters/setters (getWidth/getHeight and
setWidth/setHeight) and their types from int to double so the metadata stores
and returns fractional values instead of truncated ints.
src/main/java/dev/threeadd/packeteventssk/element/general/section/SecExprNewMeta.java-168-170 (1)

168-170: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not return arrays containing a null meta instance.

Line 169 currently returns new EntityMeta[]{createMeta(event)} even when creation fails, yielding [null]. This can trigger downstream NPEs in Skript pipelines.

Suggested fix
 `@Override`
 protected EntityMeta `@Nullable` [] get(Event event) {
-    return new EntityMeta[]{createMeta(event)};
+    EntityMeta meta = createMeta(event);
+    return meta == null ? null : new EntityMeta[]{meta};
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/dev/threeadd/packeteventssk/element/general/section/SecExprNewMeta.java`
around lines 168 - 170, SecExprNewMeta.get currently returns new
EntityMeta[]{createMeta(event)} which can produce an array [null]; change it to
call createMeta(event) into a local variable, check if that result is null and
return null (or an empty array per project convention) instead of returning an
array containing a null element, otherwise return new EntityMeta[]{meta}; ensure
you respect the `@Nullable` return and update get to use the local variable
(referencing SecExprNewMeta.get and createMeta).
src/main/java/dev/threeadd/packeteventssk/element/general/expression/prop/ExprMetaField.java-152-154 (1)

152-154: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Array compatibility check is too permissive for SET.

Line 152–154 marks all array-to-array assignments as compatible without checking component type. This can route incompatible values into the setter and fail at runtime.

Suggested fix
-            if (!isCompatible && expected.isArray() && newValue.getClass().isArray()) {
-                isCompatible = true;
+            if (!isCompatible && expected.isArray() && newValue.getClass().isArray()) {
+                Class<?> expectedComponent = expected.getComponentType();
+                Class<?> actualComponent = newValue.getClass().getComponentType();
+                isCompatible = expectedComponent != null
+                        && actualComponent != null
+                        && (expectedComponent.isAssignableFrom(actualComponent)
+                        || expectedComponent == Object.class);
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/dev/threeadd/packeteventssk/element/general/expression/prop/ExprMetaField.java`
around lines 152 - 154, The current array-to-array compatibility branch in
ExprMetaField (the block that sets isCompatible = true when expected.isArray()
&& newValue.getClass().isArray()) is too permissive; change it to check
component-type compatibility instead of accepting any arrays. Update the
compatibility check in the method around ExprMetaField so that when both
expected.isArray() and newValue.getClass().isArray() you compare
expected.getComponentType() against newValue.getClass().getComponentType()
(using isAssignableFrom or equivalent), and also handle primitive-vs-wrapper
component cases (e.g., map int[] vs Integer[] appropriately) before marking
isCompatible true so only compatible array assignments reach the setter.
src/main/java/dev/threeadd/packeteventssk/element/general/section/SecExprNewPacket.java-91-96 (1)

91-96: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard type == null before using getName().

At Line 95, this.type.getName() can throw if Line 91 resolves to null (invalid/empty literal path). Fail early with a clear error before schema lookup.

Proposed patch
         this.type = packetTypeLiteral.getSingle();
+        if (this.type == null) {
+            Skript.error("The packet type literal resolved to null.");
+            return false;
+        }
         this.schema = PacketFieldRegistry.INSTANCE.getSchema(this.type);
 
         if (this.schema == null) {
             Skript.error("Packet creation for " + this.type.getName() + " is not currently supported. Consider creating/handling it through reflection.");
             return false; // can't return an empty packet so this expr can't be used
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/dev/threeadd/packeteventssk/element/general/section/SecExprNewPacket.java`
around lines 91 - 96, Guard against a null packet type before using it: check
the result of packetTypeLiteral.getSingle() (stored in this.type) for null and
call Skript.error with a clear message and return false if it's null, before
calling PacketFieldRegistry.INSTANCE.getSchema(this.type) or
this.type.getName(); update the logic in SecExprNewPacket around the fields
this.type and this.schema so the null-check happens first and prevents calling
this.type.getName() when packetTypeLiteral is empty.
src/main/java/dev/threeadd/packeteventssk/element/general/field/packet/SkBeePacketFieldRegistrar.java-25-31 (1)

25-31: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix the SkBee availability gate flow and log message.

Line 26 logs "Hooked into SkBee NBT using NBT-API" while in the !enabled branch, which is misleading. Additionally, line 30 catches ClassNotFoundException and logs an error but lacks a return false statement, allowing registration to proceed unexpectedly. Both paths should cleanly short-circuit.

Proposed patch
             boolean enabled = (boolean) nbtApiClass.getMethod("isEnabled").invoke(null);
             if (!enabled) {
-                LogUtil.info("Hooked into SkBee NBT using NBT-API");
+                LogUtil.info("SkBee NBT API is disabled, PacketEventsSK NBT packet fields will not be registered");
                 return false;
             }
         } catch (ClassNotFoundException ignored) {
             LogUtil.error("SkBee not found, PacketEventsSK elements depending on NBT will not be registered");
+            return false;
         } catch (Exception e) {
             throw new IllegalStateException("Failed to hook into SkBee NBT", e);
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/dev/threeadd/packeteventssk/element/general/field/packet/SkBeePacketFieldRegistrar.java`
around lines 25 - 31, In SkBeePacketFieldRegistrar, fix the SkBee availability
gate: change the misleading LogUtil.info message inside the !enabled branch to
indicate SkBee NBT integration is disabled (e.g., "SkBee NBT integration
disabled, skipping NBT-API hook") and keep the existing return false; also
ensure the ClassNotFoundException catch block both logs the error via
LogUtil.error("SkBee not found, PacketEventsSK elements depending on NBT will
not be registered") and immediately returns false so registration is
short-circuited; likewise, if there is a generic Exception catch (Exception e)
in the same method, log the exception and return false to prevent continuing
when detection fails.
🟡 Minor comments (4)
src/main/java/dev/threeadd/packeteventssk/api/util/ConversionUtil.java-42-45 (1)

42-45: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Precision loss: casting to float when Vector3d expects double.

The method casts to float but Vector3d takes double arguments. This unnecessarily truncates precision.

Proposed fix
 public static Vector3d toPeVectorD(Vector vector) {
     if (vector == null) return null;
-    return new Vector3d((float) vector.getX(), (float) vector.getY(), (float) vector.getZ());
+    return new Vector3d(vector.getX(), vector.getY(), vector.getZ());
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/api/util/ConversionUtil.java`
around lines 42 - 45, The toPeVectorD method in ConversionUtil is unnecessarily
casting coordinates to float causing precision loss; update to pass the vector's
double values directly to the Vector3d constructor (i.e., remove the (float)
casts) so new Vector3d receives double arguments from vector.getX(),
vector.getY(), vector.getZ(); keep the existing null check and method signature
unchanged.
src/main/java/dev/threeadd/packeteventssk/api/simple/PlayerSkinManager.java-39-39 (1)

39-39: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Redundant Bukkit.getPlayer() call.

target is already a Player object, so Bukkit.getPlayer(target.getUniqueId()) is unnecessary and adds overhead.

Proposed fix
-        if (skin.equals(SkinManager.getPlayer(Bukkit.getPlayer(target.getUniqueId())))) {
+        if (skin.equals(SkinManager.getPlayer(target))) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/api/simple/PlayerSkinManager.java`
at line 39, The code performs a redundant Bukkit.getPlayer(...) call: inside
PlayerSkinManager use the existing Player instance `target` directly instead of
looking it up again; change the comparison from
skin.equals(SkinManager.getPlayer(Bukkit.getPlayer(target.getUniqueId()))) to
skin.equals(SkinManager.getPlayer(target)) so `target` is used as the argument
to SkinManager.getPlayer and avoid the unnecessary Bukkit.getPlayer lookup.
src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java-57-60 (1)

57-60: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

exceptionally treats all failures as "up to date".

Network failures, JSON parse errors, and cancellation all trigger the "Plugin is up to date!" message, which is misleading. Consider distinguishing between "already current" and "check failed" scenarios.

Suggested improvement
         }).exceptionally(throwable -> {
-            LogUtil.mini("<green>Plugin is up to date!");
+            if (throwable.getCause() instanceof RuntimeException && 
+                throwable.getCause().getMessage() != null &&
+                throwable.getCause().getMessage().contains("up to date")) {
+                LogUtil.mini("<green>Plugin is up to date!");
+            } else {
+                LogUtil.info("Could not determine update status");
+            }
             return true;
         });

Alternatively, use a custom exception class for cleaner discrimination.

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

In `@src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java` around
lines 57 - 60, The current CompletableFuture chain in UpdateChecker uses
.exceptionally(...) to always log "Plugin is up to date!" on any failure; change
the error handling so that only a successful version-compare path logs "up to
date" while network/parse/cancellation errors log a distinct failure message (or
propagate). Locate the CompletableFuture callback (the lambda currently passed
to .exceptionally) and replace it with a combination of .thenApply/.thenAccept
for the normal version-check logic (compare remoteVersion to localVersion and
log "<green>Plugin is up to date!" only when equal/newer) and a separate
.exceptionally or .whenComplete block that logs a clear error message including
the throwable for failures; alternatively implement a custom exception type and
use .handle(...) to branch success vs failure. Ensure you reference the
UpdateChecker method that builds the future and only log success inside the
success branch while logging errors with throwable details in the failure
branch.
src/main/java/dev/threeadd/packeteventssk/element/general/Types.java-197-197 (1)

197-197: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Skin debug text shows the wrong field for value.

Line 197 prints prop.getSignature() for both value and signature, so the value output is incorrect and debugging skin payloads becomes misleading.

Suggested fix
- return "skin: " + skin.properties().stream().map(prop -> "value: '" + prop.getSignature() + "', signature: '" + prop.getSignature() + "'").toList();
+ return "skin: " + skin.properties().stream().map(prop -> "value: '" + prop.getValue() + "', signature: '" + prop.getSignature() + "'").toList();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/element/general/Types.java` at line
197, In Types.java the skin debug string builds each property using
prop.getSignature() for both fields; change the mapping to use prop.getValue()
for the "value" portion and prop.getSignature() for the "signature" portion
(i.e., update the lambda used in skin.properties().stream().map(...) to call
prop.getValue() for the value field so the debug output correctly shows value
and signature).
🧹 Nitpick comments (9)
src/main/java/dev/threeadd/packeteventssk/api/util/LogUtil.java (1)

17-45: 💤 Low value

Consider adding a private constructor to prevent instantiation.

This is a utility class with only static methods. Adding a private constructor would make the design intent explicit and prevent accidental instantiation.

 public class LogUtil {
 
+    private LogUtil() {
+        // Utility class
+    }
+
     private static final MiniMessage MM = MiniMessage.miniMessage();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/api/util/LogUtil.java` around lines
17 - 45, LogUtil is a pure utility class and should not be instantiated; add a
private no-arg constructor in the LogUtil class (e.g., private LogUtil() { throw
new AssertionError("no instances"); }) to prevent instantiation and make intent
explicit; optionally also mark the class final if you want to prohibit
subclassing—this change touches the LogUtil class constructor only and does not
affect existing static methods like sendMessage, sendRichMessage, info, warning,
error, or mini.
src/main/java/dev/threeadd/packeteventssk/api/util/ConversionUtil.java (1)

81-91: 💤 Low value

Missing null guards for consistency.

Other conversion methods in this class return null when passed null. These methods will throw NullPointerException instead, which is inconsistent with the established pattern.

Add null guards for consistency
 public static long toTicks(Timespan timespan) {
+    if (timespan == null) return 0L;
     return timespan.getAs(Timespan.TimePeriod.TICK);
 }

 public static Display.Billboard toBillboard(AbstractDisplayMeta.BillboardConstraints billboardConstraints) {
+    if (billboardConstraints == null) return null;
     return Display.Billboard.valueOf(billboardConstraints.name());
 }

 public static AbstractDisplayMeta.BillboardConstraints toBillboardConstraints(Display.Billboard billboard) {
+    if (billboard == null) return null;
     return AbstractDisplayMeta.BillboardConstraints.valueOf(billboard.name());
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/api/util/ConversionUtil.java`
around lines 81 - 91, The three conversion methods (toTicks, toBillboard,
toBillboardConstraints) currently throw NullPointerException if given null,
which is inconsistent; add null guards so each returns null when its input is
null: in toTicks check if Timespan timespan is null and return null before
calling timespan.getAs(Timespan.TimePeriod.TICK), in toBillboard check if
AbstractDisplayMeta.BillboardConstraints billboardConstraints is null and return
null before calling Display.Billboard.valueOf(...), and in
toBillboardConstraints check if Display.Billboard billboard is null and return
null before calling AbstractDisplayMeta.BillboardConstraints.valueOf(...).
src/main/java/dev/threeadd/packeteventssk/api/simple/PlayerSkinManager.java (1)

54-54: 💤 Low value

Variable name violates Java naming conventions.

Viewer should be viewer (camelCase for local variables).

Proposed fix
-        for (Player Viewer : viewers) {
-            targetMap.put(Viewer.getUniqueId(), skin);
+        for (Player viewer : viewers) {
+            targetMap.put(viewer.getUniqueId(), skin);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/api/simple/PlayerSkinManager.java`
at line 54, The local loop variable in the for-each inside PlayerSkinManager
uses an uppercase name ("Viewer") which violates Java naming conventions; change
the loop to use a camelCase name (e.g., "viewer") in the for-each header (for
(Player viewer : viewers)) and update all references inside that loop body to
the new name so the code compiles and follows conventions.
src/main/java/dev/threeadd/packeteventssk/update/JoinUpdateListener.java (1)

19-23: 💤 Low value

thenAccept callback may execute on async thread.

When getUpdateVersion(true) completes asynchronously, the thenAccept callback runs on whichever thread completes the future (the Bukkit async scheduler thread). While Bukkit's Player.sendMessage() is generally thread-safe, consider using thenAcceptAsync with the main thread executor or wrapping the message sending in a sync task for consistency with Bukkit conventions.

Suggested fix to ensure main thread execution
         Bukkit.getScheduler().runTaskLater(PacketEventsSK.getInstance(), () ->
-                UpdateChecker.getUpdateVersion(true).thenAccept(version -> {
-                    LogUtil.sendRichMessage(player, "Update available: <green>%s", version.getUpdateVersion());
-                    LogUtil.sendRichMessage(player, "Download at: <green>%s", version.getUpdateLink());
-                }), 30L);
+                UpdateChecker.getUpdateVersion(true).thenAccept(version ->
+                    Bukkit.getScheduler().runTask(PacketEventsSK.getInstance(), () -> {
+                        LogUtil.sendRichMessage(player, "Update available: <green>%s", version.getUpdateVersion());
+                        LogUtil.sendRichMessage(player, "Download at: <green>%s", version.getUpdateLink());
+                    })
+                ), 30L);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/update/JoinUpdateListener.java`
around lines 19 - 23, The callback passed to
UpdateChecker.getUpdateVersion(true) uses thenAccept which may run on an async
thread; update JoinUpdateListener so the LogUtil.sendRichMessage calls execute
on the main Bukkit thread—either use thenAcceptAsync with a main-thread executor
or change the callback to schedule a synchronous task via
Bukkit.getScheduler().runTask(PacketEventsSK.getInstance(), () -> {
LogUtil.sendRichMessage(player, ...); });—target the thenAccept usage in
JoinUpdateListener and ensure the code that calls LogUtil.sendRichMessage runs
inside a Bukkit main-thread runnable.
src/main/java/dev/threeadd/packeteventssk/update/ModrinthVersion.java (1)

32-34: 💤 Low value

Returning mutable internal list.

getSupportedVersions() returns the internal ArrayList directly, allowing callers to modify the internal state. Consider returning an unmodifiable view.

Suggested fix
     public List<Version> getSupportedVersions() {
-        return this.supportedVersions;
+        return List.copyOf(this.supportedVersions);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/threeadd/packeteventssk/update/ModrinthVersion.java` around
lines 32 - 34, The getter ModrinthVersion.getSupportedVersions() exposes the
internal mutable field supportedVersions; change it to return an unmodifiable
view or a defensive copy (e.g., Collections.unmodifiableList(supportedVersions)
or new ArrayList<>(supportedVersions)) so external callers cannot mutate the
internal ArrayList — update the getSupportedVersions method in class
ModrinthVersion to return the safer immutable/copy result.
src/main/resources/config.yml (1)

11-12: ⚡ Quick win

Consider defaulting async to true.

The update checker defaults to running synchronously on the main thread. If the Modrinth API is slow or unreachable, this could delay server startup.

Suggested change
-  # If the update checker should run asynchronously or on the main thread
-  async: false
+  # If the update checker should run asynchronously or on the main thread
+  async: true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/config.yml` around lines 11 - 12, Change the default for
the update checker from synchronous to asynchronous by setting the config key
"async" to true in the update checker configuration (the "async" entry in
src/main/resources/config.yml), and update any associated documentation/comments
and tests that assume the old default; ensure that components reading this
config (the update-checker initialization code that consumes the "async" flag)
continue to behave correctly when async is true and that any startup blocking
logic is guarded accordingly.
src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/DisplayMetaFieldRegistrar.java (1)

292-300: ⚡ Quick win

Preserve decimal values for shadow radius/strength.

Line 294 and Line 299 coerce to intValue(), truncating fractional values. These fields are handled as floating-point elsewhere in this registrar.

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

In
`@src/main/java/dev/threeadd/packeteventssk/element/general/field/meta/DisplayMetaFieldRegistrar.java`
around lines 292 - 300, The code in DisplayMetaFieldRegistrar is truncating
fractional shadow values by using Number.intValue() for
context.getOptional("display shadow radius", Number.class) and ("display shadow
strength", Number.class); change these to preserve decimals by reading the
Number as a floating type (e.g. call Number.doubleValue() or floatValue()) and
pass that floating value to the meta setters (meta.setShadowRadius(...) and
meta.setShadowStrength(...)) so the registrar retains fractional shadow
radius/strength like the rest of the class.
src/main/java/dev/threeadd/packeteventssk/api/util/field/FieldAccessor.java (1)

8-15: ⚡ Quick win

Defensively copy aliases to keep accessor metadata immutable.

The record currently stores and exposes a mutable array reference; callers can mutate aliases after registration and change matching behavior at runtime.

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

In `@src/main/java/dev/threeadd/packeteventssk/api/util/field/FieldAccessor.java`
around lines 8 - 15, FieldAccessor currently stores the mutable String[] aliases
reference; change the record to defensively copy aliases in its canonical
constructor (store Arrays.copyOf(aliases, aliases.length) or equivalent) and
ensure any accessor that exposes aliases (the implicit aliases() accessor)
returns an immutable/copy view—e.g., replace direct exposure with
Arrays.copyOf(this.aliases, this.aliases.length) or wrap in List.of(...) if you
change the component type—so callers cannot mutate the internal array; update
FieldAccessor's canonical constructor and any place that returns or assigns the
aliases field accordingly.
src/main/java/dev/threeadd/packeteventssk/api/util/field/BaseFieldRegistry.java (1)

27-29: ⚡ Quick win

Do not expose a live mutable view of registry values.

Line 28 returns REGISTRY.values() directly, which allows external removals and mutates internal state. Return an unmodifiable snapshot/view instead.

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

In
`@src/main/java/dev/threeadd/packeteventssk/api/util/field/BaseFieldRegistry.java`
around lines 27 - 29, getAllSchemas() currently returns REGISTRY.values() which
exposes a live mutable view; change it to return an unmodifiable defensive copy
of the values instead (e.g., create a new collection from REGISTRY.values() and
wrap it with an unmodifiable view or use List.copyOf) so callers can't mutate
the internal REGISTRY; update the method getAllSchemas() to return
Collections.unmodifiableCollection(new ArrayList<>(REGISTRY.values())) (or
List.copyOf(REGISTRY.values())) to protect the internal state of REGISTRY and
still satisfy the Collection<FieldSchema<K, BaseType>> return type.

Comment thread src/main/java/dev/threeadd/packeteventssk/AddonLoader.java
Comment thread src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java Outdated
@3add 3add requested a review from Copilot May 19, 2026 16:00
@3add
Copy link
Copy Markdown
Owner Author

3add commented May 19, 2026

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

✅ Actions performed

Review triggered.

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

@3add 3add changed the title Dev Dev v1.1.2 May 19, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 108 out of 109 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (2)

src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java:93

  • getUpdateVersion can return a CompletableFuture that never completes: when latest == null you cancel latestReleaseFuture, but you never complete/cancel updateVersionFuture, and the thenApply(...) attached to latestReleaseFuture won't run on cancellation. Ensure updateVersionFuture is completed exceptionally/cancelled when the Modrinth call fails/cancels, and consider propagating exceptions with whenComplete instead of manual cancel(true) branching.
    src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java:105
  • getLatestVersionFromModrinth() uses url.openStream() without timeouts and doesn't close the reader, which can hang the server thread (especially when async: false) and leak resources. Use an HttpURLConnection (or HttpClient) with connect/read timeouts and try-with-resources, and include the exception details in the log so failures are diagnosable.

Comment thread src/main/java/dev/threeadd/packeteventssk/update/UpdateChecker.java
Comment thread src/main/resources/lang/english.lang
Comment thread src/main/resources/config.yml
@3add 3add merged commit 6618ee6 into main May 19, 2026
3 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request May 21, 2026
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.

2 participants