Compare commits

..
Author SHA1 Message Date
booky 4b766e86de Merge pull request #1617 from TheFaser/fix/sponge
fix(sponge): pass MethodHandles.lookup() and skip CancelPacketException
2026-10-30 13:22:13 +01:00
booky f611cc97f7 Merge pull request #1616 from aidanvalero/fix/fluid-count-water-blocks
Count water-holding blocks in the 26.1+ fluid count
2026-10-29 18:16:32 +01:00
TheFaser a571b061dd fix(sponge): handle CancelPacketException in PacketEventsEncoder 2026-10-29 22:04:56 +05:00
TheFaser ff5e19c172 fix(sponge): add MethodHandles.lookup() to registerListeners call 2026-10-29 22:04:44 +05:00
Aidan Valero 05b8b2d3ae Count water-holding blocks in the 26.1+ fluid count 2026-10-26 17:35:14 -05:00
booky 9adfcfdd30 Merge pull request #1608 from LeonTG/get-entity-by-uuid
Add way to get entity by uuid, like you can for entity by id
2026-10-25 01:29:40 +02:00
booky e43d3f7cd4 Merge pull request #1610 from LeonTG/grr-scores
Fix reading WrapperPlayServerUpdateScore erasing target objective in 1.8 until 1.20.2
2026-10-25 00:28:08 +02:00
booky 9e556292e6 Merge pull request #1612 from GrimAnticheat/fix/packet-events-hashcode-allocations
perf: avoid hashCode boxing allocations
2026-10-25 00:24:43 +02:00
Axionize WS2 e022e53ac9 perf: avoid hashCode boxing allocations 2026-10-21 16:41:32 -04:00
LeonTG 5d52a060f0 Add way to get entity by uuid, like you can for entity by id 2026-10-18 21:05:25 +02:00
LeonTG c1dd732ffb Fix reading WrapperPlayServerUpdateScore erasing target objective in 1.8 until 1.20.2 2026-10-18 18:05:58 +02:00
booky 7ceabaef73 Fix promise and buffer release on outbound fabric packet cancel
Inspired by https://github.com/retrooper/packetevents/pull/1540, thanks @TheFaser!
2026-10-15 13:08:27 +02:00
booky be51239dde Merge pull request #1560 from ramenrrami/2.0
Fix WrapperPlayServerStatistics read on 1.13+ servers
2026-10-15 12:50:48 +02:00
booky 39d84dc088 Minor refactor, update javadoc, mark version-dependant ids as experimental 2026-10-15 12:47:05 +02:00
booky 01438f3b25 Merge pull request #1606 from Jan1k1/fix/instrument-durability-damage
Read instrument durability damage on 26.3
2026-10-15 11:07:47 +02:00
booky ea88ee2c4e Merge pull request #1603 from xEcho1337/2.0
Improve Chunk_v1_9
2026-10-15 11:00:41 +02:00
xEcho1337 d9a301cb80 revert: chunk v1.9 package renaming 2026-10-14 11:37:49 +02:00
Jan Duchaj a2e4e738eb Read instrument durability damage on 26.3 2026-10-14 09:37:16 +02:00
retrooper a19774ea2d Merge pull request #1502 from Kowagirl/2.0
fix: remove length limit for WrapperPlayClientPluginMessage
2026-10-13 12:11:37 -04:00
xEcho1337 8827011e04 perf: optimize loop order 2026-10-13 14:57:32 +02:00
xEcho1337 aa9e65ba60 feat: add getters in setters in Chunk_v1_9 + move package 2026-10-13 14:56:50 +02:00
booky 5a623fe06e Merge remote-tracking branch 'upstream/2.0' into Kowagirl/2.0 2026-10-13 11:45:37 +02:00
booky c9d3563a4e Keep default limit of 32767 bytes per plugin message payload 2026-10-13 11:43:56 +02:00
booky cd1ee087ec Merge pull request #1600 from WhiteProject1/fix/bound-collection-allocation
fix: bound collection lengths read off the wire before allocating
2026-10-13 11:12:26 +02:00
booky d056a5b61e Merge pull request #1598 from coolomet/fix/trim-material
Fix reading/writing TrimMaterial.overrideArmorMaterials before 26.3
2026-10-13 11:07:22 +02:00
booky 1a683f68e8 Merge pull request #1602 from bridgelol/fix/user-leak-closed-during-init
Fix user leak when a channel closes during injection
2026-10-13 11:04:46 +02:00
booky 5489432c65 Remove useless ai artifacts 2026-10-13 10:57:53 +02:00
bridge 97fe8c56e6 Fix user leak when a channel closes during injection
initChannel added the closeFuture listener before setUser. If the
channel was already closed (or closed in between), Netty ran the
listener immediately, handleDisconnection found no user to remove, and
setUser then inserted one that was never removed. Each leaked User
keeps its channel reachable, so proxies accumulate them over time.

Register the user first, then the listener, on Velocity, BungeeCord,
Spigot and Sponge. Fabric already uses this order.
2026-10-11 13:18:02 +03:00
WhiteProject1 d786eebb6f fix: bound collection lengths read off the wire before allocating
readCollection, readArray and readMap take the element count straight from
the buffer and use it to size the allocation before reading a single
element. A five byte VarInt carries Integer.MAX_VALUE, so a packet with
nothing behind the count makes the JVM allocate for two billion elements.

Measured on an unpatched build, with an empty buffer behind the count:

  readList  -> OutOfMemoryError: Requested array size exceeds VM limit
  readArray -> OutOfMemoryError: Requested array size exceeds VM limit

Three serverbound wrappers reach the unbounded path, so a connected client
can trigger it: WrapperConfigClientSelectKnownPacks,
WrapperPlayClientSetGameRule and WrapperPlayClientDebugSubscriptionRequest.

maxSize does not help on its own. It is usually far larger than any real
packet, so a count under it can still size a multi-megabyte allocation from
a few bytes, and the no-arg readMap passes Integer.MAX_VALUE.

Bounded all three by the readable bytes left in the buffer, which is the
rule readByteArray, readVarIntArray and readLongArray already apply to their
lengths - readLongArray even divides by the element width. An element costs
at least one byte, so a larger count cannot be honest.

A negative count was already refused by the collection constructor; a test
keeps it that way.

83 tests pass, including the 78 that existed before.
2026-10-07 23:00:31 +03:00
booky 36cee94757 Fix GlobalPalette BITS_PER_ENTRY for 26.3
Needs to be version-specific, but requires major refactor - this is just a temporary fix until we have a good solution for this

Thanks @freppp for reporting this
2026-10-06 05:19:09 +02:00
coolomet 3a2d75c7dc fix: reading/writing TrimMaterial.overrideArmorMaterials before 26.3 2026-10-05 00:04:57 +03:00
Abhigya 5da85d7ad8 Merge pull request #1593 from Beaness/fix/entity-effect-flag-order
Fix flag order of WrapperPlayServerEntityEffect
2026-09-27 02:09:52 +05:30
BeanesandDrizzy dc5ffc6398 Fix flag order of WrapperPlayServerEntityEffect
Co-authored-by: Drizzy <67246989+DevDrizzy@users.noreply.github.com>
2026-09-26 15:28:03 +02:00
booky 5e24682ac9 Merge pull request #1589 from Jan1k1/fix/1465-bungee-silent-receive
Fix Bungee receivePacketSilently injecting past packet-decoder
2026-09-24 23:41:49 +02:00
booky e7c13af66a Always fire incoming packets in decoder context 2026-09-24 23:36:46 +02:00
booky 0ae99c18f1 [skip ci] Add waterfall test run task 2026-09-24 23:34:58 +02:00
booky 59470bd980 Merge pull request #1590 from Jan1k1/fix/click-window-button-encoding
Fix ClickWindowButton windowId/buttonId encoding
2026-09-24 23:23:24 +02:00
booky 45e4517d86 Fix wrong versioning in click window button packet wrapper 2026-09-24 23:20:19 +02:00
booky 9c6920114f Merge pull request #1456 from ItsClairton/fix/compression-handling
Handle compression only if the server sends the compression packet
2026-09-24 23:06:26 +02:00
booky bf70448c55 Don't handle compression packets in netty handler
Moves logic into internal packet listeners
2026-09-24 22:57:08 +02:00
booky 101798c4fa Tiny minor code cleanup 2026-09-24 22:31:50 +02:00
booky 4a3cf0e006 Check compression handled before calling outside handle method 2026-09-24 22:31:17 +02:00
booky 25c313be0f Merge remote-tracking branch 'upstream/2.0' into fix/compression-handling 2026-09-24 22:21:50 +02:00
Jan Duchaj 55a0291af9 Fix ClickWindowButton windowId/buttonId encoding
Pre-1.21.2 windowId is a byte (ContainerID), not a VarInt, and
buttonId became a VarInt in 1.21 with the container rework.
2026-09-24 09:35:45 +02:00
retrooper d1e3358bc7 2.14.1 snapshot is out 2026-09-23 16:56:45 -04:00
retrooper 5a8a122476 2.14.0 release 2026-09-23 16:44:03 -04:00
retrooper 8ca0c18b78 add donators for 2.14.0 release 2026-09-23 16:42:19 -04:00
Jan Duchaj 748704629a Fix Bungee silent receive to inject via PE decoder 2026-09-23 09:40:16 +02:00
Abhigya c21712295a Merge pull request #1588 from Jan1k1/fix/getplayer-nullunmarked
Mark getPlayer as NullUnmarked for Kotlin nullable casts
2026-09-23 01:08:51 +05:30
Jan Duchaj b5d88fc90f Match UserLoginEvent getPlayer nullability to PlayerEvent 2026-09-22 09:42:02 +02:00
Jan Duchaj 45c4c8302b Mark getPlayer as NullUnmarked for Kotlin nullable casts 2026-09-22 09:37:08 +02:00
booky 3ba02ddd51 Merge pull request #1582 from booky10/feat/26.3-support
26.3 support
2026-09-19 05:30:02 +02:00
booky d0d10fbf65 Add missing clone on blockstate nbt decode 2026-09-18 06:02:16 +02:00
booky 5e0ba010f4 Use java 25 toolchain for velocity module 2026-09-18 06:01:34 +02:00
booky 77d72417d3 Bump java version in runVelocity task 2026-09-18 05:33:11 +02:00
booky 8021ba07ed Merge pull request #9 from carragrive/feat/velocity-4.1.1
build(velocity): bump minimum Velocity version to 4.1.1
2026-09-18 05:30:19 +02:00
bookyandR00tB33rMan c2a50600eb Update CHANGELOG.md
Co-authored-by: R00tB33rMan <36140389+R00tB33rMan@users.noreply.github.com>
2026-09-18 04:57:44 +02:00
CarraGrive 74cd03b0ff build(velocity): bump minimum Velocity version to 4.1.1 2026-09-18 04:54:50 +02:00
booky 11873d14d1 Use double tag in json to nbt conversion 2026-09-18 04:23:19 +02:00
booky 82261fe3f3 Fix missing copy in particle packet wrapper 2026-09-18 04:22:55 +02:00
booky d961a6d683 Fix wrapped block state codec 2026-09-18 04:22:43 +02:00
booky f762a1fcd5 Replace registry in MappedEntitySet decode 2026-09-18 04:13:59 +02:00
booky 729229c565 Fix missing equality/hashcode for SignTextComponent 2026-09-18 04:13:41 +02:00
booky 328edf0dbc Add system property for disabling update checker 2026-09-18 03:33:37 +02:00
booky 8142e50df0 [skip ci] Update changelog 2026-09-18 02:50:23 +02:00
booky 9ac53fc1b7 Bump dependencies to 26.3 2026-09-18 02:30:35 +02:00
CarraGrive 8037be691e Invalidate modern delta when setting legacy delta fields in entity relative move wrappers 2026-09-18 02:20:18 +02:00
bookyandCarraGrive 37f9e2f10b Update tag slot display (recipes) to 26.3
Co-authored-by: CarraGrive <50628910+CarraGrive@users.noreply.github.com>
2026-09-18 02:18:09 +02:00
bookyandCarraGrive c3e5a08faf Simplify 26.3 ctor in StaticTrimMaterial
Co-authored-by: CarraGrive <50628910+CarraGrive@users.noreply.github.com>
2026-09-18 02:14:33 +02:00
booky 8065dbc265 Properly separate asset name and palette id for trim materials 2026-09-18 01:39:17 +02:00
booky cbc8327c80 Fix a few minor issues 2026-09-18 00:24:12 +02:00
booky 6eefd684fa Fix deepEquals/deepHashcode causing stackoverflow for certain synced entities 2026-09-17 07:10:02 +02:00
booky bf5baa4a65 Fix wrong TrimMaterial asset name tag key for 26.3 2026-09-17 07:06:58 +02:00
booky 3bba03b331 Implement builder in BlockTransformData 2026-09-17 07:04:42 +02:00
booky 01920931ee Resolve block state provider registry codec lazily 2026-09-17 07:04:42 +02:00
booky 11139134f9 Fix missing equipment assets
Not included in my registry dump as its not a real registry
2026-09-17 07:04:41 +02:00
booky 895f6789df Mark swing animation as obsolete 2026-09-17 07:04:41 +02:00
booky 778a86952a Fix gamemode being off by one on read 2026-09-17 07:04:41 +02:00
booky f9d547a6b6 Fix typo in sulfur cube archetype registry name 2026-09-17 07:04:40 +02:00
booky 8f6134187b Fix typos with block tag binding
How were these typos not noticed before?
2026-09-17 07:04:40 +02:00
booky 248541f353 Fix previous gamemode reading for login/respawn packewts 2026-09-17 07:04:40 +02:00
booky 03d1763ed0 Implement int providers, block predicates and block state providers
Way too complex for a single component
2026-09-17 07:04:39 +02:00
booky 546c2bbdd1 Fix missing optional check in PotDecorations
Works now
2026-09-17 05:49:31 +02:00
booky d3bf02d740 Fix pot decorations component 2026-09-17 05:31:01 +02:00
booky 5210d8fd77 Add internal testing 26.3 block tag 2026-09-17 04:32:22 +02:00
booky 6d34e7de66 Implement block transformers (except block state providers for now) 2026-09-16 06:04:02 +02:00
booky c28a94334e Implement network synced decorated pot pattern registry 2026-09-16 05:22:08 +02:00
booky e68699576f Start updating/implementing new components for 26.3 2026-09-16 05:09:16 +02:00
booky 28111ef588 Fix missing values for removed block/item tags 2026-09-16 04:29:05 +02:00
booky 9b24e16d8f Fix missing env attribute list library for ambient particles 2026-09-16 04:25:12 +02:00
booky 77fd9afe0b Update block / item tags
This needs to be rewritten, this sucks a lot
2026-09-16 04:14:24 +02:00
booky 4e4e89ec94 Update some registries (not components yet) 2026-09-16 04:14:04 +02:00
booky auto 5305636723 Update mappings 2026-09-16 04:13:17 +02:00
booky 5105223e36 Add new constructor to WrapperPlayServerParticle 2026-09-16 02:46:56 +02:00
booky 93a055f92d Implement clientbound add_transient_block and swing_animation packets for 26.3 2026-09-16 02:45:52 +02:00
booky 5125e6695f Update level_particles packet to 26.3 2026-09-16 02:36:24 +02:00
booky 15036ed594 Update packet types for 26.3 2026-09-16 02:00:15 +02:00
booky 16124da5bd Don't allocate new LinearVecDelta if not needed 2026-09-15 19:05:04 +02:00
booky 20906355e5 Remove swing packet, add punch packet 2026-09-15 19:02:20 +02:00
booky 46f5b80120 Merge pull request #5 from Jan1k1/fix/26.3-relmove-dual-field
Keep relative-move delta fields in sync
2026-09-15 19:01:35 +02:00
booky 5ee1e5deda Merge pull request #4 from Jan1k1/fix/26.3-step-count
Return real step count from SteppedVecDelta
2026-09-15 19:01:19 +02:00
booky bbfdbdd2bc Merge pull request #6 from Jan1k1/fix/26.3-animation-id
Fail loud on obsolete animation ids for 26.3
2026-09-15 18:54:58 +02:00
booky f9a83f32ed Simplify else if in WrapperPlayClientUpdateSign front text read 2026-09-15 18:52:46 +02:00
booky 13ef358fa3 Merge pull request #3 from Jan1k1/fix/26.3-sign-dig
Fix sign front-text read and digging action ids
2026-09-15 18:52:02 +02:00
Jan Duchaj c7db2a0d18 Fail loud on obsolete animation ids for 26.3 2026-09-15 13:54:15 +00:00
Jan Duchaj f5753a0949 Keep relative-move delta fields in sync 2026-09-15 05:53:22 +00:00
Jan Duchaj eb72f566fe Return real step count from SteppedVecDelta 2026-09-15 05:13:21 +00:00
Jan Duchaj afe4955258 Fix sign front-text read and digging action ids for 26.3 2026-09-15 05:11:55 +00:00
booky a4a3c3780e Update a few more packet structures to 26.3 2026-09-14 07:35:21 +02:00
booky 411732d328 Add minimal legacy compat for WrapperPlayServerEntityPositionSync 2026-09-14 06:26:49 +02:00
booky 1ec1adfd2b Merge remote-tracking branch 'upstream/2.0' into feat/26.3-support 2026-09-14 06:20:52 +02:00
booky fe8682e05c Merge pull request #1571 from Jan1k1/fix/block-action-type-id
fix block action type id
2026-09-14 06:19:30 +02:00
booky 5c56fa53d5 Add method to WrapperPlayServerBlockAction for getting the state type directly
Skips creating a useless blockstate
2026-09-14 06:16:29 +02:00
bookyandvypnitoo 2e49ec0965 Properly separate ItemStack + ItemStackTemplate NBT codecs
Fixes #1569
Closes #1572

Inspired by @Jan1k1's fix in https://github.com/retrooper/packetevents/pull/1572

Co-authored-by: vypnitoo <vypnitoo@gmail.com>
2026-09-14 06:08:56 +02:00
booky 0f5d0416da Merge pull request #1573 from Jan1k1/fix/equippable-slot-ids
fix equippable component slot ids
2026-09-14 05:35:40 +02:00
booky 7769fdecc9 Merge pull request #1574 from ManInMyVan/prevent-null-item-type
prevent null item types in ItemStack
2026-09-14 05:31:31 +02:00
booky 12048edba7 Add server version parameter to component id getters to future-proof API 2026-09-14 05:30:45 +02:00
booky c18d2d2d9b Merge pull request #1580 from ThatApplePieGuy/fix/bedcopy
fix WrapperPlayServerUseBed copying backwards
2026-09-14 05:26:11 +02:00
ThatApplePieGuy 268a6ce6e5 fix WrapperPlayServerUseBed copying backwards 2026-09-10 16:46:54 -06:00
ManInMyVan 94153f9d9a prevent null item types in ItemStack 2026-08-25 13:19:00 -06:00
vypnitoo 4994e81add fix equippable component slot ids 2026-08-25 16:14:41 +02:00
vypnitoo 118fec22f5 fix block action type id 2026-08-25 16:14:40 +02:00
retrooper 23832438a8 Merge pull request #1570 from Bram1903/docs/bundle-packet 2026-08-24 03:59:35 -04:00
Bram d8e5a43a55 docs: added documentation to the bundle packet 2026-08-24 09:52:46 +02:00
Savio 6de980672c Merge branch 'retrooper:2.0' into 2.0 2026-08-12 00:24:12 +02:00
booky f52b3b9232 Fix Vector3i decode for pre 1.14
Behavior didn't exactly match vanilla values; even though vanilla pre 1.17 doesn't support negative y-values, it still uses them in the protocol for e.g. item interacts
This issue caused packetevents to incorrectly return y value 0xFFF (the y value mask) instead of the expected value -1
2026-08-10 20:57:01 +02:00
booky 512f8101dd Merge pull request #1549 from MagnoliaLLC/2.0
perf: drop per-call allocations in AdventureNBTSerializer style (de)serialization
2026-08-07 18:29:01 +02:00
booky d4b543793e Merge pull request #1566 from ChengZhiMeow/2.0
fix: PluginMessage behaves differently from Vanilla
2026-08-07 18:13:36 +02:00
booky b2d5f25948 Merge pull request #1561 from ManInMyVan/location-equals
implement Location::equals
2026-08-07 18:07:38 +02:00
booky d6a8c865c9 Add missing Location#hashCode 2026-08-07 17:59:54 +02:00
booky c163700841 Merge pull request #1562 from ManInMyVan/fix-1.7-interact-action
fix 1.7 interact action
2026-08-07 17:54:36 +02:00
橙汁喵 9236ee4e55 fix: PluginMessage behaves differently from Vanilla 2026-08-05 15:32:44 +08:00
ManInMyVan 20816696bc fix 1.7 interact action 2026-08-02 14:37:20 -06:00
ManInMyVan 9f78508a18 implement Location::equals 2026-08-02 12:27:18 -06:00
ramenrrami b7ed73f454 Fix WrapperPlayServerStatistics read on 1.13+ servers 2026-08-02 19:29:25 +02:00
booky 3da1c107ce Fix trident being confused with spear for some reason 2026-07-25 06:34:05 +02:00
booky 3e0e4a2573 Fix missing spear consumable use animation 2026-07-25 06:30:18 +02:00
RootBeerandbooky f41d59b74b fix: improve descriptivity of boolean reader, store TextDecoration as field instance, and apply nullability annots.
Co-authored-by: booky <booky@booky.dev>
2026-07-15 12:30:57 -04:00
R00tB33rManandbooky 7195684a73 Apply getUTF nullability
Co-authored-by: booky <booky@booky.dev>
2026-07-15 12:23:52 -04:00
RootBeer 970917e645 fix: improve behavioral iterator 2026-07-14 14:22:54 -04:00
RootBeer c254f62a82 perf: drop per-call allocations in AdventureNBTSerializer style (de)serialization
Process + allocation spark:
- Allocation: https://spark.lucko.me/vFIsYkEE5S
- Process: https://spark.lucko.me/LZlH1hqafl

`deserializeStyle` runs for every component and recurses through children, so it's on the hot path whenever text-heavy packets go through. A couple of things made it allocate more than it needs to:
- It iterated `TextDecoration.NAMES.keys()`, and Adventure's `Index#keys()` hands back a fresh `Set.copyOf(...)` on every call (same with `NAMES.values()` on the serialize side).
- Every style field was read via a `Consumer`/`Function` (`reader.useUTF(...)`, `useBoolean(...)`, ...), so each call spun up a pile of short-lived capturing lambdas; around 20 per component once you count the internal `useX -> useNumber -> useTag` delegates (x5 for the decorations); plus the invokedynamic linkage that comes with them.

This caches the decoration names/values once in static arrays, and adds small lambda-free `getUTF`/`getNumber` readers so the style attributes are read directly instead of through a consumer. `serializeStyle` gets the same cached-decoration treatment. No behavior change; same NBT in/out.

The frames only showed up as ~0.02–0.05% in a profile, but they're hit recursively per nested component, so it compounds under component-heavy traffic (e.g. tab + scoreboards).
2026-07-14 11:32:02 -04:00
booky 0a7ae1813d Implement new linear/stepped VecDelta 2026-07-07 21:56:48 +02:00
booky 0cd8488422 Implement PositionPath and ClientboundEntityPositionSyncPacket changes 2026-07-07 20:44:18 +02:00
booky 85efd42663 Add play-sound field to explosion packet wrapper 2026-07-07 20:03:16 +02:00
booky aa17667791 Implement wrapper for new post effects packet 2026-07-07 20:00:12 +02:00
booky 8c46b02bde Add 26.3 client/server versions 2026-07-07 19:49:55 +02:00
booky 877315d7a1 Add dye color entity data type 2026-07-07 19:48:46 +02:00
booky 3df6015486 Don't clone block states during Chunk_v1_18#set
Thanks to missingreports on Discord for reporting this
2026-06-28 17:44:24 +02:00
booky 0b7bb950a1 Merge pull request #1543 from TheFaser/fix/nbt-number-type-precision
fix: use correct NBT number types instead of always casting to int
2026-06-28 14:42:10 +02:00
TheFaser 5b3008e9d7 fix: use correct NBT number types instead of always casting to int 2026-06-28 17:10:32 +05:00
booky ac4bee1000 Increment version to 2.13.1 snapshot 2026-06-22 11:43:56 +02:00
booky 1063d4e71c Release 2.13.0 2026-06-22 11:29:18 +02:00
booky cf4d94f63e Merge pull request #1537 from TheFaser/2.0
fix: add type check for channel read handler
2026-06-20 14:20:46 +02:00
TheFaser 254d004deb fix: add type check for channel read handler 2026-06-20 17:14:16 +05:00
booky b1bbbaed2f Fix entity id generation 2026-06-19 21:52:24 +02:00
booky 471a9e2114 Fix teams packet in 26.2 2026-06-19 20:52:41 +02:00
booky b1278a9b38 Merge pull request #1529 from booky10/feat/26.2-support
26.2 support
2026-06-16 13:00:59 +02:00
booky 4dd0934c1f Merge branch '2.0' into feat/26.2-support 2026-06-15 18:59:46 +02:00
booky 9ba8a4cd7a Bump to 26.2-rc-2 2026-06-15 18:59:10 +02:00
booky 775a2bdfa9 Merge pull request #1535 from Jan1k1/fix/nullable-manager-returns
Annotate nullable manager returns
2026-06-15 18:57:01 +02:00
booky d2a171632b Merge pull request #1534 from rafi67000/workflowUpdate
Workflow update
2026-06-15 18:52:45 +02:00
booky 046f653636 Merge pull request #1533 from rafi67000/gradleUpdate
Gradle update
2026-06-15 18:44:30 +02:00
booky 424f9f36de Bump more actions 2026-06-15 18:42:51 +02:00
vypnitoo 6864b9e6bb Annotate nullable manager returns 2026-06-14 16:15:24 +02:00
rafi67000 3c43c98c97 Update actions (some are deprecated) 2026-06-11 16:31:01 +02:00
rafi67000 afe526ddd4 Update plugins 2026-06-11 16:20:49 +02:00
rafi67000 02a203e97d Update libraries 2026-06-11 16:20:37 +02:00
rafi67000 0490a88ecc Update gradle to 9.5.1 2026-06-11 16:19:04 +02:00
booky 7c4dd0b039 Use mapped entity refs for handling world clocks
Fixes https://github.com/retrooper/packetevents/issues/1532
2026-06-11 13:43:47 +02:00
booky adc6e764c1 Bump fabric to 26.2-pre-3 2026-06-03 18:44:39 +02:00
booky 7a03353212 Fix missing potent sulfur block state property 2026-06-03 18:44:13 +02:00
booky 7452bd683c Update packet wrappers to 26.2-pre-3 2026-06-03 18:28:26 +02:00
booky 1815cba610 Fix tests 2026-06-03 18:11:20 +02:00
booky 3dae46a3bb Implement float providers
Used for contact damage amount calculation in sulfur cube registry data
2026-06-03 18:07:15 +02:00
booky 0330ace434 Update blocktags/itemtags 2026-06-03 17:38:57 +02:00
booky 78b2a0d462 Implement sulfur cube archtype registry
Missing FloatProviders implementation (sucks) and tags update
2026-06-03 17:26:52 +02:00
booky 4cde5f1dea Implement geyser particle type data 2026-06-03 14:43:47 +02:00
booky 6b1c874f5e Implement SulfurCubeContentComponent 2026-06-03 14:30:50 +02:00
booky 94456501c0 Update simple registry entries to 26.2-pre-3 2026-06-03 14:27:56 +02:00
booky 0affc61d05 Add 26.2 server/client version 2026-06-03 14:27:47 +02:00
booky c03519e3bd Update registry mappings to 26.2-pre-3 2026-06-03 14:27:22 +02:00
booky 3c9cf26c08 Merge pull request #1523 from Rothes/wrapper-common-plugin-message
Add PluginMessage Common Wrapper
2026-06-02 11:28:03 +02:00
booky a6175769eb Merge pull request #1526 from linsaftw/fix/chunk-read-performance
Optimize 1.18+ chunk palette reading
2026-06-02 11:24:47 +02:00
retrooper a376e3dfe1 PacketEvents 2.12.3-SNAPSHOT 2026-06-01 17:39:26 -04:00
retrooper acd2391eb4 PacketEvents 2.12.2 Release 2026-06-01 17:05:45 -04:00
retrooper af07f27c87 Merge pull request #1467 from booky10/feat/refactor-logging
Refactor logging
2026-06-01 13:42:28 -04:00
booky 9e9814dc6b Merge branch '2.0' into feat/refactor-logging 2026-06-01 18:06:15 +02:00
booky cb8fb8b926 Try to uninject from Velocity plugin initializers on termination
Fixes https://github.com/retrooper/packetevents/issues/1489
2026-06-01 12:20:31 +02:00
booky 854f12c2e4 Small refactor 2026-06-01 12:00:09 +02:00
booky a1067f5e4f Merge pull request #1468 from Beaness/legacychatlength
Add system property to allow longer chat messages on legacy versions
2026-06-01 11:18:18 +02:00
booky a84ea657b7 Minor format 2026-06-01 11:10:08 +02:00
booky 20d2bd3432 Merge pull request #1527 from Beaness/missingcopyfields
Fix missing fields in copy() methods for 5 packet wrappers
2026-06-01 11:06:23 +02:00
Beanes 17b99aead1 Fix missing fields in copy() methods for 5 packet wrappers 2026-05-31 22:40:09 +02:00
bookyandLeonTG 65464472e7 Fix platform-specific internal packet listeners
Co-authored-by: LeonTG <leontg77@gmail.com>
2026-05-31 19:32:35 +02:00
booky 932bf6c157 Remove one printStackTrace call 2026-05-31 04:09:31 +02:00
booky 2c54461432 Use own logger on velocity platform 2026-05-31 04:07:43 +02:00
booky de0c2fb65b Remove legacy colors from UpdateChecker 2026-05-31 04:06:49 +02:00
booky ccae7bf84c Don't explicitly set white as log info color 2026-05-31 04:06:28 +02:00
booky 070b6eb1e1 Merge branch '2.0' into feat/refactor-logging
# Conflicts:
#	api/build.gradle.kts
#	bungeecord/src/main/java/io/github/retrooper/packetevents/bungee/factory/BungeePacketEventsBuilder.java
#	fabric-common/src/main/java/io/github/retrooper/packetevents/factory/fabric/FabricLogger.java
#	fabric-common/src/main/java/io/github/retrooper/packetevents/factory/fabric/FabricPacketEventsAPI.java
#	netty-common/src/main/java/io/github/retrooper/packetevents/impl/netty/factory/NettyPacketEventsBuilder.java
#	spigot/build.gradle.kts
#	spigot/src/main/java/io/github/retrooper/packetevents/factory/spigot/SpigotPacketEventsBuilder.java
#	sponge/src/main/java/io/github/retrooper/packetevents/sponge/factory/SpongePacketEventsBuilder.java
#	velocity/src/main/java/io/github/retrooper/packetevents/velocity/factory/VelocityPacketEventsBuilder.java
2026-05-31 03:52:54 +02:00
booky 07135e3e7c Catch errors during uninjection 2026-05-31 03:25:28 +02:00
booky 651d8bcfd9 Fix velocity injection regression
Introduced by d0a9799718
2026-05-30 20:48:33 +02:00
booky ff5df98644 Inject into adventure's gson data component value converter registry
Fixes https://github.com/retrooper/packetevents/issues/1448
Fixes https://github.com/retrooper/packetevents/issues/1345

