Compare commits

...
Author SHA1 Message Date
NotAlexNoyle f767de3beb Exclude CODEOWNERS from language statistics 2026-10-27 08:25:14 -04:00
NotAlexNoyle 78dcd67723 Add CODEOWNERS (one staff approval) 2026-10-27 08:25:14 -04:00
NotAlexNoyle f3249e6b9e No-op update checker 2026-06-17 04:12:41 -04:00
NotAlexNoyle 0099e0e3d2 Update plugin name to PacketEvents 2026-03-25 12:59:10 -04:00
NotAlexNoyle f2569fd50e Update plugin name 2026-03-25 10:16:10 -04:00
NotAlexNoyle e90aeef31b Clarify API compatibility with 2.11.2 2026-03-25 05:22:35 -04:00
NotAlexNoyle 3d653a1856 Fi9x build 2026-03-25 05:15:30 -04:00
NotAlexNoyle b5e0b5ceca Backport to java 17 and 1.19.4 2026-03-25 04:56:47 -04: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
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
booky d49555c5e1 Fix fabric mod initialization
Fixes https://github.com/retrooper/packetevents/issues/1453
2026-02-21 03:23:47 +01:00
ruViolence dedb96e5cb Add missing equals, hashCode and toString methods 2026-02-03 22:59:21 +08: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 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 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
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
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
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
copilot-swe-agent[bot]andretrooper e4676a18fe Optimize loop performance by caching size() and using entrySet()
Co-authored-by: retrooper <49798017+retrooper@users.noreply.github.com>
2025-11-08 00:59:09 +00:00
copilot-swe-agent[bot] a5b0758b67 Initial plan 2025-11-08 00:53:13 +00: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
booky 14b162b098 Merge pull request #1380 from Rothes/palette-constructor
Add constructor with data array to ListPalette
2025-11-06 13:21:06 +01:00
Rothes f1e9a6f1e8 Guarantee data array length 2025-11-06 17:53:18 +08:00
retrooper 00c8164201 2.10.2 snapshot 2025-11-04 19:32:53 +01:00
retrooper 206d1e03bb 2.10.1 release 2025-11-04 17:42:44 +01:00
retrooper c180263e3f Merge pull request #1389 from SamB440/sponge-adventure
Validate Sponge Adventure version & fix logging
2025-11-04 13:59:17 +01:00
retrooper 8872c65ba2 Merge pull request #1374 from booky10/fix/particle-types-1-21-9
Fix 1.21.9/1.21.10 particle types
2025-11-04 13:56:53 +01:00
retrooper abe79fb351 I couldn't find a better solution to this. 2025-11-04 13:50:07 +01:00
booky b76a014432 Merge pull request #1382 from TheFaser/fix/fabric-player-head
Fix nbt list unwrapping logic
2025-11-04 12:45:10 +01:00
Rothes c7b9e15cef Verify data length 2025-11-04 04:20:02 +08:00
booky fade6da4e2 Fix missing tag unwrapping 2025-11-03 20:59:34 +01:00
retrooper 86c67bfe52 Merge pull request #1390 from retrooper/revert-1384-2.0
Revert "Check if Velocity anti-bots closed the channel before initializing"
2025-11-02 21:33:52 +01:00
retrooper 6cda366bc2 Revert "Check if Velocity anti-bots closed the channel before initializing" 2025-11-02 21:33:30 +01:00
SamB440 2771c6c5d1 Validate Sponge Adventure version & fix logging 2025-11-01 16:43:28 +00:00
booky 7ba541843b Merge pull request #1387 from Axionize/fix/lp-vector-3
Fix incorrect encoding of LPVector3d
2025-10-30 23:05:56 +01:00
TheFaser 47ac4d5894 simplify NBT list conversion logic 2025-10-30 22:30:17 +05:00
TheFaser 6c424946fe Revert "add support for decoding item profile properties from NBT lists, fix #1377"
This reverts commit 0d030d0ca7.
2025-10-30 22:29:59 +05:00
Axionize b4e5b10299 Fix incorrect mul calculation for LPVector3d 2025-10-30 12:52:32 -04:00
booky efeb9019a6 Merge pull request #1384 from linsaftw/2.0
Check if Velocity anti-bots closed the channel before initializing
2025-10-27 20:31:00 +01:00
linsaftw 5b994a58da Check if Velocity anti-bots closed the channel before initializing 2025-10-27 14:47:57 -03:00
TheFaser 0d030d0ca7 add support for decoding item profile properties from NBT lists, fix #1377 2025-10-27 11:48:08 +05:00
Rothes 8b45ddd4ef Not to inject channel if plugin is terminated 2025-10-26 20:50:36 +08:00
Rothes cff73e9e67 Add constructor with data array to ListPalette 2025-10-26 15:45:44 +08:00
Rothes a7fa150836 Support uninject on velocity 2025-10-26 15:35:36 +08:00
booky10 7225117fea Fix bees component for 1.21.9+
Fixes #1378
2025-10-26 04:46:43 +01:00
booky10 3f44016db1 Merge branch '2.0' into fix/particle-types-1-21-9 2025-10-19 23:33:46 +02:00
retrooper c0dc2c5908 2.10.1 snapshot 2025-10-19 22:38:36 +02:00
booky10 8a0ebb77eb Downgrade buildscript jackson dependency
Our publishing plugin isn't compatible with jackson v2.20.0, which is provided by the run-task plugin
2025-10-19 21:11:01 +02:00
booky10 4ebb0acbfe Implement new spell effect particle data 2025-10-19 18:20:56 +02:00
booky10 b4831c4f09 Add color data to flash particle 2025-10-19 18:04:41 +02:00
booky10 17563f1856 Implement new dragon breath particle data 2025-10-19 17:55:16 +02:00
booky10 486cf4c74d Place sources and javadoc jars in root build directory
This will now allow our actions artifact upload task to pick up these files again, which fixes our automatic javadoc generation
2025-10-19 05:01:24 +02:00
retrooper 0528f0ebc6 2.10.0 release 2025-10-19 01:06:32 +02:00
booky ce43c2ba84 Merge pull request #1370 from TheFaser/2.0
update adventure version and add support object components
2025-10-18 01:38:40 +02:00
booky10 f37bb34cdf Reapply adventure serializer patch and update it
I hate this stupid fucking shit mess, can we just stop shading adventure please?
2025-10-18 01:25:56 +02:00
booky10 3fb60fa2c5 Update adventure patch classes to v4.25.0
I hate this adventure mess we are in
2025-10-18 00:36:55 +02:00
booky10 e59c1a5d3a Revert "Temporarily revert adventure patch"
This reverts commit 3831a7d1f0.
2025-10-18 00:31:55 +02:00
booky10 3831a7d1f0 Temporarily revert adventure patch 2025-10-18 00:30:25 +02:00
booky10 f7aee7c797 Align some lines in patched adventure subproject with real adventure 2025-10-18 00:27:50 +02:00
booky10 68b0a65288 Use ItemProfile nbt codec in adventure nbt serializer 2025-10-18 00:01:22 +02:00
booky10 7633319f2a Add full support for decoding/encoding ItemProfile to/from nbt tags
I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs I hate codecs
2025-10-17 23:52:48 +02:00
booky10 ca8ca25a3f Fix PlayerModelType reading/writing
I didn't expect mojang to use a simple boolean here
2025-10-17 23:39:43 +02:00
booky10 a96657d600 Don't check for version when decoding 2025-10-17 22:25:14 +02:00
booky10 bf664a4314 Merge branch '2.0' into TheFaser/2.0 2025-10-17 22:19:46 +02:00
TheFaser 8dd5bec27f remove double version check for sprite serialization 2025-10-12 19:28:03 +05:00
booky10 e11ae8b2cf Fix SpigotReflectionUtil#recentTPS() trying to read legacy fields 2025-10-09 21:53:15 +02:00
TheFaser c8f070cf7d add backward compatibility 2025-10-08 16:38:45 +05:00
TheFaser cc76a19fe3 add player head texture support 2025-10-08 12:45:58 +05:00
TheFaser d0b4ca57d1 fix hat boolean 2025-10-08 12:45:05 +05:00
TheFaser 18d103d202 add some comments 2025-10-08 12:27:18 +05:00
TheFaser 56241cee40 remove unnecessary atlas reading 2025-10-08 12:00:31 +05:00
TheFaser 061874fa46 add support for serializing and deserializing object components 2025-10-08 02:49:54 +05:00
TheFaser c1d22c98ef update adventure version to 4.25.0 2025-10-08 02:49:03 +05:00
booky 06c7afd21a Merge pull request #1369 from ManInMyVan/feat/wrappedblockstate/hasproperty
add WrappedBlockState#hasProperty(StateValue)
2025-10-07 22:39:35 +02:00
ManInMyVan ecb360eabd add WrappedBlockState#hasProperty(StateValue) 2025-10-07 13:49:50 -06:00
booky10 56941722aa Add minimum support for ItemLock network serialization
Fixes #1129

The problem is that the lock component is serialized using codecs (to nbt) instead of using stream codecs and packetevents doesn't have a great way to parse nbt how vanilla does it yet
Vanilla allows millions of different ways to write nbt (because of user input)
2025-10-07 20:39:56 +02:00
booky 2452d753af Merge pull request #1368 from TheFaser/2.0
fix: resolve NoSuchMethodError in login event with isAllowed() check
2025-10-07 19:03:35 +02:00
TheFaser 2085a725b0 fix: resolve NoSuchMethodError in login event with isAllowed() check 2025-10-07 21:28:51 +05:00
retrooper b67f99e8ea Merge pull request #1361 from booky10/feat/1.21.9-support
1.21.9/1.21.10 support
2025-10-06 12:21:33 +02:00
retrooper eee5dd7fa2 2.10.0 snapshot 2025-10-06 12:18:57 +02:00
retrooper 9c5e2bd4c9 patch: minor corrections to copyright year 2025-10-06 12:12:01 +02:00
booky10 87efd2dcf3 Merge branch '2.0' into feat/1.21.9-support 2025-10-05 20:39:47 +02:00
booky 170e1a9cb5 Merge pull request #1362 from rafi67000/gradleUpdate
Gradle update
2025-10-05 20:37:45 +02:00
booky10 7d4ef278cd Update fastutil in buildSrc 2025-10-05 20:20:12 +02:00
booky10 05c6d3447a Don't force wrapper version in build.gradle.kts 2025-10-05 20:17:19 +02:00
booky10 ef9f8d2000 Change workflow artifact uploading paths 2025-10-05 20:15:07 +02:00
rafi67000 9d192b61ea Update MockBukkit 2025-10-03 20:01:14 +02:00
rafi67000 d4d7e96c15 Update Loom 2025-10-03 20:00:59 +02:00
booky10 918fa83388 Fix player instance not being available for first few play packets
This now pauses packet processing until the player instance has been set, see javadoc comment on the InternalPaperJoinListener for more details
2025-10-02 23:25:26 +02:00
booky10 34f26bb3bd Make fabric support 1.21.9
Also tries to fix inconsistencies in when the player object was set for fabric
2025-10-02 20:13:11 +02:00
booky10 ccbfa6cf00 Mark 1.21.10 as supported 2025-10-02 18:48:37 +02:00
rafi67000 bcb429ec7f Fix workflow 2025-10-02 13:42:47 +02:00
rafi67000 5f38d74cfc Replace deprecated task registration 2025-10-01 18:47:43 +02:00
rafi67000 5111c354c1 Update mod-publish 2025-10-01 18:46:49 +02:00
rafi67000 643b2e9975 Update shadow 2025-10-01 18:46:38 +02:00
rafi67000 d9bc12b05e Update gradle to 9.1.0 2025-10-01 16:53:31 +02:00
booky10 f7e6de8594 Fix a few minor issues 2025-10-01 03:31:18 +02:00
booky10 8275088bda Update ItemProfile component to 1.21.9 2025-10-01 02:01:48 +02:00
booky10 06dd7a5555 Update entity data component to 1.21.9 2025-10-01 01:27:36 +02:00
booky10 4fa6bccaa7 Fix compile issue because of generics 2025-10-01 00:48:27 +02:00
booky10 7df7e3700b Update packet types to 1.21.9 2025-10-01 00:39:30 +02:00
booky10 adf1b2692a Update blocktags/itemtags to 1.21.9 2025-10-01 00:30:45 +02:00
booky10 b57d3364a3 Update block state properties to 1.21.9 2025-10-01 00:21:53 +02:00
booky10 48e67537c1 Update registries to 1.21.9 2025-10-01 00:17:20 +02:00
booky10 fe7455e379 Update entity data serializers 2025-09-30 22:25:39 +02:00
booky10 01e4f20c68 Finish packet wrapper updates 2025-09-30 21:30:47 +02:00
booky10 bf066d6156 Update explosion packet to 1.21.9 2025-09-30 18:29:29 +02:00
booky10 20bf1fd89d Implement debug packet wrappers 2025-09-30 05:32:49 +02:00
booky10 f2a470f943 Start implementing debug subscription network serialization 2025-09-30 02:47:05 +02:00
booky10 845077ff35 Some packet wrapper updates 2025-09-30 01:26:41 +02:00
booky10 ff03e29b3f Implement low/less precision Vec3d 2025-09-30 01:26:27 +02:00
booky10 fad9a4873f Work aroundl warning on paper server startup for now 2025-09-29 18:13:02 +02:00
booky10 ad21d93863 Fix paper runtask 2025-09-29 16:08:21 +02:00
booky10 4d366d06cd Add 1.21.9 server/client version 2025-09-29 13:53:25 +02:00
booky10 197a3c956e Revert breaking changes
- Deprecates PlayerData#getUser()/#setUser(UserProfile) instead of removing it without warning
- Reverts changes to signatures in WrapperPlayClientClickWindow, still tries to keep the fixes made by AO
2025-09-29 04:41:54 +02:00
booky10 f8371c461d Add small editorconfig 2025-09-29 04:30:28 +02:00
booky10 02f0855d3d Add missing sealevel getters/setters to WrapperPlayServerRespawn 2025-09-29 04:30:28 +02:00
booky 22a4085978 Merge pull request #1358 from Jyguy/fix-click-window-wrapper
Fix CLICK_WINDOW wrapper write length
2025-09-29 04:30:21 +02:00
Jyguy acae93e9cf Fix CLICK_WINDOW wrapper write length 2025-09-28 21:09:08 -04:00
booky 803cf8f109 Merge pull request #1357 from Axionize/2.0
Fix Build Issues due to Missing Dependencies and with Gradle 9.0.0
2025-09-27 22:42:16 +02:00
Axionize 4af2de9fee Fix building of bungeecoord due to removal of of Bungeecoord 1.21-R0.1-SNAPSHOT from paper repos 2025-09-27 15:14:28 -04:00
Axionize d916789acb Gradle 9.0.0 support 2025-09-27 14:36:39 -04:00
retrooper 54d120c296 Merge pull request #1333 from Beaness/patch-2 2025-09-20 09:09:38 +02:00
retrooper a84cbbd209 Merge pull request #1347 from AoElite/2.0
Improved getting slots and other improvements
2025-09-19 16:22:31 +02:00
retrooper 295b6f268e Merge pull request #1350 from scienziatopazzo/2.0
fix: remove duplicate setter for userProfile | WrapperPlayServerPlayerInfo
2025-09-19 16:22:11 +02:00
scienziato1pazzo a1e674f61d fix: remove duplicate setter for userProfile 2025-09-19 15:07:11 +02:00
AoElite bf1f896b39 ensure the cause is not null 2025-09-15 00:10:58 -04:00
AoElite eeb2b40138 convert nulls to empties 2025-09-14 23:56:44 -04:00
AoElite 60ff394785 fix more issues 2025-09-14 23:56:41 -04:00
AoElite 149c017099 fix mistake 2025-09-14 23:56:39 -04:00
AoElite 233d6c150c improve compatibility 2025-09-14 20:32:41 -04:00
AoElite 96aa95f9d7 dejankify WrapperPlayClientClickWindow 2025-09-14 20:20:32 -04:00
AoElite 7e1a8a704a improve getSlots backwards compatibility 2025-09-14 19:26:26 -04:00
AoElite cd769921b9 make the reading of slots to be changeable 2025-09-14 19:26:24 -04:00
AoElite 7d33952145 handle show_entity contents better 2025-09-14 19:26:21 -04:00
retrooper 58f1134254 Merge pull request #1341 from AoElite/wrapper-pref
Refactor properties and equipment processing to dedicated method
2025-09-05 13:05:31 +02:00
AoElite 6d1f2830d1 allow property reading to be overridden in update attribute packet wrappers 2025-09-05 06:11:21 -04:00
AoElite d103dd74f9 make the readEquipment method changeable with subclass overrides to allow optional performance optimizations 2025-09-05 04:19:35 -04:00
retrooper cd0f238b97 do not throw stacktrace for handshakes, in particular when the exception is caused by the handshake exception. 2025-08-29 10:34:48 +02:00
retrooper d7a475adfd PacketEvents 2.9.6-SNAPSHOT 2025-08-26 01:39:21 +02:00
retrooper ccfb6b422c PacketEvents 2.9.5 Update 2025-08-26 01:22:29 +02:00
booky10 2c8143ddb0 Add WrappedBlockState utility constructor to WrapperPlayServerBlockChange
Fixes #1325
2025-08-25 23:02:05 +02:00
booky10 f9892c598c Don't try to read direct wolf variant below 1.21
Fixes #1327
2025-08-25 22:59:49 +02:00
booky10andMesterMan03 3eb79fd6d2 Don't encode SingleOptionInputControl entries as strings for now
Packetevents doesn't support mixed nbt lists properly, so adding a string tag to a compound list will cause errors

Fixes #1334