Adventure has their own static registry for type conversion between data component values; as we can't properly register something in this registry, we have to use a shitton of reflection to inject our own converter, as otherwise components which use our NBT holder couldn't be used with adventure's GSON serializer
2026-05-30 02:14:24 +02:00
booky d0a9799718 Implement common load/termination logic 2026-05-30 02:11:09 +02:00
booky 64f06b2ae5 Use RegistryOps for encoding dimension type
Fixes https://github.com/retrooper/packetevents/issues/1492
2026-05-30 00:54:49 +02:00
linsaftw 756495376d Optimize 1.18+ chunk palette reading 2026-05-26 13:11:04 -03:00
Rothes 9be511e283 Make constructors of common plugin message protected 2026-05-22 08:52:26 +08:00
Rothes 4ce52714ee Add WrapperCommonClientPluginMessage 2026-05-22 08:38:50 +08:00
Rothes 08c69d3f13 Add WrapperCommonServerPluginMessage 2026-05-22 08:32:29 +08:00
booky e1d312c881 Merge pull request #1522 from booky10/fix/legacy-team-colors
Fix loosing trailing color codes in teams packet
2026-05-21 15:00:17 +02:00
retrooper 9a83cf6142 minor correction to copyright year 2026-05-20 17:25:22 -04:00
booky f15b8de630 Fix loosing trailing color codes in teams packet 2026-05-19 12:33:03 +02:00
booky 79a65746fb Merge pull request #1521 from LeonTG/feature/consistent-sound-position
Consistency in WrapperPlayServerSoundEffect position
2026-05-18 14:52:46 +02:00
booky bf54466875 Minor formatting fix 2026-05-18 14:39:29 +02:00
LeonTG 66d768d00f Fix sound position multiplier not casting to double like vanilla does 2026-05-18 13:36:48 +02:00
booky 85bb33205e Merge pull request #1520 from LeonTG/fix/sound-pitch-wrong
Fix incorrect sound pitch wrapping for 1.7-1.9
2026-05-18 12:20:12 +02:00
LeonTG 89550990af Consistency in WrapperPlayServerSoundEffect position 2026-05-17 21:15:17 +02:00
LeonTG 73603f89b7 Fix incorrect sound pitch for 1.9 and below 2026-05-17 20:29:05 +02:00
retrooper 063482716d patch: pitch and yaw were incorrectly swapped in WrapperPlayServerSpawnEntity on versions lower than 1.15 2026-05-15 23:26:55 -04:00
booky 2fccee72cf Ignore unsynced environment attributes
Matches behavior of vanilla client, fixes https://github.com/retrooper/packetevents/issues/1482
2026-05-12 22:01:03 +02:00
booky 6ae02d37da Fix blocking state for potted golden dandelion 2026-05-12 13:36:06 +02:00
booky 809e18e951 Fix solid state for potted golden dandelion 2026-05-12 13:34:34 +02:00
booky 8ac26761cf Fix NPE when handling legacy reset format in certain cases
Will be properly solved with https://github.com/retrooper/packetevents/pull/1505
2026-05-11 20:29:20 +02:00
booky 778218f3d1 Don't use static immutable component map for reading item stack components
Fixes https://github.com/retrooper/packetevents/issues/1506
2026-05-11 14:29:45 +02:00
booky 47e0a76478 Add DataPalette#getAndSet
Although DataPalette#set already returns a value, the returned value is the palette index and not the actual state id. For compatibility reasons, we create a new method instead of changing behavior of this existing method

Fixes https://github.com/retrooper/packetevents/issues/1509
2026-05-11 14:24:18 +02:00
booky f7479fdf6d Merge pull request #1507 from SamB440/fix/sponge-adventure
Fix sponge module shading all of adventure
2026-05-03 15:55:49 +02:00
SamB440 ee58a29394 Fix sponge module shading all of adventure.
Sponge should only shade adventure-nbt due to it being unavailable on Sponge by default.
2026-05-03 14:44:22 +01:00
Daisy 481b04033b fix: remove length limit on custom_payload 2026-04-24 03:46:40 -04:00
booky 95afd3fce8 Cache reflection field lookup for entity id generation 2026-04-21 11:20:57 +02:00
booky 2673441c36 Fix snapshot version 2026-04-20 11:30:41 +02:00
booky de0fad35c5 Patch out Reset instance usage from legacy serializer
We can't just shade adventure v5 because of java version requirements
2026-04-20 11:29:59 +02:00
booky 28d3f43ed6 Add legacy component serializer patch module
I hate it
2026-04-20 11:29:58 +02:00
booky f25c79f631 Increment version for 2.12.1 release 2026-04-19 02:45:56 +02:00
booky bf3e80bdfb Update changelog for 2.12.1 2026-04-19 02:45:28 +02:00
booky 5fc0b3079a Add nullability annotations to nbt tags 2026-04-19 00:54:35 +02:00
booky e227e46906 Fix particle spell data option color decoding from nbt 2026-04-19 00:49:02 +02:00
booky d0c35254ca Merge pull request #1494 from ieatglu3/static-vec3i-3f-zero-consts
return immutable static constant when calling #zero in Vector3i and Vector3f
2026-04-18 20:13:43 +02:00
booky f2974eca7c Fix support for item stack templates 2026-04-18 19:05:30 +02:00
booky c1163ee723 Fix some adventure v5 compat issues with click event actions 2026-04-18 17:58:01 +02:00
booky 500adf3b78 Fix another case of BinaryTagType usage 2026-04-18 17:34:41 +02:00
booky 96c79befb1 Handle BinaryTagType being converted to an interface in adventure v5 2026-04-17 18:48:10 +02:00
booky af0d6ea44f Handle BinaryTagTypes being converted to an interface in adventure v5 2026-04-17 18:20:38 +02:00
booky ae15bf6a52 Handle signature change of ComponentBuilder#build() for adventure v5 2026-04-17 16:34:54 +02:00
booky 412ba17e50 Implemented hacked support for both adventure v4 and v5
Discussed in Discord a bit already, our adventure handling will be reworked a bit
This is just to get out support for adventure v5
2026-04-15 21:09:20 +02:00
ieatglu3 a7d7f2b87c return immutable static constant when calling #zero in Vector3i and Vector3f 2026-04-14 16:28:13 -04:00
booky bbeec89638 Merge pull request #1414 from Vrganj/compact-map-palette
Implement a custom Int2Int map for MapPalette
2026-04-14 15:22:41 +02:00
booky 03f4346e0e Merge pull request #1439 from booky10/feat/refactor-viaver-version-accessor
Refactor ViaVersion user version getter
2026-04-14 15:19:58 +02:00
booky 6776865430 Add via channel handling to sponge 2026-04-14 15:16:32 +02:00
booky 7a372654ab Fix viaversion dependency version 2026-04-14 15:16:17 +02:00
booky e840307e70 Merge branch '2.0' into feat/refactor-viaver-version-accessor 2026-04-14 15:10:43 +02:00
booky 4b584bd6e7 Merge pull request #1477 from booky10/fix/track-chunk-fluid-count
Track chunk section fluid count
2026-04-14 15:02:35 +02:00
booky 39f7932ebe Merge pull request #1488 from ytnoos/fix-painting-variants
Fix PaintingVariant read/write for >=1.21
2026-04-14 14:58:52 +02:00
booky 213f27fab0 Add missing title and author fields to painting variants 2026-04-14 14:55:47 +02:00
booky 09b4081581 Merge pull request #1490 from retrooper/revert-1460-instantwriteaftersend
Revert "Instantly run task after write operation"
2026-04-12 17:39:37 +02:00
booky afe96b3187 Revert "Instantly run task after write operation" 2026-04-12 17:34:48 +02:00
booky a3c6f99c43 Merge pull request #1487 from ytnoos/short-size-check
Fix incorrect byte size calculation for NBT short type
2026-04-12 16:36:46 +02:00
Ytnoos c16b3a1bcd Fix PaintingVariant read/write for >=1.21 2026-04-12 15:33:18 +02:00
Ytnoos 705526e13a Fix incorrect byte size calculation for NBT short type 2026-04-12 15:26:26 +02:00
booky b6c86cb522 Merge pull request #1486 from ManInMyVan/playerinfo-copy
add copy constructor for WrapperPlayServerPlayerInfoUpdate$PlayerInfo
2026-04-10 21:24:19 +02:00
ManInMyVan 95ccc6f950 add copy constructor for WrapperPlayServerPlayerInfoUpdate$PlayerInfo
meant for plugins that need to modify this without modifying the original and don't want to update the constructor every time it changes
2026-04-10 13:05:18 -06:00
booky 4d1938b975 Add 26.1.2 server version 2026-04-09 18:40:41 +02:00
Clairton Santos aae31cbb4e Restore SET_COMPRESSION logic lost during merge conflict resolution 2026-04-08 18:19:06 -03:00
Clairton Santos fbe8306d62 Merge remote-tracking branch 'origin/2.0' into fix/compression-handling
# Conflicts:
#	spigot/src/main/java/io/github/retrooper/packetevents/injector/handlers/PacketEventsEncoder.java
#	sponge/src/main/java/io/github/retrooper/packetevents/sponge/injector/handlers/PacketEventsEncoder.java
2026-04-08 18:00:49 -03:00
retrooper d7d9437ba5 Merge pull request #1478 from rafi67000/gradleUpdate
Gradle update
2026-04-07 21:49:34 -04:00
booky 97b09b011d Merge pull request #1460 from Beaness/instantwriteaftersend
Instantly run task after write operation
2026-04-07 05:03:58 +02:00
booky 17fe0bdc88 Merge branch '2.0' into instantwriteaftersend 2026-04-07 04:58:19 +02:00
booky b36eb0afe4 Simplify canceled packet handling for sponge outbound handler 2026-04-07 04:56:55 +02:00
booky 275da3343a Fix missing tasks-after-send handling for fabric
Why does this list of runnables only exist for clientbound packets? Doesn't make sense to me
2026-04-07 04:53:52 +02:00
booky d18e28e8a9 Update sponge outbound handler to match spigot's
We really need to refactor these copy-pasted handlers into a common module...
2026-04-07 04:50:57 +02:00
booky 9b2f0895d8 Remove promise handling for spigot/paper outbound handler
This was used previously while we still relied on netty's built-in MessageToMessageEncoder, which didn't allow to have proper "tasks-after-send"
2026-04-07 04:46:15 +02:00
booky 12441d0a45 Merge pull request #1383 from vadim-soude/feat/chunk-biomes
Add WrapperPlayServerChunkBiomes
2026-04-07 04:41:27 +02:00
booky e531200e2e Fix chunk biome data end index calculation 2026-04-07 04:37:48 +02:00
booky 745604631b Implement Vector2i#toString 2026-04-07 04:37:28 +02:00
booky f403e4ffa5 Use Vector2i for chunk keys instead of longs 2026-04-07 04:31:49 +02:00
booky 226fde0980 Ensure the section length prefix matches 2026-04-07 04:28:33 +02:00
booky 4c1dca3153 Refactor utility constructors into static methods 2026-04-07 04:26:58 +02:00
booky 63acbbc86f Add mojang packet name to wrapper javadoc 2026-04-07 04:22:15 +02:00
booky b70789bc30 Use map read/write to simplify wrapper logic
Although vanilla writes this is a list, this is effectively a map and this should not cause any differences
2026-04-07 04:21:57 +02:00
booky a28a04e8bf Remove unused buffer size in chunk biome data entry 2026-04-07 04:16:40 +02:00
booky 5c24615b8e Rename ChunkData -> ChunkBiomeData 2026-04-07 04:14:47 +02:00
booky 5ac8d1262d Remove constructors with default world height parameter 2026-04-07 04:10:38 +02:00
booky dbe39c61a4 Some small style fixes 2026-04-07 04:09:46 +02:00
retrooper e0455447d3 Merge pull request #1483 from roggy666/2.0
Fix 'CraftItemStack#asBukkitCopy' reflection for MC 26.1.1 and newer
2026-04-06 21:51:57 -04:00
roggy666 3ccbbcd8a1 Fix asBukkitCopy reflection for MC 26.1.1+
MC 26.1.1 introduced a new CraftItemStack.asBukkitCopy(ItemStackTemplate)
overload. The index-based method lookup (getMethod with index 0) could
resolve to the wrong overload depending on JVM method ordering, causing
"argument type mismatch" errors for item-holding disguises.

Use getMethodExact with explicit NMS_ITEM_STACK_CLASS parameter type
to always resolve the correct asBukkitCopy(ItemStack) method, with a
fallback to the old index-based lookup for older servers.
2026-04-07 03:56:05 +04:00
retrooper 3a9cee8911 patch: small change to changelog 2026-04-05 17:48:06 -04:00
retrooper 25e298e466 release: packetevents-2.12.1-SNAPSHOT 2026-04-05 17:43:28 -04:00
retrooper 2ddba25909 PacketEvents 2.12.0 Release 2026-04-05 17:32:38 -04:00
retrooper c9c1953630 patch: typo fixes 2026-04-05 16:54:20 -04:00
retrooper 3598150462 patch: remove newline in failure to detect version message; it messes up logging color 2026-04-05 16:37:13 -04:00
booky 3855390263 Explicitly use java 25 for compiling spigot/paper project 2026-04-05 21:55:59 +02:00
booky b8d219f229 Use Bukkit#getMinecraftVersion if available 2026-04-05 21:44:32 +02:00
booky 80a3652814 Don't disable packetevents if just the patch version changed
Depends on Mojang actually just doing hotfixes without protocol changes for patch versions, but let's try to see how this goes
2026-04-05 21:43:14 +02:00
booky 7859850cf1 Bump dependencies for paper 26.1.1 alpha builds 2026-04-05 21:42:15 +02:00
rafi67000 3cc6596463 Update shadow to 8.3.10 2026-04-02 14:18:17 +02:00
rafi67000 a442e31d1d Invocation of Task.project at execution time is deprecated 2026-04-02 14:18:17 +02:00
rafi67000 73e31db63f Use gradle's lazy configuration 2026-04-02 14:18:17 +02:00
rafi67000 3b6fc07fc4 Update various libraries 2026-04-02 14:18:13 +02:00
rafi67000 e80d0c166c Update java-diff-utils 2026-04-02 13:18:26 +02:00
rafi67000 b1629e1816 Update gradle to 9.4.1 2026-04-02 13:17:42 +02:00
booky a9465b2e16 Add version constant for 26.1.1 2026-04-01 18:33:49 +02:00
booky b2d05b6402 Fix command length limit for 1.20.5+
Fixes https://github.com/retrooper/packetevents/issues/1466
2026-03-31 20:02:27 +02:00
booky a34636e4d5 Merge pull request #1470 from qamulex/fix-environment-attributes-defaults
add defaults for unsynced environment attributes
2026-03-31 19:51:47 +02:00
booky 36685cad15 Merge branch '2.0' into fix-environment-attributes-defaults 2026-03-31 19:43:40 +02:00
booky d16b9b4148 Fix default value for env attribute "gameplay/turtle_egg_hatch_chance" 2026-03-31 19:40:47 +02:00
booky e0a9b964d6 Track fluid count in chunk sections for 26.1+ 2026-03-31 19:25:23 +02:00
booky ea2d00cd58 Never mark fabric server task as up-to-date 2026-03-31 19:04:00 +02:00
booky 7ba6963a24 Merge pull request #1461 from booky10/feat/26.1-support
26.1 update
2026-03-25 20:15:38 +01:00
booky 8525714531 Fix asss issue with variant registry reading 2026-03-24 20:08:43 +01:00
booky b0e3fff6b7 Fix item registry missing golden dandelion 2026-03-24 19:45:45 +01:00
booky b755994c44 Bump version to v2.12.0-SNAPSHOT 2026-03-24 17:17:42 +01:00
booky 796cf24672 Bump fabic dependency to 26.1 release 2026-03-24 17:15:36 +01:00
booky 6efc4324f8 Bump fabric to 26.1-rc-2 2026-03-21 20:12:25 +01:00
booky 61818d1b75 Include api and netty-common in fabric jar 2026-03-16 05:12:47 +01:00
booky 50f9cab76d Remove SUMMARY.md 2026-03-16 04:33:56 +01:00
booky f5b4b9a9d2 Add fabric intermediary mapped subproject for < 26.1 2026-03-16 04:33:25 +01:00
booky 5d7b2bdf33 Add fabric parent project 2026-03-16 04:17:30 +01:00
booky be7a7a2f73 Rename fabric to fabric-official 2026-03-16 04:01:26 +01:00
booky f318ce28cc Add fabric subproject for 26.1+ 2026-03-16 03:52:06 +01:00
booky 0b03d8f002 Move fabric code into new fabric-common subproject 2026-03-16 01:52:06 +01:00
booky a12a1da03f Bump fabric versions 2026-03-16 01:23:56 +01:00
booky 3731593ada Fix some gradle tasks not being marked as up-to-date 2026-03-16 01:19:36 +01:00
booky 788806e026 Add integer environment attribute type for 26.1
Unused in vanilla
2026-03-16 00:35:20 +01:00
booky bbf586f7c3 Implement component references for 26.1
26.1 adds component values which depend on registries being initialized, so we also need registry context to read them
2026-03-16 00:27:54 +01:00
booky a1f8e94c41 Update ItemDamageResistant to 26.1 2026-03-15 21:15:54 +01:00
booky cb0d5300e7 Update ItemBlocksAttacks to 26.1 2026-03-15 21:13:06 +01:00
booky bbcda0ed92 Update wrapper for ClientboundSetTimePacket to 26.1 2026-03-15 21:00:47 +01:00
booky 4cc219bb03 Update ItemProvidesBannerPatterns to 26.1 2026-03-15 20:49:40 +01:00
booky 2002e778c4 Merge branch '2.0' into feat/26.1-support 2026-03-15 20:38:21 +01:00
booky dcc3cec023 Remove ProtocolSupport dependency during compilation
Use reflection instead because jitpack sucks (and ProtocolSupport is pretty much legacy now anyway)
2026-03-08 16:43:03 +01:00
booky 989c38f377 Fix misleading nbt limiter error message 2026-03-08 15:37:15 +01:00
booky 10a6b6dbba Update pig sound sets to 26.1-snapshot-11 2026-03-03 17:26:44 +01:00
booky 77018b00a3 Update registries to 26.1-snapshot-11 2026-03-03 17:21:54 +01:00
booky 457a1a8af1 Update block tags to 26.1-snapshot-11 2026-03-03 17:16:54 +01:00
retrooper fea65c7891 Merge pull request #1452 from ruViolence/add-missing-equals-hashcode-tostring
Add missing equals, hashCode and toString methods
2026-02-27 13:58:23 -05:00
qamulex ce2b0a27ae add defaults for unsynced environment attributes 2026-02-26 22:10:16 +05:00
Beanes 646b03e5a9 Change design to existing design 2026-02-25 17:38:26 +01:00
Beanes 2a0ac8fa72 Add system property to allow longer chat messages on legacy versions 2026-02-25 14:31:26 +01:00
booky df12da1419 Add new particle types added in 26.1-snapshot-10 2026-02-24 17:30:22 +01:00
booky 0cc3f47f74 Add usages page to javadoc 2026-02-24 17:22:13 +01:00
booky a5971bb38e Properly add javadoc @versions custom tag 2026-02-24 17:22:01 +01:00
booky 588a452f79 Catch errors during tasks-after-send 2026-02-23 19:05:32 +01:00
booky 51246f60cc Merge branch '2.0' into instantwriteaftersend 2026-02-23 19:00:46 +01:00
booky fc6c134b5c Add info log message on startup 2026-02-23 18:58:53 +01:00
booky 0eead9baa7 Fix using wrong Audience import 2026-02-23 18:58:36 +01:00
booky fdd1802425 Don't spam reflection for slf4j/component logger managers 2026-02-23 18:42:25 +01:00
booky c8dcb28439 Strip legacy colors from log messages
Because of backwards compatibility
2026-02-23 18:35:37 +01:00
booky 1f3b2dbc59 Merge branch '2.0' into feat/refactor-logging 2026-02-23 18:20:58 +01:00
booky 0bb1f9d65a Add missing new entity data serializers 2026-02-21 05:05:48 +01:00
booky 33b904ce83 Fix chunk section reading
Mojang now sends fluid count on protocol
2026-02-21 05:05:41 +01:00
booky 0a7785f71d Update fabric to 26.1
Also breaks compat for older than 26.1 for now
2026-02-21 04:48:01 +01:00
booky 537765af6e Merge remote-tracking branch 'upstream/2.0' into feat/26.1-support 2026-02-21 04:47:17 +01:00
booky d2232163c1 Fix PacketType loading 2026-02-21 04:46:54 +01:00
booky 365f56902b Update gradle wrapper to v9.3.1 2026-02-21 04:45:48 +01:00
booky d49555c5e1 Fix fabric mod initialization
Fixes https://github.com/retrooper/packetevents/issues/1453
2026-02-21 03:23:47 +01:00
booky 07ce50972f Implement all new packets 2026-02-21 02:06:59 +01:00
booky 40ef51a882 Update ServerboundInteractPacket 2026-02-20 23:46:17 +01:00
booky 3e862e6e58 Update ServerboundClientCommandPacket 2026-02-20 21:55:42 +01:00
booky 8beda564e7 Update ClientboundSetTimePacket 2026-02-20 21:50:03 +01:00
booky fa2333ae79 Fix tests not passing 2026-02-20 21:28:35 +01:00
booky 9b0a521651 Fix cow variant baby asset id 2026-02-20 20:51:04 +01:00
booky 0b03494fb4 Update wolf variants 2026-02-20 20:50:57 +01:00
booky c6829237c7 Update timelines 2026-02-20 20:17:54 +01:00
booky d0b0edd967 Update pig variants registry 2026-02-20 20:02:51 +01:00
booky bc9985bca7 Update frog variant texture asset id 2026-02-20 20:02:44 +01:00
booky 705f25a257 Update lunge effect enchantment data 2026-02-20 20:02:38 +01:00
booky 6b634e4ec4 Add world clocks registry and update dimension types 2026-02-20 19:56:41 +01:00
booky d657cbd0dd Update cow/cat/chicken variants 2026-02-20 18:41:19 +01:00
booky 23d241ed66 Add trumpet noteblock instrument 2026-02-20 18:22:12 +01:00
booky 43b73120ce Update wolf sound variants 2026-02-20 18:10:29 +01:00
booky 443c874751 Update unused recipe_serializer registry
Just keep it up-to-date in case it will be used in the future
2026-02-20 16:58:23 +01:00
booky 1d5983d774 Implement new slot display types 2026-02-20 16:58:23 +01:00
booky b4f642a056 Fix ServerVersion being V_1_26 instead of V_26_1
Thanks @dawon!
2026-02-20 16:28:25 +01:00
booky 637b6ba14e Don't try to resolve non-existent step sounds 2026-02-20 05:39:31 +01:00
booky 2c9306431e Add patch version to EntryVersion
Used for mappings compression comparisons, didn't support newer versions before
2026-02-20 05:33:36 +01:00
booky 0bd43e7644 Fix item registry
I hate this
2026-02-20 05:33:05 +01:00
booky d4b59971f0 Start updating to 26.1 2026-02-20 05:15:30 +01:00
Beanes 149a45afac Instantly run task after write operation 2026-02-16 23:55:26 +01:00
Clairton Santos 2465a110d2 Handle compression only if the server sends the compression packet 2026-02-07 14:39:05 -03:00
Clairton Santos c8cbeb3b49 Handle compression only if the server sends the compression packet 2026-02-07 14:31:04 -03:00
ruViolence dedb96e5cb Add missing equals, hashCode and toString methods 2026-02-03 22:59:21 +08:00
vadim-soude 9323453184 feat : add DEFAULT_WORLD_HEIGHT 2026-01-28 17:54:08 +01:00
Vadim Soudé d661c8b4ce refactor : remove usage of deprecated methode and remove hardcoded world height - now support all versions ! 2026-01-28 16:38:49 +01:00
Vadim Soudé 6a95636733 Merge branch 'retrooper:2.0' into feat/chunk-biomes 2026-01-28 11:24:29 +01:00
booky 1b0a8bf8de Implement wrapped nbtlist support in compound list getter/setter 2026-01-27 15:41:55 +01:00
retrooper 8bf18ac3c6 bump to 2.11.3 snapshot 2026-01-26 20:03:22 -05:00
retrooper 61a91ca4a9 step 2: initiating 2.11.2 update 2026-01-26 18:58:43 -05:00
retrooper 5e281eb967 initiating 2.11.2 update 2026-01-26 18:55:40 -05:00
booky 91be6cad03 Refactor injection handling to be more generic 2026-01-26 14:35:14 +01:00
booky f0b29d0266 Initialize SynchronizedRegistriesHandler during packetevents load
Hopefully prevents a random deadlock which I am not sure how to debug/reproduce
2026-01-22 10:12:14 +01:00
booky 4ec6b01e6a Don't mix jspecify and jetbrains annotations in internal StaticChatType constructor
I don't know why, but this messes up our testing for correct annotations on the TypesBuilderData parameter
2026-01-20 09:31:27 +01:00
booky 58a1ada322 Fix various equality/nullability issues with registry values 2026-01-20 09:23:38 +01:00
booky 195ee0446a Add more equality methods for env attributes and particle data 2026-01-20 08:48:56 +01:00
booky 629080cfb3 Explicitly specify Locale#ROOT for all String#toLowerCaser() calls 2026-01-19 14:46:14 +01:00
booky 2390e06ad3 Fix dimension type copying not using new data entry
Should fix https://github.com/retrooper/packetevents/issues/1437
2026-01-19 13:37:57 +01:00
booky b6a3e39cae Remove end skylight for 1.21.8 and below
Fixes #1426
2026-01-16 23:31:02 +01:00
booky a09cb81ede Fix resize copy not ignoring empty entries 2026-01-16 19:32:00 +01:00
booky cceeb0c999 Improve Int2IntHashMap by using long-array table
Stores key and value in one long to reduce array reads/writes
Also improves resizing logic by removing unnecessary replacement logic check

(Additionally also includes some minor code format changes)
2026-01-16 19:05:07 +01:00
booky 05f0b3ebae Add link to inspiration source for Int2IntHashMap 2026-01-16 18:41:41 +01:00
booky 25f240a5f1 Add Int2IntHashMap EMPTY_VALUE constant 2026-01-16 18:31:33 +01:00
booky 6c569b72f2 Refactor ViaVersion user version getter
ViaVersion has recently implemented API which allows us to get the UserConnection from their encoder/decoder netty handlers without using reflection
(see https://github.com/ViaVersion/ViaVersion/commit/16a2a3a671b0b5f13746c704c0a26385cecb86f4)

This implements this api (currently only for spigot as sponge doesn't implement this api yet) and falls back to using reflection if this api isn't available yet
2026-01-16 18:22:40 +01:00
booky 548312ea34 Fix nullability annotations for packet events 2026-01-14 15:35:18 +01:00
booky 1c1702b11d Mark whole UpdateChecker class as internal 2026-01-14 15:32:37 +01:00
retrooper eb09f196e5 Merge pull request #1435 from nickuc-com/fix-chat-processor
Fix chat message processor for version 1.7
2026-01-11 11:31:29 -05:00
Nick d122518bcf Do not rename ChatMessageProcessorLegacy class 2026-01-10 18:32:22 -03:00
retrooper fd53b95457 code duplication in release builds suggestion corrected 2026-01-10 16:20:37 -05:00
retrooper 76af835e2e Merge pull request #1431 from GrimAnticheat/feat/vector-offset-multiple-of-blockface
Add new offset(Blockface face, int i) method to Vector3f/d/i classes
2026-01-10 16:07:15 -05:00
booky 90a196d3bc Log warning message when failing to uninject from velocity initializer
It shouldn't break anything, but it's a massive memory leak

Follow-up to #1379
2026-01-10 19:15:11 +01:00
booky ae928dbee1 Add all removed blocks to their new block tags
Follow-up to #1434 which moves the legacy chain block outside the auto-generated code block

Also fixes the same issue for grass_path
2026-01-10 19:02:27 +01:00
Nick fa701e81cf Fix chat message processor for version 1.7 2026-01-10 02:38:29 -03:00
Axionize c44e502dab Refactor: Rename offset parameter and add JavaDoc
- Renamed parameter 'i' to 'distance' in Vector3i, Vector3f, and Vector3d to improve code readability.
- Added JavaDoc to offset methods to explain the functionality as requested.
2026-01-09 22:17:35 -05:00
retrooper 8669b0f183 Recommend release builds (and fallback to development builds) to users who run outdated software. 2026-01-09 22:02:34 -05:00
retrooper 2b9e7b1166 Merge pull request #1379 from Rothes/velocity-hot-disable
Support uninject on velocity
2026-01-09 20:59:36 -05:00
retrooper 5a00e5c79f resort to more common terminology in comment 2026-01-09 20:55:46 -05:00
retrooper 887fa9ff4c Merge pull request #1434 from Ayouuuu/2.0
Add CHAIN to the CHAINS tag
2026-01-09 20:40:21 -05:00
Ayou ac962ce70d Add CHAIN to the CHAINS tag 2026-01-09 12:47:50 +08:00
Axionize 21866cc94f Add new offset(Blockface face, int i) method to Vector3f/d/i classes 2026-01-04 20:11:26 -05:00
retrooper 497c8dbd94 Update README.md 2026-01-04 19:28:20 -05:00
booky 40cd6b43cb Merge pull request #1407 from NgLoader/fix-thread-save-packet-prepare
fix: thread save packet type init
2026-01-04 23:05:35 +01:00
booky 84b3392e9a Replace more PacketType#prepare usage
Also mark methods as internal
2026-01-04 22:59:14 +01:00
booky b654ab1b54 Fix infiniburn tag parsing for 1.18.1 and older
Fixes https://github.com/retrooper/packetevents/issues/1429
2026-01-04 22:49:22 +01:00
booky 1639b73a0d Fix unexpected NPE if bukkit entity is null during unsafe lookup
Caused by these lookups being inherently unsafe
2026-01-04 21:26:23 +01:00
booky 74163d2edf Allow parsing component entity uuids as strings
Fixes https://github.com/retrooper/packetevents/issues/1430
2026-01-04 21:20:20 +01:00
booky a35742fc64 [skip ci] Bump some dependencies 2026-01-04 20:16:03 +01:00
retrooper 2768b3445f Update library description in README.md 2026-01-04 12:40:51 -05:00
Vrganj 7c0eaa2805 rename Int2IntMap to Int2IntOpenHashMap and move it out of MapPalette, simplify tableSizeFor 2025-12-23 21:32:06 +01:00
retrooper 7763337e37 increment version to 2.11.2 for snapshot builds 2025-12-21 08:56:53 +01:00
retrooper c93fcd2c0f initiating update to 2.11.1 2025-12-21 08:46:45 +01:00
booky ae20589b1a Merge pull request #1424 from nickuc-com/2.0
Fix NoSuchMethodError: 'Class ClickEvent$Action.payloadType()' error
2025-12-19 04:10:22 +01:00
Nick 6e2005c6c9 Fix NoSuchMethodError: 'Class ClickEvent$Action.payloadType()' error for Adventure 4.21 or older 2025-12-18 18:10:05 -03:00
booky d7f3ff6e06 Fix modrinth release publishing not working for some modules
Caused by our sources jar being the exact same as the last one for some modules
2025-12-18 16:53:25 +01:00
booky 75b6d14aac Normalize SimpleRegistry name inputs
Fixes https://github.com/retrooper/packetevents/issues/1419
2025-12-18 12:56:03 +01:00
booky f250854243 Fix login plugin message reading/writing 2025-12-16 15:13:53 +01:00
booky bfd1b40482 Don't wrap timelines registry twice
Should have no effect, just a small cleanup change
2025-12-16 14:27:57 +01:00
booky 941bf7c30e Add system property for activating NbtCodecException debug traces 2025-12-16 13:30:34 +01:00
booky 28f14a7b42 Finalize registry entries after all registries have been loaded
Should fix https://github.com/retrooper/packetevents/issues/1419
2025-12-15 23:31:34 +01:00
AoElite a3dc1118f8 Merge pull request #1182 from Axionize/feat/comprehensive-statetype-integrity-testing
Add comprehrensive test to ensure integrity of all StateType mappings and getting corresponding WrappedBlockStates
2025-12-12 03:06:52 -05:00
Axionize 8b9ca0541a Merge remote-tracking branch 'axionize/feat/comprehensive-statetype-integrity-testing' into feat/comprehensive-statetype-integrity-testing
# Conflicts:
#	testlibs.versions.toml
2025-12-12 02:33:47 -05:00
Axionize 6680d33abb Update StateType test for 1.21.10 and improve robustness 2025-12-12 02:24:39 -05:00
Axionize 4e6ae10528 Merge branch '2.0' into feat/comprehensive-statetype-integrity-testing
# Conflicts:
#	testlibs.versions.toml
2025-12-12 01:50:29 -05:00
booky c728f2fd05 Merge pull request #1417 from vadim-soude/feat/add-comment-WrapperPlayServerChangeGameState
Add comment to indicate the mojang name of the packet the wrapper is handling
2025-12-11 14:22:16 +01:00
Vadim Soudé aa54f50116 Add comment to indicate the mojang name of the packet the wrapper is haddling
This is some parity comment in regard of ClientboundLevelEventPacket
2025-12-11 14:13:56 +01:00
Vadim Soudé 233c89b7ad Merge branch 'retrooper:2.0' into feat/chunk-biomes 2025-12-11 14:11:17 +01:00
booky f9775eb3ce Fix sound codec typo 2025-12-10 14:58:32 +01:00
retrooper d8adfb132a bump version to 2.11.1 snapshot 2025-12-09 21:41:45 +01:00
retrooper ebd8a66d05 releasing packetevents 2.11.0 2025-12-09 21:06:09 +01:00
retrooper 024d4b93a3 Merge pull request #1405 from booky10/feat/1.21.11-support
1.21.11 support
2025-12-09 20:39:01 +01:00
retrooper a04e0eddc7 update packetevents 2.11.0 snapshot 2025-12-09 20:31:19 +01:00
retrooper 0c1e3ee82d add copyright notices 2025-12-09 20:16:38 +01:00
booky e65004c12e Update base item components for 1.21.11 2025-12-09 19:59:43 +01:00
booky e61a83e5ad Update attack range item component with changes from 1.21.11-pre4 2025-12-09 19:46:29 +01:00
booky 10d126cbe7 Merge branch '2.0' into feat/1.21.11-support 2025-12-09 17:23:06 +01:00
booky 39df65b111 Fix ClassStructureTest breaking dimension mappings test 2025-12-09 16:41:44 +01:00
booky d8c39f6463 Compare name maps using DeepComparableEntity if available 2025-12-09 15:24:09 +01:00
booky b97c13b487 Implement extra mapping steps to support version-specific named elements 2025-12-09 15:18:27 +01:00
AoElite 71c8f41bd4 Merge pull request #1411 from AoElite/resourcekey-refactor
ResourceLocation refactor
2025-12-08 22:19:04 -05:00
booky eeea9d7fdc Bump fabric minecraft version 2025-12-08 22:47:09 +01:00
booky e46deea6c5 Fix paper 1.21.11-rc2 startup errors 2025-12-08 22:42:58 +01:00
booky 0e30d2f5ee Fix VersionRange check 2025-12-08 22:23:12 +01:00
Vrganj 5310fec246 implement a custom Int2Int map for MapPalette 2025-12-08 21:38:27 +01:00
booky c2634d2dc3 Define dimension types with new data 2025-12-08 15:40:19 +01:00
AoElite d1254391aa remove redundant lowercase conversion 2025-12-08 09:27:15 -05:00
AoElite 3dae51062d Refactor ResourceLocation to use Key simplifying key handling. Additionally, fixed an issue with StateTypes creating ResourceLocations with invalid key formatting. 2025-12-08 09:14:37 -05:00
AoElite 86e454077a Show full exceptions during tests 2025-12-08 09:11:44 -05:00
booky 7d032a3e4a Implement version-specific named registry object definitions 2025-12-08 14:38:23 +01:00
booky b4b6ff015e Implement new DimensionType codec 2025-12-08 13:57:29 +01:00
booky db647ba73a WIP, start integrating env attributes into dimension types 2025-12-08 00:39:16 +01:00
booky 5dd5de04a8 Add timelines registry to sync data loading 2025-12-07 23:49:01 +01:00
retrooper bfbeb8dafc Merge pull request #1409 from groundbreakingmc/2.0
fix: correct default buffer size to match comment
2025-12-07 23:40:36 +01:00
booky 577590b1eb Load timelines registry data 2025-12-07 23:40:17 +01:00
booky c828e8b111 Refactor env attribute package structure 2025-12-07 23:11:46 +01:00
booky 9109e247db Resolve TODOs, fix tests 2025-12-07 23:06:52 +01:00
booky fe29db24cf Implement environment attribute easing types 2025-12-07 22:39:10 +01:00
booky 3c8079aee2 Finish EnvironmentAttributeMap implementation 2025-12-07 20:33:36 +01:00
GroundbreakingMC ee82a47abb fix: correct default buffer size to match comment
The code previously used 1 << 20 bytes (1MiB) for DEFAULT_MAX_SIZE,
but the comment stated 2MiB. This updates the value to 2 << 20 bytes
to match the comment and intended behavior.
2025-12-07 04:45:22 +01:00
booky 7251ee1b18 Finish env attribute types 2025-12-06 19:49:25 +01:00
booky 1582bca318 Some work on env attribute types and modifiers 2025-12-06 18:47:55 +01:00
booky 0615c78075 Some more work on timeline codecs 2025-12-06 16:58:29 +01:00
Nils Gereke fbb80124db fix: thread save Ãpacket type init 2025-11-30 21:58:54 +01:00
booky 3430b25b5e Start implementing timelines 2025-11-28 16:19:51 +01:00
booky def0ce4840 Start implementing environment attribute map entry codec
WIP, just a push before I start working on this again tomorrow
2025-11-28 04:06:23 +01:00
booky ed89d0a5a8 Update packaged biome data 2025-11-27 10:56:59 +01:00
booky 7af96fec84 Fix test failure 2025-11-27 10:56:37 +01:00
booky d8fd027415 Update block and item tags
We need to find a better solution for tags
2025-11-27 09:36:41 +01:00
booky 4441e04472 Update biomes decoding/encoding to 1.21.11 2025-11-27 01:53:59 +01:00
booky c5bec028c0 Finish environment attributes 2025-11-27 00:11:04 +01:00
booky bd6008d5a7 Start implementing environment attributes 2025-11-26 23:10:51 +01:00
booky fc4157127a Add environment attribute and timeline registry ids 2025-11-26 22:37:43 +01:00
booky ea3c9d085e Document mojang names for WrapperPlayServerOpenHorseWindow 2025-11-26 22:34:58 +01:00
booky 1b1a104cc4 Add stab digging action 2025-11-26 22:34:49 +01:00
booky 6d43d90367 Fix other remaining test issues 2025-11-25 10:16:50 +01:00
booky 3323449eea Fix zombie nautilus variant registry loading 2025-11-25 09:52:01 +01:00
booky c72ca2baa0 Implement new data component types 2025-11-25 09:49:39 +01:00
booky d4e6fff86e Add ZombieNautilusVariant to registry loading 2025-11-25 09:05:15 +01:00
booky 06c96900ec Implement ZombieNautilusVariant 2025-11-25 08:40:59 +01:00
booky a0dd21bed5 Start updating to 1.21.11 2025-11-24 17:35:08 +01:00
AoElite b25c0f9850 Merge branch '2.0' into feat/comprehensive-statetype-integrity-testing 2025-11-22 10:34:32 -05:00
AoElite f9ab88c9e4 Merge pull request #1394 from retrooper/copilot/improve-slow-code-efficiency
Optimize loop performance: cache size() calls and use entrySet() iteration
2025-11-22 10:28:27 -05:00
retrooper 3238a3eca4 Merge pull request #1401 from NoJokeFNA/patch-1
Document protocol version for 1.19.1 and 1.19.2
2025-11-20 23:04:34 +01:00
Julian 8685846be3 Document protocol version for 1.19.1 and 1.19.2
Add comment explaining protocol version for 1.19.1 and 1.19.2
2025-11-19 14:02:18 +01:00
retrooper 2ebfa4185b minor correction of a copyright year 2025-11-19 13:55:14 +01:00
booky c4b4c8d9e0 Merge pull request #1393 from MesterMan03/2.0
Fix custom click event payload field being stripped during NBT serialization
2025-11-11 00:30:25 +01:00
booky 60dd509fcb Implement proper nb string parsing
We apparently have included adventure nbt for some time now for some reason, so we can also just use it to parse SNBT strings
2025-11-10 13:43:29 +01:00
booky b6c67c320e Remove version check
We don't do any version checks in the nbt serializer when serializing
2025-11-10 13:16:56 +01:00
MesterMan03 27ba69fa43 Fix custom click event payload field being stripped during NBT serialization
- Fixed deserialization: Now properly uses NbtTagHolder with the actual payload NBT instead of hardcoded "0b"
- Fixed serialization: Now writes the payload field to NBT when it exists and is not empty (also checks for Minecraft version 1.21.6+)
- Added comprehensive tests for custom click event payload preservation
2025-11-08 00:15:12 +01:00
Vadim Soudé 1f7cd879a8 Refactor WrapperPlayServerChunkBiomes to use primitive long array instead of Long array 2025-10-27 16:16:09 +01:00
Vadim Soudé 73a67d3b0c Merge remote-tracking branch 'origin/feat/chunk-biomes' into feat/chunk-biomes 2025-10-27 15:41:13 +01:00
Vadim Soudé 4d95c55361 Add import for WrapperPlayServerChunkBiomes in PacketType 2025-10-27 15:41:03 +01:00
Vadim Soudé 8576933f7d Add WrapperPlayServerChunkBiomes for handling chunk biome packet 2025-10-27 15:36:57 +01:00
Vadim Soudé ffbbe29ef6 Add WrapperPlayServerChunkBiomes for handling chunk biome packet 2025-10-27 15:36:25 +01:00
Rothes 8b45ddd4ef Not to inject channel if plugin is terminated 2025-10-26 20:50:36 +08:00
Rothes a7fa150836 Support uninject on velocity 2025-10-26 15:35:36 +08:00
Axionize cffc7750b9 Update comprehensive StateType test for 1.21.6/1.21.7 2025-06-29 22:34:12 -04:00
Axionize 838109ccd5 Cleaner Optimized Annotation Implementation 2025-06-29 22:23:59 -04:00
Axionize 67f413cc59 New Test Annotation Implementation 2025-06-29 22:23:59 -04:00
Axionize c498332c36 Add comprehensive test to ensure integrity of all StateType mappings and WrappedBlockStates 2025-06-29 22:23:55 -04:00
688 changed files with 742905 additions and 5307 deletions

No files matched your search

+4 -4
View File
@@ -35,11 +35,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -50,7 +50,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -64,4 +64,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
+9 -9
View File
@@ -10,10 +10,10 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Validate gradle wrapper
uses: gradle/actions/wrapper-validation@v5
uses: gradle/actions/wrapper-validation@v6
- name: Set up JDK 21
uses: actions/setup-java@v5
@@ -28,43 +28,43 @@ jobs:
run: chmod +x gradlew && ./gradlew build
- name: Upload build artifacts api
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: api-build
path: build/libs/packetevents-api-*.jar
- name: Upload build artifacts spigot
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: spigot-build
path: build/libs/packetevents-spigot-*.jar
- name: Upload build artifacts netty-common
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: netty-common-build
path: build/libs/packetevents-netty-common-*.jar
- name: Upload build artifacts bungeecord
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: bungeecord-build
path: build/libs/packetevents-bungeecord-*.jar
- name: Upload build artifacts velocity
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: velocity-build
path: build/libs/packetevents-velocity-*.jar
- name: Upload build artifacts fabric
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fabric-build
path: build/libs/packetevents-fabric-*.jar
- name: Upload build artifacts sponge
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: sponge-build
path: build/libs/packetevents-sponge-*.jar
+3 -3
View File
@@ -12,13 +12,13 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Validate gradle wrapper
uses: gradle/actions/wrapper-validation@v4
uses: gradle/actions/wrapper-validation@v6
- name: Setup java 21
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: 21
distribution: temurin
+2
View File
@@ -126,3 +126,5 @@ run/
# Build Source Kotlin
/buildSrc/.kotlin/
.env
+277
View File
@@ -1,3 +1,280 @@
!!!!! v2.14.0
# PacketEvents 2.14.0 is finally out! 🎉
This minor release includes mainly support for Minecraft 26.3, but also includes a few smaller fixes and improvements.
Recent donors: **@PebbleHost, Aurel (Advanced GUI), @zer0origin**\
If you intend on donating and do not wish to be mentioned, please add such a note on your donation.
# Announcement 📢
Visit our website: https://packetevents.com/ \
Documentation: https://docs.packetevents.com/ \
Javadoc: https://javadocs.packetevents.com/
Thanks to all contributors who helped make this release possible:
- @booky10
- @Bram1903
- @carragrive
- @ChengZhiMeow
- @Jan1k1
- @ManInMyVan
- @R00tB33rMan
- @ThatApplePieGuy
- @TheFaser
## What's Changed
* Add support for 26.3 ([#1582](https://github.com/retrooper/packetevents/pull/1582))
* Fix state type in wrapper for `block_event` packet ([#1571](https://github.com/retrooper/packetevents/pull/1571))
* Fix dialog body encoding for versions prior to 26.1 ([`2e49ec0`](https://github.com/retrooper/packetevents/commit/2e49ec0965d949de69f54f6f2eea5be75ca25ac0))
* Fix equippable item component ([#1573](https://github.com/retrooper/packetevents/pull/1573))
* Prevent null types in ItemStack ([#1574](https://github.com/retrooper/packetevents/pull/1574))
* Fix errors in WrapperPlayServerUseBed copying ([#1580](https://github.com/retrooper/packetevents/pull/1580))
* Add short Javadoc to bundle packet wrapper ([#1570](https://github.com/retrooper/packetevents/pull/1570))
* Minor NBT component serializer performance improvements ([#1549](https://github.com/retrooper/packetevents/pull/1549))
* Fix limits for clientbound `custom_payload` packets ([#1566](https://github.com/retrooper/packetevents/pull/1566))
* Implement `Location#equals` ([#1561](https://github.com/retrooper/packetevents/pull/1561))
* Fix Vector3i decode for versions prior to 1.14 ([`f52b3b9`](https://github.com/retrooper/packetevents/commit/f52b3b92323b380f2ffb061ebd8e22ef1836d75c)
* Fix interact action in 1.7 ([#1562](https://github.com/retrooper/packetevents/pull/1562))
* Fix NBT Component serialization bug with numbers ([#1543](https://github.com/retrooper/packetevents/pull/1543))
**View Full Changelog**: [`v2.13.0...v2.14.0`](https://github.com/retrooper/packetevents/compare/v2.13.0...v2.14.0)
!!!!! v2.13.0
# PacketEvents 2.13.0 is finally out! 🎉
This minor release includes mainly support for Minecraft 26.2, but also includes a few smaller fixes and improvements.
Recent donors: **@PebbleHost**\
If you intend on donating and do not wish to be mentioned, please add such a note on your donation.
# Announcement 📢
Visit our website: https://packetevents.com/ \
Documentation: https://docs.packetevents.com/ \
Javadoc: https://javadocs.packetevents.com/
Thanks to all contributors who helped make this release possible:
- @booky10
- @Jan1k1
- @linsaftw
- @rafi67000
- @retrooper
- @Rothes
- @TheFaser
## What's Changed
* Improve chunk reading performance ([#1526](https://github.com/retrooper/packetevents/pull/1526))
* Add PluginMessage Common Wrapper ([#1523](https://github.com/retrooper/packetevents/pull/1523))
* Fix custom world clock use in dimension types ([`7c4dd0b`](https://github.com/retrooper/packetevents/commit/7c4dd0b039e695e5ae7d9c0562082f913cbb2677))
* Add support for 26.2 ([#1529](https://github.com/retrooper/packetevents/pull/1529), [`471a9e2`](https://github.com/retrooper/packetevents/commit/471a9e21144f0ea56e4053bda0477cca8402dc69), [`b1bbbae`](https://github.com/retrooper/packetevents/commit/b1bbbaed2f7bd8e09ff758bfa02f9b63df21c3b1))
* Update Gradle, Gradle plugins and actions ([#1533](https://github.com/retrooper/packetevents/pull/1533), [#1534](https://github.com/retrooper/packetevents/pull/1534))
* Fix nullability annotations for ProtcolManager/PlayerManager ([#1535](https://github.com/retrooper/packetevents/pull/1535))
* Ignore udp listeners during injection ([#1537](https://github.com/retrooper/packetevents/pull/1537))
**View Full Changelog**: [`v2.12.2...v2.13.0`](https://github.com/retrooper/packetevents/compare/v2.12.2...v2.13.0)
!!!!! v2.12.2
# PacketEvents 2.12.2 is finally out! 🎉
This patch release contains a few critical bug fixes as well as some optimizations and reworks.
Recent donors: **@PebbleHost, @perlsol, @TRGReal**\
If you intend on donating and do not wish to be mentioned, please add such a note on your donation.
Unfortunately, the PacketEvents PayPal account is no longer active. I hope to resolve any concerns with PayPal, who has frozen funds and activity on the account. If you want to donate, please use [GitHub Sponsors](https://github.com/sponsors/retrooper) or the newly setup [BuyMeACoffee](https://buymeacoffee.com/retrooper).
Thanks to all contributors who helped make this release possible:
- @booky10
- @Beaness
- @SamB440
- @retrooper
- @LeonTG
## What's Changed
* Rework logging system in PacketEvents (now more consistently used across API) [`a1067f5`](https://github.com/retrooper/packetevents/commit/a1067f5e4f53bcd7fbeaa19fb4d8046a3f6248ca)
* Optimize SpigotReflectionUtil.generateEntityId() method [`95afd3f`](https://github.com/retrooper/packetevents/commit/95afd3fce8bfbf7087233a3bd31e0705cd1e4df5)
* Fix transmission/copying of packet wrappers when dealing with multiple packet listeners for the following wrappers: WrapperLoginServerLoginSuccess, WrapperPlayServerDeclareCommands, WrapperPlayServerMapData, WrapperPlayServerPlayerRotation, WrapperPlayServerSpawnWeatherEntity [`20d2bd3`](https://github.com/retrooper/packetevents/commit/20d2bd34326ea9fab602ff07333fcfc713ae6ced)
* Allow for the customization of chat message length limit for legacy Minecraft versions [`a1067f5`](https://github.com/retrooper/packetevents/commit/a1067f5e4f53bcd7fbeaa19fb4d8046a3f6248ca)
* Multiple fixes for WrapperPlayServerSoundEffect [`66d768d`](https://github.com/retrooper/packetevents/commit/66d768d00f6f69c71a9ba27998976a6d2b5020f7), [`73603f8`](https://github.com/retrooper/packetevents/commit/73603f89b7aafab6ff7eed7be488b03fa5e064dc)
* Fix incorrect swapping of pitch and yaw for WrapperPlayServerSpawnEntity on Minecraft versions lower than 1.15 [`0634827`](https://github.com/retrooper/packetevents/commit/063482716d0fd858bef8e65b9c4714c8e1fd4aa9)
* Fix injection cleanup issues on Velocity ([#1489](https://github.com/retrooper/packetevents/issues/1489), [`cb8fb8b`](https://github.com/retrooper/packetevents/commit/cb8fb8b9268f7fb83f2a931432757d7d36ae220b))
**View Full Changelog**: [`v2.12.1...v2.12.2`](https://github.com/retrooper/packetevents/compare/v2.12.1...v2.12.2)
!!!!! v2.12.1
# PacketEvents 2.12.1 is finally out! 🎉
This patch release includes mainly bugfixes related to Minecraft 26.1, but also includes a few smaller features.
Recent donors: **PebbleHost, JustUsBuilds, matsu1213**\
If you intend on donating and do not wish to be mentioned, please add such a note on your donation.
# Announcement 📢
Visit our website: https://packetevents.com/ \
Documentation: https://docs.packetevents.com/ \
Javadoc: https://javadocs.packetevents.com/
Thanks to all contributors which helped make this release possible:
- @Beaness
- @booky10
- @ieatglu3
- @ManInMyVan
- @rafi67000
- @retrooper
- @roggy666
- @vadim-soude
- @Vrganj
- @ytnoos
## What's Changed
* Fix minor issues related to 26.1 ([#1483](https://github.com/retrooper/packetevents/pull/1483), [`f2974ec`](https://github.com/retrooper/packetevents/commit/f2974eca7c919ca60266016339991ea0e28a17bb))
* Add WrapperPlayServerChunkBiomes ([#1383](https://github.com/retrooper/packetevents/pull/1383))
* Mark 26.1.2 as fully supported ([`4d1938b`](https://github.com/retrooper/packetevents/commit/4d1938b97564633900d3a73061ad137b680e8fa1))
* Track chunk section fluid count ([#1477](https://github.com/retrooper/packetevents/pull/1477))
* Add support for adventure v5 ([`bbeec89...c1163ee`](https://github.com/retrooper/packetevents/compare/bbeec896384e22844a51ab28b9bc4c91f8f1daf0...c1163ee7232c9084ae25b3e2e2a6f44d602ec737))
**View Full Changelog**: [`v2.12.0...v2.12.1`](https://github.com/retrooper/packetevents/compare/v2.12.0...v2.12.1)
!!!!! v2.12.0
# PacketEvents 2.12.0 is finally out! 🎉
This update primarily adds support for Minecraft 26.1.
Again, huge thanks to all users who have donated their hard-earned money to PacketEvents since the previous release. It's been received & it's very much appreciated.
Recent donors: PebbleHost, Dylan\
If you intend on donating and do not wish to be mentioned, please add such a note on your donation.
Also, thanks to the contributors that made this update possible, especially @booky10. Open-source software thrives when it receives contributions from the community.
# Announcement 📢
Visit our website: https://packetevents.com\
Documentation: https://docs.packetevents.com\
JavaDocs: https://javadocs.packetevents.com
## What's Changed (Summary)
* Added support for Minecraft 26.1 (and 26.1.1)
* Added support for changes to Fabric, leading to the addition of new internal modules.
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.11.2...v2.12.0
### If you want to support PacketEvents, consider donating to us on [PayPal](https://paypal.me/packetevents), [Streamlabs](https://streamlabs.com/retrooper), or [GitHub Sponsors](https://github.com/sponsors/retrooper).
## Maven/Gradle Dependency Setup Guide
**Check it out**: https://docs.packetevents.com/introduction/development-setup/
!!!!! v2.11.2
# PacketEvents 2.11.2 is finally out! 🎉
This update fixes various bugs. It's encouraged that users update.
Again, huge thanks to all users who have donated their hard-earned money to PacketEvents since the previous release. It's been received & it's very much appreciated.
Recent donors: PebbleHost, SSomar1607, ipavdev, Meed, frap
Also, thanks to the contributors that made this update possible.
If you intend on donating and do not wish to be mentioned, please add such a note on your donation.
# Announcement 📢⚠️
Visit our website: https://packetevents.com\
Documentation: https://docs.packetevents.com\
JavaDocs: https://javadocs.packetevents.com\
I've released a new YouTube [video](https://youtu.be/G7qYRHpZVIo).
## What's Changed (Summary)
* Fixed SynchronizedRegistriesHandler issues
* Fixed various equality/nullability issues with Registry values
* Explicitly specify 'Locale#ROOT' for all String#toLowerCaser() calls
* Removed 'end skylight' for 1.21.8 and below
* Log warning message when failing to uninject from velocity initializer
* Recommend release builds (and fallback to development builds) to users who run outdated software.
* Add 'CHAIN' to the 'CHAINS' tag
* Add new offset(Blockface face, int i) method to Vector3f/d/i classes
* Fixed 'infiniburn' tag parsing for 1.18.1 and older
* Fixed unexpected NPE if bukkit entity is null during unsafe lookup
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.11.1...v2.11.2
## If you want to support PacketEvents, consider donating to us on [PayPal](https://paypal.me/packetevents) or sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper).
## Maven/Gradle Dependency Setup Guide
**Check it out**: https://docs.packetevents.com/introduction/development-setup/
!!!!! v2.11.1
# PacketEvents 2.11.1 is finally out! 🎉
This update fixes various bugs. It's encouraged that users update.
Thanks to all users who donated after the previous release announcement. It's been received & it's appreciated.
Recent donors: TrekCraft, 3add, Vadim Soudé
If you intend on donating and do not wish to be mentioned, please add such a note on your donation.
# Brief Announcement 📢⚠️
### Visit our website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed (Summary)
* Fixed 'Can't resolve 'minecraft:day' in 'minecraft:timeline' for V_1_21_11'
* Fixed decoding & encoding for WrapperLoginServerPluginRequest & WrapperLoginClientPluginResponse
* Improve StateTypes testing
* Added system property packetevents.debug.nbt-codec-trace
* Fixed Sound Codec
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.11.0...v2.11.1
## If you want to support PacketEvents, consider donating to us on [PayPal](https://paypal.me/packetevents) or sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.11.0
# PacketEvents 2.11.0 is finally out! 🎉
This update adds support for Minecraft 1.21.11.
# Brief Announcement 📢⚠️
### Visit our website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed (Summary)
* Added support for Minecraft 1.21.11
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.10.1...v2.11.0
## If you want to support PacketEvents, consider donating to us on [PayPal](https://paypal.me/packetevents) or sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.10.1
# PacketEvents 2.10.1 is finally out! 🎉
+2 -2
View File
@@ -1,7 +1,7 @@
<!--suppress HtmlDeprecatedAttribute -->
<div align="center">
<h2><i>PacketEvents</i></h2>
<h3><i>A powerful networking library for Minecraft packet processing and manipulation.</i></h3>
<h3>PacketEvents is a protocol library tailored to Minecraft Java Edition, designed to facilitate the processing and transmission of packets.</h3>
<a href="https://github.com/retrooper/packetevents/actions"><img src="https://img.shields.io/github/actions/workflow/status/retrooper/packetevents/gradle-publish.yml?style=for-the-badge&logo=github"></a>
<a href="https://discord.gg/DVHxPPxHZc"><img src="https://img.shields.io/discord/721686193061888071?color=5562e9&logo=discord&logoColor=white&style=for-the-badge"></a>
<img src="https://img.shields.io/github/license/retrooper/packetevents?style=for-the-badge&logo=github">
@@ -11,7 +11,7 @@
<h3>Resources</h3>
- [Read documentation](https://docs.packetevents.com/)
- [Getting Started](https://docs.packetevents.com/getting-started)
- [Getting Started](https://docs.packetevents.com/development-setup)
- [JavaDocs](https://javadocs.packetevents.com)
- [Releases](https://github.com/retrooper/packetevents/releases/)
- [Modrinth](https://modrinth.com/plugin/packetevents)
-4
View File
@@ -1,4 +0,0 @@
# Table of contents
* [Initial page](README.md)
+17 -1
View File
@@ -2,6 +2,7 @@ import com.github.retrooper.compression.strategy.dir.JsonBase64DataDirStrategy
import com.github.retrooper.compression.strategy.dir.JsonRegistryCompressionDirStrategy
import com.github.retrooper.compression.strategy.dir.JsonToNbtDirStrategy
import com.github.retrooper.excludeAdventure
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
plugins {
packetevents.`shadow-conventions`
@@ -26,14 +27,20 @@ dependencies {
api(project(":patch:adventure-text-serializer-gson", "shadow")) {
excludeAdventure()
}
api(libs.adventure.text.serializer.legacy) {
api(project(":patch:adventure-text-serializer-legacy", "shadow")) {
excludeAdventure()
}
compileOnly(libs.gson)
compileOnly(libs.adventure.text.logger.slf4j)
compileOnly(libs.checkerqual)
testRuntimeOnly(testlibs.bundles.adventure)
testRuntimeOnly(testlibs.bundles.adventure.serializers)
testImplementation(libs.bundles.adventure)
testImplementation(project(":patch:adventure-text-serializer-gson"))
testImplementation(project(":patch:adventure-text-serializer-legacy"))
testImplementation(libs.adventure.text.serializer.legacy)
testImplementation(libs.adventure.text.logger.slf4j)
testImplementation(project(":netty-common"))
testImplementation(testlibs.mockbukkit)
testImplementation(testlibs.paper.api)
@@ -41,6 +48,9 @@ dependencies {
testImplementation(testlibs.bundles.junit)
testImplementation(libs.netty)
testImplementation(libs.classgraph)
testImplementation(project(":spigot"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.11.2")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.11.2")
}
mappingCompression {
@@ -64,6 +74,9 @@ tasks {
}
javadoc {
val options = options as StandardJavadocDocletOptions
options.use(true)
options.tags("versions:A:Minecraft Versions:")
mustRunAfter(generateVersionsFile)
}
@@ -86,6 +99,9 @@ tasks {
test {
useJUnitPlatform()
testLogging {
exceptionFormat = TestExceptionFormat.FULL
}
}
shadowJar {
@@ -20,25 +20,30 @@ package com.github.retrooper.packetevents;
import com.github.retrooper.packetevents.event.EventManager;
import com.github.retrooper.packetevents.injector.ChannelInjector;
import com.github.retrooper.packetevents.manager.InternalPacketListener;
import com.github.retrooper.packetevents.manager.player.PlayerManager;
import com.github.retrooper.packetevents.manager.protocol.ProtocolManager;
import com.github.retrooper.packetevents.manager.server.ServerManager;
import com.github.retrooper.packetevents.netty.NettyManager;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.settings.PacketEventsSettings;
import com.github.retrooper.packetevents.util.logger.JulLegacyLogManager;
import com.github.retrooper.packetevents.util.LogManager;
import com.github.retrooper.packetevents.util.PEVersion;
//Note: The PEVersions class is generated. Refer to PEVersionTask.kt
import com.github.retrooper.packetevents.util.PEVersions;
import com.github.retrooper.packetevents.util.adventure.AdventureConversionInjector;
import com.github.retrooper.packetevents.util.mappings.SynchronizedRegistriesHandler;
import com.github.retrooper.packetevents.util.updatechecker.UpdateChecker;
import java.util.logging.Logger;
public abstract class PacketEventsAPI<T> {
private final EventManager eventManager = new EventManager();
private final PacketEventsSettings settings = new PacketEventsSettings();
private final UpdateChecker updateChecker = new UpdateChecker();
private final LogManager logManager = new LogManager();
private static final Logger LOGGER = Logger.getLogger(PacketEventsAPI.class.getName());
private final LogManager logManager = LogManager.construct(this);
public EventManager getEventManager() {
return eventManager;
@@ -57,15 +62,31 @@ public abstract class PacketEventsAPI<T> {
return PEVersions.CURRENT;
}
@Deprecated
public Logger getLogger() {
return LOGGER;
return JulLegacyLogManager.getLogger();
}
public LogManager getLogManager() {
return logManager;
return this.logManager;
}
public abstract void load();
public void load() {
this.getLogManager().info("Loading packetevents...");
WrappedBlockState.ensureLoad();
SynchronizedRegistriesHandler.init();
PacketType.prepare();
AdventureConversionInjector.inject();
// Register internal packet listener (should be the first listener)
// This listener doesn't do any modifications to the packets, just reads data
this.registerInternalListener();
}
protected void registerInternalListener() {
this.getEventManager().registerListener(new InternalPacketListener());
}
public abstract boolean isLoaded();
@@ -73,7 +94,15 @@ public abstract class PacketEventsAPI<T> {
public abstract boolean isInitialized();
public abstract void terminate();
public void terminate() {
try {
this.getInjector().uninject();
} catch (Throwable throwable) {
this.getLogManager().warn("Failed to uninject during termination, this error can be ignored on shutdown", throwable);
}
this.getEventManager().unregisterAllListeners();
AdventureConversionInjector.uninject();
}
public abstract boolean isTerminated();
@@ -18,8 +18,7 @@
package com.github.retrooper.packetevents.event;
import com.github.retrooper.packetevents.event.PacketEvent;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import org.jspecify.annotations.NullMarked;
/**
* The {@link PacketEvent} implements this interface.
@@ -31,7 +30,9 @@ import com.github.retrooper.packetevents.event.PacketListenerAbstract;
* @author retrooper
* @since 1.8
*/
@NullMarked
public interface CallableEvent {
default void call(PacketListenerCommon listener) {
listener.onPacketEventExternal((PacketEvent) this);
}
@@ -22,23 +22,24 @@ import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.exception.InvalidHandshakeException;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Level;
/**
* Class for event managing. Implements both, internal and API methods.
*
* @author retrooper
* @author ShadowOfHeaven (optimization)
* @apiNote It is highly recommended to register the event listeners at server start-up,
* without frequent modifications during runtime, since this class needs to recalculate all of
* its event listeners during any modifications. In other words, it assumes that reads (events fired)
* greatly outnumber writes (listeners modifications). If your case requires frequent listener modifications,
* open a pull request on GitHub and describe your case.
*
* @author retrooper
* @author ShadowOfHeaven (optimization)
*
*/
public class EventManager {
@@ -85,7 +86,7 @@ public class EventManager {
} catch (Exception t) {
// ignore handshake exceptions
if (t.getClass() != InvalidHandshakeException.class && (t.getCause() == null || t.getCause().getClass() != InvalidHandshakeException.class)) {
PacketEvents.getAPI().getLogger().log(Level.WARNING, "PacketEvents caught an unhandled exception while calling your listener.", t);
PacketEvents.getAPI().getLogManager().warn("PacketEvents caught an unhandled exception while calling your listener.", t);
}
}
if (postCallListenerAction != null) {
@@ -21,6 +21,7 @@ package com.github.retrooper.packetevents.event;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.util.TimeStampMode;
import org.jspecify.annotations.NullMarked;
/**
* An event in both of PacketEvents' event systems.
@@ -28,7 +29,9 @@ import com.github.retrooper.packetevents.util.TimeStampMode;
* @author retrooper
* @since 1.2.6
*/
@NullMarked
public abstract class PacketEvent implements CallableEvent {
private final long timestamp;
public PacketEvent() {
@@ -60,4 +63,4 @@ public abstract class PacketEvent implements CallableEvent {
public void callPacketEventExternal(PacketListenerCommon listener) {
listener.onPacketEventExternal(this);
}
}
}
@@ -24,17 +24,25 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.PacketSide;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketReceiveEvent extends ProtocolPacketEvent {
protected PacketReceiveEvent(Object channel, User user, Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
protected PacketReceiveEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(PacketSide.CLIENT, channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketReceiveEvent(int packetID, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel, User user, Object player,
Object byteBuf) throws PacketProcessException {
protected PacketReceiveEvent(
int packetID, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetID, packetType, serverVersion,
channel, user, player, byteBuf);
}
@@ -46,13 +54,8 @@ public class PacketReceiveEvent extends ProtocolPacketEvent {
@Override
public PacketReceiveEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
}
@@ -18,32 +18,38 @@
package com.github.retrooper.packetevents.event;
import com.github.retrooper.packetevents.event.simple.PacketHandshakeSendEvent;
import com.github.retrooper.packetevents.exception.PacketProcessException;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.PacketSide;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@NullMarked
public class PacketSendEvent extends ProtocolPacketEvent {
private List<Runnable> tasksAfterSend = null;
protected PacketSendEvent(Object channel, User user, Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
private @Nullable List<Runnable> tasksAfterSend = null;
protected PacketSendEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(PacketSide.SERVER, channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketSendEvent(int packetID, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel, User user,
Object player, Object byteBuf) throws PacketProcessException {
super(packetID, packetType,
serverVersion,
channel, user, player, byteBuf);
protected PacketSendEvent(
int packetID, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetID, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
@@ -65,13 +71,8 @@ public class PacketSendEvent extends ProtocolPacketEvent {
@Override
public PacketSendEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketSendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketSendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
}
@@ -18,17 +18,25 @@
package com.github.retrooper.packetevents.event;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.NullUnmarked;
/**
* Every event that has an associated player is recommended to implement this interface.
*
* @author retrooper
* @since 1.6.9
*/
@NullMarked
public interface PlayerEvent {
/**
* Associated player.
* May be null (e.g. early connection states).
*
* @return Player.
*/
<T> T getPlayer();
@NullUnmarked
<T> @UnknownNullability T getPlayer();
}
@@ -33,40 +33,50 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
@NullMarked
public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerEvent, CancellableEvent, UserEvent {
private final Object channel;
private final ConnectionState connectionState;
private final User user;
private Object player;
private Object byteBuf;
private final int packetID;
private final PacketTypeCommon packetType;
private ServerVersion serverVersion;
private final Object channel;
private final ConnectionState connectionState;
private final User user;
private @UnknownNullability Object player;
private Object byteBuf;
private boolean cancel;
private PacketWrapper<?> lastUsedWrapper;
private List<Runnable> postTasks = null;
private @Nullable PacketWrapper<?> lastUsedWrapper;
private @Nullable List<Runnable> postTasks = null;
private boolean cloned;
private boolean needsReEncode = PacketEvents.getAPI().getSettings().reEncodeByDefault();
public ProtocolPacketEvent(PacketSide packetSide, Object channel,
User user, Object player, Object byteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public ProtocolPacketEvent(
PacketSide packetSide, Object channel, User user,
@UnknownNullability Object player, Object byteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
this.channel = channel;
this.user = user;
this.player = player;
if (autoProtocolTranslation || user.getClientVersion() == null) {
this.serverVersion = PacketEvents.getAPI().getServerManager().getVersion();
} else {
//TODO Optimize
this.serverVersion = user.getClientVersion().toServerVersion();
this.serverVersion = user.getPacketVersion().toServerVersion();
}
this.byteBuf = byteBuf;
@@ -79,22 +89,25 @@ public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerE
} catch (Exception e) {
throw new PacketProcessException("Failed to read the Packet ID of a packet. (Size: " + size + ")");
}
ClientVersion version = serverVersion.toClientVersion();
ConnectionState state = packetSide == PacketSide.CLIENT ? user.getDecoderState() : user.getEncoderState();
this.packetType = PacketType.getById(packetSide, state,
version, packetID);
if (this.packetType == null) {
this.connectionState = packetSide == PacketSide.CLIENT ? user.getDecoderState() : user.getEncoderState();
PacketTypeCommon packetType = PacketType.getById(packetSide, this.connectionState, version, this.packetID);
if (packetType == null) {
// mojang messed up and keeps sending disconnect packets in the wrong protocol state
if (PacketType.getById(packetSide, ConnectionState.PLAY, version, packetID) == PacketType.Play.Server.DISCONNECT) {
throw new InvalidDisconnectPacketSend();
}
throw new PacketProcessException("Failed to map the Packet ID " + packetID + " to a PacketType constant. Bound: " + packetSide.getOpposite() + ", Connection state: " + user.getDecoderState() + ", Server version: " + serverVersion.getReleaseName());
}
this.connectionState = state;
this.packetType = packetType;
}
public ProtocolPacketEvent(int packetID, PacketTypeCommon packetType, ServerVersion serverVersion, Object channel,
User user, Object player, Object byteBuf) {
public ProtocolPacketEvent(
int packetID, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) {
this.channel = channel;
this.user = user;
this.player = player;
@@ -105,7 +118,7 @@ public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerE
this.connectionState = (packetType != null && packetType.getSide() == PacketSide.SERVER)
? user.getEncoderState() : user.getDecoderState();
cloned = true;
this.cloned = true;
}
public void markForReEncode(boolean needsReEncode) {
@@ -116,7 +129,6 @@ public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerE
return needsReEncode;
}
public boolean isClone() {
return cloned;
}
@@ -142,7 +154,8 @@ public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerE
}
@Override
public <T> T getPlayer() {
@NullUnmarked
public <T> @UnknownNullability T getPlayer() {
return (T) player;
}
@@ -159,14 +172,13 @@ public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerE
return connectionState;
}
//TODO Possibly put clientversion inside User class and remove here
@Deprecated
public ClientVersion getClientVersion() {
return user.getClientVersion();
}
@Deprecated
public void setClientVersion(@NotNull ClientVersion clientVersion) {
public void setClientVersion(ClientVersion clientVersion) {
PacketEvents.getAPI().getLogManager().debug("Setting client version with deprecated method " + clientVersion.getReleaseName());
user.setClientVersion(clientVersion);
}
@@ -175,7 +187,8 @@ public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerE
return serverVersion;
}
public void setServerVersion(@NotNull ServerVersion serverVersion) {
@Deprecated
public void setServerVersion(ServerVersion serverVersion) {
this.serverVersion = serverVersion;
}
@@ -19,8 +19,11 @@
package com.github.retrooper.packetevents.event;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class UserConnectEvent extends PacketEvent implements CancellableEvent, UserEvent {
public class UserConnectEvent extends PacketEvent implements CancellableEvent, UserEvent{
private final User user;
private boolean cancelled;
@@ -19,8 +19,11 @@
package com.github.retrooper.packetevents.event;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class UserDisconnectEvent extends PacketEvent implements UserEvent {
private final User user;
public UserDisconnectEvent(User user) {
@@ -19,6 +19,7 @@
package com.github.retrooper.packetevents.event;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jspecify.annotations.NullMarked;
/**
* Event that involves users.
@@ -26,6 +27,8 @@ import com.github.retrooper.packetevents.protocol.player.User;
* @author retrooper
* @since 2.0.0
*/
@NullMarked
public interface UserEvent {
User getUser();
}
@@ -19,10 +19,15 @@
package com.github.retrooper.packetevents.event;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.NullUnmarked;
@NullMarked
public class UserLoginEvent extends PacketEvent implements CallableEvent, UserEvent, PlayerEvent {
private final User user;
private final Object player;
private final @UnknownNullability Object player;
public UserLoginEvent(User user, Object player) {
this.user = user;
@@ -35,7 +40,8 @@ public class UserLoginEvent extends PacketEvent implements CallableEvent, UserEv
}
@Override
public <T> T getPlayer() {
@NullUnmarked
public <T> @UnknownNullability T getPlayer() {
return (T) player;
}
@@ -25,32 +25,33 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketConfigReceiveEvent extends PacketReceiveEvent {
public PacketConfigReceiveEvent(Object channel, User user,
Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public PacketConfigReceiveEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketConfigReceiveEvent(int packetId, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel,
User user, Object player, Object byteBuf) throws PacketProcessException {
protected PacketConfigReceiveEvent(
int packetId, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetId, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
public PacketConfigReceiveEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketConfigReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketConfigReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
public PacketType.Configuration.Client getPacketType() {
@@ -25,32 +25,33 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketConfigSendEvent extends PacketSendEvent {
public PacketConfigSendEvent(Object channel, User user,
Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public PacketConfigSendEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketConfigSendEvent(int packetId, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel,
User user, Object player, Object byteBuf) throws PacketProcessException {
protected PacketConfigSendEvent(
int packetId, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetId, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
public PacketConfigSendEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketConfigSendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketConfigSendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
public PacketType.Configuration.Server getPacketType() {
@@ -25,31 +25,33 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketHandshakeReceiveEvent extends PacketReceiveEvent {
public PacketHandshakeReceiveEvent(Object channel, User user,
Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public PacketHandshakeReceiveEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketHandshakeReceiveEvent(int packetId, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel,
User user, Object player, Object byteBuf) throws PacketProcessException {
protected PacketHandshakeReceiveEvent(
int packetId, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetId, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
public PacketHandshakeReceiveEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketHandshakeReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketHandshakeReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
public PacketType.Handshaking.Client getPacketType() {
@@ -7,31 +7,33 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketHandshakeSendEvent extends PacketSendEvent {
public PacketHandshakeSendEvent(Object channel, User user,
Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public PacketHandshakeSendEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketHandshakeSendEvent(int packetId, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel,
User user, Object player, Object byteBuf) throws PacketProcessException {
protected PacketHandshakeSendEvent(
int packetId, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetId, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
public PacketHandshakeSendEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketHandshakeSendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketHandshakeSendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
public PacketType.Handshaking.Client getPacketType() {
@@ -25,31 +25,33 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketLoginReceiveEvent extends PacketReceiveEvent {
public PacketLoginReceiveEvent(Object channel, User user, Object player,
Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public PacketLoginReceiveEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketLoginReceiveEvent(int packetId, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel,
User user, Object player, Object byteBuf) throws PacketProcessException {
protected PacketLoginReceiveEvent(
int packetId, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetId, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
public PacketLoginReceiveEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketLoginReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketLoginReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
@@ -25,30 +25,33 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketLoginSendEvent extends PacketSendEvent {
public PacketLoginSendEvent(Object channel, User user, Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public PacketLoginSendEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketLoginSendEvent(int packetId, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel,
User user, Object player, Object byteBuf) throws PacketProcessException {
protected PacketLoginSendEvent(
int packetId, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetId, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
public PacketLoginSendEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketLoginSendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketLoginSendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
public PacketType.Login.Server getPacketType() {
@@ -25,31 +25,33 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketPlayReceiveEvent extends PacketReceiveEvent {
public PacketPlayReceiveEvent(Object channel, User user,
Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public PacketPlayReceiveEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketPlayReceiveEvent(int packetId, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel,
User user, Object player, Object byteBuf) throws PacketProcessException {
protected PacketPlayReceiveEvent(
int packetId, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetId, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
public PacketPlayReceiveEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketPlayReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketPlayReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
public PacketType.Play.Client getPacketType() {
@@ -25,31 +25,33 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketPlaySendEvent extends PacketSendEvent {
public PacketPlaySendEvent(Object channel, User user,
Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public PacketPlaySendEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketPlaySendEvent(int packetId, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel,
User user, Object player, Object byteBuf) throws PacketProcessException {
protected PacketPlaySendEvent(
int packetId, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetId, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
public PacketPlaySendEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketPlaySendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketPlaySendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
public PacketType.Play.Server getPacketType() {
@@ -25,31 +25,33 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketStatusReceiveEvent extends PacketReceiveEvent {
public PacketStatusReceiveEvent(Object channel, User user,
Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public PacketStatusReceiveEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketStatusReceiveEvent(int packetId, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel,
User user, Object player, Object byteBuf) throws PacketProcessException {
protected PacketStatusReceiveEvent(
int packetId, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetId, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
public PacketStatusReceiveEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketStatusReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketStatusReceiveEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
public PacketType.Status.Client getPacketType() {
@@ -25,30 +25,33 @@ import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PacketStatusSendEvent extends PacketSendEvent {
public PacketStatusSendEvent(Object channel, User user, Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
public PacketStatusSendEvent(
Object channel, User user,
@UnknownNullability Object player, Object rawByteBuf,
boolean autoProtocolTranslation
) throws PacketProcessException {
super(channel, user, player, rawByteBuf, autoProtocolTranslation);
}
protected PacketStatusSendEvent(int packetId, PacketTypeCommon packetType,
ServerVersion serverVersion,
Object channel,
User user, Object player, Object byteBuf) throws PacketProcessException {
protected PacketStatusSendEvent(
int packetId, PacketTypeCommon packetType, ServerVersion serverVersion,
Object channel, User user,
@UnknownNullability Object player, Object byteBuf
) throws PacketProcessException {
super(packetId, packetType, serverVersion, channel, user, player, byteBuf);
}
@Override
public PacketStatusSendEvent clone() {
try {
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketStatusSendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
} catch (PacketProcessException e) {
e.printStackTrace();
}
return null;
Object clonedBuffer = ByteBufHelper.retainedDuplicate(getByteBuf());
return new PacketStatusSendEvent(getPacketId(), getPacketType(), getServerVersion(),
getChannel(), getUser(), getPlayer(), clonedBuffer);
}
@@ -23,7 +23,7 @@ import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.manager.protocol.ProtocolManager;
import com.github.retrooper.packetevents.event.ProtocolPacketEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.ConnectionState;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@@ -32,6 +32,7 @@ import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.github.retrooper.packetevents.util.LogManager;
import com.github.retrooper.packetevents.util.mappings.SynchronizedRegistriesHandler;
import com.github.retrooper.packetevents.wrapper.configuration.server.WrapperConfigServerConfigurationEnd;
import com.github.retrooper.packetevents.wrapper.configuration.server.WrapperConfigServerRegistryData;
import com.github.retrooper.packetevents.wrapper.handshaking.client.WrapperHandshakingClientHandshake;
import com.github.retrooper.packetevents.wrapper.login.server.WrapperLoginServerLoginSuccess;
@@ -50,6 +51,9 @@ public class InternalPacketListener extends PacketListenerAbstract {
super(priority);
}
protected void handlePlayEnter(ProtocolPacketEvent event) {
}
@Override
public void onPacketSend(PacketSendEvent event) {
User user = event.getUser();
@@ -82,6 +86,7 @@ public class InternalPacketListener extends PacketListenerAbstract {
user.setEncoderState(ConnectionState.CONFIGURATION);
} else {
user.setConnectionState(ConnectionState.PLAY);
this.handlePlayEnter(event);
}
}
@@ -106,6 +111,7 @@ public class InternalPacketListener extends PacketListenerAbstract {
if (joinGame.getDimensionCodec() != null) { // 1.16 to 1.20.1
SynchronizedRegistriesHandler.handleLegacyRegistries(user, joinGame,
joinGame.getDimensionCodec());
user.finalizeRegistries(joinGame);
}
user.setDimensionType(joinGame.getDimensionType());
@@ -119,6 +125,8 @@ public class InternalPacketListener extends PacketListenerAbstract {
user.setEncoderState(ConnectionState.CONFIGURATION);
} else if (event.getPacketType() == PacketType.Configuration.Server.CONFIGURATION_END) {
user.setEncoderState(ConnectionState.PLAY);
user.finalizeRegistries(new WrapperConfigServerConfigurationEnd(event));
this.handlePlayEnter(event);
}
}
@@ -26,15 +26,16 @@ import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface PlayerManager {
int getPing(@NotNull Object player);
@NotNull ClientVersion getClientVersion(@NotNull Object player);
Object getChannel(@NotNull Object player);
@Nullable Object getChannel(@NotNull Object player);
User getUser(@NotNull Object player);
@Nullable User getUser(@NotNull Object player);
/**
* <strong>WARNING</strong>: Usage of this method should be avoided. Please use either
@@ -26,6 +26,7 @@ import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.util.PacketTransformationUtil;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
@@ -55,7 +56,7 @@ public interface ProtocolManager {
void writePacketSilently(Object channel, Object byteBuf);
void receivePacket(Object channel, Object byteBuf);
void receivePacketSilently(Object channel, Object byteBuf);
ClientVersion getClientVersion(Object channel);
@Nullable ClientVersion getClientVersion(Object channel);
//TODO Define method that accepts an array of channels/set/list of channels.
default void sendPackets(Object channel, Object... byteBuf) {
@@ -147,13 +148,13 @@ public interface ProtocolManager {
receivePacketsSilently(channel, transformed);
}
default User getUser(Object channel) {
default @Nullable User getUser(Object channel) {
Object pipeline = ChannelHelper.getPipeline(channel);
return USERS.get(pipeline);
}
@ApiStatus.Internal
default User removeUser(Object channel) {
default @Nullable User removeUser(Object channel) {
Object pipeline = ChannelHelper.getPipeline(channel);
return USERS.remove(pipeline);
}
@@ -167,7 +168,7 @@ public interface ProtocolManager {
PacketEvents.getAPI().getInjector().updateUser(channel, user);
}
default Object getChannel(UUID uuid) {
default @Nullable Object getChannel(UUID uuid) {
return CHANNELS.get(uuid);
}
@@ -51,7 +51,10 @@ public enum ServerVersion {
//1.20 and 1.20.1 have the same protocol version. 1.20.3 and 1.20.4 have the same protocol version. 1.20.5 and 1.20.6 have the same protocol version
V_1_20(763), V_1_20_1(763), V_1_20_2(764), V_1_20_3(765), V_1_20_4(765), V_1_20_5(766), V_1_20_6(766),
//1.21 and 1.21.1 have the same protocol version. 1.21.2 and 1.21.3 have the same protocol version. 1.21.7 and 1.21.8 have the same protocol version. 1.21.9 and 1.21.10 have the same protocol version
V_1_21(767), V_1_21_1(767), V_1_21_2(768), V_1_21_3(768), V_1_21_4(769), V_1_21_5(770), V_1_21_6(771), V_1_21_7(772), V_1_21_8(772), V_1_21_9(773), V_1_21_10(773),
V_1_21(767), V_1_21_1(767), V_1_21_2(768), V_1_21_3(768), V_1_21_4(769), V_1_21_5(770), V_1_21_6(771), V_1_21_7(772), V_1_21_8(772), V_1_21_9(773), V_1_21_10(773), V_1_21_11(774),
V_26_1(775), V_26_1_1(775), V_26_1_2(775),
V_26_2(776),
V_26_3(777),
//TODO UPDATE Add server version constant
ERROR(-1, true);
@@ -18,6 +18,8 @@
package com.github.retrooper.packetevents.manager.server;
import java.util.Locale;
/**
* System Operating system.
*
@@ -36,9 +38,9 @@ public enum SystemOS {
* @return Operating System.
*/
public static SystemOS getOSNoCache() {
final String os = System.getProperty("os.name").toLowerCase();
final String os = System.getProperty("os.name").toLowerCase(Locale.ROOT);
for (SystemOS sysos : values()) {
if (os.contains(sysos.name().toLowerCase())) {
if (os.contains(sysos.name().toLowerCase(Locale.ROOT))) {
return sysos;
}
}
@@ -18,10 +18,13 @@
package com.github.retrooper.packetevents.protocol.advancements;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.ItemStackSerialization;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
public final class AdvancementDisplay {
@@ -40,8 +43,25 @@ public final class AdvancementDisplay {
private float x;
private float y;
public AdvancementDisplay(Component title, Component description, ItemStack icon, AdvancementType type, @Nullable ResourceLocation background, boolean showToast,
boolean hidden, float x, float y) {
public AdvancementDisplay(
Component title, Component description, ItemStack icon, AdvancementType type,
@Nullable ResourceLocation background, boolean showToast, boolean hidden
) {
this.title = title;
this.description = description;
this.icon = icon;
this.type = type;
this.showToast = showToast;
this.hidden = hidden;
this.background = background;
}
@ApiStatus.Obsolete
public AdvancementDisplay(
Component title, Component description, ItemStack icon, AdvancementType type,
@Nullable ResourceLocation background, boolean showToast, boolean hidden,
float x, float y
) {
this.title = title;
this.description = description;
this.icon = icon;
@@ -56,28 +76,34 @@ public final class AdvancementDisplay {
public static AdvancementDisplay read(PacketWrapper<?> wrapper) {
Component title = wrapper.readComponent();
Component description = wrapper.readComponent();
ItemStack icon = wrapper.readItemStack();
ItemStack icon = ItemStackSerialization.readTemplate(wrapper);
AdvancementType type = wrapper.readEnum(AdvancementType.class);
int flags = wrapper.readInt();
ResourceLocation background = (flags & FLAG_HAS_BACKGROUND) != 0 ? ResourceLocation.read(wrapper) : null;
boolean showToast = (flags & FLAG_SHOW_TOAST) != 0;
boolean hidden = (flags & FLAG_HIDDEN) != 0;
float x = wrapper.readFloat();
float y = wrapper.readFloat();
float x = 0f;
float y = 0f;
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_26_3)) {
x = wrapper.readFloat();
y = wrapper.readFloat();
}
return new AdvancementDisplay(title, description, icon, type, background, showToast, hidden, x, y);
}
public static void write(PacketWrapper<?> wrapper, AdvancementDisplay display) {
wrapper.writeComponent(display.title);
wrapper.writeComponent(display.description);
wrapper.writeItemStack(display.icon);
ItemStackSerialization.writeTemplate(wrapper, display.icon);
wrapper.writeEnum(display.type);
wrapper.writeInt(display.packFlags());
if (display.background != null) {
ResourceLocation.write(wrapper, display.background);
}
wrapper.writeFloat(display.x);
wrapper.writeFloat(display.y);
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_26_3)) {
wrapper.writeFloat(display.x);
wrapper.writeFloat(display.y);
}
}
public int packFlags() {
@@ -150,18 +176,30 @@ public final class AdvancementDisplay {
this.background = background;
}
/**
* @versions -26.2
*/
public float getX() {
return this.x;
}
/**
* @versions -26.2
*/
public void setX(float x) {
this.x = x;
}
/**
* @versions -26.2
*/
public float getY() {
return this.y;
}
/**
* @versions -26.2
*/
public void setY(float y) {
this.y = y;
}
@@ -18,28 +18,70 @@
package com.github.retrooper.packetevents.protocol.advancements;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class AdvancementHolder {
private ResourceLocation identifier;
private Advancement advancement;
/**
* @versions 26.3+
*/
private float x;
/**
* @versions 26.3+
*/
private float y;
@ApiStatus.Obsolete
public AdvancementHolder(ResourceLocation identifier, Advancement advancement) {
this.identifier = identifier;
this.advancement = advancement;
// legacy compat
AdvancementDisplay display = advancement.getDisplay();
if (display != null) {
this.x = display.getX();
this.y = display.getY();
}
}
public AdvancementHolder(ResourceLocation identifier, Advancement advancement, float x, float y) {
this.identifier = identifier;
this.advancement = advancement;
this.x = x;
this.y = y;
}
public static AdvancementHolder read(PacketWrapper<?> wrapper) {
ResourceLocation identifier = wrapper.readIdentifier();
Advancement advancement = Advancement.read(wrapper);
return new AdvancementHolder(identifier, advancement);
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_26_3)) {
return new AdvancementHolder(identifier, advancement);
}
float x = wrapper.readFloat();
float y = wrapper.readFloat();
// minimal legacy compat
AdvancementDisplay display = advancement.getDisplay();
if (display != null) {
display.setX(x);
display.setY(y);
}
return new AdvancementHolder(identifier, advancement, x, y);
}
public static void write(PacketWrapper<?> wrapper, AdvancementHolder holder) {
wrapper.writeIdentifier(holder.identifier);
Advancement.write(wrapper, holder.advancement);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_3)) {
wrapper.writeFloat(holder.x);
wrapper.writeFloat(holder.y);
}
}
public ResourceLocation getIdentifier() {
@@ -57,4 +99,32 @@ public final class AdvancementHolder {
public void setAdvancement(Advancement advancement) {
this.advancement = advancement;
}
/**
* @versions 26.3+
*/
public float getX() {
return this.x;
}
/**
* @versions 26.3+
*/
public void setX(float x) {
this.x = x;
}
/**
* @versions 26.3+
*/
public float getY() {
return this.y;
}
/**
* @versions 26.3+
*/
public void setY(float y) {
this.y = y;
}
}
@@ -21,11 +21,15 @@ package com.github.retrooper.packetevents.protocol.attribute;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.util.NbtCodec;
import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.MathUtil;
public interface Attribute extends MappedEntity {
NbtCodec<Attribute> CODEC = NbtCodecs.forRegistry(Attributes.getRegistry());
@Override
default ResourceLocation getName() {
return this.getName(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
@@ -0,0 +1,70 @@
package com.github.retrooper.packetevents.protocol.attribute;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.util.NbtCodec;
import com.github.retrooper.packetevents.protocol.util.NbtCodecException;
import com.github.retrooper.packetevents.protocol.util.NbtMapCodec;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
@NullMarked
public final class AttributeEntry {
public static final NbtCodec<AttributeEntry> CODEC = new NbtMapCodec<AttributeEntry>() {
@Override
public AttributeEntry decode(NBTCompound tag, PacketWrapper<?> wrapper) throws NbtCodecException {
Attribute attribute = tag.getOrThrow("attribute", Attribute.CODEC, wrapper);
AttributeModifier modifier = AttributeModifier.MAP_CODEC.decode(tag, wrapper);
return new AttributeEntry(attribute, modifier);
}
@Override
public void encode(NBTCompound tag, PacketWrapper<?> wrapper, AttributeEntry value) throws NbtCodecException {
tag.set("attribute", value.attribute, Attribute.CODEC, wrapper);
AttributeModifier.MAP_CODEC.encode(tag, wrapper, value.modifier);
}
}.codec();
private final Attribute attribute;
private final AttributeModifier modifier;
public AttributeEntry(Attribute attribute, AttributeModifier modifier) {
this.attribute = attribute;
this.modifier = modifier;
}
public static AttributeEntry read(PacketWrapper<?> wrapper) {
Attribute attribute = wrapper.readMappedEntity(Attributes.getRegistry());
AttributeModifier modifier = AttributeModifier.read(wrapper);
return new AttributeEntry(attribute, modifier);
}
public static void write(PacketWrapper<?> wrapper, AttributeEntry entry) {
wrapper.writeMappedEntity(entry.attribute);
AttributeModifier.write(wrapper, entry.modifier);
}
public Attribute getAttribute() {
return this.attribute;
}
public AttributeModifier getModifier() {
return this.modifier;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null || this.getClass() != obj.getClass()) return false;
AttributeEntry that = (AttributeEntry) obj;
if (!this.attribute.equals(that.attribute)) return false;
return this.modifier.equals(that.modifier);
}
@Override
public int hashCode() {
return Objects.hash(this.attribute, this.modifier);
}
}
@@ -0,0 +1,136 @@
package com.github.retrooper.packetevents.protocol.attribute;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTDouble;
import com.github.retrooper.packetevents.protocol.util.NbtCodecException;
import com.github.retrooper.packetevents.protocol.util.NbtMapCodec;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
import java.util.UUID;
@NullMarked
public final class AttributeModifier {
public static final NbtMapCodec<AttributeModifier> MAP_CODEC = new NbtMapCodec<AttributeModifier>() {
@Override
public AttributeModifier decode(NBTCompound tag, PacketWrapper<?> wrapper) throws NbtCodecException {
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_21)) {
throw new NbtCodecException(wrapper.getServerVersion() + " is not supported");
}
ResourceLocation id = tag.getOrThrow("id", ResourceLocation.CODEC, wrapper);
double amount = tag.getNumberTagValueOrThrow("amount").doubleValue();
AttributeOperation operation = tag.getOrThrow("operation", AttributeOperation.CODEC, wrapper);
return new AttributeModifier(id, amount, operation);
}
@Override
public void encode(NBTCompound tag, PacketWrapper<?> wrapper, AttributeModifier value) throws NbtCodecException {
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_21)) {
throw new NbtCodecException(wrapper.getServerVersion() + " is not supported");
}
tag.set("id", value.id, ResourceLocation.CODEC, wrapper);
tag.setTag("amount", new NBTDouble(value.amount));
tag.set("operation", value.operation, AttributeOperation.CODEC, wrapper);
}
};
/**
* @versions -1.20.6
*/
@ApiStatus.Obsolete
private final UUID uniqueId;
/**
* @versions 1.21+
*/
private final ResourceLocation id;
private final double amount;
private final AttributeOperation operation;
/**
* @versions -1.20.6
*/
@ApiStatus.Obsolete
public AttributeModifier(UUID uniqueId, double amount, AttributeOperation operation) {
this.uniqueId = uniqueId;
this.id = new ResourceLocation(uniqueId.toString());
this.amount = amount;
this.operation = operation;
}
/**
* @versions 1.21+
*/
public AttributeModifier(ResourceLocation id, double amount, AttributeOperation operation) {
this.uniqueId = WrapperPlayServerUpdateAttributes.PropertyModifier.generateSemiUniqueId(id);
this.id = id;
this.amount = amount;
this.operation = operation;
}
public static AttributeModifier read(PacketWrapper<?> wrapper) {
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_21)) {
UUID uniqueId = wrapper.readUUID();
double amount = wrapper.readDouble();
AttributeOperation operation = wrapper.readEnum(AttributeOperation.values());
return new AttributeModifier(uniqueId, amount, operation);
}
ResourceLocation id = ResourceLocation.read(wrapper);
double amount = wrapper.readDouble();
AttributeOperation operation = wrapper.readEnum(AttributeOperation.values());
return new AttributeModifier(id, amount, operation);
}
public static void write(PacketWrapper<?> wrapper, AttributeModifier modifier) {
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_21)) {
wrapper.writeUUID(modifier.uniqueId);
} else {
ResourceLocation.write(wrapper, modifier.id);
}
wrapper.writeDouble(modifier.amount);
wrapper.writeEnum(modifier.operation);
}
/**
* @versions -1.20.6
*/
@ApiStatus.Obsolete
public UUID getUniqueId() {
return this.uniqueId;
}
/**
* @versions 1.12+
*/
public ResourceLocation getId() {
return this.id;
}
public double getAmount() {
return this.amount;
}
public AttributeOperation getOperation() {
return this.operation;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null || this.getClass() != obj.getClass()) return false;
AttributeModifier that = (AttributeModifier) obj;
if (Double.compare(that.amount, this.amount) != 0) return false;
if (!this.id.equals(that.id)) return false;
return this.operation == that.operation;
}
@Override
public int hashCode() {
return Objects.hash(this.id, this.amount, this.operation);
}
}
@@ -18,8 +18,29 @@
package com.github.retrooper.packetevents.protocol.attribute;
public enum AttributeOperation {
ADDITION,
MULTIPLY_BASE,
MULTIPLY_TOTAL,
import com.github.retrooper.packetevents.protocol.util.CodecNameable;
import com.github.retrooper.packetevents.protocol.util.NbtCodec;
import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
import org.jspecify.annotations.NullMarked;
@NullMarked
public enum AttributeOperation implements CodecNameable {
ADDITION("add_value"),
MULTIPLY_BASE("add_multiplied_base"),
MULTIPLY_TOTAL("add_multiplied_total"),
;
public static final NbtCodec<AttributeOperation> CODEC = NbtCodecs.forEnum(values());
private final String name;
AttributeOperation(String name) {
this.name = name;
}
@Override
public String getCodecName() {
return this.name;
}
}
@@ -203,6 +203,27 @@ public final class Attributes {
public static final Attribute WAYPOINT_RECEIVE_RANGE = define("waypoint_receive_range",
null, 0d, 0d, 60_000_000d);
/**
* @versions 26.2+
*/
public static final Attribute AIR_DRAG_MODIFIER = define("air_drag_modifier", null, 1d, 0d, 2048d);
/**
* @versions 26.2+
*/
public static final Attribute BELOW_NAME_DISTANCE = define("below_name_distance", null, 10d, 0d, 512d);
/**
* @versions 26.2+
*/
public static final Attribute BOUNCINESS = define("bounciness", null, 0d, 0d, 1d);
/**
* @versions 26.2+
*/
public static final Attribute FRICTION_MODIFIER = define("friction_modifier", null, 1d, 0d, 2048d);
/**
* @versions 26.2+
*/
public static final Attribute NAME_TAG_DISTANCE = define("name_tag_distance", null, 64d, 0d, 512d);
/**
* This attribute has been renamed in 1.20.5 to {@link #JUMP_STRENGTH}
*/
@@ -31,13 +31,15 @@ import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.util.Index;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
import static com.github.retrooper.packetevents.util.adventure.AdventureIndexUtil.indexValueOrThrow;
@NullMarked
public interface ChatType extends MappedEntity, CopyableEntity<ChatType>, DeepComparableEntity {
@UnknownNullability("only nullable for 1.19")
@@ -55,11 +55,11 @@ public final class Parsers {
return REGISTRY.define(key, data -> new Parser(data, reader, writer));
}
public static Parser getByName(String name) {
public static @Nullable Parser getByName(String name) {
return REGISTRY.getByName(name);
}
public static Parser getById(ClientVersion version, int id) {
public static @Nullable Parser getById(ClientVersion version, int id) {
return REGISTRY.getById(version, id);
}
@@ -145,6 +145,10 @@ public final class Parsers {
public static final Parser BLOCK_PREDICATE = define("block_predicate", null, null);
public static final Parser ITEM_STACK = define("item_stack", null, null);
public static final Parser ITEM_PREDICATE = define("item_predicate", null, null);
/**
* @versions -26.1.2
*/
@ApiStatus.Obsolete
public static final Parser COLOR = define("color", null, null);
public static final Parser COMPONENT = define("component", null, null);
public static final Parser STYLE = define("style", null, null);
@@ -213,7 +217,7 @@ public final class Parsers {
public static final Parser UUID = define("uuid", null, null);
/**
* Added with 1.21.5
* @versions 1.21.5+
*/
public static final Parser RESOURCE_SELECTOR = define("resource_selector",
wrapper -> Collections.singletonList(wrapper.readIdentifier()),
@@ -221,28 +225,56 @@ public final class Parsers {
);
/**
* Added with 1.21.6
* @versions 1.21.6+
*/
public static final Parser HEX_COLOR = define("hex_color", null, null);
/**
* Added with 1.21.6
* @versions 1.21.6+
*/
public static final Parser DIALOG = define("dialog", null, null);
/**
* @versions 26.2+
*/
public static final Parser TEAM_COLOR = define("team_color", null, null);
/**
* @versions 26.3+
*/
public static final Parser CONTEXT_FLOAT_PROVIDER = define("context_float_provider", null, null);
/**
* @versions 26.3+
*/
public static final Parser CONTEXT_INT_PROVIDER = define("context_int_provider", null, null);
/**
* @versions 26.3+
*/
public static final Parser SLOT_SOURCE = define("slot_source", null, null);
/**
* @versions 26.3+
*/
public static final Parser FEATURE = define("feature", null, null);
/**
* @versions 26.3+
*/
public static final Parser SWING_ANIMATION = define("swing_animation", null, null);
static {
REGISTRY.unloadMappings();
}
@FunctionalInterface
public interface Reader extends Function<PacketWrapper<?>, List<Object>> {}
public interface Reader extends Function<PacketWrapper<?>, List<Object>> {
}
@FunctionalInterface
public interface Writer extends BiConsumer<PacketWrapper<?>, List<Object>> {}
public interface Writer extends BiConsumer<PacketWrapper<?>, List<Object>> {
}
public static final class Parser extends AbstractMappedEntity {
private final Reader reader;
private final Writer writer;
private final @Nullable Reader reader;
private final @Nullable Writer writer;
@Deprecated
public Parser(String name, @Nullable Function<PacketWrapper<?>, List<Object>> read, @Nullable BiConsumer<PacketWrapper<?>, List<Object>> write) {
@@ -21,11 +21,13 @@ package com.github.retrooper.packetevents.protocol.chat;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
@NullMarked
public class StaticChatType extends AbstractMappedEntity implements ChatType {
private final @UnknownNullability("only nullable for 1.19") ChatTypeDecoration chatDecoration;
@@ -61,9 +63,9 @@ public class StaticChatType extends AbstractMappedEntity implements ChatType {
@ApiStatus.Internal
public StaticChatType(
@Nullable TypesBuilderData data,
@UnknownNullability("only nullable for 1.19") ChatTypeDecoration chatDecoration,
@Nullable ChatTypeDecoration chatDecoration,
@Nullable ChatTypeDecoration overlayDecoration,
@UnknownNullability("only nullable for 1.19") ChatTypeDecoration narrationDecoration,
@Nullable ChatTypeDecoration narrationDecoration,
@Nullable NarrationPriority narrationPriority
) {
super(data);
@@ -100,10 +102,9 @@ public class StaticChatType extends AbstractMappedEntity implements ChatType {
}
@Override
public boolean deepEquals(Object obj) {
public boolean deepEquals(@Nullable Object obj) {
if (this == obj) return true;
if (!(obj instanceof StaticChatType)) return false;
if (!super.equals(obj)) return false;
StaticChatType that = (StaticChatType) obj;
if (!Objects.equals(this.chatDecoration, that.chatDecoration)) return false;
if (!Objects.equals(this.overlayDecoration, that.overlayDecoration)) return false;
@@ -113,7 +114,7 @@ public class StaticChatType extends AbstractMappedEntity implements ChatType {
@Override
public int deepHashCode() {
return Objects.hash(super.hashCode(), this.chatDecoration, this.overlayDecoration, this.narrationDecoration, this.narrationPriority);
return Objects.hash(this.chatDecoration, this.overlayDecoration, this.narrationDecoration, this.narrationPriority);
}
@Override
@@ -22,11 +22,14 @@ import com.github.retrooper.packetevents.protocol.dialog.Dialog;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTEnd;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.adventure.AdventureSupportUtil;
import com.github.retrooper.packetevents.util.adventure.NbtTagHolder;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.event.ClickEvent.Payload;
import org.jspecify.annotations.NullMarked;
import java.util.Locale;
@NullMarked
public interface ClickEvent {
@@ -45,27 +48,27 @@ public interface ClickEvent {
ClickEventAction<?> getAction();
static ClickEvent fromAdventure(net.kyori.adventure.text.event.ClickEvent clickEvent) {
switch (clickEvent.action()) {
case OPEN_URL:
return new OpenUrlClickEvent(clickEvent.value());
case OPEN_FILE:
return new OpenFileClickEvent(clickEvent.value());
case RUN_COMMAND:
return new RunCommandClickEvent(clickEvent.value());
case SUGGEST_COMMAND:
return new SuggestCommandClickEvent(clickEvent.value());
case CHANGE_PAGE:
return new ChangePageClickEvent(clickEvent.value());
case COPY_TO_CLIPBOARD:
return new CopyToClipboardClickEvent(clickEvent.value());
case SHOW_DIALOG:
switch (clickEvent.action().name().toLowerCase(Locale.ROOT)) {
case "open_url":
return new OpenUrlClickEvent(AdventureSupportUtil.getStringValue(clickEvent));
case "open_file":
return new OpenFileClickEvent(AdventureSupportUtil.getStringValue(clickEvent));
case "run_command":
return new RunCommandClickEvent(AdventureSupportUtil.getStringValue(clickEvent));
case "suggest_command":
return new SuggestCommandClickEvent(AdventureSupportUtil.getStringValue(clickEvent));
case "change_page":
return new ChangePageClickEvent(AdventureSupportUtil.getStringValue(clickEvent));
case "copy_to_clipboard":
return new CopyToClipboardClickEvent(AdventureSupportUtil.getStringValue(clickEvent));
case "show_dialog":
return new ShowDialogClickEvent((Dialog) ((Payload.Dialog) clickEvent.payload()).dialog());
case CUSTOM:
case "custom":
Payload.Custom payload = (Payload.Custom) clickEvent.payload();
NbtTagHolder nbtTag = (NbtTagHolder) payload.nbt();
return new CustomClickEvent(
new ResourceLocation(payload.key()),
nbtTag.getTag() instanceof NBTEnd ? null : nbtTag.getTag()
nbtTag == null || nbtTag.getTag() instanceof NBTEnd ? null : nbtTag.getTag()
);
default:
throw new UnsupportedOperationException("Unsupported clickevent: " + clickEvent);
@@ -0,0 +1,40 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2022 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.chat.message.reader.impl;
import com.github.retrooper.packetevents.protocol.chat.ChatTypes;
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage;
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessageLegacy;
import com.github.retrooper.packetevents.protocol.chat.message.reader.ChatMessageProcessor;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
public class ChatMessageProcessor_v1_7 implements ChatMessageProcessor {
@Override
public ChatMessage readChatMessage(@NotNull PacketWrapper<?> wrapper) {
Component chatContent = wrapper.readComponent();
return new ChatMessageLegacy(chatContent, ChatTypes.CHAT);
}
@Override
public void writeChatMessage(@NotNull PacketWrapper<?> wrapper, @NotNull ChatMessage data) {
wrapper.writeComponent(data.getChatContent());
}
}
@@ -27,10 +27,14 @@ import com.github.retrooper.packetevents.protocol.nbt.NBTType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.MathUtil;
import org.jetbrains.annotations.Range;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class AlphaColor extends Color {
public static final AlphaColor WHITE = new AlphaColor(0xFFFFFFFF);
public static final AlphaColor BLACK = new AlphaColor(0xFF000000);
public static final AlphaColor TRANSPARENT = new AlphaColor(0x00000000);
private final int alpha;
@@ -49,7 +53,7 @@ public final class AlphaColor extends Color {
@Range(from = 0L, to = 255L) int blue
) {
super(red, green, blue);
this.alpha = alpha;
this.alpha = MathUtil.clamp(alpha, 0, 255);
}
public AlphaColor(
@@ -101,8 +105,9 @@ public final class AlphaColor extends Color {
return list;
}
public AlphaColor withAlpha(@Range(from = 0L, to = 255L) int alpha) {
return new AlphaColor(alpha, this.red, this.green, this.blue);
@Override
public AlphaColor withAlpha() {
return this;
}
@Override
@@ -125,22 +130,92 @@ public final class AlphaColor extends Color {
return (this.alpha << 24) | (this.red << 16) | (this.green << 8) | this.blue;
}
@Override
public AlphaColor plus(Color other) {
return new AlphaColor(
this.alpha,
this.red + other.red,
this.green + other.green,
this.blue + other.blue
);
}
@Override
public AlphaColor minus(Color other) {
return new AlphaColor(
this.alpha,
this.red - other.red,
this.green - other.green,
this.blue - other.blue
);
}
@Override
public AlphaColor times(Color other) {
if (other.alpha() == 255 && other.red == 255 && other.green == 255 && other.blue == 255) {
return this;
}
return new AlphaColor(
(this.alpha * other.alpha()) / 255,
(this.red * other.red) / 255,
(this.green * other.green) / 255,
(this.blue * other.blue) / 255
);
}
public AlphaColor blendWith(AlphaColor source) {
int srcAlpha = source.alpha;
if (srcAlpha == 255) {
return source;
} else if (srcAlpha == 0) {
return this;
}
int alpha = srcAlpha + (this.alpha * (255 - srcAlpha)) / 255;
return new AlphaColor(
alpha,
alphaBlendChannel(alpha, srcAlpha, this.red, source.red),
alphaBlendChannel(alpha, srcAlpha, this.green, source.green),
alphaBlendChannel(alpha, srcAlpha, this.blue, source.blue)
);
}
protected static int alphaBlendChannel(int alpha, int srcAlpha, int dest, int src) {
return (src * srcAlpha + dest * (alpha - srcAlpha)) / alpha;
}
@Override
public AlphaColor asGrayscale() {
int grayscale = (int) ((float) this.red * 0.30f + (float) this.green * 0.59f + (float) this.blue * 0.11f);
return new AlphaColor(this.alpha, grayscale, grayscale, grayscale);
}
@Override
public AlphaColor scale(float scale) {
return this.scale(scale, scale, scale);
}
@Override
public AlphaColor scale(float redScale, float greenScale, float blueScale) {
return new AlphaColor(
this.alpha,
(int) ((float) this.red * redScale),
(int) ((float) this.green * greenScale),
(int) ((float) this.blue * blueScale)
);
}
@Override
public AlphaColor lerpSrgb(Color dest, float t) {
return new AlphaColor(
MathUtil.lerp(t, this.alpha, dest.alpha()),
MathUtil.lerp(t, this.red, dest.red),
MathUtil.lerp(t, this.green, dest.green),
MathUtil.lerp(t, this.blue, dest.blue)
);
}
@Override
public @Range(from = 0L, to = 255L) int alpha() {
return this.alpha;
}
@Override
public @Range(from = 0L, to = 255L) int red() {
return this.red;
}
@Override
public @Range(from = 0L, to = 255L) int green() {
return this.green;
}
@Override
public @Range(from = 0L, to = 255L) int blue() {
return this.blue;
}
}
@@ -18,31 +18,61 @@
package com.github.retrooper.packetevents.protocol.color;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTFloat;
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
import com.github.retrooper.packetevents.protocol.nbt.NBTType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.util.NbtCodec;
import com.github.retrooper.packetevents.protocol.util.NbtCodecException;
import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
import com.github.retrooper.packetevents.util.MathUtil;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.util.RGBLike;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Range;
import org.jspecify.annotations.NullMarked;
import java.util.Arrays;
import java.util.Objects;
@NullMarked
public class Color implements RGBLike {
private static final NbtCodec<Color> INT_CODEC = NbtCodecs.INT.apply(Color::new, Color::asRGB);
private static final NbtCodec<Color> FLOATS_CODEC = NbtCodecs.FLOAT.applyFixedList(3)
.apply(floats -> new Color(floats.get(0), floats.get(1), floats.get(2)),
color -> Arrays.asList(color.red / 255f, color.green / 255f, color.blue / 255f));
public static final NbtCodec<Color> CODEC = new NbtCodec<Color>() {
private final NbtCodec<Color> decodeCodec = INT_CODEC.withAlternative(FLOATS_CODEC);
@Override
public Color decode(NBT tag, PacketWrapper<?> wrapper) throws NbtCodecException {
return this.decodeCodec.decode(tag, wrapper);
}
@Override
public NBT encode(PacketWrapper<?> wrapper, Color value) throws NbtCodecException {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2)) {
return INT_CODEC.encode(wrapper, value);
}
return FLOATS_CODEC.encode(wrapper, value);
}
};
public static final Color WHITE = new Color(0xFFFFFFFF);
public static final Color BLACK = new Color(0xFF000000);
protected static final int BIT_MASK = 0xFF;
protected final int red, green, blue;
public Color(@Range(from = 0L, to = 255L) int red, @Range(from = 0L, to = 255L) int green, @Range(from = 0L, to = 255L) int blue) {
this.red = red;
this.green = green;
this.blue = blue;
public Color(
@Range(from = 0L, to = 255L) int red,
@Range(from = 0L, to = 255L) int green,
@Range(from = 0L, to = 255L) int blue
) {
this.red = MathUtil.clamp(red, 0, 255);
this.green = MathUtil.clamp(green, 0, 255);
this.blue = MathUtil.clamp(blue, 0, 255);
}
public Color(
@@ -77,47 +107,43 @@ public class Color implements RGBLike {
wrapper.writeByte(color.blue);
}
@Deprecated
public static Color decode(NBT nbt, PacketWrapper<?> wrapper) {
return decode(nbt, wrapper.getServerVersion().toClientVersion());
return CODEC.decode(nbt, wrapper);
}
@Deprecated
public static Color decode(NBT nbt, ClientVersion version) {
if (nbt instanceof NBTNumber) {
return new Color(((NBTNumber) nbt).getAsInt());
}
NBTList<?> list = (NBTList<?>) nbt;
float red = ((NBTNumber) list.getTag(0)).getAsFloat();
float green = ((NBTNumber) list.getTag(1)).getAsFloat();
float blue = ((NBTNumber) list.getTag(2)).getAsFloat();
return new Color(red, green, blue);
return decode(nbt, PacketWrapper.createDummyWrapper(version));
}
@Deprecated
public static NBT encode(PacketWrapper<?> wrapper, Color color) {
return encode(color, wrapper.getServerVersion().toClientVersion());
return CODEC.encode(wrapper, color);
}
@Deprecated
public static NBT encode(Color color, ClientVersion version) {
if (version.isNewerThanOrEquals(ClientVersion.V_1_21_2)) {
return new NBTInt(color.asRGB());
}
NBTList<NBTFloat> list = new NBTList<>(NBTType.FLOAT, 3);
list.addTag(new NBTFloat(color.red));
list.addTag(new NBTFloat(color.green));
list.addTag(new NBTFloat(color.blue));
return list;
return encode(PacketWrapper.createDummyWrapper(version), color);
}
public @NotNull Color withRed(@Range(from = 0L, to = 255L) int red) {
public AlphaColor withAlpha() {
return this.withAlpha(255);
}
public AlphaColor withAlpha(@Range(from = 0L, to = 255L) int alpha) {
return new AlphaColor(alpha, this.red, this.green, this.blue);
}
public Color withRed(@Range(from = 0L, to = 255L) int red) {
return new Color(red, green, blue);
}
public @NotNull Color withGreen(@Range(from = 0L, to = 255L) int green) {
public Color withGreen(@Range(from = 0L, to = 255L) int green) {
return new Color(red, green, blue);
}
public @NotNull Color withBlue(@Range(from = 0L, to = 255L) int blue) {
public Color withBlue(@Range(from = 0L, to = 255L) int blue) {
return new Color(red, green, blue);
}
@@ -125,6 +151,86 @@ public class Color implements RGBLike {
return (this.red << 16) | (this.green << 8) | this.blue;
}
public Color plus(Color other) {
return new Color(
this.red + other.red,
this.green + other.green,
this.blue + other.blue
);
}
public Color minus(Color other) {
return new Color(
this.red - other.red,
this.green - other.green,
this.blue - other.blue
);
}
public Color times(Color other) {
if (other instanceof AlphaColor) {
return other.times(this);
} else if (this.red == 255 && this.green == 255 && this.blue == 255) {
return other;
} else if (other.red == 255 && other.green == 255 && other.blue == 255) {
return this;
}
return new Color(
(this.red * other.red) / 255,
(this.green * other.green) / 255,
(this.blue * other.blue) / 255
);
}
public AlphaColor blendWith(AlphaColor source) {
int srcAlpha = source.alpha();
if (srcAlpha == 255) {
return source;
} else if (srcAlpha == 0) {
return this.withAlpha();
}
int alpha = srcAlpha + (255 - srcAlpha);
return new AlphaColor(
alpha,
alphaBlendChannel(alpha, srcAlpha, this.red, source.red),
alphaBlendChannel(alpha, srcAlpha, this.green, source.green),
alphaBlendChannel(alpha, srcAlpha, this.blue, source.blue)
);
}
protected static int alphaBlendChannel(int alpha, int srcAlpha, int dest, int src) {
return (src * srcAlpha + dest * (alpha - srcAlpha)) / alpha;
}
public Color asGrayscale() {
int grayscale = (int) ((float) this.red * 0.30f + (float) this.green * 0.59f + (float) this.blue * 0.11f);
return new Color(grayscale, grayscale, grayscale);
}
public Color scale(float scale) {
return this.scale(scale, scale, scale);
}
public Color scale(float redScale, float greenScale, float blueScale) {
return new Color(
(int) ((float) this.red * redScale),
(int) ((float) this.green * greenScale),
(int) ((float) this.blue * blueScale)
);
}
public Color lerpSrgb(Color dest, float t) {
return new Color(
MathUtil.lerp(t, this.red, dest.red),
MathUtil.lerp(t, this.green, dest.green),
MathUtil.lerp(t, this.blue, dest.blue)
);
}
public @Range(from = 0L, to = 255L) int alpha() {
return 255;
}
@Override
public @Range(from = 0L, to = 255L) int red() {
return red;
@@ -139,4 +245,17 @@ public class Color implements RGBLike {
public @Range(from = 0L, to = 255L) int blue() {
return blue;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Color) {
return this.asRGB() == ((Color) obj).asRGB();
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(this.asRGB());
}
}
@@ -21,9 +21,13 @@ package com.github.retrooper.packetevents.protocol.component;
import com.github.retrooper.packetevents.protocol.color.DyeColor;
import com.github.retrooper.packetevents.protocol.component.builtin.AxolotlVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.CatCollarComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.CatSoundVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.CatVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.ChickenSoundVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.ChickenVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.CowSoundVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.CowVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.CushionColorComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.FoxVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.FrogVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.HorseVariantComponent;
@@ -31,11 +35,15 @@ import com.github.retrooper.packetevents.protocol.component.builtin.LlamaVariant
import com.github.retrooper.packetevents.protocol.component.builtin.MooshroomVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.PaintingVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.ParrotVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.PigSoundVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.PigVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.PotteryPatternComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.RabbitVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.SalmonSizeComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.SheepColorComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.ShulkerColorComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.SignTextComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.SulfurCubeContentComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.TropicalFishBaseColorComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.TropicalFishPatternColorComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.TropicalFishPatternComponent;
@@ -45,25 +53,33 @@ import com.github.retrooper.packetevents.protocol.component.builtin.VillagerVari
import com.github.retrooper.packetevents.protocol.component.builtin.WolfCollarComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.WolfSoundVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.WolfVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.ZombieNautilusVariantComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ArmorTrim;
import com.github.retrooper.packetevents.protocol.component.builtin.item.BannerLayers;
import com.github.retrooper.packetevents.protocol.component.builtin.item.BlockTransformerComponent;
import com.github.retrooper.packetevents.protocol.component.builtin.item.BundleContents;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ChargedProjectiles;
import com.github.retrooper.packetevents.protocol.component.builtin.item.CustomData;
import com.github.retrooper.packetevents.protocol.component.builtin.item.DebugStickState;
import com.github.retrooper.packetevents.protocol.component.builtin.item.FireworkExplosion;
import com.github.retrooper.packetevents.protocol.component.builtin.item.FoodProperties;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemAdditionalTradeCost;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemAdventurePredicate;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemAttackRange;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemAttributeModifiers;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemBees;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemBlockStateProperties;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemBlocksAttacks;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemBreakSound;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemBrewingFuel;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemCompostable;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemConsumable;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemContainerContents;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemContainerLoot;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemCookingFuel;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemCustomModelData;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemDamageResistant;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemDamageType;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemDeathProtection;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemDyeColor;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemEnchantable;
@@ -72,11 +88,15 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemEqu
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemFireworks;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemInstrument;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemJukeboxPlayable;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemKineticWeapon;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemLock;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemLore;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemMapDecorations;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemMapPostProcessingState;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemMinimumAttackCharge;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemMobVisibility;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemModel;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemPiercingWeapon;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemPotionContents;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemPotionDurationScale;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemProfile;
@@ -85,12 +105,16 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemPro
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemRarity;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemRecipes;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemRepairable;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemSwingAnimation;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemTool;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemTooltipDisplay;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemTooltipStyle;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemUnbreakable;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemUseCooldown;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemUseEffects;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemUseRemainder;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemVillagerFood;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemWaxed;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemWeapon;
import com.github.retrooper.packetevents.protocol.component.builtin.item.LodestoneTracker;
import com.github.retrooper.packetevents.protocol.component.builtin.item.PotDecorations;
@@ -98,7 +122,6 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.Suspici
import com.github.retrooper.packetevents.protocol.component.builtin.item.WritableBookContent;
import com.github.retrooper.packetevents.protocol.component.builtin.item.WrittenBookContent;
import com.github.retrooper.packetevents.protocol.item.instrument.Instrument;
import com.github.retrooper.packetevents.protocol.mapper.MaybeMappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
@@ -116,6 +139,7 @@ import java.util.Collection;
/**
* Contains all item data component types.
*
* @versions 1.20.5+
* @see EnchantEffectComponentTypes
*/
public final class ComponentTypes {
@@ -223,6 +247,10 @@ public final class ComponentTypes {
ItemEnchantments::read, ItemEnchantments::write);
public static final ComponentType<ItemDyeColor> DYED_COLOR = define("dyed_color",
ItemDyeColor::read, ItemDyeColor::write);
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
public static final ComponentType<Integer> MAP_COLOR = define("map_color",
PacketWrapper::readInt, PacketWrapper::writeInt);
public static final ComponentType<Integer> MAP_ID = define("map_id",
@@ -263,8 +291,7 @@ public final class ComponentTypes {
ItemInstrument::read, ItemInstrument::write);
@Deprecated
public static final ComponentType<Instrument> INSTRUMENT = ITEM_INSTRUMENT.legacyMap(
inst -> inst.getInstrument().getValue(),
inst -> new ItemInstrument(new MaybeMappedEntity<>(inst)));
inst -> inst.getInstrument().getValue(), ItemInstrument::new);
public static final ComponentType<Integer> OMINOUS_BOTTLE_AMPLIFIER = define("ominous_bottle_amplifier",
PacketWrapper::readVarInt, PacketWrapper::writeVarInt);
public static final ComponentType<ItemRecipes> RECIPES = define("recipes",
@@ -480,6 +507,110 @@ public final class ComponentTypes {
public static final ComponentType<ShulkerColorComponent> SHULKER_COLOR = define("shulker/color",
ShulkerColorComponent::read, ShulkerColorComponent::write);
/**
* @versions 1.21.11+
*/
public static final ComponentType<ItemUseEffects> USE_EFFECTS = define("use_effects",
ItemUseEffects::read, ItemUseEffects::write);
/**
* @versions 1.21.11+
*/
public static final ComponentType<ItemMinimumAttackCharge> MINIMUM_ATTACK_CHARGE = define("minimum_attack_charge",
ItemMinimumAttackCharge::read, ItemMinimumAttackCharge::write);
/**
* @versions 1.21.11+
*/
public static final ComponentType<ItemDamageType> DAMAGE_TYPE = define("damage_type",
ItemDamageType::read, ItemDamageType::write);
/**
* @versions 1.21.11+
*/
public static final ComponentType<ItemAttackRange> ATTACK_RANGE = define("attack_range",
ItemAttackRange::read, ItemAttackRange::write);
/**
* @versions 1.21.11+
*/
public static final ComponentType<ItemPiercingWeapon> PIERCING_WEAPON = define("piercing_weapon",
ItemPiercingWeapon::read, ItemPiercingWeapon::write);
/**
* @versions 1.21.11+
*/
public static final ComponentType<ItemKineticWeapon> KINETIC_WEAPON = define("kinetic_weapon",
ItemKineticWeapon::read, ItemKineticWeapon::write);
/**
* @versions 1.21.11-26.2
*/
@ApiStatus.Obsolete
public static final ComponentType<ItemSwingAnimation> SWING_ANIMATION = define("swing_animation",
ItemSwingAnimation::read, ItemSwingAnimation::write);
/**
* @versions 1.21.11+
*/
public static final ComponentType<ZombieNautilusVariantComponent> ZOMBIE_NAUTILUS_VARIANT = define("zombie_nautilus/variant",
ZombieNautilusVariantComponent::read, ZombieNautilusVariantComponent::write);
/**
* @versions 26.1+
*/
public static final ComponentType<DyeColor> DYE = define("dye", DyeColor::read, DyeColor::write);
/**
* @versions 26.1+
*/
public static final ComponentType<ItemAdditionalTradeCost> ADDITIONAL_TRADE_COST = define("additional_trade_cost",
ItemAdditionalTradeCost::read, ItemAdditionalTradeCost::write);
/**
* @versions 26.1+
*/
public static final ComponentType<CatSoundVariantComponent> CAT_SOUND_VARIANT = define("cat/sound_variant",
CatSoundVariantComponent::read, CatSoundVariantComponent::write);
/**
* @versions 26.1+
*/
public static final ComponentType<ChickenSoundVariantComponent> CHICKEN_SOUND_VARIANT = define("chicken/sound_variant",
ChickenSoundVariantComponent::read, ChickenSoundVariantComponent::write);
/**
* @versions 26.1+
*/
public static final ComponentType<CowSoundVariantComponent> COW_SOUND_VARIANT = define("cow/sound_variant",
CowSoundVariantComponent::read, CowSoundVariantComponent::write);
/**
* @versions 26.1+
*/
public static final ComponentType<PigSoundVariantComponent> PIG_SOUND_VARIANT = define("pig/sound_variant",
PigSoundVariantComponent::read, PigSoundVariantComponent::write);
/**
* @versions 26.2+
*/
public static final ComponentType<SulfurCubeContentComponent> SULFUR_CUBE_CONTENT = define("sulfur_cube_content",
SulfurCubeContentComponent::read, SulfurCubeContentComponent::write);
public static final ComponentType<ItemSwingAnimation> ATTACK_ANIMATION = define("attack_animation",
ItemSwingAnimation::read, ItemSwingAnimation::write);
public static final ComponentType<ItemSwingAnimation> INTERACT_ANIMATION = define("interact_animation",
ItemSwingAnimation::read, ItemSwingAnimation::write);
public static final ComponentType<BlockTransformerComponent> BLOCK_TRANSFORMER = define("block_transformer",
BlockTransformerComponent::read, BlockTransformerComponent::write);
public static final ComponentType<ItemVillagerFood> VILLAGER_FOOD = define("villager_food",
ItemVillagerFood::read, ItemVillagerFood::write);
public static final ComponentType<ItemCompostable> COMPOSTABLE = define("compostable",
ItemCompostable::read, ItemCompostable::write);
public static final ComponentType<ItemCookingFuel> COOKING_FUEL = define("cooking_fuel",
ItemCookingFuel::read, ItemCookingFuel::write);
public static final ComponentType<ItemBrewingFuel> BREWING_FUEL = define("brewing_fuel",
ItemBrewingFuel::read, ItemBrewingFuel::write);
public static final ComponentType<ItemMobVisibility> MOB_VISIBILITY = define("mob_visibility",
ItemMobVisibility::read, ItemMobVisibility::write);
public static final ComponentType<PotteryPatternComponent> PROVIDES_POTTERY_PATTERN = define("provides_pottery_pattern",
PotteryPatternComponent::read, PotteryPatternComponent::write);
public static final ComponentType<SignTextComponent> SIGN_TEXT_FRONT = define("sign_text_front",
SignTextComponent::read, SignTextComponent::write);
public static final ComponentType<SignTextComponent> SIGN_TEXT_BACK = define("sign_text_back",
SignTextComponent::read, SignTextComponent::write);
public static final ComponentType<ItemWaxed> WAXED = define("waxed",
ItemWaxed::read, ItemWaxed::write);
public static final ComponentType<CushionColorComponent> CUSHION_COLOR = define("cushion/color",
CushionColorComponent::read, CushionColorComponent::write);
/**
* Returns an immutable view of the component types.
*
@@ -0,0 +1,75 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2026 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.netty.buffer.UnpooledByteBufAllocationHelper;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.mappings.GlobalRegistryHolder;
import com.github.retrooper.packetevents.util.mappings.IRegistryHolder;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import java.util.Map;
import java.util.WeakHashMap;
@NullMarked
public interface ComponentValueRef<T> {
@ApiStatus.Internal
static <T> ComponentValueRef<T> ofBytes(ComponentType<T> type, byte[] bytes, ClientVersion version) {
ServerVersion serverVersion = version.toServerVersion();
return asCached(registries -> {
Object byteBuf = UnpooledByteBufAllocationHelper.wrappedBuffer(bytes);
try {
PacketWrapper<?> wrapper = PacketWrapper.createUniversalPacketWrapper(byteBuf, serverVersion);
wrapper.setRegistryHolder(registries);
return type.read(wrapper);
} finally {
ByteBufHelper.release(byteBuf);
}
});
}
static <T> ComponentValueRef<T> ofStatic(T value) {
return registries -> value;
}
static <T> ComponentValueRef<T> asCached(ComponentValueRef<T> delegate) {
return new ComponentValueRef<T>() {
// I would rather want to use a weak, concurrent, identity-based hashmap, but java doesn't
// have this datatype built-in and I don't want to write it myself
private final Map<IRegistryHolder, T> values = new WeakHashMap<>();
@Override
public synchronized T resolve(IRegistryHolder registries) {
return this.values.computeIfAbsent(registries, delegate::resolve);
}
};
}
@Deprecated
default T resolveUsingGlobals() {
return this.resolve(GlobalRegistryHolder.INSTANCE);
}
T resolve(IRegistryHolder registries);
}
@@ -113,6 +113,12 @@ public final class EnchantEffectComponentTypes {
public static ComponentType<NBT> TRIDENT_SPIN_ATTACK_STRENGTH = define("trident_spin_attack_strength",
(nbt, version) -> nbt, (val, version) -> val);
/**
* @versions 1.21.11+
*/
public static ComponentType<NBT> POST_PIERCING_ATTACK = define("post_piercing_attack",
(nbt, version) -> nbt, (val, version) -> val);
static {
REGISTRY.unloadMappings();
}
@@ -22,7 +22,9 @@ import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.mappings.IRegistry;
import com.github.retrooper.packetevents.util.mappings.IRegistryHolder;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
@@ -33,13 +35,10 @@ import java.util.Optional;
@NullMarked
public interface IComponentMap {
@SuppressWarnings("unchecked")
@ApiStatus.Internal
static StaticComponentMap decode(NBT nbt, PacketWrapper<?> wrapper, IRegistry<? extends ComponentType<?>> registry) {
return decode(nbt, wrapper.getServerVersion().toClientVersion(), registry);
}
@Deprecated
@SuppressWarnings("unchecked") // safe in this case
static StaticComponentMap decode(NBT nbt, ClientVersion version, IRegistry<? extends ComponentType<?>> registry) {
ClientVersion version = wrapper.getServerVersion().toClientVersion();
NBTCompound compound = (NBTCompound) nbt;
StaticComponentMap.Builder components = StaticComponentMap.builder();
for (Map.Entry<String, NBT> entry : compound.getTags().entrySet()) {
@@ -50,21 +49,21 @@ public interface IComponentMap {
Object value = type.decode(entry.getValue(), version);
components.set((ComponentType<? super Object>) type, value);
}
return components.build();
return components.setRegistries(wrapper.getRegistryHolder()).build();
}
@SuppressWarnings("unchecked")
@ApiStatus.Internal
static NBT encode(PacketWrapper<?> wrapper, StaticComponentMap components) {
return encode(components, wrapper.getServerVersion().toClientVersion());
}
components = components.withRegistries(wrapper.getRegistryHolder());
ClientVersion version = wrapper.getServerVersion().toClientVersion();
@Deprecated
@SuppressWarnings("unchecked") // safe in this case
static NBT encode(StaticComponentMap components, ClientVersion version) {
NBTCompound compound = new NBTCompound();
for (Map.Entry<ComponentType<?>, ?> entry : components.getDelegate().entrySet()) {
String key = entry.getKey().getName().toString();
NBT value = ((ComponentType<? super Object>) entry.getKey()).encode(entry.getValue(), version);
compound.setTag(key, value);
for (ComponentType<?> type : components.getKeys()) {
String key = type.getName().toString();
Object value = components.get(type);
NBT tag = ((ComponentType<? super Object>) type).encode(value, version);
compound.setTag(key, tag);
}
return compound;
}
@@ -99,4 +98,6 @@ public interface IComponentMap {
}
<T> void set(ComponentType<T> type, Optional<T> value);
IComponentMap withRegistries(IRegistryHolder registries);
}
@@ -18,7 +18,14 @@
package com.github.retrooper.packetevents.protocol.component;
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.util.mappings.GlobalRegistryHolder;
import com.github.retrooper.packetevents.util.mappings.IRegistryHolder;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
import java.util.Collections;
import java.util.HashMap;
@@ -26,6 +33,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@NullMarked
public class PatchableComponentMap implements IComponentMap {
public static final PatchableComponentMap EMPTY = new PatchableComponentMap(
@@ -33,43 +41,181 @@ public class PatchableComponentMap implements IComponentMap {
private final Map<ComponentType<?>, ?> base;
private final Map<ComponentType<?>, Optional<?>> patches;
private final IRegistryHolder registries;
public PatchableComponentMap(StaticComponentMap base) {
this(base.getDelegate(), new HashMap<>());
this(base.delegate, new HashMap<>(), base.registries);
}
@Deprecated
public PatchableComponentMap(Map<ComponentType<?>, ?> base) {
this(base, new HashMap<>());
this(base, new HashMap<>(), GlobalRegistryHolder.INSTANCE);
}
public PatchableComponentMap(
StaticComponentMap base,
Map<ComponentType<?>, Optional<?>> patches
) {
this(base.getDelegate(), patches);
this(base.delegate, patches, base.registries);
}
@Deprecated
public PatchableComponentMap(
Map<ComponentType<?>, ?> base,
Map<ComponentType<?>, Optional<?>> patches
) {
this.base = Collections.unmodifiableMap(new HashMap<>(base));
this.patches = patches;
this(base, patches, GlobalRegistryHolder.INSTANCE);
}
@SuppressWarnings("unchecked") // no
public PatchableComponentMap(StaticComponentMap base, IRegistryHolder registries) {
this(base.delegate, new HashMap<>(), registries);
}
public PatchableComponentMap(Map<ComponentType<?>, ?> base, IRegistryHolder registries) {
this(base, new HashMap<>(), registries);
}
public PatchableComponentMap(
StaticComponentMap base,
Map<ComponentType<?>, Optional<?>> patches,
IRegistryHolder registries
) {
this(base.delegate, patches, registries);
}
public PatchableComponentMap(
Map<ComponentType<?>, ?> base,
Map<ComponentType<?>, Optional<?>> patches,
IRegistryHolder registries
) {
this.base = Collections.unmodifiableMap(new HashMap<>(base));
this.patches = patches;
this.registries = registries;
}
public static PatchableComponentMap read(PacketWrapper<?> wrapper, ItemType item, boolean lengthPrefixed) {
return read(wrapper, item.getComponents(wrapper.getServerVersion().toClientVersion()), lengthPrefixed);
}
public static PatchableComponentMap read(PacketWrapper<?> wrapper, StaticComponentMap base, boolean lengthPrefixed) {
// read component patch counts
int presentCount = wrapper.readVarInt();
int absentCount = wrapper.readVarInt();
if (presentCount == 0 && absentCount == 0) {
return new PatchableComponentMap(base);
}
PatchableComponentMap components = new PatchableComponentMap(base,
new HashMap<>(presentCount + absentCount),
wrapper.getRegistryHolder());
for (int i = 0; i < presentCount; i++) {
ComponentType<?> type = wrapper.readMappedEntity(ComponentTypes.getRegistry());
// this is not 1:1 how vanilla decodes the length prefix, vanilla slices the buffer and
// restricts reading to only the slice; packetevents just verifies the length isn't too large
// and throws an error if we actually read more/less than expected
int expectedReaderIndex;
if (lengthPrefixed) {
int size = wrapper.readVarInt();
if (size > ByteBufHelper.readableBytes(wrapper.buffer)) {
throw new RuntimeException("Component size " + size + " for " + type.getName() + " out of bounds");
}
expectedReaderIndex = ByteBufHelper.readerIndex(wrapper.buffer) + size;
} else {
expectedReaderIndex = -1;
}
// read component value
Object value = type.read(wrapper);
// if this component is length-prefixed, verify the reader index changed to the expected value
if (expectedReaderIndex != -1) {
int readerIndex = ByteBufHelper.readerIndex(wrapper.buffer);
if (readerIndex != expectedReaderIndex) {
throw new RuntimeException("Invalid component read for " + type.getName() + "; expected reader index "
+ expectedReaderIndex + ", got reader index " + readerIndex);
}
}
// set component value in component patch-map
components.set((ComponentType<Object>) type, value);
}
for (int i = 0; i < absentCount; i++) {
components.unset(wrapper.readMappedEntity(ComponentTypes.getRegistry()));
}
return components;
}
public static void write(PacketWrapper<?> wrapper, ItemStack stack, boolean lengthPrefixed) {
if (!stack.hasComponentPatches()) {
wrapper.writeShort(0);
} else {
write(wrapper, stack.getComponents(), lengthPrefixed);
}
}
public static void write(PacketWrapper<?> wrapper, PatchableComponentMap components, boolean lengthPrefixed) {
// write component patch counts
Map<ComponentType<?>, Optional<?>> allPatches = components.getPatches();
int presentCount = 0, absentCount = 0;
for (Map.Entry<ComponentType<?>, Optional<?>> patch : allPatches.entrySet()) {
if (patch.getValue().isPresent()) {
presentCount++;
} else {
absentCount++;
}
}
wrapper.writeVarInt(presentCount);
wrapper.writeVarInt(absentCount);
// write present patches
for (Map.Entry<ComponentType<?>, Optional<?>> patch : allPatches.entrySet()) {
if (patch.getValue().isPresent()) {
wrapper.writeVarInt(patch.getKey().getId(wrapper.getServerVersion().toClientVersion()));
if (lengthPrefixed) {
// easiest solution is to just temporarily replace the buffer
Object originalBuffer = wrapper.buffer;
wrapper.buffer = ByteBufHelper.allocateNewBuffer(originalBuffer);
((ComponentType<Object>) patch.getKey()).write(wrapper, patch.getValue().get());
Object componentBuffer = wrapper.buffer;
wrapper.buffer = originalBuffer;
// after writing to new buffer, write length of newly written buffer to original buffer
wrapper.writeVarInt(ByteBufHelper.readableBytes(componentBuffer));
// copy component buffer bytes to original buffer
ByteBufHelper.writeBytes(wrapper.buffer, componentBuffer);
// release component buffer
ByteBufHelper.release(componentBuffer);
} else {
((ComponentType<Object>) patch.getKey()).write(wrapper, patch.getValue().get());
}
}
}
// write absent patches
for (Map.Entry<ComponentType<?>, Optional<?>> patch : allPatches.entrySet()) {
if (!patch.getValue().isPresent()) {
wrapper.writeVarInt(patch.getKey().getId(wrapper.getServerVersion().toClientVersion()));
}
}
}
@SuppressWarnings("unchecked")
@Override
public <T> @Nullable T get(ComponentType<T> type) {
Optional<?> patched = this.patches.get(type);
if (patched != null) {
return (T) patched.orElse(null);
Object v = patched != null
? (T) patched.orElse(null)
: (T) this.base.get(type);
if (v instanceof ComponentValueRef) {
v = ((ComponentValueRef<?>) v).resolve(this.registries);
}
return (T) this.base.get(type);
return (T) v;
}
@Override
public <T> void set(ComponentType<T> type, Optional<T> value) {
Object baseVal = this.base.get(type);
if (baseVal instanceof ComponentValueRef) {
baseVal = ((ComponentValueRef<?>) baseVal).resolve(this.registries);
}
T newVal = value.orElse(null);
if (Objects.equals(baseVal, newVal)) {
this.patches.remove(type); // fallback to base
@@ -84,14 +230,24 @@ public class PatchableComponentMap implements IComponentMap {
return patched != null ? patched.isPresent() : this.base.containsKey(type);
}
public PatchableComponentMap copy() {
return new PatchableComponentMap(this.base, new HashMap<>(this.patches));
@Override
public PatchableComponentMap withRegistries(IRegistryHolder registries) {
if (this.registries != registries) {
return new PatchableComponentMap(this.base, this.patches, this.registries);
}
return this;
}
public PatchableComponentMap copy() {
return new PatchableComponentMap(this.base, new HashMap<>(this.patches), this.registries);
}
@Deprecated
public Map<ComponentType<?>, ?> getBase() {
return this.base;
}
@Deprecated
public Map<ComponentType<?>, Optional<?>> getPatches() {
return this.patches;
}
@@ -22,16 +22,21 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemAtt
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemEnchantments;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemLore;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemRarity;
import com.github.retrooper.packetevents.util.mappings.GlobalRegistryHolder;
import com.github.retrooper.packetevents.util.mappings.IRegistryHolder;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
public class StaticComponentMap implements IComponentMap {
@NullMarked
public final class StaticComponentMap implements IComponentMap {
public static final StaticComponentMap EMPTY = new StaticComponentMap(Collections.emptyMap());
@@ -46,12 +51,19 @@ public class StaticComponentMap implements IComponentMap {
.build();
private final boolean empty;
private final Map<ComponentType<?>, ?> delegate;
final Map<ComponentType<?>, ?> delegate;
final IRegistryHolder registries;
@Deprecated
public StaticComponentMap(Map<ComponentType<?>, ?> delegate) {
this(delegate, GlobalRegistryHolder.INSTANCE);
}
public StaticComponentMap(Map<ComponentType<?>, ?> delegate, IRegistryHolder registries) {
this.empty = delegate.isEmpty();
this.delegate = this.empty ? Collections.emptyMap()
: Collections.unmodifiableMap(new HashMap<>(delegate));
this.registries = registries;
}
public static Builder builder() {
@@ -63,10 +75,14 @@ public class StaticComponentMap implements IComponentMap {
return !this.empty && this.delegate.containsKey(type);
}
@SuppressWarnings("unchecked") // no
@SuppressWarnings("unchecked")
@Override
public <T> @Nullable T get(ComponentType<T> type) {
return this.empty ? null : (T) this.delegate.get(type);
Object v = this.delegate.get(type);
if (v instanceof ComponentValueRef) {
v = ((ComponentValueRef<?>) v).resolve(this.registries);
}
return (T) v;
}
@Override
@@ -74,10 +90,23 @@ public class StaticComponentMap implements IComponentMap {
throw new UnsupportedOperationException();
}
public StaticComponentMap merge(StaticComponentMap prioritizedMap) {
return builder().setAll(this).setAll(prioritizedMap).build();
@Override
public StaticComponentMap withRegistries(IRegistryHolder registries) {
if (this.registries != registries) {
return new StaticComponentMap(this.delegate, registries);
}
return this;
}
public StaticComponentMap merge(StaticComponentMap prioritizedMap) {
return builder().setAll(this).setAll(prioritizedMap).setRegistries(this.registries).build();
}
public Set<ComponentType<?>> getKeys() {
return this.delegate.keySet();
}
@Deprecated
public Map<ComponentType<?>, ?> getDelegate() {
return this.delegate;
}
@@ -107,12 +136,18 @@ public class StaticComponentMap implements IComponentMap {
public static class Builder {
private final Map<ComponentType<?>, Object> map = new HashMap<>();
private IRegistryHolder registries = GlobalRegistryHolder.INSTANCE;
public Builder() {
}
public StaticComponentMap build() {
return new StaticComponentMap(this.map);
return new StaticComponentMap(this.map, this.registries);
}
public Builder setRegistries(IRegistryHolder registries) {
this.registries = registries;
return this;
}
public Builder setAll(StaticComponentMap.Builder map) {
@@ -120,7 +155,7 @@ public class StaticComponentMap implements IComponentMap {
}
public Builder setAll(StaticComponentMap map) {
return this.setAll(map.getDelegate());
return this.setAll(map.delegate);
}
@SuppressWarnings("unchecked")
@@ -143,5 +178,15 @@ public class StaticComponentMap implements IComponentMap {
}
return this;
}
public <T> Builder set(ComponentType<T> type, @Nullable ComponentValueRef<T> ref) {
if (ref == null) {
this.map.remove(type);
} else {
// needs special handling on get
this.map.put(type, ref);
}
return this;
}
}
}
@@ -0,0 +1,59 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin;
import com.github.retrooper.packetevents.protocol.entity.cat.CatSoundVariant;
import com.github.retrooper.packetevents.protocol.entity.cat.CatSoundVariants;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
public class CatSoundVariantComponent {
private final CatSoundVariant soundVariant;
public CatSoundVariantComponent(CatSoundVariant soundVariant) {
this.soundVariant = soundVariant;
}
public static CatSoundVariantComponent read(PacketWrapper<?> wrapper) {
CatSoundVariant type = wrapper.readMappedEntity(CatSoundVariants.getRegistry());
return new CatSoundVariantComponent(type);
}
public static void write(PacketWrapper<?> wrapper, CatSoundVariantComponent component) {
wrapper.writeMappedEntity(component.soundVariant);
}
public CatSoundVariant getSoundVariant() {
return this.soundVariant;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CatSoundVariantComponent)) return false;
CatSoundVariantComponent that = (CatSoundVariantComponent) obj;
return this.soundVariant.equals(that.soundVariant);
}
@Override
public int hashCode() {
return Objects.hashCode(this.soundVariant);
}
}
@@ -0,0 +1,59 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin;
import com.github.retrooper.packetevents.protocol.entity.chicken.ChickenSoundVariant;
import com.github.retrooper.packetevents.protocol.entity.chicken.ChickenSoundVariants;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
public class ChickenSoundVariantComponent {
private final ChickenSoundVariant soundVariant;
public ChickenSoundVariantComponent(ChickenSoundVariant soundVariant) {
this.soundVariant = soundVariant;
}
public static ChickenSoundVariantComponent read(PacketWrapper<?> wrapper) {
ChickenSoundVariant type = wrapper.readMappedEntity(ChickenSoundVariants.getRegistry());
return new ChickenSoundVariantComponent(type);
}
public static void write(PacketWrapper<?> wrapper, ChickenSoundVariantComponent component) {
wrapper.writeMappedEntity(component.soundVariant);
}
public ChickenSoundVariant getSoundVariant() {
return this.soundVariant;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ChickenSoundVariantComponent)) return false;
ChickenSoundVariantComponent that = (ChickenSoundVariantComponent) obj;
return this.soundVariant.equals(that.soundVariant);
}
@Override
public int hashCode() {
return Objects.hashCode(this.soundVariant);
}
}
@@ -18,29 +18,49 @@
package com.github.retrooper.packetevents.protocol.component.builtin;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.entity.chicken.ChickenVariant;
import com.github.retrooper.packetevents.protocol.entity.chicken.ChickenVariants;
import com.github.retrooper.packetevents.protocol.mapper.MaybeMappedEntity;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import java.util.Objects;
/**
* @versions 1.21.5+
*/
public class ChickenVariantComponent {
private MaybeMappedEntity<ChickenVariant> variant;
public ChickenVariantComponent(ChickenVariant variant) {
this(new MaybeMappedEntity<>(variant));
}
/**
* @versions 1.21.5-1.21.11
*/
@ApiStatus.Obsolete
public ChickenVariantComponent(MaybeMappedEntity<ChickenVariant> variant) {
this.variant = variant;
}
public static ChickenVariantComponent read(PacketWrapper<?> wrapper) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
return new ChickenVariantComponent(ChickenVariant.read(wrapper));
}
MaybeMappedEntity<ChickenVariant> variant = MaybeMappedEntity.read(wrapper,
ChickenVariants.getRegistry(), ChickenVariant::read);
return new ChickenVariantComponent(variant);
}
public static void write(PacketWrapper<?> wrapper, ChickenVariantComponent component) {
MaybeMappedEntity.write(wrapper, component.variant, ChickenVariant::write);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
ChickenVariant.write(wrapper, component.variant.getValueOrThrow());
} else {
MaybeMappedEntity.write(wrapper, component.variant, ChickenVariant::write);
}
}
public MaybeMappedEntity<ChickenVariant> getVariant() {
@@ -0,0 +1,59 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin;
import com.github.retrooper.packetevents.protocol.entity.cow.CowSoundVariant;
import com.github.retrooper.packetevents.protocol.entity.cow.CowSoundVariants;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
public class CowSoundVariantComponent {
private final CowSoundVariant soundVariant;
public CowSoundVariantComponent(CowSoundVariant soundVariant) {
this.soundVariant = soundVariant;
}
public static CowSoundVariantComponent read(PacketWrapper<?> wrapper) {
CowSoundVariant type = wrapper.readMappedEntity(CowSoundVariants.getRegistry());
return new CowSoundVariantComponent(type);
}
public static void write(PacketWrapper<?> wrapper, CowSoundVariantComponent component) {
wrapper.writeMappedEntity(component.soundVariant);
}
public CowSoundVariant getSoundVariant() {
return this.soundVariant;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CowSoundVariantComponent)) return false;
CowSoundVariantComponent that = (CowSoundVariantComponent) obj;
return this.soundVariant.equals(that.soundVariant);
}
@Override
public int hashCode() {
return Objects.hashCode(this.soundVariant);
}
}
@@ -0,0 +1,68 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin;
import com.github.retrooper.packetevents.protocol.color.DyeColor;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 26.3+
*/
@NullMarked
public class CushionColorComponent {
private DyeColor color;
public CushionColorComponent(DyeColor color) {
this.color = color;
}
public static CushionColorComponent read(PacketWrapper<?> wrapper) {
DyeColor type = DyeColor.read(wrapper);
return new CushionColorComponent(type);
}
public static void write(PacketWrapper<?> wrapper, CushionColorComponent component) {
DyeColor.write(wrapper, component.color);
}
public DyeColor getDyeColor() {
return this.color;
}
public void setDyeColor(DyeColor color) {
this.color = color;
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof CushionColorComponent)) return false;
CushionColorComponent that = (CushionColorComponent) obj;
return this.color.equals(that.color);
}
@Override
public int hashCode() {
return Objects.hashCode(this.color);
}
}
@@ -33,12 +33,12 @@ public class PaintingVariantComponent {
}
public static PaintingVariantComponent read(PacketWrapper<?> wrapper) {
PaintingVariant variant = wrapper.readMappedEntity(PaintingVariants.getRegistry());
PaintingVariant variant = PaintingVariant.read(wrapper);
return new PaintingVariantComponent(variant);
}
public static void write(PacketWrapper<?> wrapper, PaintingVariantComponent component) {
wrapper.writeMappedEntity(component.variant);
PaintingVariant.write(wrapper, component.variant);
}
public PaintingVariant getVariant() {
@@ -0,0 +1,59 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin;
import com.github.retrooper.packetevents.protocol.entity.pig.PigSoundVariant;
import com.github.retrooper.packetevents.protocol.entity.pig.PigSoundVariants;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
public class PigSoundVariantComponent {
private final PigSoundVariant soundVariant;
public PigSoundVariantComponent(PigSoundVariant soundVariant) {
this.soundVariant = soundVariant;
}
public static PigSoundVariantComponent read(PacketWrapper<?> wrapper) {
PigSoundVariant type = wrapper.readMappedEntity(PigSoundVariants.getRegistry());
return new PigSoundVariantComponent(type);
}
public static void write(PacketWrapper<?> wrapper, PigSoundVariantComponent component) {
wrapper.writeMappedEntity(component.soundVariant);
}
public PigSoundVariant getSoundVariant() {
return this.soundVariant;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PigSoundVariantComponent)) return false;
PigSoundVariantComponent that = (PigSoundVariantComponent) obj;
return this.soundVariant.equals(that.soundVariant);
}
@Override
public int hashCode() {
return Objects.hashCode(this.soundVariant);
}
}
@@ -0,0 +1,67 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin;
import com.github.retrooper.packetevents.protocol.world.blockentity.decopot.DecoratedPotPattern;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
/**
* @versions 26.3+
*/
@NullMarked
public class PotteryPatternComponent {
private DecoratedPotPattern pattern;
public PotteryPatternComponent(DecoratedPotPattern pattern) {
this.pattern = pattern;
}
public static PotteryPatternComponent read(PacketWrapper<?> wrapper) {
DecoratedPotPattern variant = DecoratedPotPattern.read(wrapper);
return new PotteryPatternComponent(variant);
}
public static void write(PacketWrapper<?> wrapper, PotteryPatternComponent component) {
DecoratedPotPattern.write(wrapper, component.pattern);
}
public DecoratedPotPattern getPattern() {
return this.pattern;
}
public void setPattern(DecoratedPotPattern pattern) {
this.pattern = pattern;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PotteryPatternComponent)) return false;
PotteryPatternComponent that = (PotteryPatternComponent) obj;
return this.pattern.equals(that.pattern);
}
@Override
public int hashCode() {
return Objects.hashCode(this.pattern);
}
}
@@ -0,0 +1,82 @@
package com.github.retrooper.packetevents.protocol.component.builtin;
import com.github.retrooper.packetevents.protocol.color.DyeColor;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* @versions 26.3+
*/
@NullMarked
public class SignTextComponent {
private final List<Component> messages;
private final @Nullable List<Component> filteredMessages;
private final DyeColor color;
private final boolean glowing;
public SignTextComponent(
List<Component> messages, @Nullable List<Component> filteredMessages,
DyeColor color, boolean glowing
) {
this.messages = Collections.unmodifiableList(messages);
this.filteredMessages = filteredMessages != null ? Collections.unmodifiableList(filteredMessages) : null;
this.color = color;
this.glowing = glowing;
}
public static SignTextComponent read(PacketWrapper<?> wrapper) {
List<Component> messages = wrapper.readFixedList(PacketWrapper::readComponent, 4);
List<Component> filteredMessages = wrapper.readOptional(ew ->
ew.readFixedList(PacketWrapper::readComponent, 4));
DyeColor color = DyeColor.read(wrapper);
boolean glowing = wrapper.readBoolean();
return new SignTextComponent(messages, filteredMessages, color, glowing);
}
public static void write(PacketWrapper<?> wrapper, SignTextComponent component) {
wrapper.writeFixedList(component.messages, PacketWrapper::writeComponent);
wrapper.writeOptional(component.filteredMessages, (ew, v) ->
ew.writeFixedList(v, PacketWrapper::writeComponent));
DyeColor.write(wrapper, component.color);
wrapper.writeBoolean(component.glowing);
}
public List<Component> getMessages() {
return this.messages;
}
public @Nullable List<Component> getFilteredMessages() {
return this.filteredMessages;
}
public DyeColor getColor() {
return this.color;
}
public boolean isGlowing() {
return this.glowing;
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) return true;
if (!(obj instanceof SignTextComponent)) return false;
SignTextComponent that = (SignTextComponent) obj;
if (this.glowing != that.glowing) return false;
if (!this.color.equals(that.color)) return false;
if (!this.messages.equals(that.messages)) return false;
return Objects.equals(this.filteredMessages, that.filteredMessages);
}
@Override
public int hashCode() {
return Objects.hash(this.messages, this.filteredMessages, this.color, this.glowing);
}
}
@@ -0,0 +1,51 @@
package com.github.retrooper.packetevents.protocol.component.builtin;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.ItemStackSerialization;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 26.2+
*/
@NullMarked
public class SulfurCubeContentComponent {
private ItemStack stack;
public SulfurCubeContentComponent(ItemStack stack) {
this.stack = stack;
}
public static SulfurCubeContentComponent read(PacketWrapper<?> wrapper) {
ItemStack stack = ItemStackSerialization.readTemplate(wrapper);
return new SulfurCubeContentComponent(stack);
}
public static void write(PacketWrapper<?> wrapper, SulfurCubeContentComponent component) {
ItemStackSerialization.writeTemplate(wrapper, component.stack);
}
public ItemStack getStack() {
return this.stack;
}
public void setStack(ItemStack stack) {
this.stack = stack;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null || this.getClass() != obj.getClass()) return false;
SulfurCubeContentComponent that = (SulfurCubeContentComponent) obj;
return this.stack.equals(that.stack);
}
@Override
public int hashCode() {
return Objects.hashCode(this.stack);
}
}
@@ -0,0 +1,83 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.entity.nautilus.ZombieNautilusVariant;
import com.github.retrooper.packetevents.protocol.entity.nautilus.ZombieNautilusVariants;
import com.github.retrooper.packetevents.protocol.mapper.MaybeMappedEntity;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
/**
* @versions 1.21.11+
*/
public class ZombieNautilusVariantComponent {
private MaybeMappedEntity<ZombieNautilusVariant> variant;
public ZombieNautilusVariantComponent(ZombieNautilusVariant variant) {
this(new MaybeMappedEntity<>(variant));
}
/**
* @versions 1.21.11
*/
public ZombieNautilusVariantComponent(MaybeMappedEntity<ZombieNautilusVariant> variant) {
this.variant = variant;
}
public static ZombieNautilusVariantComponent read(PacketWrapper<?> wrapper) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
return new ZombieNautilusVariantComponent(ZombieNautilusVariant.read(wrapper));
}
MaybeMappedEntity<ZombieNautilusVariant> variant = MaybeMappedEntity.read(wrapper,
ZombieNautilusVariants.getRegistry(), ZombieNautilusVariant::read);
return new ZombieNautilusVariantComponent(variant);
}
public static void write(PacketWrapper<?> wrapper, ZombieNautilusVariantComponent component) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
ZombieNautilusVariant.write(wrapper, component.variant.getValueOrThrow());
} else {
MaybeMappedEntity.write(wrapper, component.variant, ZombieNautilusVariant::write);
}
}
public MaybeMappedEntity<ZombieNautilusVariant> getVariant() {
return this.variant;
}
public void setVariant(MaybeMappedEntity<ZombieNautilusVariant> variant) {
this.variant = variant;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ZombieNautilusVariantComponent)) return false;
ZombieNautilusVariantComponent that = (ZombieNautilusVariantComponent) obj;
return this.variant.equals(that.variant);
}
@Override
public int hashCode() {
return Objects.hashCode(this.variant);
}
}
@@ -0,0 +1,45 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.item.blocktransformer.BlockTransformer;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 26.3+
*/
@NullMarked
public class BlockTransformerComponent {
private final BlockTransformer transformer;
public BlockTransformerComponent(BlockTransformer transformer) {
this.transformer = transformer;
}
public static BlockTransformerComponent read(PacketWrapper<?> wrapper) {
return new BlockTransformerComponent(BlockTransformer.read(wrapper));
}
public static void write(PacketWrapper<?> wrapper, BlockTransformerComponent transformer) {
BlockTransformer.write(wrapper, transformer.transformer);
}
public BlockTransformer getTransformer() {
return this.transformer;
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof BlockTransformerComponent)) return false;
BlockTransformerComponent that = (BlockTransformerComponent) obj;
return this.transformer.equals(that.transformer);
}
@Override
public int hashCode() {
return Objects.hashCode(this.transformer);
}
}
@@ -19,6 +19,7 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.ItemStackSerialization;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.List;
@@ -33,12 +34,12 @@ public class BundleContents {
}
public static BundleContents read(PacketWrapper<?> wrapper) {
List<ItemStack> items = wrapper.readList(PacketWrapper::readPresentItemStack);
List<ItemStack> items = wrapper.readList(ItemStackSerialization::readTemplate);
return new BundleContents(items);
}
public static void write(PacketWrapper<?> wrapper, BundleContents projectiles) {
wrapper.writeList(projectiles.items, PacketWrapper::writePresentItemStack);
wrapper.writeList(projectiles.items, ItemStackSerialization::writeTemplate);
}
public void addItem(ItemStack itemStack) {
@@ -19,6 +19,7 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.ItemStackSerialization;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.List;
@@ -33,12 +34,12 @@ public class ChargedProjectiles {
}
public static ChargedProjectiles read(PacketWrapper<?> wrapper) {
List<ItemStack> items = wrapper.readList(PacketWrapper::readPresentItemStack);
List<ItemStack> items = wrapper.readList(ItemStackSerialization::readTemplate);
return new ChargedProjectiles(items);
}
public static void write(PacketWrapper<?> wrapper, ChargedProjectiles projectiles) {
wrapper.writeList(projectiles.items, PacketWrapper::writePresentItemStack);
wrapper.writeList(projectiles.items, ItemStackSerialization::writeTemplate);
}
public void addItem(ItemStack itemStack) {
@@ -21,6 +21,7 @@ package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.util.adventure.AdventureNbtUtil;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
public class CustomData {
@@ -34,9 +35,10 @@ public class CustomData {
return (NBTCompound) nbt;
}
if (nbt instanceof NBTString) {
// TODO: parse nbt string
String nbtString = ((NBTString) nbt).getValue();
return (NBTCompound) AdventureNbtUtil.fromString(nbtString);
}
throw new UnsupportedOperationException("Unsupported custom data nbt type: " + nbt.getType());
throw new UnsupportedOperationException("Unsupported custom data tag: " + nbt);
}
public static void write(PacketWrapper<?> wrapper, NBTCompound compound) {
@@ -0,0 +1,65 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2026 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
/**
* @versions 26.1+
*/
@NullMarked
public class ItemAdditionalTradeCost {
private final int cost;
public ItemAdditionalTradeCost(int cost) {
this.cost = cost;
}
public static ItemAdditionalTradeCost read(PacketWrapper<?> wrapper) {
return new ItemAdditionalTradeCost(wrapper.readVarInt());
}
public static void write(PacketWrapper<?> wrapper, ItemAdditionalTradeCost cost) {
wrapper.writeVarInt(cost.cost);
}
public ItemAdditionalTradeCost withCost(int cost) {
return new ItemAdditionalTradeCost(cost);
}
public int getCost() {
return this.cost;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ItemAdditionalTradeCost)) return false;
ItemAdditionalTradeCost that = (ItemAdditionalTradeCost) obj;
return this.cost == that.cost;
}
@Override
public int hashCode() {
return Objects.hashCode(this.cost);
}
}
@@ -141,7 +141,7 @@ public class ItemAdventurePredicate {
public static BlockPredicate read(PacketWrapper<?> wrapper) {
MappedEntitySet<StateType.Mapped> blocks = wrapper.readOptional(
ew -> MappedEntitySet.read(ew, StateTypes::getMappedById));
ew -> MappedEntitySet.read(ew, StateTypes.getRegistry()));
List<PropertyMatcher> properties = wrapper.readOptional(
ew -> wrapper.readList(PropertyMatcher::read));
NBTCompound nbt = wrapper.readOptional(PacketWrapper::readNBT);
@@ -0,0 +1,135 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
/**
* @versions 1.21.11+
*/
@NullMarked
public class ItemAttackRange {
private float minRange;
private float maxRange;
private float minCreativeRange;
private float maxCreativeRange;
private float hitboxMargin;
private float mobFactor;
public ItemAttackRange(
float minRange, float maxRange,
float minCreativeRange, float maxCreativeRange,
float hitboxMargin, float mobFactor
) {
this.minRange = minRange;
this.maxRange = maxRange;
this.minCreativeRange = minCreativeRange;
this.maxCreativeRange = maxCreativeRange;
this.hitboxMargin = hitboxMargin;
this.mobFactor = mobFactor;
}
public static ItemAttackRange read(PacketWrapper<?> wrapper) {
float minRange = wrapper.readFloat();
float maxRange = wrapper.readFloat();
float minCreativeRange = wrapper.readFloat();
float maxCreativeRange = wrapper.readFloat();
float hitboxMargin = wrapper.readFloat();
float mobFactor = wrapper.readFloat();
return new ItemAttackRange(minRange, maxRange, minCreativeRange, maxCreativeRange, hitboxMargin, mobFactor);
}
public static void write(PacketWrapper<?> wrapper, ItemAttackRange component) {
wrapper.writeFloat(component.minRange);
wrapper.writeFloat(component.maxRange);
wrapper.writeFloat(component.minCreativeRange);
wrapper.writeFloat(component.maxCreativeRange);
wrapper.writeFloat(component.hitboxMargin);
wrapper.writeFloat(component.mobFactor);
}
public float getMinRange() {
return this.minRange;
}
public void setMinRange(float minRange) {
this.minRange = minRange;
}
public float getMaxRange() {
return this.maxRange;
}
public void setMaxRange(float maxRange) {
this.maxRange = maxRange;
}
public float getMinCreativeRange() {
return this.minCreativeRange;
}
public void setMinCreativeRange(float minCreativeRange) {
this.minCreativeRange = minCreativeRange;
}
public float getMaxCreativeRange() {
return this.maxCreativeRange;
}
public void setMaxCreativeRange(float maxCreativeRange) {
this.maxCreativeRange = maxCreativeRange;
}
public float getHitboxMargin() {
return this.hitboxMargin;
}
public void setHitboxMargin(float hitboxMargin) {
this.hitboxMargin = hitboxMargin;
}
public float getMobFactor() {
return this.mobFactor;
}
public void setMobFactor(float mobFactor) {
this.mobFactor = mobFactor;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
ItemAttackRange that = (ItemAttackRange) obj;
if (Float.compare(that.minRange, this.minRange) != 0) return false;
if (Float.compare(that.maxRange, this.maxRange) != 0) return false;
if (Float.compare(that.minCreativeRange, this.minCreativeRange) != 0) return false;
if (Float.compare(that.maxCreativeRange, this.maxCreativeRange) != 0) return false;
if (Float.compare(that.hitboxMargin, this.hitboxMargin) != 0) return false;
return Float.compare(that.mobFactor, this.mobFactor) == 0;
}
@Override
public int hashCode() {
return Objects.hash(this.minRange, this.maxRange, this.minCreativeRange, this.maxCreativeRange, this.hitboxMargin, this.mobFactor);
}
}
@@ -18,6 +18,7 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.protocol.world.damagetype.DamageType;
@@ -29,13 +30,19 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
/**
* @versions 1.21.5+
*/
public class ItemBlocksAttacks {
private float blockDelaySeconds;
private float disableCooldownScale;
private List<DamageReduction> damageReductions;
private ItemDamageFunction itemDamage;
private @Nullable ResourceLocation bypassedBy;
/**
* @versions 26.1+
*/
private @Nullable MappedEntitySet<DamageType> bypassedBy;
private @Nullable Sound blockSound;
private @Nullable Sound disableSound;
@@ -43,6 +50,19 @@ public class ItemBlocksAttacks {
float blockDelaySeconds, float disableCooldownScale, List<DamageReduction> damageReductions,
ItemDamageFunction itemDamage, @Nullable ResourceLocation bypassedBy,
@Nullable Sound blockSound, @Nullable Sound disableSound
) {
this(blockDelaySeconds, disableCooldownScale, damageReductions, itemDamage,
bypassedBy != null ? new MappedEntitySet<>(bypassedBy) : null,
blockSound, disableSound);
}
/**
* @versions 26.1+
*/
public ItemBlocksAttacks(
float blockDelaySeconds, float disableCooldownScale, List<DamageReduction> damageReductions,
ItemDamageFunction itemDamage, @Nullable MappedEntitySet<DamageType> bypassedBy,
@Nullable Sound blockSound, @Nullable Sound disableSound
) {
this.blockDelaySeconds = blockDelaySeconds;
this.disableCooldownScale = disableCooldownScale;
@@ -58,7 +78,9 @@ public class ItemBlocksAttacks {
float disableCooldownScale = wrapper.readFloat();
List<DamageReduction> damageReductions = wrapper.readList(DamageReduction::read);
ItemDamageFunction itemDamage = ItemDamageFunction.read(wrapper);
ResourceLocation bypassedBy = wrapper.readOptional(PacketWrapper::readIdentifier);
MappedEntitySet<DamageType> bypassedBy = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)
? wrapper.readOptional(ew -> MappedEntitySet.read(wrapper, DamageTypes.getRegistry()))
: wrapper.readOptional(ew -> new MappedEntitySet<>(ew.readIdentifier()));
Sound blockSound = wrapper.readOptional(Sound::read);
Sound disableSound = wrapper.readOptional(Sound::read);
return new ItemBlocksAttacks(
@@ -71,7 +93,11 @@ public class ItemBlocksAttacks {
wrapper.writeFloat(attack.disableCooldownScale);
wrapper.writeList(attack.damageReductions, DamageReduction::write);
ItemDamageFunction.write(wrapper, attack.itemDamage);
wrapper.writeOptional(attack.bypassedBy, PacketWrapper::writeIdentifier);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
wrapper.writeOptional(attack.bypassedBy, MappedEntitySet::write);
} else {
wrapper.writeOptional(attack.getBypassedBy(), PacketWrapper::writeIdentifier);
}
wrapper.writeOptional(attack.blockSound, Sound::write);
wrapper.writeOptional(attack.disableSound, Sound::write);
}
@@ -108,14 +134,28 @@ public class ItemBlocksAttacks {
this.itemDamage = itemDamage;
}
public @Nullable ResourceLocation getBypassedBy() {
/**
* @versions 26.1+
*/
public @Nullable MappedEntitySet<DamageType> getBypassedBySet() {
return this.bypassedBy;
}
public void setBypassedBy(@Nullable ResourceLocation bypassedBy) {
/**
* @versions 26.1+
*/
public void setBypassedBySet(@Nullable MappedEntitySet<DamageType> bypassedBy) {
this.bypassedBy = bypassedBy;
}
public @Nullable ResourceLocation getBypassedBy() {
return this.bypassedBy != null ? this.bypassedBy.getTagKey() : null;
}
public void setBypassedBy(@Nullable ResourceLocation bypassedBy) {
this.bypassedBy = bypassedBy != null ? new MappedEntitySet<>(bypassedBy) : null;
}
public @Nullable Sound getBlockSound() {
return this.blockSound;
}
@@ -0,0 +1,56 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.world.numbers.ResolvableFloat;
import com.github.retrooper.packetevents.protocol.world.numbers.ResolvableInt;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 26.3+
*/
@NullMarked
public class ItemBrewingFuel {
private final ResolvableInt uses;
private final ResolvableFloat speedMultiplier;
public ItemBrewingFuel(ResolvableInt uses, ResolvableFloat speedMultiplier) {
this.uses = uses;
this.speedMultiplier = speedMultiplier;
}
public static ItemBrewingFuel read(PacketWrapper<?> wrapper) {
ResolvableInt uses = ResolvableInt.read(wrapper);
ResolvableFloat speedMultiplier = ResolvableFloat.read(wrapper);
return new ItemBrewingFuel(uses, speedMultiplier);
}
public static void write(PacketWrapper<?> wrapper, ItemBrewingFuel fuel) {
ResolvableInt.write(wrapper, fuel.uses);
ResolvableFloat.write(wrapper, fuel.speedMultiplier);
}
public ResolvableInt getUses() {
return this.uses;
}
public ResolvableFloat getSpeedMultiplier() {
return this.speedMultiplier;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null || this.getClass() != obj.getClass()) return false;
ItemBrewingFuel that = (ItemBrewingFuel) obj;
if (!this.uses.equals(that.uses)) return false;
return this.speedMultiplier.equals(that.speedMultiplier);
}
@Override
public int hashCode() {
return Objects.hash(this.uses, this.speedMultiplier);
}
}
@@ -0,0 +1,46 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.world.numbers.ResolvableInt;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 26.3+
*/
@NullMarked
public class ItemCompostable {
private final ResolvableInt layers;
public ItemCompostable(ResolvableInt layers) {
this.layers = layers;
}
public static ItemCompostable read(PacketWrapper<?> wrapper) {
ResolvableInt layers = ResolvableInt.read(wrapper);
return new ItemCompostable(layers);
}
public static void write(PacketWrapper<?> wrapper, ItemCompostable compostable) {
ResolvableInt.write(wrapper, compostable.layers);
}
public ResolvableInt getLayers() {
return this.layers;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null || this.getClass() != obj.getClass()) return false;
ItemCompostable that = (ItemCompostable) obj;
return this.layers.equals(that.layers);
}
@Override
public int hashCode() {
return Objects.hashCode(this.layers);
}
}
@@ -130,15 +130,19 @@ public class ItemConsumable {
DRINK,
BLOCK,
BOW,
SPEAR,
TRIDENT,
CROSSBOW,
SPYGLASS,
TOOT_HORN,
BRUSH,
/**
* Added with 1.21.4
* @versions 1.21.4+
*/
BUNDLE,
/**
* @versions 1.21.11+
*/
SPEAR,
;
}
}
@@ -19,6 +19,7 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.ItemStackSerialization;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.List;
@@ -33,12 +34,12 @@ public class ItemContainerContents {
}
public static ItemContainerContents read(PacketWrapper<?> wrapper) {
List<ItemStack> items = wrapper.readList(PacketWrapper::readItemStack);
List<ItemStack> items = wrapper.readList(ItemStackSerialization::readOptionalTemplate);
return new ItemContainerContents(items);
}
public static void write(PacketWrapper<?> wrapper, ItemContainerContents contents) {
wrapper.writeList(contents.items, PacketWrapper::writeItemStack);
wrapper.writeList(contents.items, ItemStackSerialization::writeOptionalTemplate);
}
public void addItem(ItemStack itemStack) {
@@ -0,0 +1,56 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.world.numbers.ResolvableFloat;
import com.github.retrooper.packetevents.protocol.world.numbers.ResolvableInt;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 26.3+
*/
@NullMarked
public class ItemCookingFuel {
private final ResolvableInt burnTime;
private final ResolvableFloat speedMultiplier;
public ItemCookingFuel(ResolvableInt burnTime, ResolvableFloat speedMultiplier) {
this.burnTime = burnTime;
this.speedMultiplier = speedMultiplier;
}
public static ItemCookingFuel read(PacketWrapper<?> wrapper) {
ResolvableInt uses = ResolvableInt.read(wrapper);
ResolvableFloat speedMultiplier = ResolvableFloat.read(wrapper);
return new ItemCookingFuel(uses, speedMultiplier);
}
public static void write(PacketWrapper<?> wrapper, ItemCookingFuel fuel) {
ResolvableInt.write(wrapper, fuel.burnTime);
ResolvableFloat.write(wrapper, fuel.speedMultiplier);
}
public ResolvableInt getBurnTime() {
return this.burnTime;
}
public ResolvableFloat getSpeedMultiplier() {
return this.speedMultiplier;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null || this.getClass() != obj.getClass()) return false;
ItemCookingFuel that = (ItemCookingFuel) obj;
if (!this.burnTime.equals(that.burnTime)) return false;
return this.speedMultiplier.equals(that.speedMultiplier);
}
@Override
public int hashCode() {
return Objects.hash(this.burnTime, this.speedMultiplier);
}
}
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.ApiStatus;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Custom model data was completely rewritten with 1.21.4.
@@ -131,4 +132,25 @@ public class ItemCustomModelData {
this.floats.set(0, (float) legacyId);
}
}
@Override
public final boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemCustomModelData)) return false;
ItemCustomModelData that = (ItemCustomModelData) obj;
if (!floats.equals(that.floats)) return false;
if (!flags.equals(that.flags)) return false;
if (!strings.equals(that.strings)) return false;
return colors.equals(that.colors);
}
@Override
public int hashCode() {
return Objects.hash(this.floats, this.flags, this.strings, this.colors);
}
@Override
public String toString() {
return "ItemCustomModelData{floats=" + floats + ", flags=" + ", strings=" + flags + strings + ", colors=" + colors + '}';
}
}
@@ -18,33 +18,74 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.protocol.world.damagetype.DamageType;
import com.github.retrooper.packetevents.protocol.world.damagetype.DamageTypes;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
/**
* @versions 1.21.2+
*/
@NullMarked
public class ItemDamageResistant {
private ResourceLocation typesTagKey;
/**
* @versions 26.1+
*/
private MappedEntitySet<DamageType> types;
public ItemDamageResistant(ResourceLocation typesTagKey) {
this.typesTagKey = typesTagKey;
public ItemDamageResistant(ResourceLocation types) {
this(new MappedEntitySet<>(types));
}
public ItemDamageResistant(MappedEntitySet<DamageType> types) {
this.types = types;
}
public static ItemDamageResistant read(PacketWrapper<?> wrapper) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
return new ItemDamageResistant(MappedEntitySet.read(wrapper, DamageTypes.getRegistry()));
}
return new ItemDamageResistant(wrapper.readIdentifier());
}
public static void write(PacketWrapper<?> wrapper, ItemDamageResistant resistant) {
wrapper.writeIdentifier(resistant.typesTagKey);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
MappedEntitySet.write(wrapper, resistant.types);
} else {
wrapper.writeIdentifier(resistant.getTypesTagKey());
}
}
/**
* @versions 26.1+
*/
public MappedEntitySet<DamageType> getTypes() {
return this.types;
}
/**
* @versions 26.1+
*/
public void setTypes(MappedEntitySet<DamageType> types) {
this.types = types;
}
public ResourceLocation getTypesTagKey() {
return this.typesTagKey;
ResourceLocation tagKey = this.types.getTagKey();
if (tagKey == null) {
throw new IllegalStateException("No tag key present");
}
return tagKey;
}
public void setTypesTagKey(ResourceLocation typesTagKey) {
this.typesTagKey = typesTagKey;
public void setTypesTagKey(ResourceLocation types) {
this.types = new MappedEntitySet<>(types);
}
@Override
@@ -52,16 +93,16 @@ public class ItemDamageResistant {
if (this == obj) return true;
if (!(obj instanceof ItemDamageResistant)) return false;
ItemDamageResistant that = (ItemDamageResistant) obj;
return this.typesTagKey.equals(that.typesTagKey);
return this.types.equals(that.types);
}
@Override
public int hashCode() {
return Objects.hashCode(this.typesTagKey);
return Objects.hashCode(this.types);
}
@Override
public String toString() {
return "ItemDamageResistant{typesTagKey=" + this.typesTagKey + '}';
return "ItemDamageResistant{types=" + this.types + '}';
}
}
@@ -0,0 +1,91 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.mapper.MaybeMappedEntity;
import com.github.retrooper.packetevents.protocol.world.damagetype.DamageType;
import com.github.retrooper.packetevents.protocol.world.damagetype.DamageTypes;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
/**
* @versions 1.21.11+
*/
@NullMarked
public class ItemDamageType {
private MaybeMappedEntity<DamageType> damageType;
public ItemDamageType(DamageType damageType) {
this(new MaybeMappedEntity<>(damageType));
}
/**
* @versions 1.21.11
*/
@ApiStatus.Obsolete
public ItemDamageType(MaybeMappedEntity<DamageType> damageType) {
this.damageType = damageType;
}
public static ItemDamageType read(PacketWrapper<?> wrapper) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
return new ItemDamageType(DamageType.read(wrapper));
}
MaybeMappedEntity<DamageType> damageType = MaybeMappedEntity.read(wrapper,
DamageTypes.getRegistry(), DamageType::read);
return new ItemDamageType(damageType);
}
public static void write(PacketWrapper<?> wrapper, ItemDamageType component) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
DamageType.write(wrapper, component.damageType.getValueOrThrow());
} else {
MaybeMappedEntity.write(wrapper, component.damageType, DamageType::write);
}
}
public MaybeMappedEntity<DamageType> getDamageType() {
return this.damageType;
}
public void setDamageType(DamageType damageType) {
this.setDamageType(new MaybeMappedEntity<>(damageType));
}
public void setDamageType(MaybeMappedEntity<DamageType> damageType) {
this.damageType = damageType;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
ItemDamageType that = (ItemDamageType) obj;
return this.damageType.equals(that.damageType);
}
@Override
public int hashCode() {
return Objects.hashCode(this.damageType);
}
}
@@ -114,12 +114,12 @@ public class ItemEquippable {
}
public static ItemEquippable read(PacketWrapper<?> wrapper) {
EquipmentSlot slot = wrapper.readEnum(EquipmentSlot.values());
EquipmentSlot slot = EquipmentSlot.getByComponentId(wrapper.getServerVersion(), wrapper.readVarInt());
Sound equipSound = Sound.read(wrapper);
ResourceLocation assetId = wrapper.readOptional(PacketWrapper::readIdentifier);
ResourceLocation cameraOverlay = wrapper.readOptional(PacketWrapper::readIdentifier);
MappedEntitySet<EntityType> allowedEntities = wrapper.readOptional(
ew -> MappedEntitySet.read(ew, EntityTypes::getById));
ew -> MappedEntitySet.read(ew, EntityTypes.getRegistry()));
boolean dispensable = wrapper.readBoolean();
boolean swappable = wrapper.readBoolean();
boolean damageOnHurt = wrapper.readBoolean();
@@ -139,7 +139,7 @@ public class ItemEquippable {
}
public static void write(PacketWrapper<?> wrapper, ItemEquippable equippable) {
wrapper.writeEnum(equippable.slot);
wrapper.writeVarInt(equippable.slot.getComponentId(wrapper.getServerVersion()));
Sound.write(wrapper, equippable.equipSound);
wrapper.writeOptional(equippable.assetId, PacketWrapper::writeIdentifier);
wrapper.writeOptional(equippable.cameraOverlay, PacketWrapper::writeIdentifier);
@@ -23,32 +23,43 @@ import com.github.retrooper.packetevents.protocol.item.instrument.Instrument;
import com.github.retrooper.packetevents.protocol.item.instrument.Instruments;
import com.github.retrooper.packetevents.protocol.mapper.MaybeMappedEntity;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import java.util.Objects;
/**
* @versions 1.20.5+
*/
public class ItemInstrument {
private MaybeMappedEntity<Instrument> instrument;
public ItemInstrument(Instrument instrument) {
this(new MaybeMappedEntity<>(instrument));
}
/**
* @versions 1.21.5-1.21.11
*/
@ApiStatus.Obsolete
public ItemInstrument(MaybeMappedEntity<Instrument> instrument) {
this.instrument = instrument;
}
public static ItemInstrument read(PacketWrapper<?> wrapper) {
MaybeMappedEntity<Instrument> instrument;
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5)) {
instrument = MaybeMappedEntity.read(wrapper, Instruments.getRegistry(), Instrument::read);
} else {
instrument = new MaybeMappedEntity<>(Instrument.read(wrapper));
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)
|| wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_21_5)) {
return new ItemInstrument(Instrument.read(wrapper));
}
return new ItemInstrument(instrument);
return new ItemInstrument(MaybeMappedEntity.read(wrapper, Instruments.getRegistry(), Instrument::read));
}
public static void write(PacketWrapper<?> wrapper, ItemInstrument instrument) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5)) {
MaybeMappedEntity.write(wrapper, instrument.instrument, Instrument::write);
} else {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)
|| wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_21_5)) {
Instrument.write(wrapper, instrument.instrument.getValueOrThrow());
} else {
MaybeMappedEntity.write(wrapper, instrument.instrument, Instrument::write);
}
}
@@ -34,19 +34,29 @@ public class ItemJukeboxPlayable {
private MaybeMappedEntity<IJukeboxSong> song;
/**
* Removed in 1.21.5
* @versions 1.21-1.21.4
*/
@ApiStatus.Obsolete
private boolean showInTooltip;
public ItemJukeboxPlayable(IJukeboxSong song) {
this(new MaybeMappedEntity<>(song));
}
/**
* @versions 1.21.5-1.21.11
*/
@ApiStatus.Obsolete
public ItemJukeboxPlayable(MaybeMappedEntity<IJukeboxSong> song) {
this(song, true);
}
/**
* {@link #showInTooltip} has been removed in 1.21.5
* @versions 1.21-1.21.4
* @deprecated use {@link #ItemJukeboxPlayable(MaybeMappedEntity, boolean)}
*/
@ApiStatus.Obsolete
@Deprecated
public ItemJukeboxPlayable(
@Nullable JukeboxSong song,
@Nullable ResourceLocation songKey,
@@ -56,8 +66,10 @@ public class ItemJukeboxPlayable {
}
/**
* use {@link #ItemJukeboxPlayable(MaybeMappedEntity, boolean)}
* @versions 1.21-1.21.4
* @deprecated use {@link #ItemJukeboxPlayable(MaybeMappedEntity, boolean)}
*/
@ApiStatus.Obsolete
@Deprecated
public ItemJukeboxPlayable(
@Nullable IJukeboxSong song,
@@ -68,7 +80,7 @@ public class ItemJukeboxPlayable {
}
/**
* {@link #showInTooltip} has been removed in 1.21.5
* @versions 1.21-1.21.4
*/
@ApiStatus.Obsolete
public ItemJukeboxPlayable(
@@ -80,13 +92,20 @@ public class ItemJukeboxPlayable {
}
public static ItemJukeboxPlayable read(PacketWrapper<?> wrapper) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
return new ItemJukeboxPlayable(IJukeboxSong.read(wrapper));
}
MaybeMappedEntity<IJukeboxSong> song = MaybeMappedEntity.read(wrapper, JukeboxSongs.getRegistry(), IJukeboxSong::read);
boolean showInTooltip = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5) || wrapper.readBoolean();
return new ItemJukeboxPlayable(song, showInTooltip);
}
public static void write(PacketWrapper<?> wrapper, ItemJukeboxPlayable jukeboxPlayable) {
MaybeMappedEntity.write(wrapper, jukeboxPlayable.song, IJukeboxSong::write);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
IJukeboxSong.write(wrapper, jukeboxPlayable.song.getValueOrThrow());
} else {
MaybeMappedEntity.write(wrapper, jukeboxPlayable.song, IJukeboxSong::write);
}
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_21_5)) {
wrapper.writeBoolean(jukeboxPlayable.showInTooltip);
}
@@ -137,7 +156,7 @@ public class ItemJukeboxPlayable {
}
/**
* Removed in 1.21.5
* @versions 1.21-1.21.4
*/
@ApiStatus.Obsolete
public boolean isShowInTooltip() {
@@ -145,7 +164,7 @@ public class ItemJukeboxPlayable {
}
/**
* Removed in 1.21.5
* @versions 1.21-1.21.4
*/
@ApiStatus.Obsolete
public void setShowInTooltip(boolean showInTooltip) {
@@ -0,0 +1,243 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 1.21.11+
*/
@NullMarked
public class ItemKineticWeapon {
private int contactCooldownTicks;
private int delayTicks;
private @Nullable Condition dismountConditions;
private @Nullable Condition knockbackConditions;
private @Nullable Condition damageConditions;
private float forwardMovement;
private float damageMultiplier;
private @Nullable Sound sound;
private @Nullable Sound hitSound;
public ItemKineticWeapon(
int contactCooldownTicks, int delayTicks, @Nullable Condition dismountConditions,
@Nullable Condition knockbackConditions, @Nullable Condition damageConditions,
float forwardMovement, float damageMultiplier, @Nullable Sound sound, @Nullable Sound hitSound
) {
this.contactCooldownTicks = contactCooldownTicks;
this.delayTicks = delayTicks;
this.dismountConditions = dismountConditions;
this.knockbackConditions = knockbackConditions;
this.damageConditions = damageConditions;
this.forwardMovement = forwardMovement;
this.damageMultiplier = damageMultiplier;
this.sound = sound;
this.hitSound = hitSound;
}
public static ItemKineticWeapon read(PacketWrapper<?> wrapper) {
int contactCooldownTicks = wrapper.readVarInt();
int delayTicks = wrapper.readVarInt();
Condition dismountConditions = wrapper.readOptional(Condition::read);
Condition knockbackConditions = wrapper.readOptional(Condition::read);
Condition damageConditions = wrapper.readOptional(Condition::read);
float forwardMovement = wrapper.readFloat();
float damageMultiplier = wrapper.readFloat();
Sound sound = wrapper.readOptional(Sound::read);
Sound hitSound = wrapper.readOptional(Sound::read);
return new ItemKineticWeapon(contactCooldownTicks, delayTicks, dismountConditions,
knockbackConditions, damageConditions, forwardMovement, damageMultiplier, sound, hitSound);
}
public static void write(PacketWrapper<?> wrapper, ItemKineticWeapon component) {
wrapper.writeVarInt(component.contactCooldownTicks);
wrapper.writeVarInt(component.delayTicks);
wrapper.writeOptional(component.dismountConditions, Condition::write);
wrapper.writeOptional(component.knockbackConditions, Condition::write);
wrapper.writeOptional(component.damageConditions, Condition::write);
wrapper.writeFloat(component.forwardMovement);
wrapper.writeFloat(component.damageMultiplier);
wrapper.writeOptional(component.sound, Sound::write);
wrapper.writeOptional(component.hitSound, Sound::write);
}
public int getContactCooldownTicks() {
return this.contactCooldownTicks;
}
public void setContactCooldownTicks(int contactCooldownTicks) {
this.contactCooldownTicks = contactCooldownTicks;
}
public int getDelayTicks() {
return this.delayTicks;
}
public void setDelayTicks(int delayTicks) {
this.delayTicks = delayTicks;
}
public @Nullable Condition getDismountConditions() {
return this.dismountConditions;
}
public void setDismountConditions(@Nullable Condition dismountConditions) {
this.dismountConditions = dismountConditions;
}
public @Nullable Condition getKnockbackConditions() {
return this.knockbackConditions;
}
public void setKnockbackConditions(@Nullable Condition knockbackConditions) {
this.knockbackConditions = knockbackConditions;
}
public @Nullable Condition getDamageConditions() {
return this.damageConditions;
}
public void setDamageConditions(@Nullable Condition damageConditions) {
this.damageConditions = damageConditions;
}
public float getForwardMovement() {
return this.forwardMovement;
}
public void setForwardMovement(float forwardMovement) {
this.forwardMovement = forwardMovement;
}
public float getDamageMultiplier() {
return this.damageMultiplier;
}
public void setDamageMultiplier(float damageMultiplier) {
this.damageMultiplier = damageMultiplier;
}
public @Nullable Sound getSound() {
return this.sound;
}
public void setSound(@Nullable Sound sound) {
this.sound = sound;
}
public @Nullable Sound getHitSound() {
return this.hitSound;
}
public void setHitSound(@Nullable Sound hitSound) {
this.hitSound = hitSound;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
ItemKineticWeapon that = (ItemKineticWeapon) obj;
if (this.contactCooldownTicks != that.contactCooldownTicks) return false;
if (this.delayTicks != that.delayTicks) return false;
if (Float.compare(that.forwardMovement, this.forwardMovement) != 0) return false;
if (Float.compare(that.damageMultiplier, this.damageMultiplier) != 0) return false;
if (!Objects.equals(this.dismountConditions, that.dismountConditions)) return false;
if (!Objects.equals(this.knockbackConditions, that.knockbackConditions)) return false;
if (!Objects.equals(this.damageConditions, that.damageConditions)) return false;
if (!Objects.equals(this.sound, that.sound)) return false;
return Objects.equals(this.hitSound, that.hitSound);
}
@Override
public int hashCode() {
return Objects.hash(this.contactCooldownTicks, this.delayTicks, this.dismountConditions,
this.knockbackConditions, this.damageConditions, this.forwardMovement,
this.damageMultiplier, this.sound, this.hitSound);
}
public static class Condition {
private int maxDurationTicks;
private float minSpeed;
private float minRelativeSpeed;
public Condition(int maxDurationTicks, float minSpeed, float minRelativeSpeed) {
this.maxDurationTicks = maxDurationTicks;
this.minSpeed = minSpeed;
this.minRelativeSpeed = minRelativeSpeed;
}
public static Condition read(PacketWrapper<?> wrapper) {
int maxDurationTicks = wrapper.readVarInt();
float minSpeed = wrapper.readFloat();
float minRelativeSpeed = wrapper.readFloat();
return new Condition(maxDurationTicks, minSpeed, minRelativeSpeed);
}
public static void write(PacketWrapper<?> wrapper, Condition condition) {
wrapper.writeVarInt(condition.maxDurationTicks);
wrapper.writeFloat(condition.minSpeed);
wrapper.writeFloat(condition.minRelativeSpeed);
}
public int getMaxDurationTicks() {
return this.maxDurationTicks;
}
public void setMaxDurationTicks(int maxDurationTicks) {
this.maxDurationTicks = maxDurationTicks;
}
public float getMinSpeed() {
return this.minSpeed;
}
public void setMinSpeed(float minSpeed) {
this.minSpeed = minSpeed;
}
public float getMinRelativeSpeed() {
return this.minRelativeSpeed;
}
public void setMinRelativeSpeed(float minRelativeSpeed) {
this.minRelativeSpeed = minRelativeSpeed;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
Condition condition = (Condition) obj;
if (this.maxDurationTicks != condition.maxDurationTicks) return false;
if (Float.compare(condition.minSpeed, this.minSpeed) != 0) return false;
return Float.compare(condition.minRelativeSpeed, this.minRelativeSpeed) == 0;
}
@Override
public int hashCode() {
return Objects.hash(this.maxDurationTicks, this.minSpeed, this.minRelativeSpeed);
}
}
}
@@ -0,0 +1,65 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
/**
* @versions 1.21.11+
*/
@NullMarked
public class ItemMinimumAttackCharge {
private float value;
public ItemMinimumAttackCharge(float value) {
this.value = value;
}
public static ItemMinimumAttackCharge read(PacketWrapper<?> wrapper) {
return new ItemMinimumAttackCharge(wrapper.readFloat());
}
public static void write(PacketWrapper<?> wrapper, ItemMinimumAttackCharge component) {
wrapper.writeFloat(component.value);
}
public float getValue() {
return this.value;
}
public void setValue(float value) {
this.value = value;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
ItemMinimumAttackCharge that = (ItemMinimumAttackCharge) obj;
return Float.compare(that.value, this.value) == 0;
}
@Override
public int hashCode() {
return Objects.hashCode(this.value);
}
}
@@ -0,0 +1,57 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 26.3+
*/
@NullMarked
public class ItemMobVisibility {
private final MappedEntitySet<EntityType> targetingEntityTypes;
private final float visibility;
public ItemMobVisibility(MappedEntitySet<EntityType> targetingEntityTypes, float visibility) {
this.targetingEntityTypes = targetingEntityTypes;
this.visibility = visibility;
}
public static ItemMobVisibility read(PacketWrapper<?> wrapper) {
MappedEntitySet<EntityType> targetingEntityTypes = MappedEntitySet.read(wrapper, EntityTypes.getRegistry());
float visibility = wrapper.readFloat();
return new ItemMobVisibility(targetingEntityTypes, visibility);
}
public static void write(PacketWrapper<?> wrapper, ItemMobVisibility visibility) {
MappedEntitySet.write(wrapper, visibility.targetingEntityTypes);
wrapper.writeFloat(visibility.visibility);
}
public MappedEntitySet<EntityType> getTargetingEntityTypes() {
return this.targetingEntityTypes;
}
public float getVisibility() {
return this.visibility;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
ItemMobVisibility that = (ItemMobVisibility) obj;
if (Float.compare(that.visibility, this.visibility) != 0) return false;
return this.targetingEntityTypes.equals(that.targetingEntityTypes);
}
@Override
public int hashCode() {
return Objects.hash(this.targetingEntityTypes, this.visibility);
}
}
@@ -0,0 +1,110 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 1.21.11+
*/
@NullMarked
public class ItemPiercingWeapon {
private boolean dealsKnockback;
private boolean dismounts;
private @Nullable Sound sound;
private @Nullable Sound hitSound;
public ItemPiercingWeapon(
boolean dealsKnockback, boolean dismounts,
@Nullable Sound sound, @Nullable Sound hitSound
) {
this.dealsKnockback = dealsKnockback;
this.dismounts = dismounts;
this.sound = sound;
this.hitSound = hitSound;
}
public static ItemPiercingWeapon read(PacketWrapper<?> wrapper) {
boolean dealsKnockback = wrapper.readBoolean();
boolean dismounts = wrapper.readBoolean();
Sound sound = wrapper.readOptional(Sound::read);
Sound hitSound = wrapper.readOptional(Sound::read);
return new ItemPiercingWeapon(dealsKnockback, dismounts, sound, hitSound);
}
public static void write(PacketWrapper<?> wrapper, ItemPiercingWeapon component) {
wrapper.writeBoolean(component.dealsKnockback);
wrapper.writeBoolean(component.dismounts);
wrapper.writeOptional(component.sound, Sound::write);
wrapper.writeOptional(component.hitSound, Sound::write);
}
public boolean isDealsKnockback() {
return this.dealsKnockback;
}
public void setDealsKnockback(boolean dealsKnockback) {
this.dealsKnockback = dealsKnockback;
}
public boolean isDismounts() {
return this.dismounts;
}
public void setDismounts(boolean dismounts) {
this.dismounts = dismounts;
}
public @Nullable Sound getSound() {
return this.sound;
}
public void setSound(@Nullable Sound sound) {
this.sound = sound;
}
public @Nullable Sound getHitSound() {
return this.hitSound;
}
public void setHitSound(@Nullable Sound hitSound) {
this.hitSound = hitSound;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
ItemPiercingWeapon that = (ItemPiercingWeapon) obj;
if (this.dealsKnockback != that.dealsKnockback) return false;
if (this.dismounts != that.dismounts) return false;
if (!Objects.equals(this.sound, that.sound)) return false;
return Objects.equals(this.hitSound, that.hitSound);
}
@Override
public int hashCode() {
return Objects.hash(this.dealsKnockback, this.dismounts, this.sound, this.hitSound);
}
}
@@ -24,7 +24,9 @@ import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.protocol.player.PlayerModelType;
import com.github.retrooper.packetevents.protocol.util.NbtCodec;
import com.github.retrooper.packetevents.protocol.util.NbtCodecException;
import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
import com.github.retrooper.packetevents.protocol.util.NbtMapCodec;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.object.PlayerHeadObjectContents;
@@ -220,10 +222,9 @@ public final class ItemProfile {
public static class Property {
public static final NbtCodec<Property> CODEC = new NbtCodec<ItemProfile.Property>() {
public static final NbtCodec<Property> CODEC = new NbtMapCodec<Property>() {
@Override
public ItemProfile.Property decode(NBT nbt, PacketWrapper<?> wrapper) {
NBTCompound compound = (NBTCompound) nbt;
public Property decode(NBTCompound compound, PacketWrapper<?> wrapper) throws NbtCodecException {
String name = compound.getStringTagValueOrThrow("name");
String value = compound.getStringTagValueOrThrow("value");
String signature = compound.getStringTagValueOrNull("signature");
@@ -231,16 +232,14 @@ public final class ItemProfile {
}
@Override
public NBT encode(PacketWrapper<?> wrapper, ItemProfile.Property value) {
NBTCompound compound = new NBTCompound();
public void encode(NBTCompound compound, PacketWrapper<?> wrapper, Property value) throws NbtCodecException {
compound.setTag("name", new NBTString(value.getName()));
compound.setTag("value", new NBTString(value.getValue()));
if (value.getSignature() != null) {
compound.setTag("signature", new NBTString(value.getSignature()));
}
return compound;
}
};
}.codec();
public static final NbtCodec<List<ItemProfile.Property>> PROPERTY_MAP = new NbtCodec<List<ItemProfile.Property>>() {
private final NbtCodec<List<ItemProfile.Property>> propertyList = CODEC.applyList();
@@ -18,45 +18,90 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.item.banner.BannerPattern;
import com.github.retrooper.packetevents.protocol.item.banner.BannerPatterns;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
/**
* @versions 1.21.5+
*/
@NullMarked
public class ItemProvidesBannerPatterns {
private ResourceLocation tagKey;
/**
* @versions 26.1+
*/
private MappedEntitySet<BannerPattern> set;
/**
* @versions 26.1+
*/
public ItemProvidesBannerPatterns(MappedEntitySet<BannerPattern> set) {
this.set = set;
}
public ItemProvidesBannerPatterns(ResourceLocation tagKey) {
this.tagKey = tagKey;
this(new MappedEntitySet<>(tagKey));
}
public static ItemProvidesBannerPatterns read(PacketWrapper<?> wrapper) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
MappedEntitySet<BannerPattern> set = MappedEntitySet.read(wrapper, BannerPatterns.getRegistry());
return new ItemProvidesBannerPatterns(set);
}
ResourceLocation tagKey = wrapper.readIdentifier();
return new ItemProvidesBannerPatterns(tagKey);
}
public static void write(PacketWrapper<?> wrapper, ItemProvidesBannerPatterns patterns) {
wrapper.writeIdentifier(patterns.tagKey);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
MappedEntitySet.write(wrapper, patterns.set);
} else {
wrapper.writeIdentifier(patterns.getTagKey());
}
}
/**
* @versions 26.1+
*/
public MappedEntitySet<BannerPattern> getSet() {
return this.set;
}
/**
* @versions 26.1+
*/
public void setSet(MappedEntitySet<BannerPattern> set) {
this.set = set;
}
public ResourceLocation getTagKey() {
return this.tagKey;
ResourceLocation tagKey = this.set.getTagKey();
if (tagKey == null) {
throw new IllegalStateException("No tag key present");
}
return tagKey;
}
public void setTagKey(ResourceLocation tagKey) {
this.tagKey = tagKey;
this.set = new MappedEntitySet<>(tagKey);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ItemProvidesBannerPatterns)) return false;
ItemProvidesBannerPatterns that = (ItemProvidesBannerPatterns) obj;
return this.tagKey.equals(that.tagKey);
return this.set.equals(that.set);
}
@Override
public int hashCode() {
return Objects.hashCode(this.tagKey);
return Objects.hashCode(this.set);
}
}
@@ -18,28 +18,48 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.item.trimmaterial.TrimMaterial;
import com.github.retrooper.packetevents.protocol.item.trimmaterial.TrimMaterials;
import com.github.retrooper.packetevents.protocol.mapper.MaybeMappedEntity;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import java.util.Objects;
/**
* @versions 1.21.5+
*/
public class ItemProvidesTrimMaterial {
private MaybeMappedEntity<TrimMaterial> material;
public ItemProvidesTrimMaterial(TrimMaterial material) {
this(new MaybeMappedEntity<>(material));
}
/**
* @versions 1.21.5-1.21.11
*/
@ApiStatus.Obsolete
public ItemProvidesTrimMaterial(MaybeMappedEntity<TrimMaterial> material) {
this.material = material;
}
public static ItemProvidesTrimMaterial read(PacketWrapper<?> wrapper) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
return new ItemProvidesTrimMaterial(TrimMaterial.read(wrapper));
}
MaybeMappedEntity<TrimMaterial> material = MaybeMappedEntity.read(wrapper, TrimMaterials.getRegistry(), TrimMaterial::read);
return new ItemProvidesTrimMaterial(material);
}
public static void write(PacketWrapper<?> wrapper, ItemProvidesTrimMaterial material) {
MaybeMappedEntity.write(wrapper, material.material, TrimMaterial::write);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_1)) {
TrimMaterial.write(wrapper, material.material.getValueOrThrow());
} else {
MaybeMappedEntity.write(wrapper, material.material, TrimMaterial::write);
}
}
public MaybeMappedEntity<TrimMaterial> getMaterial() {
@@ -0,0 +1,88 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 1.21.11+
*/
@NullMarked
public class ItemSwingAnimation {
private static final Type[] TYPES = Type.values();
private Type type;
private int duration;
public ItemSwingAnimation(Type type, int duration) {
this.type = type;
this.duration = duration;
}
public static ItemSwingAnimation read(PacketWrapper<?> wrapper) {
Type type = wrapper.readEnum(TYPES, Type.NONE);
int duration = wrapper.readVarInt();
return new ItemSwingAnimation(type, duration);
}
public static void write(PacketWrapper<?> wrapper, ItemSwingAnimation component) {
wrapper.writeEnum(component.type);
wrapper.writeVarInt(component.duration);
}
public Type getType() {
return this.type;
}
public void setType(Type type) {
this.type = type;
}
public int getDuration() {
return this.duration;
}
public void setDuration(int duration) {
this.duration = duration;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
ItemSwingAnimation that = (ItemSwingAnimation) obj;
if (this.duration != that.duration) return false;
return this.type == that.type;
}
@Override
public int hashCode() {
return Objects.hash(this.type, this.duration);
}
public enum Type {
NONE,
WHACK,
STAB,
}
}
@@ -141,7 +141,7 @@ public class ItemTool {
}
public static Rule read(PacketWrapper<?> wrapper) {
MappedEntitySet<StateType.Mapped> blocks = MappedEntitySet.read(wrapper, StateTypes::getMappedById);
MappedEntitySet<StateType.Mapped> blocks = MappedEntitySet.read(wrapper, StateTypes.getRegistry());
Float speed = wrapper.readOptional(PacketWrapper::readFloat);
Boolean correctForDrops = wrapper.readOptional(PacketWrapper::readBoolean);
return new Rule(blocks, speed, correctForDrops);
@@ -0,0 +1,92 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2025 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
/**
* @versions 1.21.11+
*/
@NullMarked
public class ItemUseEffects {
private boolean canSprint;
private boolean interactVibrations;
private float speedMultiplier;
public ItemUseEffects(boolean canSprint, boolean interactVibrations, float speedMultiplier) {
this.canSprint = canSprint;
this.interactVibrations = interactVibrations;
this.speedMultiplier = speedMultiplier;
}
public static ItemUseEffects read(PacketWrapper<?> wrapper) {
boolean canSprint = wrapper.readBoolean();
boolean interactVibrations = wrapper.readBoolean();
float speedMultiplier = wrapper.readFloat();
return new ItemUseEffects(canSprint, interactVibrations, speedMultiplier);
}
public static void write(PacketWrapper<?> wrapper, ItemUseEffects component) {
wrapper.writeBoolean(component.canSprint);
wrapper.writeBoolean(component.interactVibrations);
wrapper.writeFloat(component.speedMultiplier);
}
public boolean isCanSprint() {
return this.canSprint;
}
public void setCanSprint(boolean canSprint) {
this.canSprint = canSprint;
}
public boolean isInteractVibrations() {
return this.interactVibrations;
}
public void setInteractVibrations(boolean interactVibrations) {
this.interactVibrations = interactVibrations;
}
public float getSpeedMultiplier() {
return this.speedMultiplier;
}
public void setSpeedMultiplier(float speedMultiplier) {
this.speedMultiplier = speedMultiplier;
}
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
ItemUseEffects that = (ItemUseEffects) obj;
if (this.canSprint != that.canSprint) return false;
if (this.interactVibrations != that.interactVibrations) return false;
return Float.compare(that.speedMultiplier, this.speedMultiplier) == 0;
}
@Override
public int hashCode() {
return Objects.hash(this.canSprint, this.interactVibrations, this.speedMultiplier);
}
}
@@ -19,6 +19,7 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.ItemStackSerialization;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
@@ -32,12 +33,12 @@ public class ItemUseRemainder {
}
public static ItemUseRemainder read(PacketWrapper<?> wrapper) {
ItemStack target = wrapper.readItemStack();
ItemStack target = ItemStackSerialization.readTemplate(wrapper);
return new ItemUseRemainder(target);
}
public static void write(PacketWrapper<?> wrapper, ItemUseRemainder remainder) {
wrapper.writeItemStack(remainder.target);
ItemStackSerialization.writeTemplate(wrapper, remainder.target);
}
public ItemStack getTarget() {
@@ -0,0 +1,45 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
/**
* @versions 26.3+
*/
@NullMarked
public class ItemVillagerFood {
private final int nutrition;
public ItemVillagerFood(int nutrition) {
this.nutrition = nutrition;
}
public static ItemVillagerFood read(PacketWrapper<?> wrapper) {
int nutrition = wrapper.readVarInt();
return new ItemVillagerFood(nutrition);
}
public static void write(PacketWrapper<?> wrapper, ItemVillagerFood food) {
wrapper.writeVarInt(food.nutrition);
}
public int getNutrition() {
return this.nutrition;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null || this.getClass() != obj.getClass()) return false;
ItemVillagerFood that = (ItemVillagerFood) obj;
return this.nutrition == that.nutrition;
}
@Override
public int hashCode() {
return Objects.hashCode(this.nutrition);
}
}
@@ -0,0 +1,24 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
/**
* @versions 26.3+
*/
@NullMarked
public final class ItemWaxed {
public static final ItemWaxed INSTANCE = new ItemWaxed();
private ItemWaxed() {
}
public static ItemWaxed read(PacketWrapper<?> wrapper) {
return INSTANCE;
}
public static void write(PacketWrapper<?> wrapper, ItemWaxed waxed) {
// no-op
}
}
@@ -18,9 +18,13 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.ItemStackSerialization;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayDeque;
@@ -30,13 +34,20 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Queue;
/**
* @versions 1.20.5+
*/
public class PotDecorations {
private @Nullable ItemType back;
private @Nullable ItemType left;
private @Nullable ItemType right;
private @Nullable ItemType front;
private @Nullable ItemStack back;
private @Nullable ItemStack left;
private @Nullable ItemStack right;
private @Nullable ItemStack front;
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
private PotDecorations(Queue<Optional<ItemType>> items) {
this(
items.isEmpty() ? null : items.remove().orElse(null),
@@ -46,11 +57,32 @@ public class PotDecorations {
);
}
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
public PotDecorations(
@Nullable ItemType back,
@Nullable ItemType left,
@Nullable ItemType right,
@Nullable ItemType front
) {
this(
back != null ? ItemStack.builder().type(back).build() : null,
left != null ? ItemStack.builder().type(left).build() : null,
right != null ? ItemStack.builder().type(right).build() : null,
front != null ? ItemStack.builder().type(front).build() : null
);
}
/**
* @versions 26.3+
*/
public PotDecorations(
@Nullable ItemStack back,
@Nullable ItemStack left,
@Nullable ItemStack right,
@Nullable ItemStack front
) {
this.back = back;
this.left = left;
@@ -58,66 +90,167 @@ public class PotDecorations {
this.front = front;
}
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
private List<Optional<ItemType>> asList() {
return Arrays.asList(
Optional.ofNullable(this.back),
Optional.ofNullable(this.left),
Optional.ofNullable(this.right),
Optional.ofNullable(this.front)
Optional.ofNullable(this.back).map(ItemStack::getType),
Optional.ofNullable(this.left).map(ItemStack::getType),
Optional.ofNullable(this.right).map(ItemStack::getType),
Optional.ofNullable(this.front).map(ItemStack::getType)
);
}
private static Optional<ItemType> readItem(PacketWrapper<?> wrapper) {
ItemType type = wrapper.readMappedEntity(ItemTypes::getById);
return type == ItemTypes.BRICK ? Optional.empty() : Optional.of(type);
}
public static PotDecorations read(PacketWrapper<?> wrapper) {
Queue<Optional<ItemType>> items = wrapper.<Optional<ItemType>, Queue<Optional<ItemType>>>
readCollection(ArrayDeque::new, PotDecorations::readItem);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_3)) {
return new PotDecorations(
wrapper.readOptional(ItemStackSerialization::readTemplate),
wrapper.readOptional(ItemStackSerialization::readTemplate),
wrapper.readOptional(ItemStackSerialization::readTemplate),
wrapper.readOptional(ItemStackSerialization::readTemplate)
);
}
Queue<Optional<ItemType>> items = wrapper.readCollection(ArrayDeque::new, ew -> {
ItemType type = wrapper.readMappedEntity(ItemTypes.getRegistry());
return type == ItemTypes.BRICK ? Optional.empty() : Optional.of(type);
});
return new PotDecorations(items);
}
private static void writeItem(PacketWrapper<?> wrapper, Optional<ItemType> type) {
wrapper.writeMappedEntity(type.orElse(ItemTypes.BRICK));
}
public static void write(PacketWrapper<?> wrapper, PotDecorations decorations) {
wrapper.writeList(decorations.asList(), PotDecorations::writeItem);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_26_3)) {
wrapper.writeOptional(decorations.back, ItemStackSerialization::writeTemplate);
wrapper.writeOptional(decorations.left, ItemStackSerialization::writeTemplate);
wrapper.writeOptional(decorations.right, ItemStackSerialization::writeTemplate);
wrapper.writeOptional(decorations.front, ItemStackSerialization::writeTemplate);
} else {
wrapper.writeList(decorations.asList(), (ew, type) ->
ew.writeMappedEntity(type.orElse(ItemTypes.BRICK)));
}
}
public @Nullable ItemType getBack() {
/**
* @versions 26.3+
*/
public @Nullable ItemStack getBackStack() {
return this.back;
}
public void setBack(@Nullable ItemType back) {
/**
* @versions 26.3+
*/
public void setBackStack(@Nullable ItemStack back) {
this.back = back;
}
public @Nullable ItemType getLeft() {
/**
* @versions 26.3+
*/
public @Nullable ItemStack getLeftStack() {
return this.left;
}
public void setLeft(@Nullable ItemType left) {
/**
* @versions 26.3+
*/
public void setLeftStack(@Nullable ItemStack left) {
this.left = left;
}
public @Nullable ItemType getRight() {
/**
* @versions 26.3+
*/
public @Nullable ItemStack getRightStack() {
return this.right;
}
public void setRight(@Nullable ItemType right) {
/**
* @versions 26.3+
*/
public void setRightStack(@Nullable ItemStack right) {
this.right = right;
}
public @Nullable ItemType getFront() {
/**
* @versions 26.3+
*/
public @Nullable ItemStack getFrontStack() {
return this.front;
}
public void setFront(@Nullable ItemType front) {
/**
* @versions 26.3+
*/
public void setFrontStack(@Nullable ItemStack front) {
this.front = front;
}
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
public @Nullable ItemType getBack() {
return this.back != null ? this.back.getType() : null;
}
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
public void setBack(@Nullable ItemType back) {
this.back = back != null ? ItemStack.builder().type(back).build() : null;
}
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
public @Nullable ItemType getLeft() {
return this.left != null ? this.left.getType() : null;
}
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
public void setLeft(@Nullable ItemType left) {
this.left = left != null ? ItemStack.builder().type(left).build() : null;
}
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
public @Nullable ItemType getRight() {
return this.right != null ? this.right.getType() : null;
}
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
public void setRight(@Nullable ItemType right) {
this.right = right != null ? ItemStack.builder().type(right).build() : null;
}
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
public @Nullable ItemType getFront() {
return this.front != null ? this.front.getType() : null;
}
/**
* @versions 1.20.5-26.2
*/
@ApiStatus.Obsolete
public void setFront(@Nullable ItemType front) {
this.front = front != null ? ItemStack.builder().type(front).build() : null;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
@@ -89,6 +89,12 @@ public final class ComponentPredicateTypes {
@ApiStatus.Experimental
public static final ComponentPredicateType<NbtComponentPredicate> JUKEBOX_PLAYABLE =
define("jukebox_playable", NbtComponentPredicate::read, NbtComponentPredicate::write);
/**
* @versions 26.1+
*/
@ApiStatus.Experimental
public static final ComponentPredicateType<NbtComponentPredicate> VILLAGER_VARIANT =
define("villager/variant", NbtComponentPredicate::read, NbtComponentPredicate::write);
static {
REGISTRY.unloadMappings();
Loaded 100 of 688 files, more files were not shown because too many files have changed in this diff. Show more