Co-authored-by: MesterMan03 <MesterMan03+github@proton.me>
2025-08-25 22:52:41 +02:00
booky10 8ddceada42 Only error when reading chunk data if we managed to read more than allowed 2025-08-25 22:41:57 +02:00
booky10 a1c355d4c9 Cleanup NBT tag reading/writing 2025-08-25 21:20:40 +02:00
booky10 5c23459e1e Fix Direction Y/Z axis being swapped 2025-08-25 21:04:22 +02:00
booky10 af3dbc928b Mark SpigotChannelInjector encoder/decoder getters as nullable 2025-08-25 18:13:24 +02:00
booky10 bd1bc7f06a Check if the network channel is open instead of Player#isOnline if possible on kick
Player#isOnline() returns whether the player still exists in the internal bukkit player list, not whether the network channel is still active
2025-08-25 18:11:18 +02:00
retrooper 7f16b992eb Merge remote-tracking branch 'origin/2.0' into 2.0 2025-08-19 08:43:23 +02:00
retrooper 460884cbd8 patch: remove paper OfflinePlayer#isConnected reference; use Player#isOnline instead 2025-08-19 08:43:00 +02:00
Beanes 0cc99eadde Always try to fetch netty version 2025-08-18 19:49:27 +02:00
retrooper 24bf010d98 Merge pull request #1308 from Moulberry/fix/nbt-compound-getListOrThrow-NPE 2025-07-29 21:44:59 +02:00
retrooper e74adedf88 Merge pull request #1309 from Moulberry/fix/spigotchannelinjector-isplayerset-npe 2025-07-29 20:58:11 +02:00
Moulberry a34d03f422 Fix NPE in SpigotChannelInjector#isPlayerSet 2025-07-30 01:04:15 +08:00
Moulberry c0a9be3c7d Fix NBTCompound.java getListOrThrow always returning null 2025-07-30 01:01:28 +08:00
retrooper 8f352d9115 Merge pull request #1306 from rafi67000/gradleUpdate
ViaNBT, SpongeGradle, MockBukkit and shadow update
2025-07-22 23:55:39 +02:00
rafi67000 6ca306405c Update sponge plugin 2025-07-22 21:47:44 +02:00
rafi67000 d4190b2fde Update shadow plugin 2025-07-22 21:47:44 +02:00
rafi67000 30ed0bdcf3 Update ViaNBT 2025-07-22 21:47:44 +02:00
rafi67000 c3e2c3ee9e Update MockBukkit 2025-07-22 21:47:44 +02:00
retrooper 155f8520d4 increment packetevents version to 2.9.5-SNAPSHOT 2025-07-22 21:29:33 +02:00
retrooper 55b548d3ca packetevents release 2.9.4 2025-07-22 21:10:14 +02:00
retrooper 8eff09ff6e feat: SpigotConversionUtil#getEntityMetadata is now part of the API 2025-07-22 20:00:50 +02:00
retrooper 59596653a2 patch: correct WrapperPlayServerWorldBorder implementation for versions lower than 1.12 2025-07-20 20:54:10 +02:00
retrooper 4df76391cb feat: add support for extracting metadata from a Bukkit entity in SpigotReflectionUtil 2025-07-20 20:37:24 +02:00
retrooper 822f1d26b8 patch: re-add support for outdated server software with no accessible version 2025-07-19 22:04:32 +02:00
retrooper 55a42ab0e2 increment packetevents version to 2.9.4-SNAPSHOT 2025-07-17 16:47:11 +02:00
retrooper cdf3521154 packetevents 2.9.3 release 2025-07-17 16:36:51 +02:00
retrooper 820b530240 add 1.21.8 server version constant 2025-07-17 16:11:48 +02:00
retrooper 1823f61748 increment version to 2.9.3-snapshot 2025-07-17 15:54:24 +02:00
retrooper d27d8ffd6a packetevents 2.9.2 release 2025-07-17 15:18:28 +02:00
retrooper 7a57012822 Revert "Cleanup gradle configuration mess"
This reverts commit cfb054b8b2.
2025-07-17 14:01:23 +02:00
retrooper 0a10f4d861 Merge pull request #1265 from Luuzzi/2.0
fix spawn position for versions lower than 1.8 & protocol 4 support
2025-07-13 22:52:41 +02:00
retrooper d1a3145483 Merge pull request #1300 from GrimAnticheat/feature/read-list-max-size
Add new readList(Reader<K> reader, int maxSize) function to PacketWrapper
2025-07-13 22:46:25 +02:00
retrooper 08096106f8 patch: UserLoginEvent always fired in PlayerJoinEvent to provide UUID and username (so it's not a breaking change). 2025-07-13 22:41:22 +02:00
Luuzzi a3fbccc454 1.7.5 and lower doesn't have action START_JUMPING_WITH_HORSE 2025-07-13 20:36:10 +03:00
Luuzzi 9ea931d58d resolve #1301 2025-07-13 20:19:39 +03:00
Alexandr 364be4e34d Merge branch 'retrooper:2.0' into 2.0 2025-07-12 19:11:19 +03:00
Axionize b22394c288 Add new readList(Reader<K> reader, int maxSize) function to PacketWrapper 2025-07-12 09:49:19 -04:00
retrooper 208dfbc3f3 Merge pull request #1294 from booky10/fix/gradle-config-mess
Cleanup gradle configuration mess
2025-07-10 09:11:36 +02:00
booky10 cfb054b8b2 Cleanup gradle configuration mess 2025-07-10 04:58:23 +02:00
booky10 f47e6880fd [skip ci] Add fabric production run task 2025-07-10 02:53:39 +02:00
booky10 f55f791f8a [skip ci] Update gradle wrapper to v8.14.3 2025-07-10 02:53:38 +02:00
booky10 ba389ddb57 [skip ci] Fix changelog 2025-07-10 02:53:38 +02:00
booky10 2ce143d466 [skip ci] Increment version to v2.9.2 snapshot 2025-07-10 02:53:38 +02:00
booky10 b7f99503d9 Release packetevents v2.9.1 2025-07-10 02:14:43 +02:00
booky10 52adfbae8a Fix "publishMods" task name breaking shadow jar exclusions
This should be fixed properly, this is just a quick fix to get out a proper release
2025-07-10 02:08:11 +02:00
booky10 a861066cab Don't copy artifacts to root build directory 2025-07-10 02:07:21 +02:00
retrooper 1acec02bfb PacketEvents 2.9.1 snapshot 2025-07-10 01:27:48 +02:00
retrooper b88857386a Release PacketEvents 2.9.0 2025-07-10 00:42:32 +02:00
retrooper 4c48d4c1df Merge pull request #1291 from booky10/feat/publishing-workflow
Automatic release publishing
2025-07-10 00:34:47 +02:00
retrooper 68f8fd3d03 Merge pull request #1290 from booky10/fix/recursive-dialog-resolving
Store dialog click event field as reference for names
2025-07-10 00:29:56 +02:00
retrooper 2d625c6e7a feat: add setters to WrapperPlayServerWorldBorder 2025-07-10 00:15:19 +02:00
booky10 83fe2cce0d Revert "Setup testing setup v2"
This reverts commit 11e4033ec6.
2025-07-09 23:46:20 +02:00
booky10 73bfaebab6 Fix publishing type for github release
Was stable even for snapshots because version isn't set yet in root project
2025-07-09 23:39:57 +02:00
booky10 2ac61fd5cb Fix snapshot detection 2025-07-09 23:30:04 +02:00
booky10 7d31150b35 Add v2.6.0 and v2.7.0 changelogs to CHANGELOG.md 2025-07-09 23:28:19 +02:00
booky10 11e4033ec6 Setup testing setup v2 2025-07-09 23:20:51 +02:00
booky10 a6a8866727 Revert "Setup testing setup"
This reverts commit 84a0759288.
2025-07-09 23:20:08 +02:00
booky10 ce61c3ef52 Fix github tag name 2025-07-09 23:13:50 +02:00
retrooper 4602ea8107 Merge pull request #1251 from booky10/fix/attempt-fixing-random-login-race-condition-injection-issues
Attempt fixing random login race condition injection issues
2025-07-09 23:12:48 +02:00
booky10 5fb1a6c85e Write changelog to github output instead of stdout 2025-07-09 23:12:05 +02:00
retrooper 7e2ac525ac Merge pull request #1287 from booky10/feat/effect-wrapper
Add missing WrapperPlayServerEffect
2025-07-09 23:07:55 +02:00
booky10 7590d6f7de Fix missing loaders field for modrinth publishing 2025-07-09 22:58:24 +02:00
booky10 d7c2284ccb Add gradle preparation step to release workflow 2025-07-09 22:51:30 +02:00
booky10 84a0759288 Setup testing setup 2025-07-09 22:46:10 +02:00
booky10 0ca8e27fc8 Finish implementing release workflow 2025-07-09 22:43:04 +02:00
retrooper 5e30aef0a1 patch: correction of WORLD_BORDER wrapper 2025-07-09 21:26:31 +02:00
retrooper 9e53791fef patch: WrapperPlayServerWorldBorder exception fix for 1.8-1.11.2 2025-07-09 21:12:06 +02:00
booky10 8346918e86 Start implementing release automation workflow 2025-07-09 19:30:31 +02:00
booky10 7714c6253a Store dialog click event field as reference for names 2025-07-09 18:19:35 +02:00
booky10 0a00e970d7 Access ResourceKey location using fields instead of methods
Method order is sort-of unpredictable, my test in 1.21.4/1.21.6 resulted in the registry name being returned instead of the registry entry's name
2025-07-09 17:37:31 +02:00
retrooper d0dd8dc4cd patch: potentially fix SpigotConversionUtil#typeFromBukkitWorld for 1.17+ 2025-07-09 17:18:16 +02:00
booky10andjtJava bc01609828 Add missing WrapperPlayServerEffect
Based on https://github.com/retrooper/packetevents/pull/702

Fixes https://github.com/retrooper/packetevents/issues/415
Fixes https://github.com/retrooper/packetevents/pull/423

Co-authored-by: jtJava <ilovefuud@gmail.com>
2025-07-09 16:59:44 +02:00
booky10 c6e7bcb980 Remove useless zero-byte-suffix for chunk data
Mojang fixed the issue in 1.21.6, but we forgot to remove our fix too
2025-07-09 16:33:27 +02:00
booky10 8987194030 Fix changes to ChatMessage
Some small fixes to https://github.com/retrooper/packetevents/pull/1267

* Uses consistent version-specific gson serializer instead of platform-dependent one
* Uses component getters/setters instead of directly accessing field to allow for overrides to work
2025-07-09 15:52:45 +02:00
booky10 4495db796d Update comment in PlayerManagerImpl 2025-07-09 15:44:29 +02:00
booky10 e1a29a20a7 Small cleanup for listeners 2025-07-09 15:40:57 +02:00
booky10 bd5ef7cb30 Update to support paper's configuration api
Paper no longer creates the player object during the configuration phase, like vanilla
Also, paper has removed the early connection reference in the player object added by CraftBukkit in 1.20.5

PacketEvents now uses the pre-1.20.5 logic for extracting the player reference
As a result, all handshake/status/login/config packets won't have access to the player object;
play packets should always have the player set
2025-07-09 15:38:15 +02:00
booky10 36363c885c Merge branch '2.0' into fix/attempt-fixing-random-login-race-condition-injection-issues 2025-07-09 14:42:12 +02:00
retrooper a198f0e8d6 Merge pull request #1286 from retrooper/revert-1250-dev
Revert "Refactor TaskWrapper into interface and implementation classes"
2025-07-08 19:39:41 +02:00
retrooper 69cbe1e405 Revert "Refactor TaskWrapper into interface and implementation classes" 2025-07-08 19:39:19 +02:00
retrooper 2b0ec87da6 Merge pull request #1250 from ShortyDev/dev
Refactor TaskWrapper into interface and implementation classes
2025-07-08 14:46:55 +02:00
retrooper 08f95b8036 Merge branch '2.0' of https://github.com/retrooper/packetevents into 2.0 2025-07-08 14:34:42 +02:00
retrooper a15ad3a8d7 patch: typo, put actual code in comment; also removed previous sponsor of computational servers; 2025-07-08 14:34:35 +02:00
retrooper fef7f983b0 Merge pull request #1267 from iiAhmedYT/patch-1
Allow getting/setting json in ChatMessage
2025-07-08 14:27:57 +02:00
retrooper 71eae683fb Merge remote-tracking branch 'origin/2.0' into 2.0 2025-07-08 14:21:22 +02:00
retrooper f692f41025 patch: fix the plugin disabling on unsupported version check 2025-07-08 14:21:09 +02:00
retrooper 3b4acde6f8 Merge pull request #1273 from ineanto/2.0
feat: add RemoteChatSession getter
2025-07-08 14:13:17 +02:00
retrooper 6b14595582 patch: import optimization in spigot reflection util 2025-07-08 13:40:58 +02:00
retrooper 50c2a69449 patch: packetevents disables itself when running on an unsupported Minecraft version;
changing "packetevents 2.0 failed to inject" message;
2025-07-07 19:32:23 +02:00
Alexandr b62fc6922c Merge branch 'retrooper:2.0' into 2.0 2025-06-30 06:55:33 +03: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
booky 1b5479f04f Merge pull request #1269 from HSGamer/2.0
correctly parse payload in WrapperCommonClientCustomClickAction
2025-06-29 17:20:13 +02:00
booky10 ac0041ff52 Read nbt end tags as null for custom click action packet 2025-06-29 17:13:25 +02:00
Luuzzi c6f129cdd3 added setData and getData to WrappedBlockState 2025-06-28 22:49:57 +03:00
ineanto 21226e6ac9 feat: add remote chat session getter via reflection 2025-06-28 21:41:46 +02:00
hsgamer b14f5f5031 correctly parse payload in WrapperCommonClientCustomClickAction
the payload is either an NBT or NBTEnd, but no boolean byte. So we don't have to check optional
close #1268
2025-06-27 13:22:11 +07:00
Ahmed Waleed 6ff9f8c401 Allow getting/setting json in ChatMessage 2025-06-27 02:04:00 +03:00
Luuzzi 22b28b7b35 1_7_10 -> 1_7_2. Also wrapper fixes 2025-06-26 23:23:17 +03:00
Luuzzi 9e7de426c0 fix incorrect shifts(get, set) in Chunk_v1_7 2025-06-26 13:17:53 +03:00
retrooper 77abb65bab Merge pull request #1264 from booky10/feat/1.21.7-support
1.21.7 support
2025-06-26 08:50:49 +02:00
Luuzzi a5188e5d78 added support for 1.7.2-1.7.5, seems it works fine 🤔 2025-06-26 07:03:53 +03:00
Luuzzi cce0ac2d7b fix spawn position for versions lower than 1.8 2025-06-26 06:27:49 +03:00
booky10andSteaf23 001f6b9fd7 Fix InputControl encoding
Co-authored-by: Steaf23 <steafmobile@gmail.com>
2025-06-26 03:44:27 +02:00
booky10 0395378726 Update registries for 1.21.7 2025-06-26 03:09:57 +02:00
booky10 31fe7a89d9 Add 1.21.7 protocol constants 2025-06-26 03:03:38 +02:00
booky d8b47495e4 Merge pull request #1258 from dawon/bugfix/fix-waypoint-info-types
Fix WaypointInfo types
2025-06-20 14:36:29 +02:00
Jakub Zacek cba4603ad8 Fix WaypointInfo types 2025-06-20 13:55:48 +02:00
booky10 f37c74d0d9 Convert PacketEventsEncoder to simple ChannelOutboundHandlerAdapter
This allows cancelling packets without throwing exceptions around

Fixes https://github.com/retrooper/packetevents/issues/1256
2025-06-19 19:34:27 +02:00
booky10 2085dfb84b Skip generating useless CancelPacketException stacktrace 2025-06-19 19:33:40 +02:00
booky10 cdad13d5c5 Fix WrapperPlayClientEntityAction actions for 1.21.6+
Fixes https://github.com/retrooper/packetevents/issues/1254
2025-06-19 19:12:35 +02:00
retrooper 95b50a44e9 Merge pull request #1255 from Cyramek/direction-fix 2025-06-19 17:30:31 +02:00
cyramek 78f630b5c1 fix direction vector being different from vanilla 2025-06-19 16:58:27 +02:00
retrooper 08d000ea82 Merge pull request #1234 from huanmeng-qwq/impl/advancements
Implement WrapperPlayServerUpdateAdvancements
2025-06-19 12:19:42 +02:00
booky10 28c4fdc7ce Merge branch '2.0' into fix/attempt-fixing-random-login-race-condition-injection-issues 2025-06-19 02:58:42 +02:00
booky10 96c81a69ae Fix compatibility with netty v4.0 (e.g. used by minecraft 1.8) 2025-06-19 02:58:21 +02:00
booky10 83720c6a81 Fix race condition on login for versions older than 1.20.5 2025-06-19 02:48:09 +02:00
booky10 c95acffab6 Resolve user in loginevent for 1.20.5+ 2025-06-19 02:01:37 +02:00
booky10 c2beb331f1 Implement support for resolving player connection through transferCookieConnection field
This makes it possible to get the connection info from a player object much sooner than otherwise
2025-06-19 01:57:07 +02:00
booky10 2667431ec9 Don't resolve entity id getter method by name 2025-06-18 23:19:23 +02:00
booky10 21ce0f4d34 Small cleanup to other advancement classes 2025-06-18 23:00:40 +02:00
booky10 21c1a7dfa8 Clean up Advancement class
- Removes version parameter from read method
- Convert comments to javadoc
- Add constructor for constructing Advancement without criteria list parameter
- Reorder getters/setters
2025-06-18 23:00:25 +02:00
booky10 518a995e8e Add abstraction class for criterion value in AdvancementProgress 2025-06-18 22:58:49 +02:00
booky10 e20e0854ab Remove unused ClientAsset 2025-06-18 22:58:28 +02:00
booky10 7c3cde51f0 Reformat WrapperPlayServerUpdateAdvancements
- Convert comments to javadoc
- Reorder getter/setter
- Don't make "showAdvancements" field nullable
2025-06-18 22:33:28 +02:00
booky10 cc18a7ad08 Don't register debug listener 2025-06-18 22:28:49 +02:00
booky10 35fa135e9e Fix formatting of Advancement/AdvancementDisplay 2025-06-18 22:26:52 +02:00
booky10 c68fe76156 Merge branch '2.0' into impl/advancements 2025-06-18 22:23:57 +02:00
retrooper 80846cfea2 Merge pull request #1247 from booky10/feat/1.21.6-support
1.21.6 support
2025-06-18 22:03:28 +02:00
retrooper 1a1b03c1f5 i'm not religious, but god bless aboookyrica 2025-06-18 22:01:26 +02:00
booky10 c411a1925b Also support void promises for sponge 2025-06-18 21:46:08 +02:00
booky10 d8b4f5b1b6 Account for void promises while writing on spigot platform 2025-06-18 21:37:16 +02:00
booky10 486c9a493a Add hydration block state property 2025-06-18 21:02:04 +02:00
booky10 b1ed98f53d Fix fabric connection error 2025-06-18 21:01:53 +02:00
ShortyDev ca8ca782fc refactor TaskWrapper into interface and implementation classes 2025-06-18 20:10:49 +02:00
booky10 c75f039c99 Update adventure to v4.23.0 2025-06-18 19:08:38 +02:00
booky10 c1324fe7fe Update adventure to v4.22.0 2025-06-17 18:06:52 +02:00
booky10 781d4a7c82 Add new ui sound category 2025-06-17 18:06:52 +02:00
retrooper 590479adda patch: ensure consistent naming of #getGameMode and #setGameMode 2025-06-17 16:48:37 +02:00
retrooper df2c50ccfc patch: ensure code can compile 2025-06-17 13:50:49 +02:00
retrooper f5b60ea3f2 feat: changed WrapperPlayServerUpdateAdvancements design; updated it to 1.21.5; relocated advancement classes to advancements folder; (requires some testing still) 2025-06-17 13:45:56 +02:00
booky10 c95194f147 Fix test errors 2025-06-16 05:16:03 +02:00
booky10 56a643f8d0 Implement item attribute display for 1.21.6 2025-06-16 04:54:42 +02:00
booky10 7daed688e0 Update equippable component to 1.21.6 2025-06-16 04:28:11 +02:00
booky10 f3782dffe1 Finish implement dialog bodies 2025-06-16 04:21:09 +02:00
booky10 b06063ebf7 Finish implement dialog inputs 2025-06-16 03:53:28 +02:00
booky10 6cb3d301d8 Finish implementing dialog types 2025-06-16 03:16:39 +02:00
booky10 1aab738dd5 Implement dialog actions 2025-06-16 02:44:07 +02:00
booky10 0aafad8b58 Some more dialog progress 2025-06-13 17:04:21 +02:00
huanmeng-qwq 910d77252e fix: Advancement#read & write 2025-06-13 21:59:52 +08:00
retrooper 524e6ca16d patch: added copyright notice to update advancements wrapper 2025-06-13 15:15:58 +02:00
retrooper 1aa88d05bf feat: more progress to WrapperPlayServerUpdateAdvancements; updating to 1.21.5 (incomplete) 2025-06-13 15:11:40 +02:00
huanmeng-qwq 70271f3694 update 2025-06-13 11:52:41 +08:00
booky10 62201ae3fa Start implementing dialogs 2025-06-11 17:55:36 +02:00
booky10 8ce56fc346 Quick fabric module update 2025-06-11 16:45:44 +02:00
booky10 8029fd1b4e Update block and item tags for 1.21.6 2025-06-11 16:39:27 +02:00
booky10 de19712dbb Add missing WrapperConfigServerPing 2025-06-11 16:33:12 +02:00
booky10 1d41037bdd Implement WrapperPlayClientChangeGameMode 2025-06-11 16:26:53 +02:00
booky10 a98b8c5604 Implement WrapperPlayServerWaypoint 2025-06-11 16:24:47 +02:00
booky10 7d5d2682b7 Implement waypoint api 2025-06-11 16:21:36 +02:00
booky10 2b5f8027f0 Implement new clientbound show dialog packet wrappers partially 2025-06-11 15:45:09 +02:00
booky10 1e37351b48 Implement new clientbound clear dialog packet wrappers 2025-06-11 15:40:49 +02:00
booky10 70c8aad74e Implement new serverbound custom click action packet wrappers 2025-06-11 15:38:03 +02:00
booky10 5527546f05 Update existing packet wrappers to 1.21.6 2025-06-11 15:18:56 +02:00
booky10 56671341ae Update packet type mappings for 1.21.6 2025-06-11 15:03:11 +02:00
booky10 41ea688ff3 Update registries for 1.21.6 2025-06-11 14:54:16 +02:00
booky10 004195144d Implement new cloud height for dimension types 2025-06-11 14:22:55 +02:00
booky10 962aefba17 Add new 1.21.6 version constants 2025-06-11 14:13:15 +02:00
huanmeng-qwq 88ec7a583d remove final modifier 2025-05-28 10:36:09 +08:00
huanmeng-qwq 2303d362d7 add setter 2025-05-28 10:32:34 +08:00
retrooper da0e95fa03 Merge pull request #1238 from booky10/fix/enchantment-refs
Fix issues with enchantment loading
2025-05-25 11:56:07 +02:00
booky10 c98bfad8b8 Merge branch '2.0' into fix/enchantment-refs 2025-05-25 04:59:33 +02:00
booky10 3dfb8389dc Bump gradle wrapper validation action to v4
I hope this fixes these random errors while building
2025-05-25 04:57:03 +02:00
booky10 7c74dd2e05 Allocate new buffer when re-encoding clientbound buffers with a limited capacity
Bungee now limits the maximum capacity of bytebufs, presumably because of https://github.com/SpigotMC/BungeeCord/commit/1279cca971b2d32b6bd75103d3a555fbbd629392

This now allocates a completely new bytebuf to ensure we don't run into the maximum bytebuf capacity

Fixes https://github.com/retrooper/packetevents/issues/1227
2025-05-25 04:56:21 +02:00
booky10 05eabbf667 Decode enchantment type exclusive set as mapped entity ref set on registry synchronization 2025-05-25 04:22:12 +02:00
booky10 d1cafe2bcc Resolve self-reference registry after adding entries to registry
Only relevant to enchantments for now
2025-05-25 03:57:49 +02:00
booky10 26078fcb59 Implement MappedEntityRefSet 2025-05-25 03:44:03 +02:00
booky10 3d602b9f96 Fix item reading/writing for 1.13/1.13.1
Just for future reference, so I don't have to remap + decompile these jars again:
* 1.12.2 logic: https://haste.pinofett.de/degt0ejhbr.java
* 1.13/1.13.1 logic: https://haste.pinofett.de/omr31l9mv9.java
* 1.13.2 logic: https://haste.pinofett.de/iul6y7vvny.java
2025-05-25 02:57:11 +02:00
huanmeng-qwq df4f9e425e update 2025-05-24 14:44:41 +08:00
huanmeng-qwq efb9766388 convert time to Optional 2025-05-23 18:17:27 +08:00
huanmeng-qwq ab0ad68d43 update 2025-05-23 18:12:38 +08:00
huanmeng-qwq 1be8db5ff4 update 2025-05-23 18:09:36 +08:00
huanmeng-qwq 1f68ee1f46 convert showAdvances to Optional 2025-05-23 18:00:13 +08:00
huanmeng-qwq e7c6ae4726 Implement WrapperPlayServerStatistics 2025-05-23 17:48:09 +08:00
huanmeng-qwq 5db1671895 Implement WrapperPlayServerUpdateAdvancements 2025-05-23 17:47:49 +08:00
retrooper 023a0da619 packetevents description change 2025-05-16 15:46:40 +02:00
retrooper 51863fa435 bump version to 2.8.1 snapshot 2025-05-15 15:20:19 +02:00
retrooper f46ec64e60 update: 2.8.0 release 2025-05-15 14:33:04 +02:00
retrooper f0d7a8e84d patch: fix tropical fish pattern mappings 2025-05-15 14:12:49 +02:00
retrooper ac4fac85ed Merge pull request #1220 from Loyisa/2.0
fix: minecraft:air isn't empty in <1.11
2025-05-14 23:49:46 +02:00
retrooper 8f274e0695 Merge pull request #1224 from Bram1903/fix/legacy-item-damage
Fixed: ItemStack#getDamageValue & ItemStack#setDamageValue
2025-05-14 13:03:45 +02:00
Bram cd0892ffe4 Fixed: ItemStack#getDamageValue & ItemStack#setDamageValue on version 1.12.2 and below 2025-05-11 20:42:43 +02:00
Loyisa f9398b58f7 fix: minecraft:air isn't empty in 1.8 2025-05-06 18:43:51 +08:00
booky10 9c9f5cf41d Fix missing saddle EquipmentSlotGroup 2025-05-03 17:50:21 +02:00
retrooper 5983395561 chore: update adventure to 4.21.0 (for 1.21.5 support) 2025-05-01 13:35:53 +02:00
retrooper 686bb4fd3f Merge pull request #1216 from Axionize/fix/teleport-flags
Fix Setting RelativeFlags
2025-05-01 13:31:24 +02:00
retrooper ff4ac7eefc Merge pull request #1162 from Rubenicos/fix/field-lookup
Fix recursive field lookup
2025-04-30 21:04:16 +02:00
retrooper 20b52fbcd9 Merge pull request #1212 from Beaness/patch-1
Add missing copy fields to spawn player wrapper
2025-04-30 21:01:33 +02:00
Axionize 424fd149e7 Fix setting relativeflags 2025-04-30 14:24:34 -04:00
Beanes e372f4f30a Add missing copy fields to spawn player wrapper 2025-04-28 21:11:59 +02:00
retrooper b520a2ea99 Merge pull request #1205 from booky10/feat/versioned-itemstacks
Add version and registry context to ItemStacks
2025-04-28 17:51:48 +02:00
booky10 4e4174b7d3 Add version and registry context to ItemStacks
As logic related to ItemStack has changed quite a lot throughout the versions, this now adds a version (and registry) field to ItemStacks
These fields are populated by packetevents automatically when reading ItemStacks

Using this new version, this properly updates the ItemStack api methods to how vanilla handles stuff now
Additionally, this should fix issues related to modern handling of item amounts breaking legacy negative stack sizes
(E.g. see https://github.com/retrooper/packetevents/pull/1192 and https://github.com/retrooper/packetevents/pull/1062)
2025-04-19 04:54:21 +02:00
booky10 0931f7c9e7 Merge remote-tracking branch 'upstream/2.0' into 2.0 2025-04-18 23:33:58 +02:00
booky10 4faf97cdb4 Increase bytebuf capacity when writing zero-byte-suffix for chunk data
See https://github.com/retrooper/packetevents/issues/1202#issuecomment-2816226784 for more info

Fixes #1202
2025-04-18 23:33:30 +02:00
booky 71fa7be70d Merge pull request #1158 from spring-dependency-management/spring-dependency-management-patch-1
Check classes before copying from last
2025-04-18 23:16:33 +02:00
booky a7cb0ce6bf Merge pull request #1177 from Axionize/refactor/eliminate-static-ProtocolManager-USERS-&-CHANNELS-use
Eliminate usage of static ProtocolManager fields which should be accessed on an instance basis
2025-04-18 20:03:04 +02:00
booky10 8fa1b820d4 Don't iterate over all channels when disconnecting a channel without a UUID 2025-04-18 19:09:01 +02:00
booky10 05f42bc9d5 Mark internal fields/methods as internal 2025-04-18 19:08:14 +02:00
booky10 b635dcbe54 Merge branch '2.0' into refactor/eliminate-static-ProtocolManager-USERS-&-CHANNELS-use 2025-04-18 19:01:42 +02:00
booky10 a1def4170c Check if last wrapper is an instance of this wrapper when copying 2025-04-18 18:59:02 +02:00
booky 53f1fc495b Merge pull request #1191 from Axionize/feat/runtime-obselete-annotation
Add new RuntimeObsolete annotation used for checking if a field is obsolete at runtime via reflection
2025-04-18 18:55:37 +02:00
booky10 17086d3017 Add registry #getByNameOrThrow/#getByIdOrThrow api 2025-04-18 18:30:56 +02:00
booky10 d604e9d6af Fix nbt encoding/decoding of MappedEntitySet tags 2025-04-18 18:25:56 +02:00
booky 76aba6fb8d Merge pull request #1159 from spring-dependency-management/spring-dependency-management-patch-2
Add getWrapperClass() to packet type
2025-04-18 18:04:37 +02:00
booky10 5e8ad3e6e2 Add missing wrapper class for structure block packet 2025-04-18 18:00:58 +02:00
booky10 2f780a22a0 Merge branch '2.0' into spring-dependency-management-patch-2 2025-04-18 17:57:47 +02:00
booky 7549b22604 Merge pull request #1192 from ManInMyVan/fix/itemstack-type-getter
make itemstack type getter always return type
2025-04-18 17:48:32 +02:00
booky 8083725b96 Merge pull request #1197 from Luuzzi/2.0
fixed a floating-point issue in .nbt files
2025-04-18 15:31:21 +02:00
booky 3e624ebde5 Merge pull request #1203 from Bram1903/fix/NullDisconnectLog
[Fix] Disconnected `null` due to invalid packet console log
2025-04-18 15:11:19 +02:00
booky 16f031c585 Merge pull request #1204 from MachineBreaker/patch-1
Remove server version check for SelectBundleItem selectedItemIndex check
2025-04-18 13:56:27 +02:00
MachineBreaker 32f7d0b68b Actually remove the version check since its useless 2025-04-18 07:35:36 -04:00
MachineBreaker 8a3a418d05 Use correct server version for SelectBundleItem selectedItemIndex check 2025-04-18 07:33:54 -04:00
Bram 3a76049868 Fixed: Disconnected null due to invalid packet 2025-04-18 13:06:57 +02:00
booky10 e7495c2e85 Remove ingredient from TrimMaterial for 1.21.5 2025-04-14 18:54:45 +02:00
booky10 a2726516b3 Fix 1.21.5 player chat message writing 2025-04-14 18:50:36 +02:00
booky10 bf57fef29c Remove template item from TrimPattern for 1.21.5 2025-04-14 18:06:43 +02:00
retrooper a9679cd5b2 Merge pull request #1199 from bridgelol/patch-1
chore: bump adventure to 4.20.0
2025-04-12 14:39:52 +02:00
Bridge 8e3eba761d chore: bump adventure to 4.20.0 2025-04-12 14:02:04 +02:00
retrooper b4ef9b90b9 patch: slight change to project description 2025-04-12 09:35:39 +02:00
Luuzzi b2ccbe0bed fixed a floating-point issue in .nbt files 2025-04-11 09:49:35 +03:00
ManInMyVan 1913c6603e make itemstack type getter always return type 2025-04-07 17:25:52 -06:00
Axionize 9eafaaab7d Add new RuntimeObsolete annotation used for checking if a field is obsolete at runtime via reflection 2025-04-07 18:05:40 -04:00
booky e672aa2b92 Merge pull request #1190 from retrooper/revert-1180-fix/fix-goat-horn-cooldown
Revert "Fix Goat Horn Cooldown"
2025-04-07 23:02:46 +02:00
spring-dependency-management c32300cd04 rebase on 1.21.5 2025-04-05 02:01:15 +01:00
Axionize 39d45d8d1f Remove usage of direct external/public static references to ProtocolManager.CHANNELS and ProtocolManager.USERS
Fields will remain accessible for backwards compatibility in the unlikely case of a developer meddling these values in their own code.

All usage of both these fields is now wrapped in interface methods which can be overwritten by other ProtocolManagers.
2025-03-29 03:56:34 -04:00
Rubén 2b03bbce7c Fix recursive field lookup 2025-03-08 12:14:06 -06:00
spring-dependency-management 319568d92a oops 2025-03-06 19:10:27 +00:00
spring-dependency-management f666047ae5 Some missing oops 2025-03-06 16:56:13 +00:00
spring-dependency-management e86beec90f add interface 2025-03-06 16:55:55 +00:00
spring-dependency-management 3d416fc961 Add getWrapperClass() to packet type 2025-03-06 16:47:50 +00:00
spring-dependency-management 2cd2f5d7f9 Check classes before copying 2025-03-06 15:35:31 +00:00
602 changed files with 457342 additions and 9512 deletions

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
[*.java]
indent_style = space
indent_size = 4
ij_continuation_indent_size = 8
ij_java_names_count_to_use_import_on_demand = 9999
ij_java_class_count_to_use_import_on_demand = 9999
+1
View File
@@ -0,0 +1 @@
.gitea/CODEOWNERS linguist-detectable=false
+3
View File
@@ -0,0 +1,3 @@
# Pull requests request review from the eligible staff team(s).
# One approval from either an Admin or Developer satisfies branch protection.
* @trueog/Admins @trueog/Developers
+10 -10
View File
@@ -10,13 +10,13 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Validate gradle wrapper
uses: gradle/actions/wrapper-validation@v3
uses: gradle/actions/wrapper-validation@v5
- name: Set up JDK 21
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'
@@ -31,40 +31,40 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: api-build
path: api/build/libs
path: build/libs/packetevents-api-*.jar
- name: Upload build artifacts spigot
uses: actions/upload-artifact@v4
with:
name: spigot-build
path: spigot/build/libs
path: build/libs/packetevents-spigot-*.jar
- name: Upload build artifacts netty-common
uses: actions/upload-artifact@v4
with:
name: netty-common-build
path: netty-common/build/libs
path: build/libs/packetevents-netty-common-*.jar
- name: Upload build artifacts bungeecord
uses: actions/upload-artifact@v4
with:
name: bungeecord-build
path: bungeecord/build/libs
path: build/libs/packetevents-bungeecord-*.jar
- name: Upload build artifacts velocity
uses: actions/upload-artifact@v4
with:
name: velocity-build
path: velocity/build/libs
path: build/libs/packetevents-velocity-*.jar
- name: Upload build artifacts fabric
uses: actions/upload-artifact@v4
with:
name: fabric-build
path: fabric/build/libs
path: build/libs/packetevents-fabric-*.jar
- name: Upload build artifacts sponge
uses: actions/upload-artifact@v4
with:
name: sponge-build
path: sponge/build/libs
path: build/libs/packetevents-sponge-*.jar
+51
View File
@@ -0,0 +1,51 @@
name: Release
on:
workflow_dispatch:
permissions:
contents: write
jobs:
release:
name: Publish Release
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Validate gradle wrapper
uses: gradle/actions/wrapper-validation@v5
- name: Setup java 21
uses: actions/setup-java@v5
with:
java-version: 21
distribution: temurin
- name: Prepare gradle
run: ./gradlew printVersion --no-daemon
- name: Extract changelog
id: changelog
run: |
OUTPUT_DELIMITER="$(uuidgen)"
echo "changelog<<$OUTPUT_DELIMITER" >> "$GITHUB_OUTPUT"
# extract tag name and use it to get changelog section
TAG_NAME="v$(./gradlew -q --no-daemon printVersion)"
awk -v tag="${TAG_NAME}" '
$1 == "!!!!!" && $2 == tag {found=1; next}
$1 == "!!!!!" && found {exit}
found
' CHANGELOG.md >> "$GITHUB_OUTPUT"
# end output
echo "$OUTPUT_DELIMITER" >> "$GITHUB_OUTPUT"
- name: Publish plugin
env:
GITHUB_API_TOKEN: ${{ github.token }}
MODRINTH_API_TOKEN: ${{ secrets.MODRINTH_PUBLISH_TOKEN }}
CHANGELOG: ${{ steps.changelog.outputs.changelog }}
run: ./gradlew publishMods --no-daemon -PnoDryPublish
+2
View File
@@ -126,3 +126,5 @@ run/
# Build Source Kotlin
/buildSrc/.kotlin/
.env
+451
View File
@@ -0,0 +1,451 @@
!!!!! 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, Suleyman Abulkhasan, 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/retrooperdev) 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/retrooperdev) 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/retrooperdev) 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! 🎉
This update includes some bug fixes.
# Brief Announcement 📢⚠️
### Visit our website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed (Summary)
* Fixed for certain particle types on 1.21.9 & 1.21.10 Minecraft
* Fixed the bee's component on 1.21.9 & 1.21.10 Minecraft
* Correction of 'mul' calculation in LpVector3d
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.10.0...v2.10.1
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.10.0
# PacketEvents 2.10.0 is finally out! 🎉
This update includes critical bug fixes & minor additions to the API.
# Brief Announcement 📢⚠️
### We have our very own website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed (Summary)
* Added 1.21.9 & 1.21.10 support
* Various bug fixes (such as TPS reading, PlayerModelType reading/writing, and more)
* Update adventure API
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.9.5...v2.10.0
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.9.5
# PacketEvents 2.9.5 is out now! 🎉
This update includes critical bug fixes & minor additions to the API.
# Brief Announcement 📢⚠️
### We have our very own website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed (Summary)
* Injector bug fix (for Spigot)
* WolfVariant issue fixed
* Chunk Data error fixed
* NBT tag issues fixed
* Direction Y/Z axis being swapped fixed
* Added WrappedBlockState to constructor of WrapperPlayServerBlockChange
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.9.4...v2.9.5
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.9.4
# PacketEvents 2.9.4 is out now! 🎉
This update includes minor bug fixes & minor additions to the API.
# Brief Announcement 📢⚠️
### We have our very own website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed (Summary)
* Added SpigotConversionUtil#getEntityMetadata to retrieve metadata from a Bukkit entity.
* Fixed outdated 1.8 Spigot forks from being unable to load on PacketEvents.
* Fixed WrapperPlayServerWorldBorder for versions lower than 1.12.
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.9.3...v2.9.4
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.9.3
# PacketEvents 2.9.3 is out now! 🎉
This is an update that adds support for Minecraft 1.21.8 server builds.
# Brief Announcement 📢⚠️
### We have our very own website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed (Summary)
* Added support for 1.21.8 Minecraft server builds.
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.9.2...v2.9.3
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.9.2
# PacketEvents 2.9.2 is out now! 🎉
This is a patch update that fixes issues with UserLoginEvent (which previously contained null user data) and with importing Adventure serializers.
# Brief Announcement 📢⚠️
### We have our very own website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed (Summary)
* Added support for 1.7.2+ Minecraft protocol (useful for proxies)
* Fixed UserLoginEvent. It is now (always) triggered by PlayerJoinEvent to prevent User instances from containing null data.
* Fixed importing Adventure serializers.
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.9.1...v2.9.2
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.9.1
# PacketEvents 2.9.1 is out now! 🎉
This is a hotfix patch update to fix issues with 2.9.0 release assets. See below for the 2.9.0 changelog.
### New update now supports Minecraft version 1.21.6 & 1.21.7. We suggest that you update, as numerous bugs have been fixed.
# Brief Announcement 📢⚠️
### We have our very own website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed? (Summary)
* Added 1.21.6 support
* Added 1.21.7 support
* Bug fixes
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.8.0...v2.9.1
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.9.0
# PacketEvents 2.9.0 is out now! 🎉
### New update now supports Minecraft version 1.21.6 & 1.21.7. We suggest that you update, as numerous bugs have been fixed.
# Brief Announcement 📢⚠️
### We have our very own website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed? (Summary)
* Added 1.21.6 support
* Added 1.21.7 support
* Bug fixes
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.8.0...v2.9.0
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.8.0
# PacketEvents 2.8.0 is out now! 🎉
### New update now supports Minecraft version 1.21.5. Please update, as numerous bugs have been fixed.
# Brief Announcement 📢⚠️
### We have our very own website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed? (Summary)
* Added 1.21.5 support
* Various bugs fixed
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.7.0...v2.8.0
## Contributors 🏅
This update wouldn't be possible without these contributors ❤️: @booky10, @Axionize, @Bram1903, @ManInMyVan, @ytnoos,
@AoElite, @HaHaWTH, @divinepablo, @scienziatopazzo, @bridgelol, @MachineBreaker, @Luuzzi, @Beaness, @Rubenicos, @Loyisa
## New Contributors
* @HaHaWTH made their first contribution in https://github.com/retrooper/packetevents/pull/1097
* @divinepablo made their first contribution in https://github.com/retrooper/packetevents/pull/1098
* @scienziatopazzo made their first contribution in https://github.com/retrooper/packetevents/pull/1105
* @bridgelol made their first contribution in https://github.com/retrooper/packetevents/pull/1199
* @Luuzzi made their first contribution in https://github.com/retrooper/packetevents/pull/1197
* @Beaness made their first contribution in https://github.com/retrooper/packetevents/pull/1212
* @Rubenicos made their first contribution in https://github.com/retrooper/packetevents/pull/1162
* @Loyisa made their first contribution in https://github.com/retrooper/packetevents/pull/1220
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.7.0
# PacketEvents v2.7.0 is out now! 🎉
### New update with support of the latest Minecraft version. In addition to that, countless bugs were fixed.
# Brief Announcement 📢⚠️
### We have our own website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed? (Summary)
* Added 1.21.4 support
* Fix: Potion contents item component for 1.21.2/1.21.3
* Fix: NPC objects to have unique server team names
* Add missing ServerVersion#V_1_9_1
* Validation checks added for window click type
**Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.6.0...v2.7.0
## New Contributors
* @Axionize made their first contribution in https://github.com/retrooper/packetevents/pull/1048
* @ShreyasAyyengar made their first contribution in https://github.com/retrooper/packetevents/pull/1044
* @mfnalex made their first contribution in https://github.com/retrooper/packetevents/pull/1076
## Contributors 🏅
This update wouldn't be possible without these contributors ❤️: @booky10, @rafi67000, @ShreyasAyyengar, @AoElite,
@Tecnio, @Axionize, @mfnalex
### If you want to support PacketEvents, and any upcoming events we plan for the future, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!! v2.6.0
# PacketEvents v2.6.0 is out now! 🎉
### New update with support of new platforms & the latest Minecraft version. In addition to that, countless bugs were fixed.
# Brief Announcement 📢⚠️
### We have our own website: https://packetevents.com
### Documentation: https://docs.packetevents.com
### JavaDocs: https://javadocs.packetevents.com
## What's Changed? (Summary)
* 1.21.2 and 1.21.3 Minecraft support
* Sponge support added
* Fabric support added (also server-side)
* Utilizing the proper bStats API
* Registry element issues fixed
* Mappings issues fixed
* AdvancedSlimePaper issues fixed
* BungeeCord issues fixed
### **Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.5.0...v2.6.0
## Contributors 🏅
This update wouldn't be possible without these contributors ❤️: @booky10, @ManInMyVan, @SamB440, @rafi67000, @Bram1903,
@AbhigyaKrishna
### If you want to support PacketEvents, and any upcoming events we plan for the future, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
## Maven/Gradle Dependency
### **Check out**: https://docs.packetevents.com/getting-started
!!!!!
+4 -6
View File
@@ -1,7 +1,7 @@
<!--suppress HtmlDeprecatedAttribute -->
<div align="center">
<h2><i>packetevents</i></h2>
<h3><i>Precision meets performance—a powerful tool for mastering Minecraft packet manipulation with speed and finesse.</i></h3>
<h2><i>PacketEvents</i></h2>
<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,11 +11,11 @@
<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/)
- [GitHub](https://github.com/retrooper/packetevents/releases/)
- [Modrinth](https://modrinth.com/plugin/packetevents)
- [GitHub](https://github.com/retrooper/packetevents/releases/)
- [SpigotMC](https://www.spigotmc.org/resources/packetevents-api.80279/)
- [Development Builds](https://ci.codemc.io/job/retrooper/job/packetevents)
- [Statistics](https://bstats.org/plugin/bukkit/packetevents/11327)
@@ -28,8 +28,6 @@
<a href="https://www.ej-technologies.com"><img src="https://www.ej-technologies.com/images/product_banners/jprofiler_small.png"><br>
<a href="https://github.com/radstevee"><img src="https://github.com/radstevee.png" width="50px" alt="radstevee"/></a><br>
<h3>Credits</h3>
<i>Here are some projects that we are heavily inspired by, thus we have integrated</i>\
-13
View File
@@ -31,15 +31,6 @@ dependencies {
}
compileOnly(libs.gson)
testImplementation(libs.bundles.adventure)
testImplementation(project(":patch:adventure-text-serializer-gson"))
testImplementation(libs.adventure.text.serializer.legacy)
testImplementation(project(":netty-common"))
testImplementation(testlibs.mockbukkit)
testImplementation(testlibs.slf4j)
testImplementation(testlibs.bundles.junit)
testImplementation(libs.netty)
testImplementation(libs.classgraph)
}
mappingCompression {
@@ -83,10 +74,6 @@ tasks {
packageName = "com.github.retrooper.packetevents.util"
}
test {
useJUnitPlatform()
}
shadowJar {
exclude {
val path = it.path
@@ -0,0 +1,28 @@
package com.github.retrooper.packetevents.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.Documented;
/**
* Marks an API element as obsolete and makes this information available
* at runtime via reflection. Use in conjunction with an IDE-recognized
* annotation like @ApiStatus.Obsolete if IDE warnings are also desired.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD}) // Adjust targets as needed
public @interface RuntimeObsolete {
/**
* Specifies in which version the API became obsolete.
* Should generally match the value in the corresponding @ApiStatus.Obsolete annotation.
*/
String since() default "";
/**
* Optional: Add a reason or replacement suggestion.
*/
String reason() default "";
}
@@ -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);
}
@@ -76,7 +76,7 @@ public class EventManager {
* be the final decider whether the event has been cancelled or not.
*
* @param event {@link PacketEvent}
* @param postCallListenerAction The action to be ran after all the listeners have finished processing
* @param postCallListenerAction The action to be run after all the listeners have finished processing
*/
public void callEvent(PacketEvent event, @Nullable Runnable postCallListenerAction) {
for (PacketListenerCommon listener : listeners) {
@@ -84,7 +84,7 @@ public class EventManager {
event.call(listener);
} catch (Exception t) {
// ignore handshake exceptions
if (t.getClass() != InvalidHandshakeException.class) {
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);
}
}
@@ -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,22 @@
package com.github.retrooper.packetevents.event;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
/**
* 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.
*
* @return Player.
*/
<T> T getPlayer();
<T> @UnknownNullability T getPlayer();
}
@@ -32,40 +32,50 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
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.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.NullMarked;
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 final 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;
@@ -78,22 +88,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;
@@ -104,7 +117,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) {
@@ -115,7 +128,6 @@ public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerE
return needsReEncode;
}
public boolean isClone() {
return cloned;
}
@@ -141,10 +153,16 @@ public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerE
}
@Override
public <T> T getPlayer() {
public <T> @UnknownNullability T getPlayer() {
return (T) player;
}
@Deprecated
@ApiStatus.Internal
public void setPlayer(Object player) {
this.player = player;
}
/**
* Gets the connection state this packet has been sent/received in.
*/
@@ -152,14 +170,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);
}
@@ -168,7 +185,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,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 UserLoginEvent extends PacketEvent implements CallableEvent, UserEvent, PlayerEvent {
private final User user;
private final Object 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);
}
@@ -2,4 +2,9 @@ package com.github.retrooper.packetevents.exception;
public class CancelPacketException extends RuntimeException {
public static final CancelPacketException INSTANCE = new CancelPacketException();
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
@@ -32,12 +32,15 @@ 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;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerJoinGame;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRespawn;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public class InternalPacketListener extends PacketListenerAbstract {
public InternalPacketListener() {
@@ -65,10 +68,12 @@ public class InternalPacketListener extends PacketListenerAbstract {
//Map username with channel
synchronized (channel) {
ProtocolManager.CHANNELS.put(profile.getUUID(), channel);
PacketEvents.getAPI().getProtocolManager().setChannel(profile.getUUID(), channel);
}
PacketEvents.getAPI().getLogManager().debug("Mapped player UUID with their channel.");
if (PacketEvents.getAPI().getLogManager().isDebug()) {
PacketEvents.getAPI().getLogManager().debug("Mapped player UUID with their channel " + profile.getUUID() + " " + channel);
}
// Switch the user's connection state to new state, but the variable event.getConnectionState() remains LOGIN
// We switch user state immediately to remain in sync with vanilla, allowing you to encode packets immediately
@@ -86,12 +91,11 @@ public class InternalPacketListener extends PacketListenerAbstract {
WrapperConfigServerRegistryData packet = new WrapperConfigServerRegistryData(event);
if (packet.getElements() != null) { // 1.20.2 to 1.20.5
SynchronizedRegistriesHandler.handleRegistry(user, packet.getServerVersion().toClientVersion(),
SynchronizedRegistriesHandler.handleRegistry(user, packet,
packet.getRegistryKey(), packet.getElements());
}
if (packet.getRegistryData() != null) { // since 1.20.5
SynchronizedRegistriesHandler.handleLegacyRegistries(user, packet.getServerVersion()
.toClientVersion(), packet.getRegistryData());
SynchronizedRegistriesHandler.handleLegacyRegistries(user, packet, packet.getRegistryData());
}
}
@@ -101,8 +105,9 @@ public class InternalPacketListener extends PacketListenerAbstract {
user.setEntityId(joinGame.getEntityId());
if (joinGame.getDimensionCodec() != null) { // 1.16 to 1.20.1
SynchronizedRegistriesHandler.handleLegacyRegistries(user, joinGame.getServerVersion().toClientVersion(),
SynchronizedRegistriesHandler.handleLegacyRegistries(user, joinGame,
joinGame.getDimensionCodec());
user.finalizeRegistries(joinGame);
}
user.setDimensionType(joinGame.getDimensionType());
@@ -116,6 +121,7 @@ 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));
}
}
@@ -33,8 +33,10 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public interface ProtocolManager {
@ApiStatus.Internal
Map<UUID, Object> CHANNELS = new ConcurrentHashMap<>();
// Use SocketAddress because ProtocolLib wraps Channels with NettyChannelProxy class
@ApiStatus.Internal
Map<Object, User> USERS = new ConcurrentHashMap<>();
default Collection<User> getUsers() {
@@ -150,11 +152,13 @@ public interface ProtocolManager {
return USERS.get(pipeline);
}
@ApiStatus.Internal
default User removeUser(Object channel) {
Object pipeline = ChannelHelper.getPipeline(channel);
return USERS.remove(pipeline);
}
@ApiStatus.Internal
default void setUser(Object channel, User user) {
synchronized (channel) {
Object pipeline = ChannelHelper.getPipeline(channel);
@@ -166,4 +170,23 @@ public interface ProtocolManager {
default Object getChannel(UUID uuid) {
return CHANNELS.get(uuid);
}
@ApiStatus.Internal
default void setChannel(UUID uuid, Object channel) {
CHANNELS.put(uuid, channel);
}
@ApiStatus.Internal
default void removeChannel(Object channel) {
CHANNELS.values().remove(channel);
}
@ApiStatus.Internal
default void removeChannelById(UUID uuid) {
CHANNELS.remove(uuid);
}
default boolean hasChannel(Object channel) {
return CHANNELS.containsValue(channel);
}
}
@@ -32,7 +32,8 @@ import org.jetbrains.annotations.NotNull;
*/
public enum ServerVersion {
//TODO Rename to MinecraftVersion?
V_1_7_10(5),
V_1_7_2(4), V_1_7_4(4), V_1_7_5(4),
V_1_7_6(5), V_1_7_7(5), V_1_7_8(5), V_1_7_9(5), V_1_7_10(5),
V_1_8(47), V_1_8_3(47), V_1_8_8(47),
V_1_9(107), V_1_9_1(108), V_1_9_2(109), V_1_9_4(110),
//1.10 and 1.10.1 are redundant
@@ -49,8 +50,8 @@ public enum ServerVersion {
V_1_19(759), V_1_19_1(760), V_1_19_2(760), V_1_19_3(761), V_1_19_4(762),
//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
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),
//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_11(774),
//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;
}
}
@@ -103,6 +103,10 @@ public class ByteBufHelper {
PacketEvents.getAPI().getNettyManager().getByteBufOperator().writeShort(buffer, value);
}
public static void writeShortLE(Object buffer, int value) {
PacketEvents.getAPI().getNettyManager().getByteBufOperator().writeShortLE(buffer, value);
}
public static int readMedium(Object buffer) {
return PacketEvents.getAPI().getNettyManager().getByteBufOperator().readMedium(buffer);
}
@@ -42,6 +42,7 @@ public interface ByteBufOperator {
void writeByte(Object buffer, int value);
void writeShort(Object buffer, int value);
void writeShortLE(Object buffer, int value);
void writeMedium(Object buffer, int value);
void writeInt(Object buffer, int value);
void writeLong(Object buffer, long value);
@@ -0,0 +1,144 @@
/*
* 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.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.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
public class Advancement {
private @Nullable ResourceLocation parent;
private @Nullable AdvancementDisplay display;
/**
* Removed with 1.20.2
*/
private List<String> criteria;
private List<List<String>> requirements;
/**
* Added with 1.20
*/
private boolean sendsTelemetryData;
public Advancement(
@Nullable ResourceLocation parent,
@Nullable AdvancementDisplay display,
List<List<String>> requirements,
boolean sendsTelemetryData
) {
this(parent, display, Collections.emptyList(), requirements, sendsTelemetryData);
}
@ApiStatus.Obsolete
public Advancement(
@Nullable ResourceLocation parent,
@Nullable AdvancementDisplay display,
List<String> criteria,
List<List<String>> requirements,
boolean sendsTelemetryData
) {
this.parent = parent;
this.display = display;
this.criteria = criteria;
this.requirements = requirements;
this.sendsTelemetryData = sendsTelemetryData;
}
public static Advancement read(PacketWrapper<?> wrapper) {
ResourceLocation parentId = wrapper.readOptional(ResourceLocation::read);
AdvancementDisplay display = wrapper.readOptional(AdvancementDisplay::read);
List<String> criteria = wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_20_2)
? wrapper.readList(PacketWrapper::readString) : null;
List<List<String>> requirements = wrapper.readList(
ew -> wrapper.readList(PacketWrapper::readString));
boolean sendsTelemetryData = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20)
&& wrapper.readBoolean();
return new Advancement(parentId, display, criteria, requirements, sendsTelemetryData);
}
public static void write(PacketWrapper<?> wrapper, Advancement advancement) {
wrapper.writeOptional(advancement.parent, ResourceLocation::write);
wrapper.writeOptional(advancement.display, AdvancementDisplay::write);
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_20_2)) {
wrapper.writeList(advancement.criteria, PacketWrapper::writeString);
}
wrapper.writeList(advancement.getRequirements(), (ew, anyList) ->
ew.writeList(anyList, PacketWrapper::writeString));
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20)) {
wrapper.writeBoolean(advancement.sendsTelemetryData);
}
}
public @Nullable ResourceLocation getParent() {
return this.parent;
}
public void setParent(@Nullable ResourceLocation parent) {
this.parent = parent;
}
public @Nullable AdvancementDisplay getDisplay() {
return this.display;
}
public void setDisplay(@Nullable AdvancementDisplay display) {
this.display = display;
}
/**
* Removed with 1.20.2
*/
public List<String> getCriteria() {
return this.criteria;
}
/**
* Removed with 1.20.2
*/
public void setCriteria(List<String> criteria) {
this.criteria = criteria;
}
public List<List<String>> getRequirements() {
return this.requirements;
}
public void setRequirements(List<List<String>> requirements) {
this.requirements = requirements;
}
/**
* Added with 1.20
*/
public boolean isSendsTelemetryData() {
return this.sendsTelemetryData;
}
/**
* Added with 1.20
*/
public void setSendsTelemetryData(boolean sendsTelemetryData) {
this.sendsTelemetryData = sendsTelemetryData;
}
}
@@ -0,0 +1,168 @@
/*
* 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.advancements;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
public final class AdvancementDisplay {
public static final int FLAG_HAS_BACKGROUND = 0b001;
public static final int FLAG_SHOW_TOAST = 0b010;
public static final int FLAG_HIDDEN = 0b100;
private Component title;
private Component description;
private ItemStack icon;
private AdvancementType type;
private boolean showToast;
private boolean hidden;
private @Nullable ResourceLocation background;
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) {
this.title = title;
this.description = description;
this.icon = icon;
this.type = type;
this.showToast = showToast;
this.hidden = hidden;
this.background = background;
this.x = x;
this.y = y;
}
public static AdvancementDisplay read(PacketWrapper<?> wrapper) {
Component title = wrapper.readComponent();
Component description = wrapper.readComponent();
ItemStack icon = wrapper.readItemStack();
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();
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);
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);
}
public int packFlags() {
int flags = 0;
if (this.background != null) {
flags |= FLAG_HAS_BACKGROUND;
}
if (this.showToast) {
flags |= FLAG_SHOW_TOAST;
}
if (this.hidden) {
flags |= FLAG_HIDDEN;
}
return flags;
}
public Component getTitle() {
return this.title;
}
public void setTitle(Component title) {
this.title = title;
}
public Component getDescription() {
return this.description;
}
public void setDescription(Component description) {
this.description = description;
}
public ItemStack getIcon() {
return this.icon;
}
public void setIcon(ItemStack icon) {
this.icon = icon;
}
public AdvancementType getType() {
return this.type;
}
public void setType(AdvancementType type) {
this.type = type;
}
public boolean isShowToast() {
return this.showToast;
}
public void setShowToast(boolean showToast) {
this.showToast = showToast;
}
public boolean isHidden() {
return this.hidden;
}
public void setHidden(boolean hidden) {
this.hidden = hidden;
}
public @Nullable ResourceLocation getBackground() {
return this.background;
}
public void setBackground(@Nullable ResourceLocation background) {
this.background = background;
}
public float getX() {
return this.x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return this.y;
}
public void setY(float y) {
this.y = y;
}
}
@@ -0,0 +1,60 @@
/*
* 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.advancements;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
public final class AdvancementHolder {
private ResourceLocation identifier;
private Advancement advancement;
public AdvancementHolder(ResourceLocation identifier, Advancement advancement) {
this.identifier = identifier;
this.advancement = advancement;
}
public static AdvancementHolder read(PacketWrapper<?> wrapper) {
ResourceLocation identifier = wrapper.readIdentifier();
Advancement advancement = Advancement.read(wrapper);
return new AdvancementHolder(identifier, advancement);
}
public static void write(PacketWrapper<?> wrapper, AdvancementHolder holder) {
wrapper.writeIdentifier(holder.identifier);
Advancement.write(wrapper, holder.advancement);
}
public ResourceLocation getIdentifier() {
return this.identifier;
}
public void setIdentifier(ResourceLocation identifier) {
this.identifier = identifier;
}
public Advancement getAdvancement() {
return this.advancement;
}
public void setAdvancement(Advancement advancement) {
this.advancement = advancement;
}
}
@@ -0,0 +1,75 @@
/*
* 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.advancements;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.Nullable;
import java.util.Map;
public final class AdvancementProgress {
private Map<String, CriterionProgress> criteria;
public AdvancementProgress(Map<String, CriterionProgress> criteria) {
this.criteria = criteria;
}
public static AdvancementProgress read(PacketWrapper<?> wrapper) {
Map<String, CriterionProgress> criteria = wrapper.readMap(PacketWrapper::readString, CriterionProgress::read);
return new AdvancementProgress(criteria);
}
public static void write(PacketWrapper<?> wrapper, AdvancementProgress progress) {
wrapper.writeMap(progress.getCriteria(), PacketWrapper::writeString, CriterionProgress::write);
}
public Map<String, CriterionProgress> getCriteria() {
return this.criteria;
}
public void setCriteria(Map<String, CriterionProgress> criteria) {
this.criteria = criteria;
}
public static final class CriterionProgress {
private @Nullable Long obtainedTimestamp;
public CriterionProgress(@Nullable Long obtainedTimestamp) {
this.obtainedTimestamp = obtainedTimestamp;
}
public static CriterionProgress read(PacketWrapper<?> wrapper) {
return new CriterionProgress(wrapper.readOptional(PacketWrapper::readLong));
}
public static void write(PacketWrapper<?> wrapper, CriterionProgress progress) {
wrapper.writeOptional(progress.obtainedTimestamp, PacketWrapper::writeLong);
}
public @Nullable Long getObtainedTimestamp() {
return this.obtainedTimestamp;
}
public void setObtainedTimestamp(@Nullable Long obtainedTimestamp) {
this.obtainedTimestamp = obtainedTimestamp;
}
}
}
@@ -0,0 +1,27 @@
/*
* 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.advancements;
public enum AdvancementType {
TASK,
CHALLENGE,
GOAL,
;
}
@@ -0,0 +1,39 @@
/*
* 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.attribute;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public interface AttributeDisplay {
static AttributeDisplay read(PacketWrapper<?> wrapper) {
AttributeDisplayType<?> type = wrapper.readMappedEntity(AttributeDisplayTypes.getRegistry());
return type.read(wrapper);
}
@SuppressWarnings("unchecked") // not unchecked
static void write(PacketWrapper<?> wrapper, AttributeDisplay display) {
wrapper.writeMappedEntity(display.getType());
((AttributeDisplayType<? super AttributeDisplay>) display.getType()).write(wrapper, display);
}
AttributeDisplayType<?> getType();
}
@@ -0,0 +1,31 @@
/*
* 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.attribute;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public interface AttributeDisplayType<T extends AttributeDisplay> extends MappedEntity {
T read(PacketWrapper<?> wrapper);
void write(PacketWrapper<?> wrapper, T display);
}
@@ -0,0 +1,56 @@
/*
* 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.attribute;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class AttributeDisplayTypes {
private static final VersionedRegistry<AttributeDisplayType<?>> REGISTRY = new VersionedRegistry<>("attribute_display_type");
private AttributeDisplayTypes() {
}
@ApiStatus.Internal
public static <T extends AttributeDisplay> AttributeDisplayType<T> define(
String name, PacketWrapper.Reader<T> reader, PacketWrapper.Writer<T> writer
) {
return REGISTRY.define(name, data ->
new StaticAttributeDisplayType<>(data, reader, writer));
}
public static VersionedRegistry<AttributeDisplayType<?>> getRegistry() {
return REGISTRY;
}
public static final AttributeDisplayType<DefaultAttributeDisplay> DEFAULT = define("default",
DefaultAttributeDisplay::read, DefaultAttributeDisplay::write);
public static final AttributeDisplayType<HiddenAttributeDisplay> HIDDEN = define("hidden",
HiddenAttributeDisplay::read, HiddenAttributeDisplay::write);
public static final AttributeDisplayType<OverrideAttributeDisplay> OVERRIDE = define("override",
OverrideAttributeDisplay::read, OverrideAttributeDisplay::write);
static {
REGISTRY.unloadMappings();
}
}
@@ -187,6 +187,22 @@ public final class Attributes {
public static final Attribute TEMPT_RANGE = define("tempt_range",
null, 10d, 0d, 2048d);
/**
* Added with 1.21.6
*/
public static final Attribute CAMERA_DISTANCE = define("camera_distance",
null, 4d, 0d, 32d);
/**
* Added with 1.21.6
*/
public static final Attribute WAYPOINT_TRANSMIT_RANGE = define("waypoint_transmit_range",
null, 0d, 0d, 60_000_000d);
/**
* Added with 1.21.6
*/
public static final Attribute WAYPOINT_RECEIVE_RANGE = define("waypoint_receive_range",
null, 0d, 0d, 60_000_000d);
/**
* This attribute has been renamed in 1.20.5 to {@link #JUMP_STRENGTH}
*/
@@ -0,0 +1,44 @@
/*
* 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.attribute;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class DefaultAttributeDisplay implements AttributeDisplay {
public static final DefaultAttributeDisplay INSTANCE = new DefaultAttributeDisplay();
private DefaultAttributeDisplay() {
}
public static DefaultAttributeDisplay read(PacketWrapper<?> wrapper) {
return INSTANCE;
}
public static void write(PacketWrapper<?> wrapper, DefaultAttributeDisplay display) {
// NO-OP
}
@Override
public AttributeDisplayType<?> getType() {
return AttributeDisplayTypes.DEFAULT;
}
}
@@ -0,0 +1,44 @@
/*
* 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.attribute;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class HiddenAttributeDisplay implements AttributeDisplay {
public static final HiddenAttributeDisplay INSTANCE = new HiddenAttributeDisplay();
private HiddenAttributeDisplay() {
}
public static HiddenAttributeDisplay read(PacketWrapper<?> wrapper) {
return INSTANCE;
}
public static void write(PacketWrapper<?> wrapper, HiddenAttributeDisplay display) {
// NO-OP
}
@Override
public AttributeDisplayType<?> getType() {
return AttributeDisplayTypes.HIDDEN;
}
}
@@ -0,0 +1,64 @@
/*
* 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.attribute;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
@NullMarked
public class OverrideAttributeDisplay implements AttributeDisplay {
private final Component component;
public OverrideAttributeDisplay(Component component) {
this.component = component;
}
public static OverrideAttributeDisplay read(PacketWrapper<?> wrapper) {
return new OverrideAttributeDisplay(wrapper.readComponent());
}
public static void write(PacketWrapper<?> wrapper, OverrideAttributeDisplay display) {
wrapper.writeComponent(display.component);
}
@Override
public AttributeDisplayType<?> getType() {
return AttributeDisplayTypes.OVERRIDE;
}
public Component getComponent() {
return this.component;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof OverrideAttributeDisplay)) return false;
OverrideAttributeDisplay that = (OverrideAttributeDisplay) obj;
return this.component.equals(that.component);
}
@Override
public int hashCode() {
return Objects.hashCode(this.component);
}
}
@@ -0,0 +1,52 @@
/*
* 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.attribute;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Reader;
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Writer;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class StaticAttributeDisplayType<T extends AttributeDisplay> extends AbstractMappedEntity implements AttributeDisplayType<T> {
private final Reader<T> reader;
private final Writer<T> writer;
@ApiStatus.Internal
public StaticAttributeDisplayType(@Nullable TypesBuilderData data, Reader<T> reader, Writer<T> writer) {
super(data);
this.reader = reader;
this.writer = writer;
}
@Override
public T read(PacketWrapper<?> wrapper) {
return this.reader.apply(wrapper);
}
@Override
public void write(PacketWrapper<?> wrapper, T display) {
this.writer.accept(wrapper, display);
}
}
@@ -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")
@@ -72,7 +72,12 @@ public class ChatTypeDecoration {
wrapper.writeStyle(decoration.style);
}
@Deprecated
public static ChatTypeDecoration decode(NBT nbt, ClientVersion version) {
return decode(nbt, PacketWrapper.createDummyWrapper(version));
}
public static ChatTypeDecoration decode(NBT nbt, PacketWrapper<?> wrapper) {
NBTCompound compound = (NBTCompound) nbt;
String translationKey = compound.getStringTagValueOrThrow("translation_key");
NBT paramsTag = compound.getTagOrThrow("parameters");
@@ -90,11 +95,16 @@ public class ChatTypeDecoration {
}
NBTCompound styleTag = compound.getCompoundTagOrNull("style");
Style style = styleTag == null ? empty() :
AdventureSerializer.serializer(version).nbt().deserializeStyle(styleTag);
wrapper.getSerializers().nbt().deserializeStyle(styleTag, wrapper);
return new ChatTypeDecoration(translationKey, params, style);
}
@Deprecated
public static NBT encode(ChatTypeDecoration decoration, ClientVersion version) {
return encode(decoration, PacketWrapper.createDummyWrapper(version));
}
public static NBT encode(ChatTypeDecoration decoration, PacketWrapper<?> wrapper) {
NBTList<NBTString> paramsTag = NBTList.createStringList();
for (Parameter param : decoration.parameters) {
paramsTag.addTag(new NBTString(param.getId()));
@@ -104,8 +114,8 @@ public class ChatTypeDecoration {
compound.setTag("translation_key", new NBTString(decoration.translationKey));
compound.setTag("parameters", paramsTag);
if (!decoration.style.isEmpty()) {
compound.setTag("style", AdventureSerializer.serializer(version)
.nbt().serializeStyle(decoration.style));
compound.setTag("style", wrapper.getSerializers()
.nbt().serializeStyle(decoration.style, wrapper));
}
return compound;
}
@@ -28,6 +28,20 @@ import java.util.Optional;
public class Node {
public static final byte TYPE_MASK = 0b11;
public static final byte TYPE_ROOT = 0b00;
public static final byte TYPE_LITERAL = 0b01;
public static final byte TYPE_ARGUMENT = 0b10;
public static final byte FLAG_MASK = ~TYPE_MASK;
public static final byte FLAG_EXECUTABLE = 0b000100;
public static final byte FLAG_REDIRECT = 0b001000;
public static final byte FLAG_CUSTOM_SUGGESTIONS = 0b010000;
/**
* Added with 1.21.6
*/
public static final byte FLAG_RESTRICTED = 0b100000;
private byte flags;
private List<Integer> children;
private int redirectNodeIndex;
@@ -27,6 +27,7 @@ import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
import java.util.ArrayList;
import java.util.Arrays;
@@ -36,9 +37,10 @@ import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
@NullMarked
public final class Parsers {
private static final VersionedRegistry<Parser> REGISTRY = new VersionedRegistry<>("argument_type");
private static final VersionedRegistry<Parser> REGISTRY = new VersionedRegistry<>("command_argument_type");
private Parsers() {
}
@@ -218,6 +220,15 @@ public final class Parsers {
(wrapper, value) -> wrapper.writeIdentifier((ResourceLocation) value.get(0))
);
/**
* Added with 1.21.6
*/
public static final Parser HEX_COLOR = define("hex_color", null, null);
/**
* Added with 1.21.6
*/
public static final Parser DIALOG = define("dialog", null, null);
static {
REGISTRY.unloadMappings();
}
@@ -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
@@ -0,0 +1,71 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class ChangePageClickEvent implements ClickEvent {
private final int page;
@ApiStatus.Obsolete
public ChangePageClickEvent(String page) {
this(Integer.parseInt(page));
}
public ChangePageClickEvent(int page) {
this.page = page;
}
public static ChangePageClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
int page = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5)
? compound.getNumberTagValueOrThrow("page").intValue()
: Integer.parseInt(compound.getStringTagValueOrThrow("value"));
return new ChangePageClickEvent(page);
}
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, ChangePageClickEvent clickEvent) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5)) {
compound.setTag("page", new NBTInt(clickEvent.page));
} else {
compound.setTag("value", new NBTString(Integer.toString(clickEvent.page)));
}
}
@Override
public ClickEventAction<?> getAction() {
return ClickEventActions.CHANGE_PAGE;
}
@Override
public net.kyori.adventure.text.event.ClickEvent asAdventure() {
return net.kyori.adventure.text.event.ClickEvent.changePage(this.page);
}
public int getPage() {
return this.page;
}
}
@@ -0,0 +1,76 @@
/*
* 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.chat.clickevent;
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.NbtTagHolder;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.event.ClickEvent.Payload;
import org.jspecify.annotations.NullMarked;
@NullMarked
public interface ClickEvent {
static ClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
String actionName = compound.getStringTagValueOrThrow("action");
ClickEventAction<?> action = ClickEventActions.getRegistry().getByNameOrThrow(actionName);
return action.decode(compound, wrapper);
}
@SuppressWarnings("unchecked") // not unchecked
static void encode(NBTCompound compound, PacketWrapper<?> wrapper, ClickEvent clickEvent) {
compound.set("action", clickEvent.getAction().getName(), ResourceLocation::encode, wrapper);
((ClickEventAction<? super ClickEvent>) clickEvent.getAction()).encode(compound, wrapper, 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:
return new ShowDialogClickEvent((Dialog) ((Payload.Dialog) clickEvent.payload()).dialog());
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()
);
default:
throw new UnsupportedOperationException("Unsupported clickevent: " + clickEvent);
}
}
net.kyori.adventure.text.event.ClickEvent asAdventure();
}
@@ -0,0 +1,34 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public interface ClickEventAction<T extends ClickEvent> extends MappedEntity {
boolean isAllowFromServer();
T decode(NBTCompound compound, PacketWrapper<?> wrapper);
void encode(NBTCompound compound, PacketWrapper<?> wrapper, T clickEvent);
}
@@ -0,0 +1,89 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.protocol.util.NbtMapDecoder;
import com.github.retrooper.packetevents.protocol.util.NbtMapEncoder;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class ClickEventActions {
private static final VersionedRegistry<ClickEventAction<?>> REGISTRY = new VersionedRegistry<>("click_event_action");
private ClickEventActions() {
}
@ApiStatus.Internal
public static <T extends ClickEvent> ClickEventAction<T> define(
String name, boolean allowFromServer,
NbtMapDecoder<T> decoder, NbtMapEncoder<T> encoder
) {
return REGISTRY.define(name, data -> new StaticClickEventAction<>(
data, allowFromServer, decoder, encoder));
}
public static VersionedRegistry<ClickEventAction<?>> getRegistry() {
return REGISTRY;
}
public static final ClickEventAction<OpenUrlClickEvent> OPEN_URL = define("open_url", true,
OpenUrlClickEvent::decode, OpenUrlClickEvent::encode);
public static final ClickEventAction<OpenFileClickEvent> OPEN_FILE = define("open_file", false,
OpenFileClickEvent::decode, OpenFileClickEvent::encode);
public static final ClickEventAction<RunCommandClickEvent> RUN_COMMAND = define("run_command", true,
RunCommandClickEvent::decode, RunCommandClickEvent::encode);
/**
* Removed in 1.9
*/
@ApiStatus.Obsolete
public static final ClickEventAction<TwitchUserInfoClickEvent> TWITCH_USER_INFO = define("twitch_user_info", false,
TwitchUserInfoClickEvent::decode, TwitchUserInfoClickEvent::encode);
public static final ClickEventAction<SuggestCommandClickEvent> SUGGEST_COMMAND = define("suggest_command", true,
SuggestCommandClickEvent::decode, SuggestCommandClickEvent::encode);
/**
* Added with 1.8
*/
public static final ClickEventAction<ChangePageClickEvent> CHANGE_PAGE = define("change_page", true,
ChangePageClickEvent::decode, ChangePageClickEvent::encode);
/**
* Added with 1.15
*/
public static final ClickEventAction<CopyToClipboardClickEvent> COPY_TO_CLIPBOARD = define("copy_to_clipboard", true,
CopyToClipboardClickEvent::decode, CopyToClipboardClickEvent::encode);
/**
* Added with 1.21.6
*/
public static final ClickEventAction<ShowDialogClickEvent> SHOW_DIALOG = define("show_dialog", true,
ShowDialogClickEvent::decode, ShowDialogClickEvent::encode);
/**
* Added with 1.21.6
*/
public static final ClickEventAction<CustomClickEvent> CUSTOM = define("custom", true,
CustomClickEvent::decode, CustomClickEvent::encode);
static {
REGISTRY.unloadMappings();
}
}
@@ -0,0 +1,57 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class CopyToClipboardClickEvent implements ClickEvent {
private final String value;
public CopyToClipboardClickEvent(String value) {
this.value = value;
}
public static CopyToClipboardClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
String value = compound.getStringTagValueOrThrow("value");
return new CopyToClipboardClickEvent(value);
}
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, CopyToClipboardClickEvent clickEvent) {
compound.setTag("value", new NBTString(clickEvent.value));
}
@Override
public ClickEventAction<?> getAction() {
return ClickEventActions.COPY_TO_CLIPBOARD;
}
@Override
public net.kyori.adventure.text.event.ClickEvent asAdventure() {
return net.kyori.adventure.text.event.ClickEvent.copyToClipboard(this.value);
}
public String getValue() {
return this.value;
}
}
@@ -0,0 +1,72 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
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.NbtTagHolder;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public class CustomClickEvent implements ClickEvent {
private final ResourceLocation id;
private final @Nullable NBT payload;
public CustomClickEvent(ResourceLocation id, @Nullable NBT payload) {
this.id = id;
this.payload = payload;
}
public static CustomClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
ResourceLocation id = compound.getOrThrow("id", ResourceLocation::decode, wrapper);
NBT payload = compound.getTagOrNull("payload");
return new CustomClickEvent(id, payload);
}
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, CustomClickEvent clickEvent) {
compound.set("id", clickEvent.id, ResourceLocation::encode, wrapper);
if (clickEvent.payload != null) {
compound.setTag("payload", clickEvent.payload);
}
}
@Override
public ClickEventAction<?> getAction() {
return ClickEventActions.CUSTOM;
}
@Override
public net.kyori.adventure.text.event.ClickEvent asAdventure() {
return net.kyori.adventure.text.event.ClickEvent.custom(
this.id.key(), new NbtTagHolder(this.payload != null ? this.payload : NBTEnd.INSTANCE));
}
public ResourceLocation getId() {
return this.id;
}
public @Nullable NBT getPayload() {
return this.payload;
}
}
@@ -0,0 +1,60 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class OpenFileClickEvent implements ClickEvent {
private final String path;
public OpenFileClickEvent(String path) {
this.path = path;
}
public static OpenFileClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
boolean v1215 = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5);
String path = compound.getStringTagValueOrThrow(v1215 ? "path" : "value");
return new OpenFileClickEvent(path);
}
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, OpenFileClickEvent clickEvent) {
boolean v1215 = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5);
compound.setTag(v1215 ? "path" : "value", new NBTString(clickEvent.path));
}
@Override
public ClickEventAction<?> getAction() {
return ClickEventActions.OPEN_FILE;
}
@Override
public net.kyori.adventure.text.event.ClickEvent asAdventure() {
return net.kyori.adventure.text.event.ClickEvent.openFile(this.path);
}
public String getPath() {
return this.path;
}
}
@@ -0,0 +1,60 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class OpenUrlClickEvent implements ClickEvent {
private final String url;
public OpenUrlClickEvent(String url) {
this.url = url;
}
public static OpenUrlClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
boolean v1215 = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5);
String url = compound.getStringTagValueOrThrow(v1215 ? "url" : "value");
return new OpenUrlClickEvent(url);
}
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, OpenUrlClickEvent clickEvent) {
boolean v1215 = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5);
compound.setTag(v1215 ? "url" : "value", new NBTString(clickEvent.url));
}
@Override
public ClickEventAction<?> getAction() {
return ClickEventActions.OPEN_URL;
}
@Override
public net.kyori.adventure.text.event.ClickEvent asAdventure() {
return net.kyori.adventure.text.event.ClickEvent.openUrl(this.url);
}
public String getUrl() {
return this.url;
}
}
@@ -0,0 +1,60 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class RunCommandClickEvent implements ClickEvent {
private final String command;
public RunCommandClickEvent(String command) {
this.command = command;
}
public static RunCommandClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
boolean v1215 = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5);
String command = compound.getStringTagValueOrThrow(v1215 ? "command" : "value");
return new RunCommandClickEvent(command);
}
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, RunCommandClickEvent clickEvent) {
boolean v1215 = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5);
compound.setTag(v1215 ? "command" : "value", new NBTString(clickEvent.command));
}
@Override
public ClickEventAction<?> getAction() {
return ClickEventActions.RUN_COMMAND;
}
@Override
public net.kyori.adventure.text.event.ClickEvent asAdventure() {
return net.kyori.adventure.text.event.ClickEvent.runCommand(this.command);
}
public String getCommand() {
return this.command;
}
}
@@ -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.chat.clickevent;
import com.github.retrooper.packetevents.protocol.dialog.Dialog;
import com.github.retrooper.packetevents.protocol.dialog.Dialogs;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntityRef;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class ShowDialogClickEvent implements ClickEvent {
private final MappedEntityRef<Dialog> dialog;
public ShowDialogClickEvent(Dialog dialog) {
this(new MappedEntityRef.Static<>(dialog));
}
public ShowDialogClickEvent(MappedEntityRef<Dialog> dialog) {
this.dialog = dialog;
}
public static ShowDialogClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
MappedEntityRef<Dialog> dialog = MappedEntityRef.decode(compound.getTagOrThrow("dialog"),
Dialogs.getRegistry(), Dialog::decode, wrapper);
return new ShowDialogClickEvent(dialog);
}
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, ShowDialogClickEvent clickEvent) {
compound.setTag("dialog", MappedEntityRef.encode(wrapper, Dialog::encode, clickEvent.dialog));
}
@Override
public ClickEventAction<?> getAction() {
return ClickEventActions.SHOW_DIALOG;
}
@Override
public net.kyori.adventure.text.event.ClickEvent asAdventure() {
return net.kyori.adventure.text.event.ClickEvent.showDialog(this.dialog.get());
}
public MappedEntityRef<Dialog> getDialogRef() {
return this.dialog;
}
public Dialog getDialog() {
return this.dialog.get();
}
}
@@ -0,0 +1,63 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.util.NbtMapDecoder;
import com.github.retrooper.packetevents.protocol.util.NbtMapEncoder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class StaticClickEventAction<T extends ClickEvent> extends AbstractMappedEntity implements ClickEventAction<T> {
private final boolean allowFromServer;
private final NbtMapDecoder<T> decoder;
private final NbtMapEncoder<T> encoder;
@ApiStatus.Internal
public StaticClickEventAction(
@Nullable TypesBuilderData data, boolean allowFromServer,
NbtMapDecoder<T> decoder, NbtMapEncoder<T> encoder
) {
super(data);
this.allowFromServer = allowFromServer;
this.decoder = decoder;
this.encoder = encoder;
}
@Override
public boolean isAllowFromServer() {
return this.allowFromServer;
}
@Override
public T decode(NBTCompound compound, PacketWrapper<?> wrapper) {
return this.decoder.decode(compound, wrapper);
}
@Override
public void encode(NBTCompound compound, PacketWrapper<?> wrapper, T clickEvent) {
this.encoder.encode(compound, wrapper, clickEvent);
}
}
@@ -0,0 +1,60 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class SuggestCommandClickEvent implements ClickEvent {
private final String command;
public SuggestCommandClickEvent(String command) {
this.command = command;
}
public static SuggestCommandClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
boolean v1215 = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5);
String command = compound.getStringTagValueOrThrow(v1215 ? "command" : "value");
return new SuggestCommandClickEvent(command);
}
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, SuggestCommandClickEvent clickEvent) {
boolean v1215 = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5);
compound.setTag(v1215 ? "command" : "value", new NBTString(clickEvent.command));
}
@Override
public ClickEventAction<?> getAction() {
return ClickEventActions.SUGGEST_COMMAND;
}
@Override
public net.kyori.adventure.text.event.ClickEvent asAdventure() {
return net.kyori.adventure.text.event.ClickEvent.suggestCommand(this.command);
}
public String getCommand() {
return this.command;
}
}
@@ -0,0 +1,62 @@
/*
* 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.chat.clickevent;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Removed in 1.9
*/
@NullMarked
@ApiStatus.Obsolete
public class TwitchUserInfoClickEvent implements ClickEvent {
private final String value;
public TwitchUserInfoClickEvent(String value) {
this.value = value;
}
public static TwitchUserInfoClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
String value = compound.getStringTagValueOrThrow("value");
return new TwitchUserInfoClickEvent(value);
}
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, TwitchUserInfoClickEvent clickEvent) {
compound.setTag("value", new NBTString(clickEvent.value));
}
@Override
public ClickEventAction<?> getAction() {
return ClickEventActions.TWITCH_USER_INFO;
}
@Override
public net.kyori.adventure.text.event.ClickEvent asAdventure() {
throw new UnsupportedOperationException();
}
public String getValue() {
return this.value;
}
}
@@ -19,6 +19,8 @@
package com.github.retrooper.packetevents.protocol.chat.message;
import com.github.retrooper.packetevents.protocol.chat.ChatType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
import net.kyori.adventure.text.Component;
public class ChatMessage {
@@ -34,14 +36,22 @@ public class ChatMessage {
return chatContent;
}
public ChatType getType() {
return type;
public String getChatContentJson(ClientVersion version) {
return AdventureSerializer.serializer(version).asJson(this.getChatContent());
}
public void setChatContent(Component chatContent) {
this.chatContent = chatContent;
}
public void setChatContentJson(ClientVersion version, String json) {
this.setChatContent(AdventureSerializer.serializer(version).fromJson(json));
}
public ChatType getType() {
return type;
}
public void setType(ChatType type) {
this.type = type;
}
@@ -53,7 +53,7 @@ public class ChatMessageProcessor_v1_21_5 implements ChatMessageProcessor {
@Override
public void writeChatMessage(@NotNull PacketWrapper<?> wrapper, @NotNull ChatMessage data) {
ChatMessage_v1_21_5 newData = (ChatMessage_v1_21_5) data;
wrapper.writeInt(newData.getGlobalIndex());
wrapper.writeVarInt(newData.getGlobalIndex());
wrapper.writeUUID(newData.getSenderUUID());
wrapper.writeVarInt(newData.getIndex());
wrapper.writeOptional(newData.getSignature(), PacketWrapper::writeBytes);
@@ -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;
}
}
@@ -28,19 +28,29 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
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.Objects;
@NullMarked
public class Color implements RGBLike {
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(
@@ -65,6 +75,21 @@ public class Color implements RGBLike {
wrapper.writeInt(color.asRGB());
}
public static Color readShort(PacketWrapper<?> wrapper) {
return new Color(wrapper.readUnsignedByte(), wrapper.readUnsignedByte(), wrapper.readUnsignedByte());
}
public static void writeShort(PacketWrapper<?> wrapper, Color color) {
wrapper.writeByte(color.red);
wrapper.writeByte(color.green);
wrapper.writeByte(color.blue);
}
public static Color decode(NBT nbt, PacketWrapper<?> wrapper) {
return decode(nbt, wrapper.getServerVersion().toClientVersion());
}
@Deprecated
public static Color decode(NBT nbt, ClientVersion version) {
if (nbt instanceof NBTNumber) {
return new Color(((NBTNumber) nbt).getAsInt());
@@ -76,6 +101,11 @@ public class Color implements RGBLike {
return new Color(red, green, blue);
}
public static NBT encode(PacketWrapper<?> wrapper, Color color) {
return encode(color, wrapper.getServerVersion().toClientVersion());
}
@Deprecated
public static NBT encode(Color color, ClientVersion version) {
if (version.isNewerThanOrEquals(ClientVersion.V_1_21_2)) {
return new NBTInt(color.asRGB());
@@ -87,15 +117,23 @@ public class Color implements RGBLike {
return list;
}
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);
}
@@ -103,6 +141,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;
@@ -117,4 +235,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());
}
}
@@ -39,10 +39,13 @@ import com.github.retrooper.packetevents.protocol.component.builtin.ShulkerColor
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;
import com.github.retrooper.packetevents.protocol.component.builtin.TypedBlockEntityData;
import com.github.retrooper.packetevents.protocol.component.builtin.TypedEntityData;
import com.github.retrooper.packetevents.protocol.component.builtin.VillagerVariantComponent;
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.BundleContents;
@@ -52,6 +55,7 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.DebugSt
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.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;
@@ -62,6 +66,7 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemCon
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemContainerLoot;
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;
@@ -70,11 +75,14 @@ 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.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;
@@ -83,11 +91,13 @@ 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.ItemWeapon;
import com.github.retrooper.packetevents.protocol.component.builtin.item.LodestoneTracker;
@@ -245,12 +255,18 @@ public final class ComponentTypes {
ArmorTrim::read, ArmorTrim::write);
public static final ComponentType<DebugStickState> DEBUG_STICK_STATE = define("debug_stick_state",
DebugStickState::read, DebugStickState::write);
public static final ComponentType<NBTCompound> ENTITY_DATA = define("entity_data",
PacketWrapper::readNBT, PacketWrapper::writeNBT);
public static final ComponentType<TypedEntityData> TYPED_ENTITY_DATA = define("entity_data",
TypedEntityData::read, TypedEntityData::write);
@Deprecated
public static final ComponentType<NBTCompound> ENTITY_DATA = TYPED_ENTITY_DATA
.legacyMap(TypedEntityData::getCompound, TypedEntityData::new);
public static final ComponentType<NBTCompound> BUCKET_ENTITY_DATA = define("bucket_entity_data",
PacketWrapper::readNBT, PacketWrapper::writeNBT);
public static final ComponentType<NBTCompound> BLOCK_ENTITY_DATA = define("block_entity_data",
PacketWrapper::readNBT, PacketWrapper::writeNBT);
public static final ComponentType<TypedBlockEntityData> TYPED_BLOCK_ENTITY_DATA = define("block_entity_data",
TypedBlockEntityData::read, TypedBlockEntityData::write);
@Deprecated
public static final ComponentType<NBTCompound> BLOCK_ENTITY_DATA = TYPED_BLOCK_ENTITY_DATA
.legacyMap(TypedBlockEntityData::getCompound, TypedBlockEntityData::new);
public static final ComponentType<ItemInstrument> ITEM_INSTRUMENT = define("instrument",
ItemInstrument::read, ItemInstrument::write);
@Deprecated
@@ -472,6 +488,47 @@ 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+
*/
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);
/**
* Returns an immutable view of the component types.
*
@@ -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,14 +22,22 @@ 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.wrapper.PacketWrapper;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
import java.util.Map;
import java.util.Optional;
@NullMarked
public interface IComponentMap {
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) {
NBTCompound compound = (NBTCompound) nbt;
@@ -45,6 +53,11 @@ public interface IComponentMap {
return components.build();
}
static NBT encode(PacketWrapper<?> wrapper, StaticComponentMap components) {
return encode(components, wrapper.getServerVersion().toClientVersion());
}
@Deprecated
@SuppressWarnings("unchecked") // safe in this case
static NBT encode(StaticComponentMap components, ClientVersion version) {
NBTCompound compound = new NBTCompound();
@@ -0,0 +1,84 @@
/*
* 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.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.world.blockentity.BlockEntityType;
import com.github.retrooper.packetevents.protocol.world.blockentity.BlockEntityTypes;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
@NullMarked
public final class TypedBlockEntityData {
private static final BlockEntityType FALLBACK_TYPE = BlockEntityTypes.FURNACE;
/**
* @versions 1.21.9+
*/
private final BlockEntityType type;
private final NBTCompound compound;
public TypedBlockEntityData(NBTCompound compound) {
this(FALLBACK_TYPE, compound);
}
public TypedBlockEntityData(BlockEntityType type, NBTCompound compound) {
this.type = type;
this.compound = compound;
}
public static TypedBlockEntityData read(PacketWrapper<?> wrapper) {
BlockEntityType type = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_9)
? wrapper.readMappedEntity(BlockEntityTypes.getRegistry()) : FALLBACK_TYPE;
NBTCompound compound = wrapper.readNBT();
return new TypedBlockEntityData(type, compound);
}
public static void write(PacketWrapper<?> wrapper, TypedBlockEntityData data) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_9)) {
wrapper.writeMappedEntity(data.type);
}
wrapper.writeNBT(data.compound);
}
public BlockEntityType getType() {
return this.type;
}
public NBTCompound getCompound() {
return this.compound;
}
@Override
public boolean equals(Object obj) {
if (obj == null || this.getClass() != obj.getClass()) return false;
TypedBlockEntityData that = (TypedBlockEntityData) obj;
if (!this.type.equals(that.type)) return false;
return this.compound.equals(that.compound);
}
@Override
public int hashCode() {
return Objects.hash(this.type, this.compound);
}
}
@@ -0,0 +1,84 @@
/*
* 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.type.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
@NullMarked
public final class TypedEntityData {
private static final EntityType FALLBACK_TYPE = EntityTypes.PIG;
/**
* @versions 1.21.9+
*/
private final EntityType type;
private final NBTCompound compound;
public TypedEntityData(NBTCompound compound) {
this(FALLBACK_TYPE, compound);
}
public TypedEntityData(EntityType type, NBTCompound compound) {
this.type = type;
this.compound = compound;
}
public static TypedEntityData read(PacketWrapper<?> wrapper) {
EntityType type = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_9)
? wrapper.readMappedEntity(EntityTypes.getRegistry()) : FALLBACK_TYPE;
NBTCompound compound = wrapper.readNBT();
return new TypedEntityData(type, compound);
}
public static void write(PacketWrapper<?> wrapper, TypedEntityData data) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_9)) {
wrapper.writeMappedEntity(data.type);
}
wrapper.writeNBT(data.compound);
}
public EntityType getType() {
return this.type;
}
public NBTCompound getCompound() {
return this.compound;
}
@Override
public boolean equals(Object obj) {
if (obj == null || this.getClass() != obj.getClass()) return false;
TypedEntityData that = (TypedEntityData) obj;
if (!this.type.equals(that.type)) return false;
return this.compound.equals(that.compound);
}
@Override
public int hashCode() {
return Objects.hash(this.type, this.compound);
}
}
@@ -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.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(MaybeMappedEntity<ZombieNautilusVariant> variant) {
this.variant = variant;
}
public static ZombieNautilusVariantComponent read(PacketWrapper<?> wrapper) {
MaybeMappedEntity<ZombieNautilusVariant> variant = MaybeMappedEntity.read(wrapper,
ZombieNautilusVariants.getRegistry(), ZombieNautilusVariant::read);
return new ZombieNautilusVariantComponent(variant);
}
public static void write(PacketWrapper<?> wrapper, ZombieNautilusVariantComponent component) {
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);
}
}
@@ -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,7 +35,8 @@ 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());
}
@@ -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);
}
}
@@ -20,8 +20,10 @@ package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.attribute.Attribute;
import com.github.retrooper.packetevents.protocol.attribute.AttributeDisplay;
import com.github.retrooper.packetevents.protocol.attribute.AttributeOperation;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.attribute.DefaultAttributeDisplay;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes.PropertyModifier;
@@ -133,24 +135,39 @@ public class ItemAttributeModifiers {
private Attribute attribute;
private Modifier modifier;
private EquipmentSlotGroup slotGroup;
private AttributeDisplay display;
@ApiStatus.Obsolete
public ModifierEntry(Attribute attribute, Modifier modifier, EquipmentSlotGroup slotGroup) {
this(attribute, modifier, slotGroup, DefaultAttributeDisplay.INSTANCE);
}
public ModifierEntry(
Attribute attribute, Modifier modifier,
EquipmentSlotGroup slotGroup, AttributeDisplay display
) {
this.attribute = attribute;
this.modifier = modifier;
this.slotGroup = slotGroup;
this.display = display;
}
public static ModifierEntry read(PacketWrapper<?> wrapper) {
Attribute attribute = wrapper.readMappedEntity(Attributes::getById);
Modifier modifier = Modifier.read(wrapper);
EquipmentSlotGroup slot = wrapper.readEnum(EquipmentSlotGroup.values());
return new ModifierEntry(attribute, modifier, slot);
AttributeDisplay display = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_6)
? AttributeDisplay.read(wrapper) : DefaultAttributeDisplay.INSTANCE;
return new ModifierEntry(attribute, modifier, slot, display);
}
public static void write(PacketWrapper<?> wrapper, ModifierEntry entry) {
wrapper.writeMappedEntity(entry.attribute);
Modifier.write(wrapper, entry.modifier);
wrapper.writeEnum(entry.slotGroup);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_6)) {
AttributeDisplay.write(wrapper, entry.display);
}
}
public Attribute getAttribute() {
@@ -321,7 +338,12 @@ public class ItemAttributeModifiers {
CHEST("chest"),
HEAD("head"),
ARMOR("armor"),
BODY("body");
BODY("body"),
/**
* Added with 1.21.5
*/
SADDLE("saddle"),
;
public static final Index<String, EquipmentSlotGroup> ID_INDEX = Index.create(
EquipmentSlotGroup.class, EquipmentSlotGroup::getId);
@@ -18,6 +18,7 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.component.builtin.TypedEntityData;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
@@ -68,37 +69,50 @@ public class ItemBees {
public static class BeeEntry {
private NBTCompound entityData;
private TypedEntityData entityData;
private int ticksInHive;
private int minTicksInHive;
@Deprecated
public BeeEntry(NBTCompound entityData, int ticksInHive, int minTicksInHive) {
this(new TypedEntityData(entityData), ticksInHive, minTicksInHive);
}
public BeeEntry(TypedEntityData entityData, int ticksInHive, int minTicksInHive) {
this.entityData = entityData;
this.ticksInHive = ticksInHive;
this.minTicksInHive = minTicksInHive;
}
public static BeeEntry read(PacketWrapper<?> wrapper) {
NBTCompound entityData = wrapper.readNBT();
TypedEntityData entityData = TypedEntityData.read(wrapper);
int ticksInHive = wrapper.readVarInt();
int minTicksInHive = wrapper.readVarInt();
return new BeeEntry(entityData, ticksInHive, minTicksInHive);
}
public static void write(PacketWrapper<?> wrapper, BeeEntry bee) {
wrapper.writeNBT(bee.entityData);
TypedEntityData.write(wrapper, bee.entityData);
wrapper.writeVarInt(bee.ticksInHive);
wrapper.writeVarInt(bee.minTicksInHive);
}
public NBTCompound getEntityData() {
public TypedEntityData getTypedEntityData() {
return this.entityData;
}
public void setEntityData(NBTCompound entityData) {
public void setTypedEntityData(TypedEntityData entityData) {
this.entityData = entityData;
}
public NBTCompound getEntityData() {
return this.entityData.getCompound();
}
public void setEntityData(NBTCompound entityData) {
this.entityData = new TypedEntityData(entityData);
}
public int getTicksInHive() {
return this.ticksInHive;
}
@@ -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 + '}';
}
}
@@ -0,0 +1,78 @@
/*
* 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.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.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));
}
public ItemDamageType(MaybeMappedEntity<DamageType> damageType) {
this.damageType = damageType;
}
public static ItemDamageType read(PacketWrapper<?> wrapper) {
MaybeMappedEntity<DamageType> damageType = MaybeMappedEntity.read(wrapper,
DamageTypes.getRegistry(), DamageType::read);
return new ItemDamageType(damageType);
}
public static void write(PacketWrapper<?> wrapper, ItemDamageType component) {
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);
}
}
@@ -24,6 +24,7 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.protocol.player.EquipmentSlot;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.protocol.sound.Sounds;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
@@ -41,7 +42,18 @@ public class ItemEquippable {
private boolean dispensable;
private boolean swappable;
private boolean damageOnHurt;
/**
* Added with 1.21.5
*/
private boolean equipOnInteract;
/**
* Added with 1.21.6
*/
private boolean canBeSheared;
/**
* Added with 1.21.6
*/
private Sound shearingSound;
@ApiStatus.Obsolete
public ItemEquippable(
@@ -58,6 +70,7 @@ public class ItemEquippable {
dispensable, swappable, damageOnHurt, false);
}
@ApiStatus.Obsolete
public ItemEquippable(
EquipmentSlot slot,
Sound equipSound,
@@ -68,6 +81,24 @@ public class ItemEquippable {
boolean swappable,
boolean damageOnHurt,
boolean equipOnInteract
) {
this(slot, equipSound, assetId, cameraOverlay, allowedEntities,
dispensable, swappable, damageOnHurt, equipOnInteract,
false, Sounds.ITEM_SHEARS_SNIP);
}
public ItemEquippable(
EquipmentSlot slot,
Sound equipSound,
@Nullable ResourceLocation assetId,
@Nullable ResourceLocation cameraOverlay,
@Nullable MappedEntitySet<EntityType> allowedEntities,
boolean dispensable,
boolean swappable,
boolean damageOnHurt,
boolean equipOnInteract,
boolean canBeSheared,
Sound shearingSound
) {
this.slot = slot;
this.equipSound = equipSound;
@@ -78,6 +109,8 @@ public class ItemEquippable {
this.swappable = swappable;
this.damageOnHurt = damageOnHurt;
this.equipOnInteract = equipOnInteract;
this.canBeSheared = canBeSheared;
this.shearingSound = shearingSound;
}
public static ItemEquippable read(PacketWrapper<?> wrapper) {
@@ -90,9 +123,19 @@ public class ItemEquippable {
boolean dispensable = wrapper.readBoolean();
boolean swappable = wrapper.readBoolean();
boolean damageOnHurt = wrapper.readBoolean();
boolean equipOnInteract = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5) && wrapper.readBoolean();
boolean equipOnInteract = false;
boolean canBeSheared = false;
Sound shearingSound = Sounds.ITEM_SHEARS_SNIP;
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5)) {
equipOnInteract = wrapper.readBoolean();
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_6)) {
canBeSheared = wrapper.readBoolean();
shearingSound = Sound.read(wrapper);
}
}
return new ItemEquippable(slot, equipSound, assetId,
cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt, equipOnInteract);
cameraOverlay, allowedEntities, dispensable, swappable,
damageOnHurt, equipOnInteract, canBeSheared, shearingSound);
}
public static void write(PacketWrapper<?> wrapper, ItemEquippable equippable) {
@@ -106,6 +149,10 @@ public class ItemEquippable {
wrapper.writeBoolean(equippable.damageOnHurt);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_5)) {
wrapper.writeBoolean(equippable.equipOnInteract);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_6)) {
wrapper.writeBoolean(equippable.canBeSheared);
Sound.write(wrapper, equippable.shearingSound);
}
}
}
@@ -187,6 +234,34 @@ public class ItemEquippable {
this.equipOnInteract = equipOnInteract;
}
/**
* Added with 1.21.6
*/
public boolean isCanBeSheared() {
return this.canBeSheared;
}
/**
* Added with 1.21.6
*/
public void setCanBeSheared(boolean canBeSheared) {
this.canBeSheared = canBeSheared;
}
/**
* Added with 1.21.6
*/
public Sound getShearingSound() {
return this.shearingSound;
}
/**
* Added with 1.21.6
*/
public void setShearingSound(Sound shearingSound) {
this.shearingSound = shearingSound;
}
@Deprecated
public @Nullable ResourceLocation getModel() {
return this.assetId;
@@ -199,27 +274,28 @@ public class ItemEquippable {
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemEquippable)) return false;
ItemEquippable that = (ItemEquippable) obj;
if (this.dispensable != that.dispensable) return false;
if (this.swappable != that.swappable) return false;
if (this.damageOnHurt != that.damageOnHurt) return false;
if (this.equipOnInteract != that.equipOnInteract) return false;
if (this.canBeSheared != that.canBeSheared) return false;
if (this.slot != that.slot) return false;
if (!Objects.equals(this.equipSound, that.equipSound)) return false;
if (!this.equipSound.equals(that.equipSound)) return false;
if (!Objects.equals(this.assetId, that.assetId)) return false;
if (!Objects.equals(this.cameraOverlay, that.cameraOverlay)) return false;
if (!Objects.equals(this.allowedEntities, that.allowedEntities)) return false;
return Objects.equals(this.equipOnInteract, that.equipOnInteract);
return this.shearingSound.equals(that.shearingSound);
}
@Override
public int hashCode() {
return Objects.hash(this.slot, this.equipSound, this.assetId, this.cameraOverlay, this.allowedEntities, this.dispensable, this.swappable, this.damageOnHurt, this.equipOnInteract);
return Objects.hash(this.slot, this.equipSound, this.assetId, this.cameraOverlay, this.allowedEntities, this.dispensable, this.swappable, this.damageOnHurt, this.equipOnInteract, this.canBeSheared, this.shearingSound);
}
@Override
public String toString() {
return "ItemEquippable{slot=" + this.slot + ", equipSound=" + this.equipSound + ", assetId=" + this.assetId + ", cameraOverlay=" + this.cameraOverlay + ", allowedEntities=" + this.allowedEntities + ", dispensable=" + this.dispensable + ", swappable=" + this.swappable + ", damageOnHurt=" + this.damageOnHurt + ", equipOnInteract=" + this.equipOnInteract + '}';
return "ItemEquippable{slot=" + this.slot + ", equipSound=" + this.equipSound + ", assetId=" + this.assetId + ", cameraOverlay=" + this.cameraOverlay + ", allowedEntities=" + this.allowedEntities + ", dispensable=" + this.dispensable + ", swappable=" + this.swappable + ", damageOnHurt=" + this.damageOnHurt + ", equipOnInteract=" + this.equipOnInteract + ", canBeSheared=" + this.canBeSheared + ", shearingSound=" + this.shearingSound + '}';
}
}
@@ -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);
}
}
}
@@ -18,46 +18,100 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import java.util.Objects;
@NullMarked
public class ItemLock {
private String code;
private static final String FALLBACK_LOCK_STRING = "packetevents$invalid_lock";
/**
* @versions 1.20.5-1.21.1
*/
@ApiStatus.Obsolete
private String code;
/**
* @versions 1.21.2+
*/
private NBTCompound predicate;
/**
* @versions 1.20.5-1.21.1
*/
@ApiStatus.Obsolete
public ItemLock(String code) {
this.code = code;
this.predicate = new NBTCompound();
}
public ItemLock(NBTCompound predicate) {
this.code = FALLBACK_LOCK_STRING;
this.predicate = predicate;
}
public static ItemLock read(PacketWrapper<?> wrapper) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2)) {
return new ItemLock(wrapper.readNBT());
}
NBTString codeTag = (NBTString) wrapper.readNBTRaw();
return new ItemLock(codeTag.getValue());
}
public static void write(PacketWrapper<?> wrapper, ItemLock lock) {
wrapper.writeNBTRaw(new NBTString(lock.code));
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2)) {
wrapper.writeNBT(lock.predicate);
} else {
wrapper.writeNBTRaw(new NBTString(lock.code));
}
}
/**
* @versions 1.20.5-1.21.1
*/
@ApiStatus.Obsolete
public String getCode() {
return this.code;
}
/**
* @versions 1.20.5-1.21.1
*/
@ApiStatus.Obsolete
public void setCode(String code) {
this.code = code;
}
/**
* @versions 1.21.2+
*/
public NBTCompound getPredicate() {
return this.predicate;
}
/**
* @versions 1.21.2+
*/
public void setPredicate(NBTCompound predicate) {
this.predicate = predicate;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemLock)) return false;
if (obj == null || this.getClass() != obj.getClass()) return false;
ItemLock itemLock = (ItemLock) obj;
return this.code.equals(itemLock.code);
if (!this.code.equals(itemLock.code)) return false;
return this.predicate.equals(itemLock.predicate);
}
@Override
public int hashCode() {
return Objects.hashCode(this.code);
return Objects.hash(this.code, this.predicate);
}
}
@@ -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,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);
}
}
@@ -18,40 +18,148 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
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.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 org.jetbrains.annotations.Nullable;
import net.kyori.adventure.text.object.PlayerHeadObjectContents;
import net.kyori.adventure.text.object.PlayerHeadObjectContents.ProfileProperty;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
public class ItemProfile {
import static net.kyori.adventure.text.object.PlayerHeadObjectContents.property;
@NullMarked
public final class ItemProfile {
private @Nullable String name;
private @Nullable UUID id;
private List<Property> properties;
/**
* @versions 1.21.9+
*/
private SkinPatch skinPatch;
public ItemProfile(
@Nullable String name,
@Nullable UUID id,
List<Property> properties
) {
this(name, id, properties, SkinPatch.EMPTY);
}
public ItemProfile(
@Nullable String name,
@Nullable UUID id,
List<Property> properties,
SkinPatch skinPatch
) {
this.name = name;
this.id = id;
this.properties = properties;
this.skinPatch = skinPatch;
}
public static ItemProfile read(PacketWrapper<?> wrapper) {
String name = wrapper.readOptional(ew -> ew.readString(16));
UUID id = wrapper.readOptional(PacketWrapper::readUUID);
String name;
UUID id;
boolean partial = wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_21_9) || !wrapper.readBoolean();
if (!partial) {
id = wrapper.readUUID();
name = wrapper.readString(16);
} else {
name = wrapper.readOptional(ew -> ew.readString(16));
id = wrapper.readOptional(PacketWrapper::readUUID);
}
List<Property> properties = wrapper.readList(Property::read);
return new ItemProfile(name, id, properties);
SkinPatch skinPatch = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_9)
? SkinPatch.read(wrapper) : SkinPatch.EMPTY;
return new ItemProfile(name, id, properties, skinPatch);
}
public static void write(PacketWrapper<?> wrapper, ItemProfile profile) {
wrapper.writeOptional(profile.name, (ew, name) -> ew.writeString(name, 16));
wrapper.writeOptional(profile.id, PacketWrapper::writeUUID);
boolean partial;
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_9)) {
partial = profile.name == null || profile.id == null;
wrapper.writeBoolean(!partial);
} else {
// always partial profile (which is way simpler, why did they change this?)
partial = true;
}
if (!partial) {
wrapper.writeUUID(profile.id);
wrapper.writeString(profile.name, 16);
} else {
wrapper.writeOptional(profile.name, (ew, name) -> ew.writeString(name, 16));
wrapper.writeOptional(profile.id, PacketWrapper::writeUUID);
}
wrapper.writeList(profile.properties, Property::write);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_9)) {
SkinPatch.write(wrapper, profile.skinPatch);
}
}
public static ItemProfile decode(NBT nbt, PacketWrapper<?> wrapper) {
if (nbt instanceof NBTString) {
String name = ((NBTString) nbt).getValue();
return new ItemProfile(name, null, new ArrayList<>());
}
NBTCompound compound = (NBTCompound) nbt;
UUID id = compound.getOrNull("id", NbtCodecs.UUID, wrapper);
String name = compound.getStringTagValueOrNull("name");
List<Property> properties = compound.getOrSupply("properties",
Property.PROPERTY_MAP, ArrayList::new, wrapper);
SkinPatch patch = SkinPatch.decode(compound, wrapper);
return new ItemProfile(name, id, properties, patch);
}
public static NBT encode(PacketWrapper<?> wrapper, ItemProfile profile) {
NBTCompound compound = new NBTCompound();
if (profile.id != null) {
compound.set("id", profile.id, NbtCodecs.UUID, wrapper);
}
if (profile.name != null) {
compound.setTag("name", new NBTString(profile.name));
}
if (!profile.properties.isEmpty()) {
compound.set("properties", profile.properties, Property.PROPERTY_MAP, wrapper);
}
SkinPatch.encode(compound, wrapper, profile.skinPatch);
return compound;
}
public static ItemProfile fromAdventure(PlayerHeadObjectContents headContents) {
List<ProfileProperty> advProps = headContents.profileProperties();
List<Property> properties = new ArrayList<>(advProps.size());
for (ProfileProperty property : advProps) {
properties.add(Property.fromAdventure(property));
}
return new ItemProfile(headContents.name(), headContents.id(), properties);
}
public List<ProfileProperty> getAdventureProperties() {
if (this.properties.isEmpty()) {
return Collections.emptyList();
}
List<ProfileProperty> properties = new ArrayList<>(this.properties.size());
for (Property property : this.properties) {
properties.add(property.asAdventure());
}
return Collections.unmodifiableList(properties);
}
public @Nullable String getName() {
@@ -82,6 +190,20 @@ public class ItemProfile {
this.properties = properties;
}
/**
* @versions 1.21.9+
*/
public SkinPatch getSkinPatch() {
return this.skinPatch;
}
/**
* @versions 1.21.9+
*/
public void setSkinPatch(SkinPatch skinPatch) {
this.skinPatch = skinPatch;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
@@ -89,16 +211,60 @@ public class ItemProfile {
ItemProfile that = (ItemProfile) obj;
if (!Objects.equals(this.name, that.name)) return false;
if (!Objects.equals(this.id, that.id)) return false;
return this.properties.equals(that.properties);
if (!this.properties.equals(that.properties)) return false;
return this.skinPatch.equals(that.skinPatch);
}
@Override
public int hashCode() {
return Objects.hash(this.name, this.id, this.properties);
return Objects.hash(this.name, this.id, this.properties, this.skinPatch);
}
public static class Property {
public static final NbtCodec<Property> CODEC = new NbtMapCodec<Property>() {
@Override
public Property decode(NBTCompound compound, PacketWrapper<?> wrapper) throws NbtCodecException {
String name = compound.getStringTagValueOrThrow("name");
String value = compound.getStringTagValueOrThrow("value");
String signature = compound.getStringTagValueOrNull("signature");
return new ItemProfile.Property(name, value, signature);
}
@Override
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()));
}
}
}.codec();
public static final NbtCodec<List<ItemProfile.Property>> PROPERTY_MAP = new NbtCodec<List<ItemProfile.Property>>() {
private final NbtCodec<List<ItemProfile.Property>> propertyList = CODEC.applyList();
@Override
public List<ItemProfile.Property> decode(NBT nbt, PacketWrapper<?> wrapper) {
if (nbt instanceof NBTCompound) {
Map<String, NBT> tags = ((NBTCompound) nbt).getTags();
List<ItemProfile.Property> properties = new ArrayList<>(tags.size());
for (Map.Entry<String, NBT> entry : tags.entrySet()) {
for (String value : NbtCodecs.STRING_LIST.decode(entry.getValue(), wrapper)) {
properties.add(new ItemProfile.Property(entry.getKey(), value, null));
}
}
return properties;
}
return this.propertyList.decode(nbt, wrapper);
}
@Override
public NBT encode(PacketWrapper<?> wrapper, List<ItemProfile.Property> value) {
return this.propertyList.encode(wrapper, value);
}
};
private String name;
private String value;
private @Nullable String signature;
@@ -123,6 +289,14 @@ public class ItemProfile {
(ew, signature) -> ew.writeString(signature, 1024));
}
public static Property fromAdventure(ProfileProperty property) {
return new Property(property.name(), property.value(), property.signature());
}
public ProfileProperty asAdventure() {
return property(this.name, this.value, this.signature);
}
public String getName() {
return this.name;
}
@@ -162,4 +336,95 @@ public class ItemProfile {
return Objects.hash(this.name, this.value, this.signature);
}
}
public static class SkinPatch {
public static final SkinPatch EMPTY = new SkinPatch(null, null, null, null);
private final @Nullable ResourceLocation body;
private final @Nullable ResourceLocation cape;
private final @Nullable ResourceLocation elytra;
private final @Nullable PlayerModelType model;
public SkinPatch(
@Nullable ResourceLocation body,
@Nullable ResourceLocation cape,
@Nullable ResourceLocation elytra,
@Nullable PlayerModelType model
) {
this.body = body;
this.cape = cape;
this.elytra = elytra;
this.model = model;
}
public static SkinPatch read(PacketWrapper<?> wrapper) {
ResourceLocation body = wrapper.readOptional(ResourceLocation::read);
ResourceLocation cape = wrapper.readOptional(ResourceLocation::read);
ResourceLocation elytra = wrapper.readOptional(ResourceLocation::read);
PlayerModelType model = wrapper.readOptional(PlayerModelType::read);
return new SkinPatch(body, cape, elytra, model);
}
public static void write(PacketWrapper<?> wrapper, SkinPatch patch) {
wrapper.writeOptional(patch.body, ResourceLocation::write);
wrapper.writeOptional(patch.cape, ResourceLocation::write);
wrapper.writeOptional(patch.elytra, ResourceLocation::write);
wrapper.writeOptional(patch.model, PlayerModelType::write);
}
public static SkinPatch decode(NBTCompound nbt, PacketWrapper<?> wrapper) {
ResourceLocation body = nbt.getOrNull("texture", ResourceLocation.CODEC, wrapper);
ResourceLocation cape = nbt.getOrNull("cape", ResourceLocation.CODEC, wrapper);
ResourceLocation elytra = nbt.getOrNull("elytra", ResourceLocation.CODEC, wrapper);
PlayerModelType model = nbt.getOrNull("model", PlayerModelType.CODEC, wrapper);
return new SkinPatch(body, cape, elytra, model);
}
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, SkinPatch patch) {
if (patch.body != null) {
compound.set("texture", patch.body, ResourceLocation.CODEC, wrapper);
}
if (patch.cape != null) {
compound.set("cape", patch.cape, ResourceLocation.CODEC, wrapper);
}
if (patch.elytra != null) {
compound.set("elytra", patch.elytra, ResourceLocation.CODEC, wrapper);
}
if (patch.model != null) {
compound.set("model", patch.model, PlayerModelType.CODEC, wrapper);
}
}
public @Nullable ResourceLocation getBody() {
return this.body;
}
public @Nullable ResourceLocation getCape() {
return this.cape;
}
public @Nullable ResourceLocation getElytra() {
return this.elytra;
}
public @Nullable PlayerModelType getModel() {
return this.model;
}
@Override
public boolean equals(Object obj) {
if (obj == null || this.getClass() != obj.getClass()) return false;
SkinPatch skinPatch = (SkinPatch) obj;
if (!Objects.equals(this.body, skinPatch.body)) return false;
if (!Objects.equals(this.cape, skinPatch.cape)) return false;
if (!Objects.equals(this.elytra, skinPatch.elytra)) return false;
return this.model == skinPatch.model;
}
@Override
public int hashCode() {
return Objects.hash(this.body, this.cape, this.elytra, this.model);
}
}
}
@@ -37,8 +37,9 @@ public class ItemRecipes {
public static ItemRecipes read(PacketWrapper<?> wrapper) {
NBTList<?> recipes = (NBTList<?>) wrapper.readNBTRaw();
List<ResourceLocation> recipeKeys = new ArrayList<>(recipes.size());
for (int i = 0; i < recipes.size(); i++) {
int size = recipes.size();
List<ResourceLocation> recipeKeys = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
NBTString tag = (NBTString) recipes.getTag(i);
recipeKeys.add(new ResourceLocation(tag.getValue()));
}
@@ -0,0 +1,87 @@
/*
* 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 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(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,
}
}
@@ -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);
}
}
@@ -0,0 +1,97 @@
/*
* 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.debug;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
/**
* @versions 1.21.9+
*/
@NullMarked
public interface DebugSubscription<T> extends MappedEntity {
T read(PacketWrapper<?> wrapper);
void write(PacketWrapper<?> wrapper, T value);
final class Event<T> {
private final DebugSubscription<T> subscription;
private final T value;
public Event(DebugSubscription<T> subscription, T value) {
this.subscription = subscription;
this.value = value;
}
public static Event<?> read(PacketWrapper<?> wrapper) {
@SuppressWarnings("unchecked")
DebugSubscription<? super Object> subscription = (DebugSubscription<? super Object>) wrapper.readMappedEntity(DebugSubscriptions.getRegistry());
Object value = subscription.read(wrapper);
return new Event<>(subscription, value);
}
public static <T> void write(PacketWrapper<?> wrapper, Event<T> event) {
wrapper.writeMappedEntity(event.subscription);
event.subscription.write(wrapper, event.value);
}
public DebugSubscription<T> getSubscription() {
return this.subscription;
}
public T getValue() {
return this.value;
}
}
final class Update<T> {
private final DebugSubscription<T> subscription;
private final @Nullable T value;
public Update(DebugSubscription<T> subscription, @Nullable T value) {
this.subscription = subscription;
this.value = value;
}
public static Update<?> read(PacketWrapper<?> wrapper) {
@SuppressWarnings("unchecked")
DebugSubscription<? super Object> subscription = (DebugSubscription<? super Object>) wrapper.readMappedEntity(DebugSubscriptions.getRegistry());
Object value = wrapper.readOptional(subscription::read);
return new Update<>(subscription, value);
}
public static <T> void write(PacketWrapper<?> wrapper, Update<T> event) {
wrapper.writeMappedEntity(event.subscription);
wrapper.writeOptional(event.value, event.subscription::write);
}
public DebugSubscription<T> getSubscription() {
return this.subscription;
}
public @Nullable T getValue() {
return this.value;
}
}
}
@@ -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.debug;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugBeeInfo;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugBrainDump;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugBreezeInfo;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugEntityBlockIntersection;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugGameEventInfo;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugGameEventListenerInfo;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugGoalInfo;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugHiveInfo;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugNeighborUpdateInfo;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugPathInfo;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugPoiInfo;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugRaidsInfo;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugStructureInfos;
import com.github.retrooper.packetevents.protocol.debug.struct.DebugVillageSections;
import com.github.retrooper.packetevents.protocol.debug.struct.RedstoneOrientation;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
/**
* @versions 1.21.9+
*/
@NullMarked
public final class DebugSubscriptions {
private static final VersionedRegistry<DebugSubscription<?>> REGISTRY = new VersionedRegistry<>("debug_subscription");
private DebugSubscriptions() {
}
public static VersionedRegistry<DebugSubscription<?>> getRegistry() {
return REGISTRY;
}
@ApiStatus.Internal
public static <T> DebugSubscription<T> define(String name) {
return define(name, null, null);
}
@ApiStatus.Internal
public static <T> DebugSubscription<T> define(
String name,
PacketWrapper.@Nullable Reader<T> reader,
PacketWrapper.@Nullable Writer<T> writer
) {
return REGISTRY.define(name, data -> new StaticDebugSubscription<>(data, reader, writer));
}
public static final DebugSubscription<?> DEDICATED_SERVER_TICK_TIME = define("dedicated_server_tick_time");
public static final DebugSubscription<DebugBeeInfo> BEES = define("bees", DebugBeeInfo::read, DebugBeeInfo::write);
public static final DebugSubscription<DebugBrainDump> BRAINS = define("brains", DebugBrainDump::read, DebugBrainDump::write);
public static final DebugSubscription<DebugBreezeInfo> BREEZES = define("breezes", DebugBreezeInfo::read, DebugBreezeInfo::write);
public static final DebugSubscription<DebugGoalInfo> GOAL_SELECTORS = define("goal_selectors", DebugGoalInfo::read, DebugGoalInfo::write);
public static final DebugSubscription<DebugPathInfo> ENTITY_PATHS = define("entity_paths", DebugPathInfo::read, DebugPathInfo::write);
public static final DebugSubscription<DebugEntityBlockIntersection> ENTITY_BLOCK_INTERSECTIONS = define("entity_block_intersections", DebugEntityBlockIntersection::read, DebugEntityBlockIntersection::write);
public static final DebugSubscription<DebugHiveInfo> BEE_HIVES = define("bee_hives", DebugHiveInfo::read, DebugHiveInfo::write);
public static final DebugSubscription<DebugPoiInfo> POIS = define("pois", DebugPoiInfo::read, DebugPoiInfo::write);
public static final DebugSubscription<RedstoneOrientation> REDSTONE_WIRE_ORIENTATIONS = define("redstone_wire_orientations", RedstoneOrientation::read, RedstoneOrientation::write);
public static final DebugSubscription<DebugVillageSections> VILLAGE_SECTIONS = define("village_sections", DebugVillageSections::read, DebugVillageSections::write);
public static final DebugSubscription<DebugRaidsInfo> RAIDS = define("raids", DebugRaidsInfo::read, DebugRaidsInfo::write);
public static final DebugSubscription<DebugStructureInfos> STRUCTURES = define("structures", DebugStructureInfos::read, DebugStructureInfos::write);
public static final DebugSubscription<DebugGameEventListenerInfo> GAME_EVENT_LISTENERS = define("game_event_listeners", DebugGameEventListenerInfo::read, DebugGameEventListenerInfo::write);
public static final DebugSubscription<DebugNeighborUpdateInfo> NEIGHBOR_UPDATES = define("neighbor_updates", DebugNeighborUpdateInfo::read, DebugNeighborUpdateInfo::write);
public static final DebugSubscription<DebugGameEventInfo> GAME_EVENTS = define("game_events", DebugGameEventInfo::read, DebugGameEventInfo::write);
static {
REGISTRY.unloadMappings();
}
}
@@ -0,0 +1,63 @@
/*
* 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.debug;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
/**
* @versions 1.21.9+
*/
@NullMarked
public class StaticDebugSubscription<T> extends AbstractMappedEntity implements DebugSubscription<T> {
private final PacketWrapper.@Nullable Reader<T> reader;
private final PacketWrapper.@Nullable Writer<T> writer;
@ApiStatus.Internal
public StaticDebugSubscription(
@Nullable TypesBuilderData data,
PacketWrapper.@Nullable Reader<T> reader,
PacketWrapper.@Nullable Writer<T> writer
) {
super(data);
this.reader = reader;
this.writer = writer;
}
@Override
public T read(PacketWrapper<?> wrapper) {
if (this.reader == null) {
throw new IllegalStateException(this + " doesn't support network reading");
}
return this.reader.apply(wrapper);
}
@Override
public void write(PacketWrapper<?> wrapper, T value) {
if (this.writer == null) {
throw new IllegalStateException(this + " doesn't support network writing");
}
this.writer.accept(wrapper, value);
}
}
@@ -0,0 +1,94 @@
/*
* 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.debug.path;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
/**
* @versions 1.21.9+
*/
@NullMarked
public final class DebugNode {
private final Vector3i pos;
private final float walkedDistance;
private final float costMalus;
private final boolean closed;
private final DebugPathType type;
private final float f;
public DebugNode(
Vector3i pos, float walkedDistance, float costMalus,
boolean closed, DebugPathType type, float f
) {
this.pos = pos;
this.walkedDistance = walkedDistance;
this.costMalus = costMalus;
this.closed = closed;
this.type = type;
this.f = f;
}
public static DebugNode read(PacketWrapper<?> wrapper) {
Vector3i pos = new Vector3i(wrapper.readInt(), wrapper.readInt(), wrapper.readInt());
float walkedDistance = wrapper.readFloat();
float costMalus = wrapper.readFloat();
boolean closed = wrapper.readBoolean();
DebugPathType type = wrapper.readEnum(DebugPathType.values());
float f = wrapper.readFloat();
return new DebugNode(pos, walkedDistance, costMalus, closed, type, f);
}
public static void write(PacketWrapper<?> wrapper, DebugNode node) {
wrapper.writeInt(node.pos.x);
wrapper.writeInt(node.pos.y);
wrapper.writeInt(node.pos.z);
wrapper.writeFloat(node.walkedDistance);
wrapper.writeFloat(node.costMalus);
wrapper.writeBoolean(node.closed);
wrapper.writeEnum(node.type);
wrapper.writeFloat(node.f);
}
public Vector3i getPos() {
return this.pos;
}
public float getWalkedDistance() {
return this.walkedDistance;
}
public float getCostMalus() {
return this.costMalus;
}
public boolean isClosed() {
return this.closed;
}
public DebugPathType getType() {
return this.type;
}
public float getF() {
return this.f;
}
}
@@ -0,0 +1,105 @@
/*
* 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.debug.path;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jspecify.annotations.NullMarked;
import java.util.List;
import java.util.Set;
/**
* Network structure for representing vanilla pathfinder paths.
*
* @versions 1.21.9+
*/
@NullMarked
public final class DebugPath {
private final boolean reached;
private final int nextNodeIndex;
private final Vector3i target;
private final List<DebugNode> nodes;
private final Set<DebugNode> targetNodes;
private final List<DebugNode> openSet;
private final List<DebugNode> closedSet;
public DebugPath(
boolean reached, int nextNodeIndex, Vector3i target, List<DebugNode> nodes,
Set<DebugNode> targetNodes, List<DebugNode> openSet, List<DebugNode> closedSet
) {
this.reached = reached;
this.nextNodeIndex = nextNodeIndex;
this.target = target;
this.nodes = nodes;
this.targetNodes = targetNodes;
this.openSet = openSet;
this.closedSet = closedSet;
}
public static DebugPath read(PacketWrapper<?> wrapper) {
boolean reached = wrapper.readBoolean();
int nextNodeIndex = wrapper.readInt();
Vector3i target = wrapper.readBlockPosition();
List<DebugNode> nodes = wrapper.readList(DebugNode::read);
Set<DebugNode> targetNodes = wrapper.readSet(DebugNode::read);
List<DebugNode> openSet = wrapper.readList(DebugNode::read);
List<DebugNode> closedSet = wrapper.readList(DebugNode::read);
return new DebugPath(reached, nextNodeIndex, target, nodes, targetNodes, openSet, closedSet);
}
public static void write(PacketWrapper<?> wrapper, DebugPath path) {
wrapper.writeBoolean(path.reached);
wrapper.writeInt(path.nextNodeIndex);
wrapper.writeBlockPosition(path.target);
wrapper.writeList(path.nodes, DebugNode::write);
wrapper.writeSet(path.targetNodes, DebugNode::write);
wrapper.writeList(path.openSet, DebugNode::write);
wrapper.writeList(path.closedSet, DebugNode::write);
}
public boolean isReached() {
return this.reached;
}
public int getNextNodeIndex() {
return this.nextNodeIndex;
}
public Vector3i getTarget() {
return this.target;
}
public List<DebugNode> getNodes() {
return this.nodes;
}
public Set<DebugNode> getTargetNodes() {
return this.targetNodes;
}
public List<DebugNode> getOpenSet() {
return this.openSet;
}
public List<DebugNode> getClosedSet() {
return this.closedSet;
}
}
Loaded 100 of 602 files, more files were not shown because too many files have changed in this diff. Show more