Compare commits

...
508 Commits
Author SHA1 Message Date
retrooper 476c61ed47 bump version up to 2.7.0 release 2024-12-10 21:34:52 +01:00
retrooper 4b6bfbc08b Merge pull request #1085 from booky10/workaround/revert-shadow-color-support
Temporarily revert shadow color support
2024-12-10 20:52:44 +01:00
booky10 0be838c58f Temporarily revert shadow color support
Will be un-reverted when adventure v4.18.0 gets released
2024-12-10 20:32:19 +01:00
booky10 d6c81f32cd Fix shadow color adventure support check 2024-12-04 18:03:46 +01:00
booky10 5d2104dd91 Merge pull request #1076 from mfnalex/feat/fix-npe-nbtinterpret
fix NPE for nbtInterpret
2024-12-04 18:00:55 +01:00
retrooper 969ce9d6a3 Merge pull request #1081 from Tecnio/2.0
bugfix: Added input validation for window click
2024-12-04 16:37:18 +01:00
Tecnio 55b456cb95 bugfix: Added input validation for window click 2024-12-04 18:34:40 +03:00
booky10 062ffc18f9 Merge pull request #1078 from AoElite/biomefix
fix npe if music tag isn't present on older versions
2024-12-04 12:32:42 +01:00
AoElite 95cbd40655 fix npe if music tag isn't present on older versions 2024-12-04 05:38:55 -05:00
retrooper 70d94137dd Merge pull request #1049 from booky10/feat/1.21.4-support
1.21.4 support
2024-12-03 22:50:55 +01:00
mfnalex bbea70d1db fix NPE for nbtInterpret 2024-12-03 20:23:31 +01:00
booky10 b5e5b752a4 Bump fabric version info 2024-12-03 18:42:39 +01:00
retrooper 28b4dd8e08 bump version up to 2.7.0 SNAPSHOT 2024-12-03 18:33:07 +01:00
retrooper 1ae92a8b9d correction to comments mistakenly referring to 1.21.5 2024-12-03 17:57:29 +01:00
booky10 00bbea33f6 Bump fabric minecraft version to 1.21.4-rc3 2024-12-02 23:10:59 +01:00
booky10 3fd3c397a6 Rename attribute constants to remove "type" prefix 2024-12-02 22:56:33 +01:00
booky10 f1f95a0aac Fix name of equipment asset mapping file reference 2024-12-02 22:20:25 +01:00
booky10 6e90a3e376 Update serverbound packet type mappings 2024-12-02 22:05:26 +01:00
booky10 41d51453a5 Update mappings for all changed registries 2024-12-02 22:01:06 +01:00
booky10andBeanes c74f8b2559 Add precision loss fix while writing, not while reading
This fixes *slightly* incorrect velocity values being provided in the wrapper, while still writing the correct short value

Co-authored-by: Beanes <sikyserver@gmail.com>
2024-12-02 21:45:35 +01:00
booky10 be2eb6a8ce Update generated block tags and item tags 2024-12-02 21:40:45 +01:00
Beanesandbooky10 9819db60cd Work around loss of precision when unpacking entity velocity
Solution was discussed on discord (https://discord.com/channels/721686193061888071/721686193515003966/1313231483225378946)

Closes #1074

Co-authored-by: booky10 <boooky10@gmail.com>
2024-12-02 21:26:55 +01:00
booky10 2a86e0d355 Update trim material structure to 1.21.4 2024-12-02 21:05:12 +01:00
booky10 4a209a342e Update biome music nbt structure to 1.21.4 2024-12-02 20:46:22 +01:00
booky10 33e5b58e3b Update custom model data component to 1.21.4 2024-12-02 20:21:21 +01:00
booky10 fd11bd24a9 Add new player loaded packet type and wrapper 2024-11-30 12:48:06 +01:00
booky10 8c1f14de57 Add wrappers for new pick item packets 2024-11-30 12:46:27 +01:00
booky10 bc615355c8 Add 1.21.4 serverbound packet type constants 2024-11-30 12:42:02 +01:00
booky10 28730806f9 Small javadoc notice for ParticleTrailData duration 2024-11-29 15:23:31 +01:00
booky10 4ec975fcd1 Update block state properties to 1.21.4 2024-11-29 15:20:55 +01:00
booky10 b6ce588e10 Add new item consumable use animation 2024-11-29 15:17:13 +01:00
booky10 a1510b5f6d Update equippable item component 2024-11-29 15:15:58 +01:00
booky10 913d527a64 Mark creaking transient entity type as obsolete 2024-11-29 15:13:51 +01:00
booky10 a1e250b521 Add new sound constants 2024-11-29 15:13:18 +01:00
booky10 887c107216 Add resin trim material constant 2024-11-29 15:12:15 +01:00
booky10 b6fb699a27 Add onground flag to WrapperPlayClientVehicleMove 2024-11-29 15:09:19 +01:00
booky10 575aa4619c Add initial support for shadow colors in component styles 2024-11-29 15:07:06 +01:00
booky10 3f787c0e35 Update particle types to 1.21.4 2024-11-29 14:41:37 +01:00
retrooper a0fc7f6978 Merge pull request #1065 from rafi67000/missingServerVersion
Add missing ServerVersion.V_1_9_1
2024-11-25 17:32:54 +01:00
rafi67000 2cd069ea72 Add missing ServerVersion.V_1_9_1 2024-11-24 22:13:00 +01:00
retrooper d4b4b24e3c WrapperPlayServerResourcePackSend#setPrompt added 2024-11-17 16:35:30 +01:00
retrooper dca7daec04 Merge pull request #1044 from ShreyasAyyengar/2.0
fix: NPC objects to have unique server team names.
2024-11-14 19:43:35 +01:00
booky10 b686eb467f Fix javadoc warnings 2024-11-13 15:16:01 +01:00
booky10 d1f0618c0e Merge branch '2.0' into feat/1.21.4-support 2024-11-13 14:28:59 +01:00
Shreyas Ayyengar ce06511b52 fix: initial team name not longer than 16 characters. 2024-11-11 14:41:56 -08:00
Shreyas Ayyengar a2b0c0f28e fix: truncate team name for versions older than V_1_18 2024-11-10 10:13:20 -08:00
retrooper da71044fc4 rename BlockFace#getHorizontalId to adhere to naming convention 2024-11-08 14:47:41 +01:00
booky10 4167c949fe Merge pull request #1048 from Axionize/blockface-get-horizontal
add getHorizontalID
2024-11-07 16:02:57 +01:00
booky10 6f490a7e93 Merge pull request #1057 from booky10/fix/potion-contents-component
Fix potion contents item component for 1.21.2/1.21.3
2024-11-07 16:01:51 +01:00
booky10 b14dfc710a Fix potion contents item component for 1.21.2/1.21.3 2024-11-06 23:36:07 +01:00
You 1877bae091 add getHorizontalID 2024-11-04 22:27:29 -05:00
retrooper 4cf7069254 Bump version up to 2.6.1-SNAPSHOT 2024-11-03 21:31:26 +01:00
retrooper d4c89ebff0 Final javadoc update 2024-11-03 20:35:26 +01:00
retrooper f58005a412 Update javadoc overview 2024-11-03 20:34:07 +01:00
retrooper 382931f4f8 Merge pull request #1050 from booky10/fix/sponge-artifact-upload
Fix sponge artifacts not getting uploaded
2024-11-03 20:32:44 +01:00
booky10 7be5b84b5d Fix sponge artifacts not getting uploaded 2024-11-03 20:31:53 +01:00
retrooper 0db35d3bd7 Stable release of 2.6.0 2024-11-03 20:22:12 +01:00
booky10 6e2da40aa5 Update block and item tags for 24w44a 2024-11-03 18:37:18 +01:00
booky10 dae7c2e90b Update item types for 24w44a 2024-11-03 18:37:11 +01:00
booky10 04db0ba88d Update state types for 24w44a 2024-11-03 18:37:06 +01:00
retrooper 9680bc77b3 relocate bstats in shadowNoAdventure task. 2024-11-02 22:53:43 +01:00
retrooper 85c0d3d9d3 Merge pull request #1018 from AbhigyaKrishna/2.0
Introduce a jar task to build without adventure dependencies
2024-11-02 22:46:38 +01:00
booky10 b348af9581 Update WrapperPlayServerHeldItemChange to 24w44a 2024-10-30 15:23:16 +01:00
booky10 aedb43b487 Update WrapperPlayServerPlayerInfoUpdate to 24w44a 2024-10-30 15:21:07 +01:00
booky10 3b86806d8e Update WrapperPlayServerParticle to 24w44a 2024-10-30 15:17:18 +01:00
booky10 c4cc09d8e0 Add 1.21.4 version constants 2024-10-30 15:14:51 +01:00
Shreyas Ayyengar 1a3b2471b3 refactor: add get/set for teamName 2024-10-28 11:19:55 -07:00
ShreyasAyyengar 3a004572c1 fix: NPC objects to have unique server team names. 2024-10-29 01:59:16 +08:00
retrooper feabf561c5 Merge pull request #1043 from booky10/fix/block-state-mapping-indexes
Fix block state mapping indexes
2024-10-28 17:16:12 +01:00
retrooper 5247ccd129 Add support for 1.16.1 join game codec (fix error) 2024-10-28 17:03:05 +01:00
booky10 c77390b86c Implement more dynamic wrapped block state mapping indexes 2024-10-28 15:52:11 +01:00
booky10 8ecad1f93e Introduce static field for legacy mapping index 2024-10-28 15:41:26 +01:00
booky10 dae82c4d65 Fix legacy mapping index being broken 2024-10-28 15:40:17 +01:00
booky10 8f8cc8ac43 Removed left over debug code from fabric module refactor 2024-10-28 14:46:50 +01:00
retrooper f66626ae74 Merge pull request #1042 from booky10/fix/bstats-shadow-issues
Include relocated bstats classes in published shadow jar
2024-10-28 14:43:30 +01:00
booky10 4ffcbcad91 Include relocated bstats classes in published shadow jar
This moves bstats dependencies to a separate gradle dependency configuration, which is always shadowed and used in compile classpath
2024-10-28 14:41:31 +01:00
booky10 fc31b7de7b Merge pull request #1032 from booky10/fix/fabric-module
Fabric module refactor
2024-10-27 05:09:00 +01:00
booky10 c24f2d7849 Re-add deprecated FabricPacketEventsBuilder for some backwards compatibility 2024-10-27 03:04:21 +01:00
booky10 b316f54fd8 Simplify platform-specific pre launch entrypoint handler logic 2024-10-27 02:58:42 +01:00
booky10 2fda301027 Load packetevents api instance on prelaunch 2024-10-27 02:57:56 +01:00
booky10 9e6f3fbb2a Fix channel to user association in fabric module 2024-10-27 02:50:01 +02:00
booky10 980d306100 Bump fabric loom to v1.8.11 2024-10-27 01:46:15 +02:00
booky10 9d4a44b403 Merge branch '2.0' into fix/fabric-module 2024-10-27 01:46:04 +02:00
booky10 52d92e6c1a Merge pull request #975 from booky10/feat/1.21.2-update
1.21.2/1.21.3 update
2024-10-27 01:43:19 +02:00
booky10 0a96edb1bb Merge pull request #1034 from booky10/fix/slime-paper-support
Fix support for unsafe entity id getter on AdvancedSlimePaper
2024-10-27 01:37:04 +02:00
booky10 3ced349018 Merge pull request #1028 from Bram1903/feat/bStatsUpdate
[Feat] bStats Sponge Support
2024-10-27 00:49:16 +02:00
booky10 9649c99f90 Merge branch '2.0' into feat/bStatsUpdate 2024-10-27 00:49:01 +02:00
booky10 0b587d398d Merge pull request #1022 from rafi67000/gradleUpdate
Update gradle
2024-10-27 00:47:50 +02:00
booky10 47eaa1d1ca Add accesswidener to fabric.mod.json 2024-10-27 00:38:52 +02:00
booky10 cbd170729d Bump version up to 2.6.0-SNAPSHOT 2024-10-27 00:30:45 +02:00
rafi67000 6997bb4615 Revert "Update loom"
This reverts commit 76ea2aa665.
2024-10-25 19:55:17 +02:00
rafi67000 dc6db3cfaa Revert "Update SpongeGradle"
This reverts commit 72c337a68c.
2024-10-25 19:53:14 +02:00
rafi67000 72c337a68c Update SpongeGradle 2024-10-25 19:51:21 +02:00
rafi67000 a9d0389adf Merge pull request #13 from retrooper/2.0
Sponge
2024-10-25 19:48:42 +02:00
rafi67000 76ea2aa665 Update loom 2024-10-25 19:40:45 +02:00
booky10 672700afc5 Add 1.21.3 server version
Thanks mojang for fixing the salmon!
2024-10-23 18:14:45 +02:00
retrooper d8a44fe8b6 Merge pull request #1037 from booky10/fix/javadoc-link
Fix javadoc link in readme
2024-10-23 07:08:37 +02:00
booky10 2a777092d2 Fix javadoc link in readme 2024-10-23 01:14:01 +02:00
booky10 083a060371 Fix legacy attribute naming "remapping" 2024-10-22 18:18:56 +02:00
booky10 b1b5dee5f0 Fix NPE when copying WrapperPlayServerChunkData below 1.18 2024-10-22 18:14:23 +02:00
booky10 05dfea6da2 Fix classloading loop in SynchronizedRegistriesHandler 2024-10-22 18:07:27 +02:00
booky10 208d6911f0 Expose packet side in channel injector 2024-10-22 01:10:20 +02:00
booky10 07ca508df1 Change default value of legacy lookup to true 2024-10-21 21:53:48 +02:00
booky10 40ab1419c5 Fix support for unsafe entity id getter on AdvancedSlimePaper 2024-10-21 21:43:28 +02:00
booky10 cb48134548 Remove TODOs, tests were successful 2024-10-21 19:27:37 +02:00
booky10 ce287ad7db Fix writing packets on fabric client side 2024-10-21 19:20:55 +02:00
booky10 be1e743571 Invert protocol manager send/receive methods if in client environment 2024-10-21 18:34:03 +02:00
booky10 a57b911fd2 Skip injection of fabric channels on the wrong side 2024-10-21 18:10:16 +02:00
booky10 a3b7fc8908 Refactor handshake handling to support non-inet socket addresses 2024-10-21 17:58:46 +02:00
booky10 85717a84b7 Associate player instance with player connection channel
The behaviour of the fabric platform is a bit different here, as the player instance gets re-created on respawn
2024-10-21 03:55:57 +02:00
booky10 6a8e96382e Add method for creating packetevents instance 2024-10-21 03:31:35 +02:00
booky10 52b6cb6a71 Fix writing of WrapperPlayClientCraftRecipeRequest 2024-10-21 02:31:49 +02:00
booky10 eda7d9273f Fix serialization of SingleInputOptionDisplay 2024-10-21 02:31:48 +02:00
booky10 9391b16f50 Fix missing sealevel write in login packet 2024-10-21 02:31:47 +02:00
booky10 bd499550d8 Reuse entity position sync EntityPositionData in more places for 1.21.2 2024-10-21 02:31:46 +02:00
booky10 dd6eb173a0 Fix ENTITY_POSITION_SYNC packet id 2024-10-21 02:31:45 +02:00
booky10 78c994987f Update client settings packet wrapper to 1.21.2
Also refactors it's logic into a common class, as it was previously split in config and play state packets
2024-10-21 02:31:45 +02:00
booky10 d11a0bade5 Add tip and creaking block state properties for 1.21.2 2024-10-21 01:36:03 +02:00
booky10 e54035a683 Work around classloading loop only present on fabric 2024-10-21 01:32:17 +02:00
booky10 5ef51406eb Refactor clientbound and serverbound packet handling for same behaviour 2024-10-21 01:32:05 +02:00
booky10 9843e9fd68 Fix refcount issues with PacketEncoder 2024-10-21 01:32:04 +02:00
booky10 f3bdcbec83 Fix PacketDecoder handling of serverbound packets 2024-10-21 01:32:03 +02:00
booky10 a5d3cf5957 Fix wrong packetencoder side 2024-10-21 01:32:03 +02:00
booky10 aa87cf8032 Fix fabric logger level remapping 2024-10-21 01:32:02 +02:00
booky10 07137ddb26 Call correct packet events depending on packet side 2024-10-21 01:32:01 +02:00
booky10 92076e8559 Move fabric mod metadata to common sourceset 2024-10-21 01:32:00 +02:00
booky10 5356a011ec Refactor fabric network handlers
This removes compression handling from encoder, as vanilla compression setup does not interfere with packetevents
This also refactors the packet encoder to be based directly on the ChannelOutboundHandlerAdapter, instead of the MessageToByteEncoder

Requires testing - there could be a retain missing in the PacketEncoder
2024-10-20 06:03:00 +02:00
booky10 b72502b8a1 Implement support for fabric client again 2024-10-20 06:02:59 +02:00
booky10 20bee30f69 Refactor fabric packetevents builder to work on both server and client 2024-10-20 06:02:59 +02:00
booky10 4f29b8a2c9 Split fabric client and server sources 2024-10-20 06:02:58 +02:00
booky10 ef867acc36 Fix fabric mod icon 2024-10-20 06:02:58 +02:00
booky10 da37c4320e Remove fabric api dependency
It's not used by packetevents, there is no need to depend on it
2024-10-20 06:02:57 +02:00
booky10 6b2d3cbc7e Small cleanup of WrapperPlayServerExplosion
Didn't think I would have updated this already, but its already up-to-date! Yay!
2024-10-20 04:46:26 +02:00
booky10 397310df8b Update WrapperPlayServerDeclareRecipes to 1.21.2 2024-10-20 04:42:45 +02:00
booky10 04d444cc30 Update WrapperPlayServerEntityTeleport to 1.21.2 2024-10-20 03:32:36 +02:00
booky10 eb68151a73 Update WrapperPlayServerPlayerPositionAndLook to 1.21.2 2024-10-20 03:04:59 +02:00
booky10 a2fcc30fbb Update WrapperPlayServerCraftRecipeResponse to 1.21.2 2024-10-20 02:33:24 +02:00
booky10 6cdc535cbc Update WrapperPlayServerTimeUpdate to 1.21.2 2024-10-20 02:26:08 +02:00
booky10 095550e041 Update WrapperPlayClientCraftRecipeRequest to 1.21.2 2024-10-20 02:18:42 +02:00
booky10 3b4a0609e3 Update WrapperPlayClientSetDisplayedRecipe to 1.21.2 2024-10-20 02:08:17 +02:00
booky10 54fe6b0dbd Add player input packet wrapper 2024-10-20 02:05:12 +02:00
booky10 ff2b73e9b1 Update WrapperLoginServerLoginSuccess to 1.21.2 2024-10-20 01:51:30 +02:00
booky10 bb3630840d Update particle network and nbt serialization to 1.21.2 2024-10-20 01:39:21 +02:00
booky10 555aed78f3 Fix items without any overrides missing their default base components 2024-10-20 01:10:11 +02:00
booky10 1ed52f3f4e Fix versioned item type base components 2024-10-20 00:03:03 +02:00
booky10 72a44648cd Fix removed music disc tag causing tests to fail 2024-10-19 23:57:48 +02:00
booky10 2db8e75a66 Update sound registry to 1.21.2 2024-10-19 05:48:18 +02:00
booky10 e9064c4e87 Implement new trail and block crumble particles 2024-10-19 05:44:21 +02:00
booky10 680cbbf932 Fix item component mappings 2024-10-19 05:25:31 +02:00
booky10 7285af4481 Update damage type registry 2024-10-19 05:17:00 +02:00
booky10 bd4f5c2ecf Add 1.21.2 state type mappings 2024-10-19 05:14:10 +02:00
booky10 dd94a9a677 Refactor block entity types to registries 2024-10-19 05:13:24 +02:00
booky10 341c70f6dd Add creaking heart block entity type 2024-10-19 05:10:59 +02:00
booky10 41a8a47060 Add pale garden biome 2024-10-19 05:09:53 +02:00
booky10 881ad034a6 Refactor attributes to include default, minimum and maximum values
Also adds utility for calculating final attribute value
Additionally, strips "category" prefix for 1.21.2+
And adds the new attribute for 1.21.2
2024-10-19 05:02:06 +02:00
booky10 4a1c86cba3 Update block and item tags 2024-10-19 02:54:52 +02:00
booky10 56c9b73bcb Add new entity types for 1.21.2 2024-10-19 02:42:56 +02:00
booky10 93bac071ac Add new item types for 1.21.2 2024-10-19 02:34:29 +02:00
booky10 f88c9f027d Implement new item components for 1.21.2 2024-10-19 02:29:02 +02:00
booky10 1cb2219dbb Update FoodProperties serialization to 1.21.2 2024-10-19 02:09:40 +02:00
booky10 e00d5822f2 Fix serialization of ItemRecipes component type 2024-10-19 02:04:20 +02:00
booky10 f64846f339 Add initial logic for loading item base components from file 2024-10-19 01:58:42 +02:00
booky10 fd2480abbc Add item base component data for 1.20.5 to 1.21.2 2024-10-19 01:08:21 +02:00
booky10 4d820eef6d Add new state types for 1.21.2 2024-10-18 23:54:18 +02:00
booky10 6bddd197db Add block state mappings for 1.21.2 2024-10-18 23:54:07 +02:00
booky10 8439ca103c Fix modern block state mapping indices 2024-10-18 23:26:57 +02:00
booky10 60e546b075 Mark current recipe wrappers as obsolete 2024-10-18 18:11:21 +02:00
booky10 cfc0e5b260 Finish implementing serialization of new recipe data 2024-10-18 18:08:39 +02:00
booky10 3c11278949 Implement WrapperPlayServerRecipeBookSettings 2024-10-18 17:31:05 +02:00
booky10 8bde89d4ee Implement WrapperPlayServerRecipeBookRemove 2024-10-18 03:19:21 +02:00
booky10 a5ebc356ad Start implementing WrapperPlayServerRecipeBookAdd
Recipe display types are too much work for now, I'll do them later

Also, mojang has removed the ability for custom item recipes... for whatever reason?
2024-10-18 03:16:24 +02:00
booky10 aeb37c0a28 Implement WrapperPlayServerPlayerRotation 2024-10-18 02:37:58 +02:00
booky10 85106c8e59 Implement WrapperPlayServerEntityPositionSync 2024-10-18 02:36:42 +02:00
booky10 06d350bb1e Update packet mappings to rc1 2024-10-18 02:31:26 +02:00
booky10 a612ffeba1 Use mapped entity registry reading when reading modern ItemStacks 2024-10-18 02:12:52 +02:00
booky10 651051f136 Merge branch '2.0' into feat/1.21.2-update 2024-10-18 02:10:02 +02:00
Bram 3000d76272 Removed: Old bStats classes 2024-10-17 11:34:53 +02:00
retrooper e136327742 Update README text 2024-10-16 23:30:05 +02:00
Bram e1a22373d6 Re-added: Old Metric classes to prevent breaking changes, but marked the classes as deprecated 2024-10-15 16:10:57 +02:00
Bram b7f4375599 Fixed: Coding convention issue 2024-10-15 15:55:18 +02:00
Bram bf97a66dd7 Changed: Position of the plugin started message to outside the class constructor into the actual initiation event 2024-10-15 15:45:44 +02:00
Bram 9077e346f2 Removed: Internal bStats classes
Added: bStats as gradle dependency
Added: Sponge bStats Support
Changed: Velocity bStats initialisation, due to a reworked approach in a recent bStats update
Changed: Sponge Gradle Plugin version being specified in the build.gradle.kts rather than in the libs.versions.toml
2024-10-15 15:43:09 +02:00
retrooper 0031d6aae3 Merge pull request #670 from SamB440/feat/sponge
(WIP) Sponge support
2024-10-13 23:03:35 +02:00
SamB440 cec46d111b Don't store the ServerPlayer 2024-10-13 21:30:18 +01:00
SamB440 ef151757db Don't include non-nbt adventure 2024-10-13 21:30:18 +01:00
SamB440 fef29a0697 Update to new build logic 2024-10-13 21:30:17 +01:00
SamB440 b58b71a5b1 Fix ViaVersion compatibility (as via fixed injector) 2024-10-13 21:30:17 +01:00
SamB440 8a4fc799e4 Update to JDK 21 and support latest Sponge API 2024-10-13 21:30:17 +01:00
SamB440 979fc09e13 Sponge support 2024-10-13 21:30:17 +01:00
rafi67000 13fa3504bf Remove unused and deprecated import 2024-10-08 17:41:09 +02:00
rafi67000 adbaa5cfbc Update test libraries 2024-10-08 17:30:40 +02:00
rafi67000 1881336a14 Update runTask 2024-10-08 17:15:51 +02:00
rafi67000 100d02904e Update shadow 2024-10-08 17:15:45 +02:00
rafi67000 be8e15e087 Update gradle to 8.10.2 2024-10-08 17:15:38 +02:00
retrooper 487bcc3461 Merge pull request #1021 from booky10/fix/food-properties
Fix order of reading fields in food properties
2024-10-06 16:53:21 +02:00
booky10 1f86c651b8 Fix order of reading fields in food properties 2024-10-06 13:39:10 +02:00
AbhigyaKrishna 388001447f feat: jar task to produce jars without adventure 2024-10-04 17:17:59 +05:30
AbhigyaKrishna 13c59e2b5e refactor: make jar names consistent 2024-10-04 17:17:21 +05:30
AbhigyaKrishna 5c236bb4ed feat: configure javadoc plugin 2024-10-04 17:16:52 +05:30
booky10 fea6e90f12 Merge pull request #1015 from ManInMyVan/missing-breaks
add breaks in WrapperHandshakingClientHandshake::setNextConnectionState
2024-09-29 23:52:40 +02:00
ManInMyVan fb098bd169 add breaks in WrapperHandshakingClientHandshake::setNextConnectionState 2024-09-29 15:46:01 -06:00
booky10 612b2bb6cc Merge pull request #1014 from ManInMyVan/fix/legacy-rail-mappings
fix legacy rail mappings
2024-09-29 04:00:06 +02:00
ManInMyVan a145c10e5d fix detector rail id 2024-09-28 19:54:23 -06:00
ManInMyVan cb57f4fd6a fix legacy rail mappings 2024-09-28 17:43:31 -06:00
retrooper ed28da338a Merge pull request #1006 from booky10/fix/viaversion-map-deco-errors
Fix errors with viaversion and map decorations
2024-09-24 18:16:54 +02:00
retrooper 0d86b3b297 Merge pull request #1004 from booky10/fix/workaround-paper-library-loading-problems
Force usage of plugin classloader to lookup classes of other plugins
2024-09-24 18:16:22 +02:00
booky10 90bd1841f0 Revert unused import 2024-09-23 18:45:52 +02:00
booky10 be24877913 Merge pull request #1003 from booky10/fix/registry-element-equality
Fix registry element equality check
2024-09-23 18:43:57 +02:00
retrooper 7218c365e3 Merge pull request #1009 from booky10/fix/nbt-component-booleans
Allow any numbers when reading nbt booleans
2024-09-23 18:21:03 +02:00
booky10 33dd09362a Allow any numbers when reading nbt booleans
Vanilla accepts every number type and so should packetevents
2024-09-23 17:36:16 +02:00
booky10 4aae57075a Merge pull request #1005 from booky10/fix/more-bungee-injector-issues 2024-09-23 09:58:09 +02:00
booky10 d90240641e Convert MapDecorationTypes to proper registry 2024-09-21 16:50:01 +02:00
booky10 a5871befe6 Norm registry key input strings 2024-09-21 16:47:08 +02:00
booky10 fa56d226f3 Add ResourceLocation#normString utility
This prepends the vanilla key namespace to the specified input key, if no other namespace has been specified
2024-09-21 16:45:58 +02:00
booky10 a5ff4a9ad8 Only print component map patches for ItemStack#toString 2024-09-21 16:42:53 +02:00
booky10 d61c690075 Release buffers after recompression 2024-09-21 16:26:01 +02:00
booky10 873589bd7f Clear recyclable out list after usage 2024-09-21 16:25:47 +02:00
booky10 032f2ff228 Use proper logging for bungee instead of stdout 2024-09-21 16:25:19 +02:00
booky10 0c733b31a7 Force usage of plugin classloader to lookup classes of other plugins
Works around issues caused by some plugins loading packetevents through the library loader, which doesn't know about the classloader of plugins
2024-09-21 16:00:20 +02:00
booky10 2baaf18db6 Fix missing DeepComparableEntity interface
Caused by me just cherry-picking some commits from another branch
2024-09-21 15:26:53 +02:00
booky10 4d7314e2d8 Check for deep equals before using vanilla registry element
Could potentially solve #962, although I can't reproduce that issue

This may be caused by two different changes to packetevents:
1. We did a little memory optimization so only elements different to the vanilly registry get stored
2. We fixed an issue where some elements would not equal the "same" vanilla element

This could cause every custom element to just never be registered, so we now do explicit deep-equals checks before saving the vanilla element instead
2024-09-21 15:21:02 +02:00
booky10 f1f4ffe6b2 Implement DeepComparableEntity for all dynamic registry entries 2024-09-21 15:21:01 +02:00
retrooper 2fac9dc516 Bump version up to 2.5.1-SNAPSHOT 2024-09-20 23:37:15 +02:00
retrooper ab8faf358c 2.5.0 Release 2024-09-20 22:07:20 +02:00
retrooper 243ce3c5dd Merge pull request #990 from Elikill58/2.0
Add wrapper for BossBar packet
2024-09-20 21:57:25 +02:00
retrooper d4762195f9 adhere to packetevents' convention of capitalizing UUID in setters & getters 2024-09-20 21:53:46 +02:00
retrooper 121e1615b6 remove awkward comment break in PEVersion#toStringWithoutSnapshot docs 2024-09-20 21:49:46 +02:00
retrooper 350d33ae6f Merge remote-tracking branch 'origin/2.0' into 2.0 2024-09-20 21:47:15 +02:00
retrooper d4f7bced86 bstats metrics do not collect snapshot & commit, solely version is captured. 2024-09-20 21:46:18 +02:00
retrooper 8037e659a8 Merge pull request #1000 from booky10/fix/particle-data-again
Revert some fixes for particle data decoding/encoding
2024-09-20 21:12:04 +02:00
retrooper 28c7849252 Merge pull request #999 from booky10/fix/bungee-injection
Rework bungee injector to allow for packet cancellation
2024-09-20 21:07:09 +02:00
retrooper cb277bf16a Merge pull request #995 from booky10/fix/packet-sending-race-condition
Synchronize packet encoding
2024-09-20 21:04:50 +02:00
booky10 0612e1e188 Revert some fixes for particle data decoding/encoding
Mojang's codecs are confusing
2024-09-20 20:30:08 +02:00
booky10 7a9f83129e Fix incorrect list recycling usage 2024-09-20 20:11:05 +02:00
booky10 a17e5f13a7 Rework bungee injector to allow for packet cancellation 2024-09-20 20:04:29 +02:00
retrooper 02a565bf39 Merge pull request #996 from booky10/fix/bungee-injection
Fix support for new bungee compression
2024-09-20 19:44:01 +02:00
booky10 f1d7d5ac81 Merge pull request #992 from galacticwarrior9/add-biomeeffects-getters 2024-09-18 08:33:30 +02:00
retrooper a1663f5a03 Merge pull request #994 from booky10/fix/pre-1.20.5-registry-data-limit
Remove nbt reading limit in registry-data packet for pre 1.20.5
2024-09-17 23:22:28 +02:00
booky10 909492cfae Fix support for new bungee compression 2024-09-17 16:39:46 +02:00
booky10 a3b4cc21f5 Synchronize packet encoding
Resolves concurrency issues which may happen when sending the same packet wrapper to different players, concurrently

This is not a perfect solution, but the alternative would be refactoring the packetwrapper to be based on buffers passed during encoding as parameters, which would be too much effort and would require breaking changes
2024-09-17 16:29:30 +02:00
booky10 402ebd729e Remove nbt reading limit in registry-data packet for pre 1.20.5 2024-09-17 16:21:49 +02:00
galacticwarrior9 349b5dc110 Add missing getters to BiomeEffects 2024-09-17 13:43:07 +01:00
Elikill58 c778cc3368 Convert list to EnumSet 2024-09-16 23:03:43 +02:00
Elikill58 26e5aab84e Rename divison to overlay 2024-09-16 19:54:01 +02:00
Elikill58 79da4e1bc4 Convert flags 2024-09-16 19:50:29 +02:00
Elikill58 51b550ca5e Use adventure's enum 2024-09-16 11:29:37 +02:00
Elikill58 2877b74c42 Remove own config... 2024-09-15 19:54:08 +02:00
Elikill58 c67d1a86c5 Fix missing import 2024-09-15 19:41:28 +02:00
Elikill58 5cf9b34fd2 Add wrapper for BossBar packet 2024-09-15 19:24:59 +02:00
retrooper 99acbe4960 Merge pull request #980 from booky10/fix/javadoc-links
Update javadoc overview links
2024-09-02 22:27:53 +02:00
booky10 2bf64b6107 Update javadoc overview links 2024-09-02 22:26:07 +02:00
retrooper 4e86af8754 Add Javadocs URL 2024-09-02 22:22:44 +02:00
retrooper 6bf639f18a Update links to documentation. 2024-09-02 22:11:34 +02:00
retrooper 9a7bb17459 Merge pull request #978 from AoElite/2.0
fixed runAtFixedRate not using ticks when running on folia
2024-09-01 22:38:57 +02:00
AoElite 6b84c683ee fixed runAtFixedRate not using ticks when running on folia 2024-09-01 16:33:12 -04:00
booky10 1260aa1de5 Add some transformations for slot changes 2024-08-30 22:53:19 +02:00
booky10 bdccde4040 Fix compile issue with StaticConsumeEffectType 2024-08-30 21:44:45 +02:00
booky10 7cdb95116a Implement all new components 2024-08-30 21:21:06 +02:00
booky10 c9d42f8e8e Check for deep equals before using vanilla registry element
Could potentially solve #962, although I can't reproduce that issue

This may be caused by two different changes to packetevents:
1. We did a little memory optimization so only elements different to the vanilly registry get stored
2. We fixed an issue where some elements would not equal the "same" vanilla element

This could cause every custom element to just never be registered, so we now do explicit deep-equals checks before saving the vanilla element instead
2024-08-30 20:34:37 +02:00
booky10 1e738f038f Implement DeepComparableEntity for all dynamic registry entries 2024-08-30 20:31:32 +02:00
booky10 57fb06ca5f Implement dynamic instrument registry 2024-08-30 20:28:59 +02:00
booky10 83d925ead0 Implement most 1.21.2 packet wrapper changes 2024-08-30 20:14:00 +02:00
booky10 ce1baaad7a Setup new 1.21.2 packet types 2024-08-30 20:13:52 +02:00
booky10 a370f6e7b7 Setup 1.21.2 server version and client version constants 2024-08-30 20:13:42 +02:00
booky10 dc015dc457 Merge pull request #935 from rafi67000/gradleUpdate
Gradle, and shadow update
2024-08-29 22:34:52 +02:00
booky10 fd7bc84cd5 Merge pull request #972 from booky10/fix/workaround-spigot-item-conversion-issues
Use global synchronized registries as fallback
2024-08-29 17:46:19 +02:00
booky10 9fd5b3b912 Use global synchronized registries as fallback for spigot and fabric
Works around issues where plugins convert items to bukkit items, which doesn't preserve registry holder context, e.g. https://github.com/nulli0n/ExcellentEnchants-spigot/blob/8623159ca61b60e1d3cae22c77a99e82b15b9d5f/Core/src/main/java/su/nightexpress/excellentenchants/hook/impl/PacketEventsHook.java
2024-08-29 12:49:12 +02:00
rafi67000 a2d259af58 Update to Gradle 8.10 2024-08-27 20:29:28 +02:00
rafi67000 6cc21a6d98 Merge branch 'retrooper:2.0' into gradleUpdate 2024-08-27 20:13:20 +02:00
retrooper e105770dde Merge pull request #967 from KermanIsPretty/fix/join-game-data-codec-1.7
Fix 1.8< clients not having Reduced Debug Info.
2024-08-27 12:28:49 +02:00
booky10 68b7ee51dc Merge pull request #968 from ManInMyVan/tuff-walls
tuff walls exceed cube
2024-08-26 19:50:22 +02:00
ManInMyVan a4a375f411 tuff walls exceed cube 2024-08-26 11:19:35 -06:00
KermanIsPretty ae6b3d18a4 Fix 1.8< clients not having reducedDebugInfo. 2024-08-25 15:50:02 -05:00
booky10 8763b0e77f Merge pull request #966 from ManInMyVan/fix-inconsistency
Fix inconsistency in StateTypes
2024-08-25 10:55:44 +02:00
ManInMyVan 2440b64981 Fix inconsistency in StateTypes 2024-08-25 01:02:36 -06:00
retrooper ebe73587fe Merge pull request #959 from AoElite/2.0
API for checking if packetevents is terminated
2024-08-22 17:34:43 +02:00
AoElite 5b87ac4f61 unnecessary fix 2024-08-21 08:56:58 -04:00
AoElite d9a3f33199 implement for test 2024-08-21 08:29:16 -04:00
AoElite 9f44834514 don't forget netty one 2024-08-20 21:04:03 -04:00
AoElite 314d4a2813 option to kick on join if terminated & added API for checking if terminated 2024-08-20 21:02:39 -04:00
retrooper 97fee0c898 Merge pull request #956 from booky10/fix/particle-data-decoding-1.20.4
Fix particle data decoding and encoding for <1.20.5
2024-08-21 00:19:56 +02:00
booky10 bdc96a88cd Merge branch '2.0' into fix/particle-data-decoding-1.20.4 2024-08-20 19:33:29 +02:00
retrooper af1691e6e5 Merge pull request #957 from booky10/fix/bungeecord-resolving
Fix bungeecord artifact not resolving
2024-08-20 19:03:40 +02:00
booky10 e4058f7f15 Fix bungeecord artifact not resolving 2024-08-20 18:06:55 +02:00
booky10 7f0c922e10 Fix particle data decoding and encoding for <1.20.5 2024-08-20 17:57:54 +02:00
retrooper 453793eb60 Merge pull request #955 from booky10/fix/item-adventure-predicate-component-reading
Read item adventure predicate nbt and property matchers as optionals
2024-08-20 17:37:45 +02:00
booky10 015e7a4647 Read item adventure predicate nbt and property matchers as optionals 2024-08-20 16:59:17 +02:00
retrooper 45c0c580f7 Merge pull request #954 from booky10/fix/1.19-issues
Fix some 1.19 issues related to registries
2024-08-20 15:39:11 +02:00
booky10 1c12a868c8 Fix chattype decoding and encoding for 1.19 2024-08-20 15:20:54 +02:00
booky10 a3f22320d5 Fix error when handling empty legacy registries 2024-08-20 15:10:57 +02:00
retrooper f4bb1dd8fc kick players even if user is null & they throw an exception, kick user for exceptions also in encoder. 2024-08-18 07:11:01 +02:00
retrooper 5203b3a376 Merge pull request #943 from ManInMyVan/static-getByName
Make BlockTags::getByName static
2024-08-17 20:22:28 +02:00
retrooper fe66d743a9 Merge pull request #949 from booky10/fix/1.16.5-errors
Fix some errors related to old minecraft versions
2024-08-17 20:01:13 +02:00
retrooper 1d1cf84c60 Merge pull request #950 from booky10/fix/dynamic-registry-elements-equality
Don't do deep equals checks for dynamic registry entries
2024-08-17 19:57:02 +02:00
booky10 1c81aab994 Don't do deep equals checks for dynamic registry entries 2024-08-17 19:12:52 +02:00
booky10 52559f6fc8 Fix binary tag holder for adventure <4.10.0 2024-08-17 17:55:29 +02:00
booky10 06cc25bf23 Add workaround to make DimensionType#getId work for 1.16.2 to 1.18.2 2024-08-17 17:49:32 +02:00
booky10 86cf0d51ed Replace usages of translation fallback in ComponentSerializerImpl 2024-08-17 17:36:25 +02:00
booky10 5fbb052d6f Fix wrong recipe serializer definition key 2024-08-17 17:36:09 +02:00
booky10 b7021fcd1f Fix support for adventure <4.10
Replaces Index#valueToKey usages with alternative
Fixes error on join in 1.16.5
2024-08-17 17:22:22 +02:00
booky10 64db7f13c6 Fix support for adventure <4.11
Replaces Index#valueOrThrow usages with copied implementation
Fixes error on join in 1.16.5
2024-08-17 17:05:41 +02:00
retrooper 20c9fdf634 Merge pull request #947 from booky10/fix/dimension-type-npes
Handle null values correctly in StaticDimensionType#equals
2024-08-17 17:03:29 +02:00
booky10 a71035a157 Handle null values correctly in StaticDimensionType#equals 2024-08-17 16:19:56 +02:00
ManInMyVan b0002102e3 Make BlockTags::getByName static 2024-08-15 19:29:07 -06:00
retrooper a3e65cfcbe Merge pull request #939 from rexlManu/2.0
(Velocity) Avoid user if channel cannot be found
2024-08-14 09:35:48 +02:00
Emmanuel Lampe edd9c5ce3d Merge branch 'retrooper:2.0' into 2.0 2024-08-14 05:22:04 +02:00
retrooper e918e6b10a Merge remote-tracking branch 'origin/2.0' into 2.0 2024-08-13 21:04:18 +02:00
retrooper f6c309fd18 add copyright notice to Metrics 2024-08-13 21:03:20 +02:00
retrooper 322a99dbc4 final change in README 2024-08-13 17:50:54 +02:00
retrooper 6793dee0bc More fixes to README 2024-08-13 17:46:39 +02:00
retrooper d33751dbb0 fix BUILD STATUS in README 2024-08-13 17:41:26 +02:00
retrooper fa67de16a1 fixed issues in README 2024-08-13 17:40:10 +02:00
retrooper 57fc21f411 patch readme 2024-08-13 17:37:27 +02:00
retrooper 9999ee3b4a updated README for packetevents 2024-08-13 17:32:03 +02:00
retrooper 4a90cadeb1 Merge pull request #933 from booky10/fix/bungee-server-nullability
Account for null servers in bungee
2024-08-12 18:49:59 +02:00
retrooper 048903f33f Merge pull request #934 from booky10/fix/translation-fallback-adventure
Fix compatibility with adventure versions older than 4.13.0
2024-08-12 18:48:09 +02:00
retrooper 3fa5eaf2a3 Merge pull request #932 from booky10/fix/dimension-type-mappings
Fix dimension type mappings
2024-08-12 18:47:01 +02:00
rafi67000 93bd6d5ac9 Update wrapper 2024-08-12 17:24:04 +02:00
rafi67000 aa5535615c A little tweak... 2024-08-12 17:22:15 +02:00
booky10 9ccd85178d Fix compatibility with adventure versions older than 4.13.0
Translation fallback methods didn't exist before
2024-08-12 17:11:16 +02:00
rafi67000 14fd279c06 Update and switch to maintained shadow fork 2024-08-12 17:07:20 +02:00
rafi67000 6df845324b Update gradle to 8.9 2024-08-12 17:06:59 +02:00
booky10 c3f233ca61 Account for null servers in bungee 2024-08-12 16:47:52 +02:00
booky10 ed4f018b34 Fix dimension type mappings 2024-08-12 16:44:09 +02:00
retrooper ef4bc1c02e github sponsors added as funding option 2024-08-12 09:32:44 +02:00
retrooper ca725b68a5 fix: NPE error in DimensionType#decode 2024-08-12 09:09:02 +02:00
booky10 40f7463e93 Merge pull request #927 from AoElite/2.0
Fix sound exception on 1.21
2024-08-12 00:57:46 +02:00
AoElite 7778768c30 tweak 2024-08-11 18:55:09 -04:00
AoElite 6a6be44ab2 fix sound exception on 1.21 2024-08-11 15:57:12 -04:00
Abhigya fe67c23ad4 Merge pull request #926 from AoElite/2.0
Release item buffer regardless of exception
2024-08-11 23:45:40 +05:30
AoElite c09348d4f7 release item buffer regardless of exception 2024-08-11 13:55:17 -04:00
retrooper e04cd2108f Merge pull request #919 from libraryaddict/patch-2
Fix #916 via removing explicit type call of nbt get
2024-08-10 17:18:35 +02:00
retrooper 39f0dee9f1 Merge pull request #912 from booky10/feat/1.21.1-server-version
Add 1.21.1 version support
2024-08-10 17:16:20 +02:00
libraryaddict 9b9ae8d36c Fix #916 2024-08-10 22:47:03 +12:00
retrooper fc934195de Merge pull request #866 from booky10/feat/network-synced-registries
Network synced registries
2024-08-09 07:49:14 +02:00
retrooper 6c4db8029b chore: bump up version to 2.5.0-SNAPSHOT 2024-08-09 07:46:25 +02:00
retrooper c4ce7b7a87 packetevents version represented as string only provides snapshotCommit if it is a snapshot, not for stable releases. 2024-08-09 07:44:31 +02:00
booky10 b751c63625 Add 1.21.1 version support 2024-08-08 16:44:16 +02:00
retrooper 31ac149b42 Merge pull request #909 from booky10/feat/peversion-build-timestamp
Add build timestamp to PEVersions class
2024-08-06 19:08:17 +02:00
booky10 2f45e9e469 Add equality methods for all dynamic registry value classes 2024-08-06 17:55:27 +02:00
booky10 7b152ff264 Don't store exact copies of vanilla registry elements 2024-08-06 17:25:55 +02:00
booky10 e9eb441a1c Implement caching on bungee platform 2024-08-06 17:19:23 +02:00
booky10 55c1093783 Fix biome and enchantment type definitions on bungee 2024-08-06 17:17:05 +02:00
booky10 963ec4e978 Revert some debug changes which weren't meant to be pushed 2024-08-06 17:09:53 +02:00
booky10 26c30f46e7 Implement key-based registry caching and velocity proxy per-server caching
Bungee isn't finished yet
2024-08-06 17:06:55 +02:00
booky10 c2cdafb17f Add system property to force disable caching 2024-08-06 16:09:38 +02:00
booky10 22060a9889 Actually make caching work by not decoding registries when not needed 2024-08-06 16:08:55 +02:00
booky10 e1a54099a4 Add build timestamp to PEVersions class 2024-08-06 15:24:28 +02:00
retrooper 3fa6a0f69a fix: wrong tag name used in ParticleDustData 2024-08-05 22:48:26 +02:00
retrooper 676cb6c3ce feature: cache legacy registries 2024-08-05 22:34:54 +02:00
retrooper a3063f0bcb feature: cache registries globally on non-proxy servers
Each kind of registry has a VersionedRegistry. This VersionedRegistry now contains a SimpleRegistry as a cache. If the cache is not null, it will be used globally. This makes the usage of registries convenient for PacketEvents users as they no longer need to access them within each user instance. If the plugin is on proxy, we shall store all registries for each user. If the plugin is not on proxy, we shall only store the dimension type registry for each user and globally cache the rest.
2024-08-05 22:17:53 +02:00
retrooper c1520401b6 deletion: remove hard-coded 1.21 enchantment type mappings (as temporary fix) 2024-08-05 22:07:57 +02:00
booky10 d988d0c684 Fix backwards compatibility for dimension type codec 2024-08-04 23:00:46 +02:00
booky10 e2283d6f4e Fix backwards compatibility for encoding trim patterns 2024-08-04 22:39:25 +02:00
booky10 ea56cfde04 Add backwards compatibility support for chat types 2024-08-04 22:34:44 +02:00
booky10 16733e587e Add full legacy data support for biomes 2024-08-04 21:58:28 +02:00
booky10 b247807f0f Fix biome mapping test 2024-08-04 20:30:26 +02:00
booky10 679aea8181 Add even more biome mappings 2024-08-04 18:47:30 +02:00
booky10 f0d499a008 Add more biome mappings 2024-08-04 18:41:22 +02:00
booky10 b5320f2ae7 Fix data reading for biomes and enchantment types 2024-08-04 18:24:52 +02:00
retrooper 0fd0821a93 Merge pull request #907 from booky10/fix/fire-legacy-mappings
Map legacy block ids for fire block
2024-08-04 18:17:59 +02:00
booky10 c7c1b9da17 Map legacy block ids for fire block 2024-08-04 18:15:03 +02:00
retrooper d67d307788 Merge pull request #906 from booky10/fix/component-equality
Fix some component equality checking issues
2024-08-04 18:10:45 +02:00
booky10 c057f18914 Merge branch '2.0' into feat/network-synced-registries 2024-08-04 18:05:46 +02:00
booky10 7a5b425dbb Merge pull request #1 from libraryaddict/feat/network-synced-registries
Feat/network synced registries
2024-08-04 18:01:20 +02:00
booky10 9b22739977 Remove setters from jukebox song interface 2024-08-04 17:56:03 +02:00
booky10 12e0869e0a Fix JukeboxSongs#values javadoc 2024-08-04 17:55:22 +02:00
booky10 0039ab8704 Resolve small backwards compatibility issues 2024-08-04 17:55:12 +02:00
retrooper 7da389db14 feature: 1.21 enchantment mappings (ordered alphabetically) 2024-08-04 16:14:17 +02:00
libraryaddict 1f85797768 Merge pull request #1 from packetevents/2.0
Feature: Create Damage Event wrapper using new Damage Types
2024-08-04 23:49:55 +12:00
retrooper 3c55703718 feature: damage event wrapper using new damage types 2024-08-04 10:50:28 +02:00
booky10 e3734c2d94 Fix some component equality checking issues 2024-08-01 22:41:22 +02:00
Emmanuel Lampe afc571e331 fix(velocity): check for fake connections 2024-08-01 09:59:47 +02:00
libraryaddict 4549d07a6c IJukeboxSong 2024-07-31 17:36:11 +12:00
libraryaddict acc220729b Rename JukeboxSong and StaticJukeboxSong 2024-07-31 01:45:15 +12:00
libraryaddict b27f64c3b1 Missing license disclaimer thingy 2024-07-30 21:17:32 +12:00
libraryaddict 1f7a09a561 Current WIP, adds damage types and jukebox 2024-07-30 21:14:15 +12:00
retrooper f0b15c3f94 Merge pull request #900 from booky10/fix/number-issues-adventure-nbt-serializer
Allow item hover event count to be specified as any number
2024-07-27 11:32:31 +02:00
booky10 cc03d3029d Allow item hover event count to be specified as any number
Fixes compatibility with vanilla codec, as vanilla allows any number to be decoded within DFU
2024-07-23 17:57:46 +02:00
retrooper ef2d24c5ff Merge pull request #894 from booky10/fix/chunk-codec-issues
Fix chunk codec issues
2024-07-23 13:58:58 +02:00
retrooper 6a69d1bcb4 Generics usage in ProtocolPacketEvent for platform-dependent player 2024-07-22 18:50:35 +02:00
retrooper ea1e11d690 Merge pull request #874 from Bram1903/fix/LatestFabricSupport
Fabric 1.21 Support
2024-07-22 11:32:47 +02:00
retrooper 65b51fa6f5 Update javadocs link. 2024-07-19 17:27:25 +02:00
retrooper dae31cedf6 Fix fabric injection, packet listeners now work. 2024-07-19 17:21:32 +02:00
retrooper 6179f997c9 Update fabric version 2024-07-19 16:42:50 +02:00
retrooper 8cb083c29a Correction in PacketListenerPriority documentation, MONITOR should be avoided when modifying. 2024-07-19 13:21:57 +02:00
retrooper 7dd2434ea9 Modification of PacketEvents settings is now marked as internal API behavior. Generally, you are not advised to change the settings.
Unnecessary static in PacketEventsAPI fixed.
2024-07-19 13:17:34 +02:00
booky10 66ca952a1d Add getter/setter for light data in Chunk_v1_9 packet
Would otherwise be impossible to send new chunk layers for 1.9 to 1.13
2024-07-18 19:57:10 +02:00
booky10 d6fef1180f Don't read sky data in overworld dimension for 1.14 to 1.15.2
Sky data in overworld was only present before 1.14
2024-07-18 18:48:13 +02:00
booky10 32451165ba Don't allow usage of singleton palette before 1.18 2024-07-18 18:47:28 +02:00
Bram 2c806b2d4e Removed: foojay-resolver in favor of the foojay-resolver-convention 2024-07-14 11:17:40 +02:00
Bram a8dadfdfff Merge branch 'refs/heads/2.0' into fix/LatestFabricSupport
# Conflicts:
#	settings.gradle.kts
2024-07-14 11:16:32 +02:00
booky10 4524b4289c Merge pull request #883 from booky10/fix/1.21-item-attribute-modifiers-component
Fix reading/writing of item attribute modifier component in 1.21
2024-07-12 23:18:36 +02:00
retrooper 67010e8f11 Merge pull request #885 from booky10/feat/javadoc-publishing
Implement automatic javadoc publishing
2024-07-12 16:39:42 +02:00
retrooper 245ee7699a Merge pull request #890 from booky10/fix/null-material-types
Fix missing material types for vault and heavy core
2024-07-12 16:38:11 +02:00
booky10 25dfb3c5b9 Fix missing material types for vault and heavy core 2024-07-12 16:36:57 +02:00
booky10 52709f279b Update javadoc links 2024-07-11 17:43:23 +02:00
booky10 13d6437638 Remove javadoc pages deployment
Will be handled in different repo, see https://github.com/packetevents/packetevents.github.io
2024-07-11 16:51:46 +02:00
booky10 7a3505070e Restrict javadoc deployment for tag pushes 2024-07-11 01:27:31 +02:00
booky10 7d79603d08 Move api javadoc to pages root 2024-07-11 00:57:37 +02:00
booky10 7890a8ae97 Add javadoc overview 2024-07-11 00:55:54 +02:00
booky10 c73e149f43 Fix spigot javadoc jar generation 2024-07-11 00:24:13 +02:00
booky10 2f72766aac Fix wrong action name 2024-07-10 23:50:33 +02:00
booky10 43d915d09c Add id-token permission to javadoc extraction job 2024-07-10 23:49:47 +02:00
booky10 3444b07f6a Try if github pages upload action works 2024-07-10 23:46:23 +02:00
booky10 3cfb1c5b3e Add initial javadoc upload workflow
Designed to not work yet, just testing if it outputs correct stuff as act is broken for me
2024-07-10 23:15:39 +02:00
booky10 150736b170 Update github build workflow actions 2024-07-10 23:11:20 +02:00
booky10 1f325a36d6 Enable javadoc jar generation 2024-07-10 23:10:56 +02:00
booky10 bdc8f6ef82 Use jvm 21 for kotlin jvm toolchain in buildscript 2024-07-10 23:10:44 +02:00
booky10 d365e4b949 Add foojay resolver convention plugin
Allows automatic download of specified java toolchain jvm version
2024-07-10 23:10:25 +02:00
booky10 4f4a3ba87b Update gradle wrapper to v8.8 2024-07-10 23:06:44 +02:00
retrooper 7ceeaa5f3f Merge pull request #872 from ShadowOfHeaven-Me/2.0
Optimized the EventManager
2024-07-10 21:07:52 +02:00
retrooper 6f968275c1 Merge pull request #882 from KoutaChan/fix-pallet-shift
Fix: Palette index calculation error
2024-07-10 18:29:41 +02:00
booky10 245b7a0d2a Fix reading/writing of item attribute modifier component in 1.21 2024-07-10 16:29:36 +02:00
KoutaChan 13b1007c1c Fix: pallet bit 2024-07-10 23:26:15 +09:00
KoutaChan c164908aac Fix: bit shift error 2024-07-10 23:22:40 +09:00
KoutaChan 1dd28f124a Fix: Palette index calculation error 2024-07-10 23:02:53 +09:00
retrooper 149483ef21 Merge pull request #881 from booky10/fix/version-hash-publishing
Don't specify version hash in published maven pom
2024-07-10 15:49:32 +02:00
booky10 0a689564ce Don't specify version hash in published maven pom 2024-07-10 15:44:33 +02:00
retrooper facc6bc074 Merge pull request #877 from booky10/feat/versioning-commit-hash
Add current commit hash to project version
2024-07-09 22:57:14 +02:00
booky10 41224c9faf Fix snapshot commit for release versions 2024-07-09 22:54:15 +02:00
retrooper 14548f5679 Even more clarity, now LGTM 2024-07-09 22:47:50 +02:00
retrooper d31d0b2487 Correction and clarity to the PEVersion#snapshotCommit method documentation 2024-07-09 22:43:38 +02:00
retrooper 1366872acb Merge pull request #870 from AbhigyaKrishna/mappings-reading-optimization
Mappings reading optimization
2024-07-09 11:41:11 +02:00
retrooper 40fcd23d87 More clarity on the deprecation reason in PEVersion#asArray 2024-07-09 11:31:48 +02:00
retrooper ba7d09ee91 Correction in the documentation of PEVersion: Accuracy in the content and grammar whilst ensuring clarity. 2024-07-09 11:19:08 +02:00
booky10 b0fa4eb3b7 Don't include snapshot commit hash in file name 2024-07-09 01:54:40 +02:00
Bram a8bf163355 Fix: Left behind old shadow plugin convention 2024-07-08 19:00:31 +02:00
booky10 f81730c689 Add snapshot commit api to PEVersion 2024-07-08 15:18:07 +02:00
booky10 a830fe8b63 Adjust PEVersionTask regex to allow any commit hash length 2024-07-08 04:18:25 +02:00
booky10 05c116271e Add current commit hash to project version
Only added when version is a snapshot version
Disables itself if no git directory is found
2024-07-08 04:09:31 +02:00
booky10 a08f89813e Allow chat type decoration parameters to be defined directly 2024-07-08 03:47:39 +02:00
booky10 87fa35dea0 Fix enchantment registry not being able to be replaced
Caused by directly referencing static registry
2024-07-08 03:45:32 +02:00
booky10 4ed644313a Allow enchantment definition slots to be defined directly 2024-07-08 03:43:34 +02:00
booky10 9fdd1615bd Merge branch '2.0' into feat/network-synced-registries 2024-07-08 03:25:15 +02:00
booky10 4ab220f189 Make TrimMaterial override armor materials optional 2024-07-08 03:25:00 +02:00
booky10 adef187685 Fix MappedEntitySet codec 2024-07-08 03:24:21 +02:00
booky10 0e5a443e9b Fix various issues encountered on login 2024-07-08 03:01:45 +02:00
booky10 4961ad6e8d Add biome registry handling to SynchronizedRegistriesHandler
Seems like I forgot to add it there
2024-07-08 02:44:32 +02:00
booky10 e056f1ca0a Implement synchronized painting variant registries 2024-07-08 02:43:58 +02:00
retrooper 9d43fd7a35 Stop re-encoding by default on BungeeCord 2024-07-07 23:56:29 +02:00
AbhigyaKrishna 45bafb37fe feat: HashedByteArray -> BinaryNBTCompound 2024-07-05 22:52:16 +05:30
AbhigyaKrishna 3554f3c6ac feat: Read compound tags in binary format to save memory 2024-07-05 22:42:32 +05:30
AbhigyaKrishna 10d4cf4a9d feat: fabric adventure dependency fix 2024-07-05 20:17:04 +05:30
retrooper 7a1621aa37 Final correction for bungee injector. 2024-07-05 14:11:57 +02:00
retrooper 22a5e67c69 Another correction, but probably obsolete 2024-07-05 13:56:33 +02:00
retrooper 8737ba218a Correct decompress decode method on Bungee. Reflection error. 2024-07-05 13:51:47 +02:00
Bram 98e0a35f0c Removed: Unused Mod Properties in the Fabric module gradle.properties 2024-07-05 10:01:21 +02:00
Bram 21500f3cab Fixed: Another issue in the PacketEventsInjectorMixin 2024-07-04 23:58:13 +02:00
Bram 750d87937a Switched: johnrengelman shadow to googler's shadowjar for Java 21 support (See https://github.com/johnrengelman/shadow/issues/908) 2024-07-04 23:55:25 +02:00
Bram f78ffc9a5c Fixed: PacketEventsInjectorMixin 2024-07-04 23:33:10 +02:00
Bram 48b789d268 Added: foojay-resolver (fixes issues with the latest Fabric Loom dependency
Re-added: Parchment (mixed something up)
Fixed: Compile issue with removed class import
2024-07-04 23:29:29 +02:00
ShadowOfHeaven a765347cba Added a class description 2024-07-04 23:02:54 +02:00
ShadowOfHeaven 21fe4c920d Just a little sneak of my name there 2024-07-04 22:55:05 +02:00
Bram d35505b83a Updated: Fabric Loom 0.11-SNAPSHOT -> 1.7.2
Updated: Gradle Wrapper 8.5 -> 8.7 (Required by Fabric Loom)
Removed: parchmentmc (Fabric Loom provides native support for Parchment mappings as of version 0.9)
Changed: Fabric Dependency id from fabric -> fabric-api (see: https://fabricmc.net/2022/11/24/1193.html)
2024-07-04 21:36:50 +02:00
ShadowOfHeaven 930d1370ce Removed the User value association system. Another PR will be made 2024-07-04 09:45:25 +02:00
ShadowOfHeaven 4f01b9b2d6 Added a User value association system 2024-07-04 00:35:46 +02:00
ShadowOfHeaven 79ae548463 Optimized the EventManager v2 2024-07-03 19:59:41 +02:00
booky10 08120db4b4 Add small biome mapping test 2024-07-03 18:18:38 +02:00
booky10 11d2d979cc Fix biome mapping not being compressed and shadowed 2024-07-03 18:18:26 +02:00
booky10 3822609afe Implement most particle data codecs
Theoretically required for full support of biome data serialization
2024-07-03 18:15:25 +02:00
booky10 dd057ca20f Finish biome effects implementation 2024-07-03 15:16:32 +02:00
ShadowOfHeaven 42403c9f51 Optimized the EventManager 2024-07-03 00:37:35 +02:00
AbhigyaKrishna 9eb6b11fe0 fix: Statistics not being cached 2024-07-03 02:27:32 +05:30
booky10 8c02988330 Save dimension type as reference while decoding
Reference gets resolved when calling the getter, this allows legacy version registries to be swapped before resolving the new dimension type
2024-07-02 18:58:12 +02:00
AbhigyaKrishna fd7223a259 fix: Statistics reading 2024-07-02 15:37:16 +05:30
AbhigyaKrishna b22560852f chores: Update licence 2024-07-02 15:30:06 +05:30
AbhigyaKrishna 3498720e8c feat: Change SequentialNBTReader class design to resemble reader 2024-07-02 15:24:46 +05:30
AbhigyaKrishna 457aed221b fix: NBTEnd not being read when there is no data 2024-07-02 14:39:24 +05:30
AbhigyaKrishna d6fb68d8e7 chores: Update licence 2024-07-02 03:32:50 +05:30
AbhigyaKrishna 0e6c15eb8b feat: Diff load order 2024-07-02 03:30:00 +05:30
AbhigyaKrishna 485124bfef feat: change diff tags order
'removals' tags now come before 'additions' tag
Order: removals, additions, changes
2024-07-02 03:27:53 +05:30
AbhigyaKrishna 3517d1fd00 feat: Refactor SequentialNBTReader 2024-07-02 03:07:38 +05:30
AbhigyaKrishna 7d80f08e1c fix: nbt reading 2024-07-02 03:04:31 +05:30
AbhigyaKrishna ff0af88299 chores: Removed debug statements 2024-07-02 02:16:25 +05:30
booky10 ba08959d39 Add wolf_variant registry and start with biome registry
Biome registry is required for wolf variant registry to fully work
2024-07-01 22:41:13 +02:00
AbhigyaKrishna 050aab96f7 fix: SequentialNBTReader parsing 2024-07-02 02:11:00 +05:30
booky10 afcdfae5a1 Fix version being ignored in User#getMinWorldHeight 2024-07-01 21:13:46 +02:00
booky10 8908cce24f Implement enchantment effect component types 2024-07-01 21:08:49 +02:00
booky10 31447cb6cf Fix test errors 2024-07-01 20:21:02 +02:00
booky10 884ab800f5 Start working on enchantment registry 2024-07-01 19:11:32 +02:00
booky10 6e87103114 Move everything related to registries from InternalPacketListener to new class 2024-07-01 16:24:55 +02:00
booky10 c3b8c213d3 Implement trim_material as a synchronized registry 2024-07-01 16:22:14 +02:00
booky10 33f50a0eb9 Implement trim_pattern as a synchronized registry 2024-07-01 16:12:32 +02:00
booky10 3f309bc92d Migrate usages of chat types to new registry 2024-07-01 16:04:33 +02:00
booky10 8315b8d335 Implement chat_type as a synchronized registry 2024-07-01 15:59:15 +02:00
booky10 902c99aca2 Revert some now useless changes to MappedEntity#getId 2024-07-01 15:41:52 +02:00
booky10 f4fc20a1c8 Revert formatting changes in ChunkReader_v1_7 2024-07-01 15:36:50 +02:00
booky10 0690c45558 Add quality methods to StaticDimensionType 2024-07-01 15:35:11 +02:00
booky10 699fd9ac02 Finish migrating Dimension to DimensionType 2024-07-01 15:32:08 +02:00
booky10 b01db5ca2a Work on creating registries of sent registries 2024-07-01 12:39:13 +02:00
booky10 4fdc9c67ad Finish encode of DimensionType 2024-07-01 12:38:56 +02:00
AbhigyaKrishna 395ed0d58e fix: version mapper initialization 2024-07-01 10:03:17 +05:30
AbhigyaKrishna bcad08260c feat: Implement sequential reading for all mappings 2024-07-01 09:55:34 +05:30
AbhigyaKrishna 06be6d52b2 feat: Implement closeable on sequential reader 2024-07-01 09:55:05 +05:30
AbhigyaKrishna 7ec896b8b0 feat: Updated block mappings for easier access to v2 mapping deserializer 2024-07-01 09:37:39 +05:30
AbhigyaKrishna 2717a94db5 feat: Implement sequential reader in type builder 2024-07-01 09:08:19 +05:30
AbhigyaKrishna 2ea20e3d19 feat: Bump Compression Task version 2024-07-01 09:07:43 +05:30
AbhigyaKrishna 94d939ba67 feat: Changes to mappings format 2024-07-01 08:13:25 +05:30
AbhigyaKrishna 620af0aec0 feat: SequentialNBTReader 2024-07-01 07:15:07 +05:30
AbhigyaKrishna 2299d82b92 feat: Improved NBTSerializer class 2024-07-01 05:56:54 +05:30
AbhigyaKrishna 25dbe61f64 feat: NBTLimiter class rewrite
Rewritten NBTLimiter class with better approach for better extendability
2024-07-01 05:53:41 +05:30
retrooper ecd183156a * Bump version up to 2.4.1-SNAPSHOT
* Marked SpigotReflectionUtil.getEntityById as internal
2024-07-01 00:20:35 +02:00
booky10 3f0cb7e799 Start working on dimension type registry 2024-06-30 23:33:40 +02:00
booky10 7b209c9733 Revert changes to Dimension 2024-06-30 22:37:10 +02:00
booky10 dfd490afc8 Merge branch '2.0' into feat/network-synced-registries 2024-06-30 22:34:34 +02:00
booky10 92564a3a09 More WIP changes to networked registries 2024-06-27 16:10:20 +02:00
booky10 172cfceed7 WIP starting network synchronized registries 2024-06-25 20:47:01 +02:00
436 changed files with 445757 additions and 30438 deletions

No files matched your search

+1 -3
View File
@@ -1,5 +1,3 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: retrooper
custom: ['https://paypal.me/retrooperdev']
github: [retrooper]
+19 -10
View File
@@ -8,16 +8,19 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Validate gradle wrapper
uses: gradle/actions/wrapper-validation@v3
- name: Set up JDK 21
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'adopt'
cache: 'gradle'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
@@ -25,37 +28,43 @@ jobs:
run: chmod +x gradlew && ./gradlew build
- name: Upload build artifacts api
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: api-build
path: api/build/libs
- name: Upload build artifacts spigot
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: spigot-build
path: spigot/build/libs
- name: Upload build artifacts netty-common
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: netty-common-build
path: netty-common/build/libs
- name: Upload build artifacts bungeecord
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: bungeecord-build
path: bungeecord/build/libs
- name: Upload build artifacts velocity
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: velocity-build
path: velocity/build/libs
- name: Upload build artifacts fabric
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: fabric-build
path: fabric/build/libs
path: fabric/build/libs
- name: Upload build artifacts sponge
uses: actions/upload-artifact@v4
with:
name: sponge-build
path: sponge/build/libs
+31 -22
View File
@@ -1,33 +1,42 @@
# packetevents
<!--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>
<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">
<a href="https://bstats.org/plugin/bukkit/packetevents/11327"><img src="https://img.shields.io/bstats/servers/11327?style=for-the-badge"></a>
<a href="https://github.com/retrooper/packetevents/releases"><img src="https://img.shields.io/github/downloads/retrooper/packetevents/total.svg?style=for-the-badge&logo=github"></a>
</div>
<h3>Resources</h3>
[![](https://img.shields.io/badge/License-GPLv3-yellow.svg)](https://github.com/retrooper/packetevents/blob/2.0/LICENSE) [![](https://github.com/retrooper/packetevents/actions/workflows/build.yml/badge.svg)](https://github.com/retrooper/packetevents/actions) [![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/prqzNg9tRU)
- [Read documentation](https://docs.packetevents.com/)
- [Getting Started](https://docs.packetevents.com/getting-started)
- [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)
- [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)
PacketEvents is a fast and efficient multi-platform packet processing library. Our packet wrappers are easy to use with multi-version support. With our API you can write code that runs on Spigot, BungeeCord, Velocity, and Fabric! Switch to PacketEvents today by joining \
our [Discord Server](https://discord.me/packetevents) for help.
<h3>Sponsors</h3>
### Links
* [Find release builds on Modrinth](https://modrinth.com/plugin/packetevents)
* [Find development builds on Jenkins](https://ci.codemc.io/job/retrooper/job/packetevents)
* [View documentation on our JavaDocs Page](https://packetevents.github.io/javadocs)
<i>Thanks to the following sponsors for supporting this project:</i>
### Setup
[How to Setup PacketEvents](https://github.com/retrooper/packetevents/wiki/Depending-on-pre%E2%80%90built-PacketEvents)
<a href="https://pebblehost.com"><img src="https://pebblehost.com/src/img/logos/main-old.png" width=150><br>
### Examples / How to use PacketEvents
[Example repository](https://github.com/retrooper/packetevents-example)
<a href="https://www.ej-technologies.com"><img src="https://www.ej-technologies.com/images/product_banners/jprofiler_small.png"><br>
### Sponsorships
[![](https://www.ej-technologies.com/images/product_banners/jprofiler_small.png)](https://www.ej-technologies.com/products/jprofiler/overview.html)
<a href="https://github.com/radstevee"><img src="https://github.com/radstevee.png" width="50px" alt="radstevee"/></a><br>
### Statistics
PacketEvents optionally collects statistics using [bStats](https://bstats.org/)\
Check out our [bStats page](https://bstats.org/plugin/bukkit/packetevents/11327)
<h3>Credits</h3>
### Credit to these projects
[wiki.vg/Protocol](https://wiki.vg/Protocol)\
[netty](https://github.com/netty/netty)\
[gson](https://github.com/google/gson)\
[adventure](https://github.com/KyoriPowered/adventure)\
<i>Here are some projects that we are heavily inspired by, thus we have integrated</i>\
<i>small portions of their code into our work.</i>
[Protocol Documentation for the Minecraft Java Edition](https://wiki.vg/Protocol)\
[ViaVersion](https://github.com/ViaVersion/ViaVersion)\
[ProtocolSupport](https://github.com/ProtocolSupport/ProtocolSupport)\
[adventure](https://github.com/KyoriPowered/adventure)\
[MCProtocolLib](https://github.com/GeyserMC/MCProtocolLib/)
+26 -5
View File
@@ -21,6 +21,7 @@ java {
dependencies {
compileOnlyApi(libs.bundles.adventure)
compileOnlyApi(libs.bundles.adventure.serializers)
implementation(libs.adventure.api)
api(project(":patch:adventure-text-serializer-gson", "shadow")) {
excludeAdventure()
@@ -37,6 +38,7 @@ dependencies {
testImplementation(testlibs.mockbukkit)
testImplementation(testlibs.slf4j)
testImplementation(testlibs.bundles.junit)
testImplementation(libs.netty)
}
mappingCompression {
@@ -47,7 +49,13 @@ mappingCompression {
compress("block/legacy_block_mappings.json")
compress("block/modern_block_mappings.json")
compress("enchantment/enchantment_type_data.json")
compress("item/item_base_components.json")
compress("stats/statistics.json")
compress("world/biome_data.json")
}
with<JsonArrayCompressionStrategy> {
@@ -60,23 +68,34 @@ mappingCompression {
compress("command/argument_parser_mappings.json")
compress("damage/damagetype_mappings.json")
compress("enchantment/effect_component_type.json")
compress("entity/entity_data_type_mappings.json")
compress("entity/painting_mappings.json")
compress("entity/wolf_variant_mappings.json")
compress("item/item_armor_material_mappings.json")
compress("item/consume_effect_type_mappings.json")
compress("item/equipment_asset_mappings.json")
compress("item/item_banner_pattern_mappings.json")
compress("item/item_component_mappings.json")
compress("item/item_instrument_mappings.json")
compress("item/item_jukebox_song_mappings.json")
compress("item/item_map_decoration_type_mappings.json")
compress("item/item_potion_mappings.json")
compress("item/item_trim_material_mappings.json")
compress("item/item_trim_pattern_mappings.json")
compress("item/recipe_book_category.json")
compress("item/recipe_display_types.json")
compress("item/recipe_serializer_mappings.json")
compress("item/recipe_slot_display_types.json")
compress("particle/particle_type_mappings.json")
compress("sound/sound_mappings.json")
compress("world/biome_mappings.json")
compress("world/world_position_source_mappings.json")
}
@@ -88,15 +107,17 @@ mappingCompression {
compress("entity/legacy_entity_type_mappings.json")
compress("item/item_type_mappings.json")
compress("world/dimension_type_mappings.json")
}
}
tasks {
assemble {
setDependsOn(dependsOn.filterNot { it == "shadowNoAdventure" })
}
javadoc {
setDestinationDir(file("${project.layout.buildDirectory.asFile.get()}/docs/javadoc"))
options {
(this as CoreJavadocOptions).addBooleanOption("Xdoclint:none", true)
}
mustRunAfter(generateVersionsFile)
}
@@ -34,22 +34,22 @@ import com.github.retrooper.packetevents.util.updatechecker.UpdateChecker;
import java.util.logging.Logger;
public abstract class PacketEventsAPI<T> {
private static final EventManager EVENT_MANAGER = new EventManager();
private static final PacketEventsSettings SETTINGS = new PacketEventsSettings();
private static final UpdateChecker UPDATE_CHECKER = new UpdateChecker();
private static final LogManager LOG_MANAGER = new LogManager();
private final EventManager eventManager = new EventManager();
private final PacketEventsSettings settings = new PacketEventsSettings();
private final UpdateChecker updateChecker = new UpdateChecker();
private final LogManager logManager = new LogManager();
private static final Logger LOGGER = Logger.getLogger(PacketEventsAPI.class.getName());
public EventManager getEventManager() {
return EVENT_MANAGER;
return eventManager;
}
public PacketEventsSettings getSettings() {
return SETTINGS;
return settings;
}
public UpdateChecker getUpdateChecker() {
return UPDATE_CHECKER;
return updateChecker;
}
public PEVersion getVersion() {
@@ -62,7 +62,7 @@ public abstract class PacketEventsAPI<T> {
}
public LogManager getLogManager() {
return LOG_MANAGER;
return logManager;
}
public abstract void load();
@@ -75,6 +75,8 @@ public abstract class PacketEventsAPI<T> {
public abstract void terminate();
public abstract boolean isTerminated();
public abstract T getPlugin();
public abstract ServerManager getServerManager();
@@ -23,12 +23,36 @@ import com.github.retrooper.packetevents.exception.InvalidHandshakeException;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Level;
/**
* Class for event managing. Implements both, internal and API methods.
*
* @apiNote It is highly recommended to register the event listeners at server start-up,
* without frequent modifications during runtime, since this class needs to recalculate all of
* its event listeners during any modifications. In other words, it assumes that reads (events fired)
* greatly outnumber writes (listeners modifications). If your case requires frequent listener modifications,
* open a pull request on GitHub and describe your case.
*
* @author retrooper
* @author ShadowOfHeaven (optimization)
*
*/
public class EventManager {
private final Map<PacketListenerPriority, Set<PacketListenerCommon>> listenersMap =
Collections.synchronizedMap(new EnumMap<>(PacketListenerPriority.class));
//Using a ConcurrentHashMap is faster and more secure here, compared to Collections.synchronizedMap(new EnumMap<>(PacketListenerPriority.class))
//This is mainly due to:
//1. On each modification Collections.synchronizedMap synchronizes the whole Map object, while ConcurrentHashMap only it's internal, currently modified Node
//2. ConcurrentHashMap won't fail in a multi-thread environment, while Collections.synchronizedMap is said to have a lot of potential problems,
//being a generalized method for synchronization
private final Map<PacketListenerPriority, Set<PacketListenerCommon>> listenersMap = new ConcurrentHashMap<>();
//Since reads greatly outnumber writes, create an array for the best possible iteration time
//Updated as a whole on writes, no index modifications are allowed
private volatile PacketListenerCommon[] listeners = new PacketListenerCommon[0];
/**
* Call the PacketEvent.
@@ -43,32 +67,43 @@ public class EventManager {
callEvent(event, null);
}
/**
* Call the PacketEvent.
* This method processes the event on all the registered dynamic packet event listeners.
* The {@link PacketListenerPriority#LOWEST} prioritized listeners will be processing first,
* the {@link PacketListenerPriority#MONITOR} will be processing last and can
* 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
*/
public void callEvent(PacketEvent event, @Nullable Runnable postCallListenerAction) {
for (PacketListenerPriority priority : PacketListenerPriority.values()) {
Set<PacketListenerCommon> listeners = listenersMap.get(priority);
if (listeners != null) {
for (PacketListenerCommon listener : listeners) {
try {
event.call(listener);
} catch (Exception t) {
// ignore handshake exceptions
if (t.getClass() != InvalidHandshakeException.class) {
PacketEvents.getAPI().getLogger().log(Level.WARNING, "PacketEvents caught an unhandled exception while calling your listener.", t);
}
}
if (postCallListenerAction != null) {
postCallListenerAction.run();
}
for (PacketListenerCommon listener : listeners) {
try {
event.call(listener);
} catch (Exception t) {
// ignore handshake exceptions
if (t.getClass() != InvalidHandshakeException.class) {
PacketEvents.getAPI().getLogger().log(Level.WARNING, "PacketEvents caught an unhandled exception while calling your listener.", t);
}
}
if (postCallListenerAction != null) {
postCallListenerAction.run();
}
}
// For performance reasons, we don't want to re-encode the packet if it's not needed.
if (event instanceof ProtocolPacketEvent && !((ProtocolPacketEvent<?>) event).needsReEncode()) {
((ProtocolPacketEvent<?>) event).setLastUsedWrapper(null);
if (event instanceof ProtocolPacketEvent && !((ProtocolPacketEvent) event).needsReEncode()) {
((ProtocolPacketEvent) event).setLastUsedWrapper(null);
}
}
/**
* Register the dynamic packet event listener.
*
* @param listener {@link PacketListenerCommon}
* @param priority {@link PacketListenerPriority}
*/
public PacketListenerCommon registerListener(PacketListener listener, PacketListenerPriority priority) {
PacketListenerCommon packetListenerAbstract = listener.asAbstract(priority);
return registerListener(packetListenerAbstract);
@@ -80,12 +115,8 @@ public class EventManager {
* @param listener {@link PacketListenerCommon}
*/
public PacketListenerCommon registerListener(PacketListenerCommon listener) {
Set<PacketListenerCommon> listenerSet = listenersMap.get(listener.getPriority());
if (listenerSet == null) {
listenerSet = new CopyOnWriteArraySet<>();
}
listenerSet.add(listener);
listenersMap.put(listener.getPriority(), listenerSet);
this.registerListenerNoRecalculation(listener);
this.recalculateListeners();
return listener;
}
@@ -96,21 +127,22 @@ public class EventManager {
*/
public PacketListenerCommon[] registerListeners(PacketListenerCommon... listeners) {
for (PacketListenerCommon listener : listeners) {
registerListener(listener);
this.registerListenerNoRecalculation(listener);
}
this.recalculateListeners();
return listeners;
}
public void unregisterListener(PacketListenerCommon listener) {
Set<PacketListenerCommon> listenerSet = listenersMap.get(listener.getPriority());
if (listenerSet == null) return;
listenerSet.remove(listener);
if (this.unregisterListenerNoRecalculation(listener)) this.recalculateListeners();
}
public void unregisterListeners(PacketListenerCommon... listeners) {
boolean modified = false;
for (PacketListenerCommon listener : listeners) {
unregisterListener(listener);
modified |= this.unregisterListenerNoRecalculation(listener);//OR - at least one of these needs to be true to return true, meaning the boolean will permanently stay true if once set so
}
if (modified) this.recalculateListeners();
}
@@ -118,6 +150,36 @@ public class EventManager {
* Unregister all dynamic packet event listeners.
*/
public void unregisterAllListeners() {
listenersMap.clear();
this.listenersMap.clear();
synchronized (this) {//like booky10 said, the synchronization is necessary here
this.listeners = new PacketListenerCommon[0];
}
}
//Needs to be synchronized in order to avoid race conditions (for example where the 'listeners' variable
//is overridden by its non-up-to-date value, simply because it finished a bit later than the most recent update)
private void recalculateListeners() {
synchronized (this) {
List<PacketListenerCommon> list = new ArrayList<>();
//adds from LOWEST to MONITOR, so in the correct order
for (PacketListenerPriority priority : PacketListenerPriority.values()) {
Set<PacketListenerCommon> set = this.listenersMap.get(priority);
if (set != null) list.addAll(set);
}
this.listeners = list.toArray(new PacketListenerCommon[0]);
}
}
//Internal registration methods, specifically separated for lesser overhead when registering an array of Listeners
private void registerListenerNoRecalculation(PacketListenerCommon listener) {
Set<PacketListenerCommon> listenerSet = this.listenersMap.computeIfAbsent(listener.getPriority(), p -> new CopyOnWriteArraySet<>());
listenerSet.add(listener);
}
//Returns true if the listener was removed, so a modification occurred
private boolean unregisterListenerNoRecalculation(PacketListenerCommon listener) {
Set<PacketListenerCommon> listenerSet = this.listenersMap.get(listener.getPriority());
return listenerSet != null && listenerSet.remove(listener);
}
}
@@ -30,8 +30,7 @@ package com.github.retrooper.packetevents.event;
*/
public enum PacketListenerPriority {
/**
* Listener is of very low importance.
* This listener will be ran first.
* This listener will be run first and has little say in the outcome of events.
*/
LOWEST,
@@ -41,8 +40,11 @@ public enum PacketListenerPriority {
LOW,
/**
* Default listener priority.
* Listener is neither important nor unimportant and may run normally.
* The normal listener priority.
* If possible, always pick this.
* It allows other projects to easily overturn your decisions.
* Moreover, it is pretty bold to assume that your project should
* always have the final say.
*/
NORMAL,
@@ -52,13 +54,13 @@ public enum PacketListenerPriority {
HIGH,
/**
* Listener is of critical importance and wants to decide the cancellation of an event.
* Listener is of critical importance. Use this to decide the final state of packets.
*/
HIGHEST,
/**
* Listener is purely trying to decide the cancellation of an event.
* This listener should be ran last.
* Only use this priority if you want to perform logic based on the outcome of an event.
* Please do not modify packets in this stage.
*/
MONITOR;
@@ -18,7 +18,6 @@
package com.github.retrooper.packetevents.event;
import com.github.retrooper.packetevents.event.simple.*;
import com.github.retrooper.packetevents.exception.PacketProcessException;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
@@ -26,7 +25,7 @@ import com.github.retrooper.packetevents.protocol.PacketSide;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.User;
public class PacketReceiveEvent extends ProtocolPacketEvent<Object> {
public class PacketReceiveEvent extends ProtocolPacketEvent {
protected PacketReceiveEvent(Object channel, User user, Object player, Object rawByteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
super(PacketSide.CLIENT, channel, user, player, rawByteBuf, autoProtocolTranslation);
@@ -29,7 +29,7 @@ import com.github.retrooper.packetevents.protocol.player.User;
import java.util.ArrayList;
import java.util.List;
public class PacketSendEvent extends ProtocolPacketEvent<Object> {
public class PacketSendEvent extends ProtocolPacketEvent {
private List<Runnable> tasksAfterSend = null;
protected PacketSendEvent(Object channel, User user, Object player, Object rawByteBuf,
@@ -24,11 +24,11 @@ package com.github.retrooper.packetevents.event;
* @author retrooper
* @since 1.6.9
*/
public interface PlayerEvent<T> {
public interface PlayerEvent {
/**
* Associated player.
*
* @return Player.
*/
T getPlayer();
<T> T getPlayer();
}
@@ -36,14 +36,15 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
public abstract class ProtocolPacketEvent<T> extends PacketEvent implements PlayerEvent<T>, CancellableEvent, UserEvent {
public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerEvent, CancellableEvent, UserEvent {
private final Object channel;
private final ConnectionState connectionState;
private final User user;
private final T player;
private final Object player;
private Object byteBuf;
private final int packetID;
private final PacketTypeCommon packetType;
@@ -55,7 +56,7 @@ public abstract class ProtocolPacketEvent<T> extends PacketEvent implements Play
private boolean needsReEncode = PacketEvents.getAPI().getSettings().reEncodeByDefault();
public ProtocolPacketEvent(PacketSide packetSide, Object channel,
User user, T player, Object byteBuf,
User user, Object player, Object byteBuf,
boolean autoProtocolTranslation) throws PacketProcessException {
this.channel = channel;
this.user = user;
@@ -92,7 +93,7 @@ public abstract class ProtocolPacketEvent<T> extends PacketEvent implements Play
}
public ProtocolPacketEvent(int packetID, PacketTypeCommon packetType, ServerVersion serverVersion, Object channel,
User user, T player, Object byteBuf) {
User user, Object player, Object byteBuf) {
this.channel = channel;
this.user = user;
this.player = player;
@@ -123,8 +124,15 @@ public abstract class ProtocolPacketEvent<T> extends PacketEvent implements Play
return channel;
}
public SocketAddress getAddress() {
return ChannelHelper.remoteAddress(this.channel);
}
/**
* <strong>WARNING:</strong> This doesn't support local addresses or unix sockets.
*/
public InetSocketAddress getSocketAddress() {
return (InetSocketAddress) ChannelHelper.remoteAddress(channel);
return (InetSocketAddress) this.getAddress();
}
@Override
@@ -133,8 +141,8 @@ public abstract class ProtocolPacketEvent<T> extends PacketEvent implements Play
}
@Override
public T getPlayer() {
return player;
public <T> T getPlayer() {
return (T) player;
}
public ConnectionState getConnectionState() {
@@ -213,7 +221,7 @@ public abstract class ProtocolPacketEvent<T> extends PacketEvent implements Play
}
@Override
public ProtocolPacketEvent<?> clone() {
public ProtocolPacketEvent clone() {
return this instanceof PacketReceiveEvent ? ((PacketReceiveEvent) this).clone()
: ((PacketSendEvent) this).clone();
}
@@ -20,7 +20,7 @@ package com.github.retrooper.packetevents.event;
import com.github.retrooper.packetevents.protocol.player.User;
public class UserLoginEvent extends PacketEvent implements CallableEvent, UserEvent, PlayerEvent<Object> {
public class UserLoginEvent extends PacketEvent implements CallableEvent, UserEvent, PlayerEvent {
private final User user;
private final Object player;
@@ -35,8 +35,8 @@ public class UserLoginEvent extends PacketEvent implements CallableEvent, UserEv
}
@Override
public Object getPlayer() {
return player;
public <T> T getPlayer() {
return (T) player;
}
@Override
@@ -18,9 +18,11 @@
package com.github.retrooper.packetevents.injector;
import com.github.retrooper.packetevents.protocol.PacketSide;
import com.github.retrooper.packetevents.protocol.player.User;
public interface ChannelInjector {
default boolean isServerBound() {
return true;
}
@@ -34,4 +36,8 @@ public interface ChannelInjector {
void setPlayer(Object channel, Object player);
boolean isProxy();
default PacketSide getPacketSide() {
return PacketSide.SERVER;
}
}
@@ -26,31 +26,20 @@ import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.manager.protocol.ProtocolManager;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.ConnectionState;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.protocol.nbt.NBTType;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.LogManager;
import com.github.retrooper.packetevents.util.mappings.SynchronizedRegistriesHandler;
import com.github.retrooper.packetevents.wrapper.configuration.server.WrapperConfigServerRegistryData;
import com.github.retrooper.packetevents.wrapper.configuration.server.WrapperConfigServerRegistryData.RegistryElement;
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 java.net.InetSocketAddress;
import java.util.List;
public class InternalPacketListener extends PacketListenerAbstract {
private static final ResourceLocation DIMENSION_TYPE_REGISTRY_KEY =
ResourceLocation.minecraft("dimension_type");
public InternalPacketListener() {
this(PacketListenerPriority.LOWEST);
}
@@ -92,94 +81,37 @@ public class InternalPacketListener extends PacketListenerAbstract {
}
}
// The server sends dimension information in configuration phase >= 1.20.2
// The server sends dimension information in configuration phase, since 1.20.2
else if (event.getPacketType() == PacketType.Configuration.Server.REGISTRY_DATA) {
WrapperConfigServerRegistryData registryData = new WrapperConfigServerRegistryData(event);
WrapperConfigServerRegistryData packet = new WrapperConfigServerRegistryData(event);
// Store world data
NBTCompound registryDataTag = registryData.getRegistryData();
NBTList<NBTCompound> list = null;
if (registryDataTag != null) { // <1.20.5
//Handle dimension type
NBTCompound dimensionTypes = registryDataTag
.getCompoundTagOrNull(DIMENSION_TYPE_REGISTRY_KEY.toString());
if (dimensionTypes == null) {
dimensionTypes = registryDataTag
.getCompoundTagOrNull(DIMENSION_TYPE_REGISTRY_KEY.getKey());
}
if (dimensionTypes != null) {
list = dimensionTypes.getCompoundListTagOrNull("value");
}
if (list == null) {
list = new NBTList<>(NBTType.COMPOUND);
PacketEvents.getAPI().getLogger().warning("Can't find dimension type registry in registry data, "
+ "this may cause issues; available registries: " + registryDataTag.getTags().keySet());
}
} else if (DIMENSION_TYPE_REGISTRY_KEY.equals(registryData.getRegistryKey())) { // >=1.20.5
// remap to legacy format
list = new NBTList<>(NBTType.COMPOUND);
List<RegistryElement> elements = registryData.getElements();
if (elements != null) {
int i = 0;
for (RegistryElement element : elements) {
NBTCompound tag = new NBTCompound();
tag.setTag("name", new NBTString(element.getId().toString()));
tag.setTag("id", new NBTInt(i++));
if (element.getData() != null) { // may be null because of known packs not being sent
tag.setTag("element", element.getData());
}
list.addTag(tag);
}
}
if (packet.getElements() != null) { // 1.20.2 to 1.20.5
SynchronizedRegistriesHandler.handleRegistry(user, packet.getServerVersion().toClientVersion(),
packet.getRegistryKey(), packet.getElements());
}
if (list != null) {
user.setWorldNBT(list);
if (packet.getRegistryData() != null) { // since 1.20.5
SynchronizedRegistriesHandler.handleLegacyRegistries(user, packet.getServerVersion()
.toClientVersion(), packet.getRegistryData());
}
}
// The server sends dimension information in login packet for >= 1.17 and < 1.20.2
// The server sends registry info in login packet for 1.16 to 1.20.1
else if (event.getPacketType() == PacketType.Play.Server.JOIN_GAME) {
WrapperPlayServerJoinGame joinGame = new WrapperPlayServerJoinGame(event);
user.setEntityId(joinGame.getEntityId());
user.setDimension(joinGame.getDimension());
if (event.getServerVersion().isOlderThanOrEquals(ServerVersion.V_1_16_5)) {
return; // Fixed world height, no tags are sent to the client
if (joinGame.getDimensionCodec() != null) { // 1.16 to 1.20.1
SynchronizedRegistriesHandler.handleLegacyRegistries(user, joinGame.getServerVersion().toClientVersion(),
joinGame.getDimensionCodec());
}
// Store world data
NBTCompound dimensionCodec = joinGame.getDimensionCodec();
if (dimensionCodec != null) {
NBTList<NBTCompound> types = null;
NBTCompound dimensionTypes = dimensionCodec
.getCompoundTagOrNull(DIMENSION_TYPE_REGISTRY_KEY.toString());
if (dimensionTypes == null) {
dimensionTypes = dimensionCodec
.getCompoundTagOrNull(DIMENSION_TYPE_REGISTRY_KEY.getKey());
}
if (dimensionTypes != null) { // account for dimension type registry somehow going missing
types = dimensionTypes.getCompoundListTagOrNull("value");
}
if (types == null) {
types = new NBTList<>(NBTType.COMPOUND);
PacketEvents.getAPI().getLogger().warning("Can't find dimension type registry in join packet, "
+ "this may cause issues; available registries: " + dimensionCodec.getTags().keySet());
}
user.setWorldNBT(types);
}
// Update world height
user.switchDimensionType(joinGame.getServerVersion(), joinGame.getDimension());
user.setDimensionType(joinGame.getDimensionType());
}
// Respawn is used to switch dimensions
else if (event.getPacketType() == PacketType.Play.Server.RESPAWN) {
WrapperPlayServerRespawn respawn = new WrapperPlayServerRespawn(event);
user.setDimension(respawn.getDimension());
if (event.getServerVersion().isOlderThanOrEquals(ServerVersion.V_1_16_5)) {
return; // Fixed world height, no tags are sent to the client
}
user.switchDimensionType(respawn.getServerVersion(), respawn.getDimension());
WrapperPlayServerRespawn packet = new WrapperPlayServerRespawn(event);
user.setDimensionType(packet.getDimensionType());
} else if (event.getPacketType() == PacketType.Play.Server.CONFIGURATION_START) {
user.setEncoderState(ConnectionState.CONFIGURATION);
} else if (event.getPacketType() == PacketType.Configuration.Server.CONFIGURATION_END) {
@@ -191,16 +123,18 @@ public class InternalPacketListener extends PacketListenerAbstract {
public void onPacketReceive(PacketReceiveEvent event) {
User user = event.getUser();
if (event.getPacketType() == PacketType.Handshaking.Client.HANDSHAKE) {
Object channel = event.getChannel();
InetSocketAddress address = event.getSocketAddress();
WrapperHandshakingClientHandshake handshake = new WrapperHandshakingClientHandshake(event);
ConnectionState nextState = handshake.getNextConnectionState();
ClientVersion clientVersion = handshake.getClientVersion();
//Update client version for this event call(and user)
WrapperHandshakingClientHandshake packet = new WrapperHandshakingClientHandshake(event);
ClientVersion clientVersion = packet.getClientVersion();
ConnectionState state = packet.getNextConnectionState();
LogManager logger = PacketEvents.getAPI().getLogManager();
if (logger.isDebug()) {
logger.debug("Processed handshake for " + event.getAddress() + ": "
+ state.name() + " / " + packet.getClientVersion().getReleaseName());
}
user.setClientVersion(clientVersion);
PacketEvents.getAPI().getLogManager().debug("Processed " + address.getHostString() + ":" + address.getPort() + "'s client version. Client Version: " + clientVersion.getReleaseName());
//Transition into LOGIN or STATUS connection state immediately, to remain in sync with vanilla
user.setConnectionState(nextState);
user.setConnectionState(state);
} else if (event.getPacketType() == PacketType.Login.Client.LOGIN_SUCCESS_ACK) {
user.setDecoderState(ConnectionState.CONFIGURATION);
} else if (event.getPacketType() == PacketType.Play.Client.CONFIGURATION_ACK) {
@@ -104,10 +104,13 @@ public interface ProtocolManager {
PacketWrapper<?>[] wrappers = PacketTransformationUtil.transform(wrapper);
Object[] buffers = new Object[wrappers.length];
for (int i = 0; i < wrappers.length; i++) {
wrappers[i].prepareForSend(channel, outgoing);
buffers[i] = wrappers[i].buffer;
// Fix race condition when sending packets to multiple people (due to when the buffer is freed)
wrappers[i].buffer = null;
PacketWrapper<?> wrappper = wrappers[i];
synchronized (wrappper.bufferLock) {
wrappper.prepareForSend(channel, outgoing);
buffers[i] = wrappper.buffer;
// Fix race condition when sending packets to multiple people (due to when the buffer is freed)
wrappper.buffer = null;
}
}
return buffers;
}
@@ -18,6 +18,10 @@
package com.github.retrooper.packetevents.manager.server;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.User;
import org.jetbrains.annotations.Nullable;
public interface ServerManager {
/**
* Get the server version.
@@ -34,4 +38,20 @@ public interface ServerManager {
default SystemOS getOS() {
return SystemOS.getOS();
}
/**
* Gets a platform-specific network-synchronized-registries cache key.
* <p>
* This tells packetevents, if a registry should be cached or read again. On
* backend servers with global registries, this may be a constant value. On
* proxy servers with per-server registries, this may be a value which depends
* on the current server the {@link User} is on.
*
* @param user the {@link User} for which the registry gets read
* @param version the version the packet is for
* @return some value or null for no caching at all
*/
default @Nullable Object getRegistryCacheKey(User user, ClientVersion version) {
return null; // no caching
}
}
@@ -34,7 +34,7 @@ public enum ServerVersion {
//TODO Rename to MinecraftVersion?
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_2(109), V_1_9_4(110),
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
V_1_10(210), V_1_10_1(210), V_1_10_2(210),
V_1_11(315), V_1_11_2(316),
@@ -49,7 +49,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),
V_1_21(767),
//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),
//TODO UPDATE Add server version constant
ERROR(-1, true);
@@ -18,7 +18,35 @@
package com.github.retrooper.packetevents.protocol.attribute;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.MathUtil;
public interface Attribute extends MappedEntity {
@Override
default ResourceLocation getName() {
return this.getName(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
}
ResourceLocation getName(ClientVersion version);
default double sanitizeValue(double value) {
return this.sanitizeValue(value, PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
}
default double sanitizeValue(double value, ClientVersion version) {
if (!Double.isNaN(value)) {
return MathUtil.clamp(value, this.getMinValue(), this.getMaxValue());
}
return this.getMinValue();
}
double getDefaultValue();
double getMinValue();
double getMaxValue();
}
@@ -20,98 +20,338 @@ package com.github.retrooper.packetevents.protocol.attribute;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
public final class Attributes {
public class Attributes {
private static final VersionedRegistry<Attribute> REGISTRY = new VersionedRegistry<>(
"attribute", "attribute/attribute_mappings");
private static final Map<String, Attribute> ATTRIBUTE_MAP = new HashMap<>();
private static final Map<Byte, Map<Integer, Attribute>> ATTRIBUTE_ID_MAP = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("attribute/attribute_mappings");
public static Attribute define(String key) {
TypesBuilderData data = TYPES_BUILDER.define(key);
Attribute attribute = new Attribute() {
@Override
public ResourceLocation getName() {
return data.getName();
}
@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Attribute) {
return this.getName().equals(((Attribute) obj).getName());
}
return false;
}
};
MappingHelper.registerMapping(TYPES_BUILDER, ATTRIBUTE_MAP, ATTRIBUTE_ID_MAP, attribute);
return attribute;
private Attributes() {
}
private static Attribute define(
String key, @Nullable String legacyPrefix,
double def, double min, double max
) {
return REGISTRY.define(key, data ->
new StaticAttribute(data, legacyPrefix, def, min, max));
}
public static VersionedRegistry<Attribute> getRegistry() {
return REGISTRY;
}
// with minecraft:key
public static Attribute getByName(String name) {
return ATTRIBUTE_MAP.get(name);
// "remapping" to support < 1.21.2
String normedName = ResourceLocation.normString(name);
if (normedName.startsWith(ResourceLocation.VANILLA_NAMESPACE + ":generic.")
|| normedName.startsWith(ResourceLocation.VANILLA_NAMESPACE + ":player.")
|| normedName.startsWith(ResourceLocation.VANILLA_NAMESPACE + ":zombie.")) {
normedName = normedName.substring(name.indexOf('.') + 1);
}
return REGISTRY.getByName(normedName);
}
public static Attribute getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, Attribute> idMap = ATTRIBUTE_ID_MAP.get((byte) index);
return idMap.get(id);
return REGISTRY.getById(version, id);
}
public static final Attribute GENERIC_ARMOR = define("generic.armor");
public static final Attribute GENERIC_ARMOR_TOUGHNESS = define("generic.armor_toughness");
public static final Attribute GENERIC_ATTACK_DAMAGE = define("generic.attack_damage");
public static final Attribute GENERIC_ATTACK_KNOCKBACK = define("generic.attack_knockback");
public static final Attribute GENERIC_ATTACK_SPEED = define("generic.attack_speed");
public static final Attribute GENERIC_FLYING_SPEED = define("generic.flying_speed");
public static final Attribute GENERIC_FOLLOW_RANGE = define("generic.follow_range");
@ApiStatus.Obsolete // renamed in 1.20.5
public static final Attribute HORSE_JUMP_STRENGTH = define("horse.jump_strength");
public static final Attribute GENERIC_KNOCKBACK_RESISTANCE = define("generic.knockback_resistance");
public static final Attribute GENERIC_LUCK = define("generic.luck");
public static final Attribute GENERIC_MAX_HEALTH = define("generic.max_health");
public static final Attribute GENERIC_MOVEMENT_SPEED = define("generic.movement_speed");
public static final Attribute ZOMBIE_SPAWN_REINFORCEMENTS = define("zombie.spawn_reinforcements");
public static final Attribute ARMOR = define("armor",
"generic", 0d, 0d, 30d);
public static final Attribute ARMOR_TOUGHNESS = define("armor_toughness",
"generic", 0d, 0d, 20d);
public static final Attribute ATTACK_DAMAGE = define("attack_damage",
"generic", 2d, 0d, 2048d);
public static final Attribute ATTACK_KNOCKBACK = define("attack_knockback",
"generic", 0d, 0d, 5d);
public static final Attribute ATTACK_SPEED = define("attack_speed",
"generic", 4d, 0d, 1024d);
public static final Attribute FLYING_SPEED = define("flying_speed",
"generic", 0.4d, 0d, 1024d);
public static final Attribute FOLLOW_RANGE = define("follow_range",
"generic", 32d, 0d, 2048d);
public static final Attribute KNOCKBACK_RESISTANCE = define("knockback_resistance",
"generic", 0d, 0d, 1d);
public static final Attribute LUCK = define("luck",
"generic", 0d, -1024d, 1024d);
public static final Attribute MAX_HEALTH = define("max_health",
"generic", 20d, 1d, 1024d);
public static final Attribute MOVEMENT_SPEED = define("movement_speed",
"generic", 0.7d, 0d, 1024d);
public static final Attribute SPAWN_REINFORCEMENTS = define("spawn_reinforcements",
"zombie", 0d, 0d, 1d);
// Added in 1.20.2
public static final Attribute GENERIC_MAX_ABSORPTION = define("generic.max_absorption");
/**
* Added with 1.20.2
*/
public static final Attribute MAX_ABSORPTION = define("max_absorption",
"generic", 0d, 0d, 2048d);
// Added in 1.20.5
public static final Attribute PLAYER_BLOCK_BREAK_SPEED = define("player.block_break_speed");
public static final Attribute PLAYER_BLOCK_INTERACTION_RANGE = define("player.block_interaction_range");
public static final Attribute PLAYER_ENTITY_INTERACTION_RANGE = define("player.entity_interaction_range");
public static final Attribute GENERIC_FALL_DAMAGE_MULTIPLIER = define("generic.fall_damage_multiplier");
public static final Attribute GENERIC_GRAVITY = define("generic.gravity");
public static final Attribute GENERIC_JUMP_STRENGTH = define("generic.jump_strength");
public static final Attribute GENERIC_SAFE_FALL_DISTANCE = define("generic.safe_fall_distance");
public static final Attribute GENERIC_SCALE = define("generic.scale");
public static final Attribute GENERIC_STEP_HEIGHT = define("generic.step_height");
/**
* Added with 1.20.5
*/
public static final Attribute BLOCK_BREAK_SPEED = define("block_break_speed",
"player", 1d, 0d, 1024d);
/**
* Added with 1.20.5
*/
public static final Attribute BLOCK_INTERACTION_RANGE = define("block_interaction_range",
"player", 4.5d, 0d, 64d);
/**
* Added with 1.20.5
*/
public static final Attribute ENTITY_INTERACTION_RANGE = define("entity_interaction_range",
"player", 3d, 0d, 64d);
/**
* Added with 1.20.5
*/
public static final Attribute FALL_DAMAGE_MULTIPLIER = define("fall_damage_multiplier",
"generic", 1d, 0d, 100d);
/**
* Added with 1.20.5
*/
public static final Attribute GRAVITY = define("gravity",
"generic", 0.08d, -1d, 1d);
/**
* Added with 1.20.5
*/
public static final Attribute JUMP_STRENGTH = define("jump_strength",
"generic", 0.42d, 0d, 32d);
/**
* Added with 1.20.5
*/
public static final Attribute SAFE_FALL_DISTANCE = define("safe_fall_distance",
"generic", 3d, 0d, 1024d);
/**
* Added with 1.20.5
*/
public static final Attribute SCALE = define("scale",
"generic", 1d, 1d / 16d, 16d);
/**
* Added with 1.20.5
*/
public static final Attribute STEP_HEIGHT = define("step_height",
"generic", 0.6d, 0d, 10d);
// Added in 1.21
public static final Attribute GENERIC_BURNING_TIME = define("generic.burning_time");
public static final Attribute GENERIC_EXPLOSION_KNOCKBACK_RESISTANCE = define("generic.explosion_knockback_resistance");
public static final Attribute PLAYER_MINING_EFFICIENCY = define("player.mining_efficiency");
public static final Attribute GENERIC_MOVEMENT_EFFICIENCY = define("generic.movement_efficiency");
public static final Attribute GENERIC_OXYGEN_BONUS = define("generic.oxygen_bonus");
public static final Attribute PLAYER_SNEAKING_SPEED = define("player.sneaking_speed");
public static final Attribute PLAYER_SUBMERGED_MINING_SPEED = define("player.submerged_mining_speed");
public static final Attribute PLAYER_SWEEPING_DAMAGE_RATIO = define("player.sweeping_damage_ratio");
public static final Attribute GENERIC_WATER_MOVEMENT_EFFICIENCY = define("generic.water_movement_efficiency");
/**
* Added with 1.21
*/
public static final Attribute BURNING_TIME = define("burning_time",
"generic", 0d, 1d, 1024d);
/**
* Added with 1.21
*/
public static final Attribute EXPLOSION_KNOCKBACK_RESISTANCE = define("explosion_knockback_resistance",
"generic", 0d, 0d, 1d);
/**
* Added with 1.21
*/
public static final Attribute MINING_EFFICIENCY = define("mining_efficiency",
"player", 0d, 0d, 1024d);
/**
* Added with 1.21
*/
public static final Attribute MOVEMENT_EFFICIENCY = define("movement_efficiency",
"generic", 0d, 0d, 1d);
/**
* Added with 1.21
*/
public static final Attribute OXYGEN_BONUS = define("oxygen_bonus",
"generic", 0d, 0d, 1024d);
/**
* Added with 1.21
*/
public static final Attribute SNEAKING_SPEED = define("sneaking_speed",
"player", 0.3d, 0d, 1d);
/**
* Added with 1.21
*/
public static final Attribute SUBMERGED_MINING_SPEED = define("submerged_mining_speed",
"player", 0.2d, 0d, 20d);
/**
* Added with 1.21
*/
public static final Attribute SWEEPING_DAMAGE_RATIO = define("sweeping_damage_ratio",
"player", 0d, 0d, 1d);
/**
* Added with 1.21
*/
public static final Attribute WATER_MOVEMENT_EFFICIENCY = define("water_movement_efficiency",
"generic", 0d, 0d, 1d);
/**
* Added with 1.21.2
*/
public static final Attribute TEMPT_RANGE = define("tempt_range",
null, 10d, 0d, 2048d);
/**
* This attribute has been renamed in 1.20.5 to {@link #JUMP_STRENGTH}
*/
@ApiStatus.Obsolete
public static final Attribute HORSE_JUMP_STRENGTH = define("horse.jump_strength",
null, 0.7d, 0d, 2d);
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_ARMOR = ARMOR;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_ARMOR_TOUGHNESS = ARMOR_TOUGHNESS;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_ATTACK_DAMAGE = ATTACK_DAMAGE;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_ATTACK_KNOCKBACK = ATTACK_KNOCKBACK;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_ATTACK_SPEED = ATTACK_SPEED;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_FLYING_SPEED = FLYING_SPEED;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_FOLLOW_RANGE = FOLLOW_RANGE;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_KNOCKBACK_RESISTANCE = KNOCKBACK_RESISTANCE;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_LUCK = LUCK;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_MAX_HEALTH = MAX_HEALTH;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_MOVEMENT_SPEED = MOVEMENT_SPEED;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute ZOMBIE_SPAWN_REINFORCEMENTS = SPAWN_REINFORCEMENTS;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_MAX_ABSORPTION = MAX_ABSORPTION;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute PLAYER_BLOCK_BREAK_SPEED = BLOCK_BREAK_SPEED;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute PLAYER_BLOCK_INTERACTION_RANGE = BLOCK_INTERACTION_RANGE;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute PLAYER_ENTITY_INTERACTION_RANGE = ENTITY_INTERACTION_RANGE;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_FALL_DAMAGE_MULTIPLIER = FALL_DAMAGE_MULTIPLIER;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_GRAVITY = GRAVITY;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_JUMP_STRENGTH = JUMP_STRENGTH;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_SAFE_FALL_DISTANCE = SAFE_FALL_DISTANCE;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_SCALE = SCALE;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_STEP_HEIGHT = STEP_HEIGHT;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_BURNING_TIME = BURNING_TIME;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_EXPLOSION_KNOCKBACK_RESISTANCE = EXPLOSION_KNOCKBACK_RESISTANCE;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute PLAYER_MINING_EFFICIENCY = MINING_EFFICIENCY;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_MOVEMENT_EFFICIENCY = MOVEMENT_EFFICIENCY;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_OXYGEN_BONUS = OXYGEN_BONUS;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute PLAYER_SNEAKING_SPEED = SNEAKING_SPEED;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute PLAYER_SUBMERGED_MINING_SPEED = SUBMERGED_MINING_SPEED;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute PLAYER_SWEEPING_DAMAGE_RATIO = SWEEPING_DAMAGE_RATIO;
/**
* All attribute "type" prefixes were removed with 1.21.2
*/
@Deprecated
public static final Attribute GENERIC_WATER_MOVEMENT_EFFICIENCY = WATER_MOVEMENT_EFFICIENCY;
static {
TYPES_BUILDER.unloadFileMappings();
REGISTRY.unloadMappings();
}
}
@@ -0,0 +1,67 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.Nullable;
public class StaticAttribute extends AbstractMappedEntity implements Attribute {
private final @Nullable ResourceLocation legacyName;
private final double defaultValue;
private final double minValue;
private final double maxValue;
StaticAttribute(
TypesBuilderData data, String legacyPrefix,
double defaultValue, double minValue, double maxValue
) {
super(data);
this.defaultValue = defaultValue;
this.minValue = minValue;
this.maxValue = maxValue;
this.legacyName = legacyPrefix == null ? null : new ResourceLocation(
data.getName().getNamespace(), legacyPrefix + "." + data.getName().getKey());
}
@Override
public ResourceLocation getName(ClientVersion version) {
assert this.data != null; // not marked as nullable in ctor
return version.isNewerThanOrEquals(ClientVersion.V_1_21_2) || this.legacyName == null
? this.data.getName() : this.legacyName;
}
@Override
public double getDefaultValue() {
return this.defaultValue;
}
@Override
public double getMinValue() {
return this.minValue;
}
@Override
public double getMaxValue() {
return this.maxValue;
}
}
@@ -19,17 +19,39 @@
package com.github.retrooper.packetevents.protocol.chat;
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage_v1_19_1;
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
import com.github.retrooper.packetevents.protocol.mapper.DeepComparableEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
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.ClientVersion;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
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;
public interface ChatType extends MappedEntity {
import java.util.Objects;
import static com.github.retrooper.packetevents.util.adventure.AdventureIndexUtil.indexValueOrThrow;
public interface ChatType extends MappedEntity, CopyableEntity<ChatType>, DeepComparableEntity {
@UnknownNullability("only nullable for 1.19")
ChatTypeDecoration getChatDecoration();
@ApiStatus.Obsolete(since = "1.19.1")
@Nullable ChatTypeDecoration getOverlayDecoration();
@UnknownNullability("only nullable for 1.19")
ChatTypeDecoration getNarrationDecoration();
@ApiStatus.Obsolete(since = "1.19.1")
@Nullable NarrationPriority getNarrationPriority();
static ChatType readDirect(PacketWrapper<?> wrapper) {
ChatTypeDecoration chatDecoration = ChatTypeDecoration.read(wrapper);
ChatTypeDecoration narrationDecoration = ChatTypeDecoration.read(wrapper);
@@ -41,9 +63,105 @@ public interface ChatType extends MappedEntity {
ChatTypeDecoration.write(wrapper, chatType.getNarrationDecoration());
}
static ChatType decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
// everything is nullable in 1.19, even the chat format!
NBTCompound compound = (NBTCompound) nbt;
NBTCompound chatTag = compound.getCompoundTagOrNull("chat");
NBTCompound narrationTag = compound.getCompoundTagOrNull("narration");
ChatTypeDecoration overlay = null;
NarrationPriority narrationPriority = null;
if (version.isOlderThan(ClientVersion.V_1_19_1)) {
NBTCompound overlayTag = compound.getCompoundTagOrNull("overlay");
if (overlayTag != null) {
// why is this nullable? why is this wrapped? There is no reason to wrap this...
overlayTag = overlayTag.getCompoundTagOrNull("description");
if (overlayTag != null) {
overlay = ChatTypeDecoration.decode(overlayTag, version);
}
}
if (chatTag != null) {
chatTag = chatTag.getCompoundTagOrNull("description");
}
if (narrationTag != null) {
// the priority is the ONLY value which isn't nullable!
narrationPriority = indexValueOrThrow(NarrationPriority.ID_INDEX,
narrationTag.getStringTagValueOrThrow("priority"));
narrationTag = narrationTag.getCompoundTagOrNull("description");
}
} else {
// ensure this isn't null in everything but 1.19
Objects.requireNonNull(chatTag, "NBT chat does not exist");
Objects.requireNonNull(narrationTag, "NBT narration does not exist");
}
ChatTypeDecoration chat = chatTag == null ? null : ChatTypeDecoration.decode(chatTag, version);
ChatTypeDecoration narration = narrationTag == null ? null : ChatTypeDecoration.decode(narrationTag, version);
return new StaticChatType(data, chat, overlay, narration, narrationPriority);
}
static NBT encode(ChatType chatType, ClientVersion version) {
NBTCompound compound = new NBTCompound();
NBT chatTag = chatType.getChatDecoration() == null ? null :
ChatTypeDecoration.encode(chatType.getChatDecoration(), version);
NBT narrationTag = chatType.getNarrationDecoration() == null ? null :
ChatTypeDecoration.encode(chatType.getNarrationDecoration(), version);
if (version.isOlderThan(ClientVersion.V_1_19_1)) {
ChatTypeDecoration overlayDeco = chatType.getOverlayDecoration();
if (overlayDeco != null) {
NBTCompound overlayCompound = new NBTCompound();
overlayCompound.setTag("description",
ChatTypeDecoration.encode(overlayDeco, version));
compound.setTag("overlay", overlayCompound);
}
if (narrationTag != null) {
NBTCompound narrationCompound = new NBTCompound();
narrationCompound.setTag("description", narrationTag);
if (chatType.getNarrationPriority() != null) {
narrationCompound.setTag("priority", new NBTString(chatType.getNarrationPriority().getId()));
}
narrationTag = narrationCompound;
}
if (chatTag != null) {
NBTCompound chatCompound = new NBTCompound();
chatCompound.setTag("description", chatTag);
chatTag = chatCompound;
}
}
if (chatTag != null) {
compound.setTag("chat", chatTag);
}
if (narrationTag != null) {
compound.setTag("narration", narrationTag);
}
return compound;
}
class Bound extends ChatMessage_v1_19_1.ChatTypeBoundNetwork {
public Bound(ChatType type, Component name, @Nullable Component targetName) {
super(type, name, targetName);
}
}
@ApiStatus.Obsolete(since = "1.19.1")
enum NarrationPriority {
CHAT("chat"),
SYSTEM("system");
public static final Index<String, NarrationPriority> ID_INDEX = Index.create(
NarrationPriority.class, NarrationPriority::getId);
private final String id;
NarrationPriority(String id) {
this.id = id;
}
public String getId() {
return this.id;
}
}
}
@@ -18,23 +18,29 @@
package com.github.retrooper.packetevents.protocol.chat;
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage_v1_19_1;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.util.Index;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.BiFunction;
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.Parameter.*;
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.Parameter.CONTENT;
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.Parameter.SENDER;
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.Parameter.TARGET;
import static com.github.retrooper.packetevents.util.adventure.AdventureIndexUtil.indexValueOrThrow;
import static java.util.Arrays.asList;
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
import static net.kyori.adventure.text.format.Style.empty;
@@ -53,32 +59,6 @@ public class ChatTypeDecoration {
this.style = style;
}
public ChatTypeDecoration(NBTCompound nbt) {
//Read the translation key
this.translationKey = nbt.getStringTagValueOrDefault("translation_key", null);
//Read parameters
List<Parameter> temporaryList = new ArrayList<>();
NBTList<NBTString> parametersTag = nbt.getStringListTagOrNull("parameters");
if (parametersTag != null) {
for (NBTString p : parametersTag.getTags()) {
Parameter parameter = Parameter.valueByName(p.getValue().toUpperCase());
if (parameter != null) {
temporaryList.add(parameter);
}
}
}
this.parameters = Collections.unmodifiableList(temporaryList);
//Read style
NBTCompound styleTag = nbt.getCompoundTagOrNull("style");
if (styleTag != null) {
style = AdventureSerializer.getNBTSerializer().deserializeStyle(styleTag);
} else {
style = empty();
}
}
public static ChatTypeDecoration read(PacketWrapper<?> wrapper) {
String translationKey = wrapper.readString();
List<Parameter> parameters = wrapper.readList(ew -> ew.readEnum(Parameter.values()));
@@ -92,6 +72,44 @@ public class ChatTypeDecoration {
wrapper.writeStyle(decoration.style);
}
public static ChatTypeDecoration decode(NBT nbt, ClientVersion version) {
NBTCompound compound = (NBTCompound) nbt;
String translationKey = compound.getStringTagValueOrThrow("translation_key");
NBT paramsTag = compound.getTagOrThrow("parameters");
List<Parameter> params;
if (paramsTag instanceof NBTList<?>) {
params = new ArrayList<>();
NBTList<?> paramsTagList = (NBTList<?>) paramsTag;
for (NBT paramTag : paramsTagList.getTags()) {
String paramId = ((NBTString) paramTag).getValue();
params.add(indexValueOrThrow(Parameter.ID_INDEX, paramId));
}
} else {
String paramId = ((NBTString) paramsTag).getValue();
params = Collections.singletonList(indexValueOrThrow(Parameter.ID_INDEX, paramId));
}
NBTCompound styleTag = compound.getCompoundTagOrNull("style");
Style style = styleTag == null ? empty() :
AdventureSerializer.getNBTSerializer().deserializeStyle(styleTag);
return new ChatTypeDecoration(translationKey, params, style);
}
public static NBT encode(ChatTypeDecoration decoration, ClientVersion version) {
NBTList<NBTString> paramsTag = NBTList.createStringList();
for (Parameter param : decoration.parameters) {
paramsTag.addTag(new NBTString(param.getId()));
}
NBTCompound compound = new NBTCompound();
compound.setTag("translation_key", new NBTString(decoration.translationKey));
compound.setTag("parameters", paramsTag);
if (!decoration.style.isEmpty()) {
compound.setTag("style", AdventureSerializer.getNBTSerializer()
.serializeStyle(decoration.style));
}
return compound;
}
public static ChatTypeDecoration withSender(String translationKey) {
return new ChatTypeDecoration(translationKey, asList(SENDER, CONTENT), empty());
}
@@ -131,24 +149,46 @@ public class ChatTypeDecoration {
return this.style;
}
public enum Parameter {
SENDER((component, type) -> type.getName()),
TARGET((component, type) -> type.getTargetName() != null ? type.getTargetName() : Component.empty()),
CONTENT((component, type) -> component);
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ChatTypeDecoration)) return false;
ChatTypeDecoration that = (ChatTypeDecoration) obj;
if (!this.translationKey.equals(that.translationKey)) return false;
if (!this.parameters.equals(that.parameters)) return false;
return this.style.equals(that.style);
}
@Override
public int hashCode() {
return Objects.hash(this.translationKey, this.parameters, this.style);
}
public enum Parameter {
SENDER("sender", (component, type) -> type.getName()),
TARGET("target", (component, type) -> type.getTargetName() != null
? type.getTargetName() : Component.empty()),
CONTENT("content", (component, type) -> component);
public static final Index<String, Parameter> ID_INDEX = Index.create(
Parameter.class, Parameter::getId);
private final String id;
private final BiFunction<Component, ChatType.Bound, Component> selector;
Parameter(BiFunction<Component, ChatType.Bound, Component> selector) {
Parameter(String id, BiFunction<Component, ChatType.Bound, Component> selector) {
this.id = id;
this.selector = selector;
}
@Nullable
public static Parameter valueByName(String name) {
try {
return valueOf(name);
} catch (IllegalArgumentException ex) {
return null;
}
public String getId() {
return this.id;
}
@Deprecated
public static @Nullable Parameter valueByName(String id) {
return ID_INDEX.value(id);
}
}
}
@@ -19,71 +19,50 @@
package com.github.retrooper.packetevents.protocol.chat;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import org.jetbrains.annotations.ApiStatus;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.incomingDirectMessage;
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.outgoingDirectMessage;
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.teamMessage;
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.withSender;
public class ChatTypes {
public final class ChatTypes {
private static final Map<String, ChatType> CHAT_TYPE_MAP = new HashMap<>();
//Key - mappings version, value - map with chat type ids and chat types
private static final Map<Byte, Map<Integer, ChatType>> CHAT_TYPE_ID_MAP = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("chat/chat_type_mappings");
private static final VersionedRegistry<ChatType> REGISTRY = new VersionedRegistry<>(
"chat_type", "chat/chat_type_mappings");
private ChatTypes() {
}
@ApiStatus.Internal
public static ChatType define(String key) {
return define(key, withSender("chat.type.text"));
}
@ApiStatus.Internal
public static ChatType define(String key, ChatTypeDecoration chatDeco) {
return define(key, chatDeco, withSender("chat.type.text.narrate"));
}
@ApiStatus.Internal
public static ChatType define(String key, ChatTypeDecoration chatDeco, ChatTypeDecoration narrationDeco) {
TypesBuilderData data = TYPES_BUILDER.define(key);
ChatType chatType = new ChatType() {
@Override
public ChatTypeDecoration getChatDecoration() {
return chatDeco;
}
@Override
public ChatTypeDecoration getNarrationDecoration() {
return narrationDeco;
}
@Override
public ResourceLocation getName() {
return data.getName();
}
@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
}
};
MappingHelper.registerMapping(TYPES_BUILDER, CHAT_TYPE_MAP, CHAT_TYPE_ID_MAP, chatType);
return chatType;
return REGISTRY.define(key, data ->
new StaticChatType(data, chatDeco, narrationDeco));
}
public static VersionedRegistry<ChatType> getRegistry() {
return REGISTRY;
}
//with minecraft:key
public static ChatType getByName(String name) {
return CHAT_TYPE_MAP.get(name);
return REGISTRY.getByName(name);
}
public static ChatType getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
return CHAT_TYPE_ID_MAP.get((byte) index).get(id);
return REGISTRY.getById(version, id);
}
public static final ChatType CHAT = define("chat");
@@ -115,13 +94,14 @@ public class ChatTypes {
/**
* Returns an immutable view of the chat types.
*
* @return Chat Types
*/
public static Collection<ChatType> values() {
return Collections.unmodifiableCollection(CHAT_TYPE_MAP.values());
return REGISTRY.getEntries();
}
static {
TYPES_BUILDER.unloadFileMappings();
REGISTRY.unloadMappings();
}
}
@@ -18,41 +18,103 @@
package com.github.retrooper.packetevents.protocol.chat;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;
public class StaticChatType implements ChatType {
import java.util.Objects;
private final ChatTypeDecoration chatDecoration;
private final ChatTypeDecoration narrationDecoration;
public class StaticChatType extends AbstractMappedEntity implements ChatType {
public StaticChatType(ChatTypeDecoration chatDecoration, ChatTypeDecoration narrationDecoration) {
private final @UnknownNullability("only nullable for 1.19") ChatTypeDecoration chatDecoration;
private final @Nullable ChatTypeDecoration overlayDecoration;
private final @UnknownNullability("only nullable for 1.19") ChatTypeDecoration narrationDecoration;
private final @Nullable NarrationPriority narrationPriority;
public StaticChatType(
ChatTypeDecoration chatDecoration,
ChatTypeDecoration narrationDecoration
) {
this(null, chatDecoration, null, narrationDecoration, null);
}
public StaticChatType(
@Nullable TypesBuilderData data,
ChatTypeDecoration chatDecoration,
ChatTypeDecoration narrationDecoration
) {
this(data, chatDecoration, null, narrationDecoration, null);
}
public StaticChatType(
@UnknownNullability("only nullable for 1.19") ChatTypeDecoration chatDecoration,
@Nullable ChatTypeDecoration overlayDecoration,
@UnknownNullability("only nullable for 1.19") ChatTypeDecoration narrationDecoration,
@Nullable NarrationPriority narrationPriority
) {
this(null, chatDecoration, overlayDecoration, narrationDecoration, narrationPriority);
}
public StaticChatType(
@Nullable TypesBuilderData data,
@UnknownNullability("only nullable for 1.19") ChatTypeDecoration chatDecoration,
@Nullable ChatTypeDecoration overlayDecoration,
@UnknownNullability("only nullable for 1.19") ChatTypeDecoration narrationDecoration,
@Nullable NarrationPriority narrationPriority
) {
super(data);
this.chatDecoration = chatDecoration;
this.overlayDecoration = overlayDecoration;
this.narrationDecoration = narrationDecoration;
this.narrationPriority = narrationPriority;
}
@Override
public ChatTypeDecoration getChatDecoration() {
public ChatType copy(@Nullable TypesBuilderData newData) {
return new StaticChatType(newData, this.chatDecoration,
this.overlayDecoration, this.narrationDecoration, this.narrationPriority);
}
@Override
public @UnknownNullability("only nullable for 1.19") ChatTypeDecoration getChatDecoration() {
return this.chatDecoration;
}
@Override
public ChatTypeDecoration getNarrationDecoration() {
public @Nullable ChatTypeDecoration getOverlayDecoration() {
return this.overlayDecoration;
}
@Override
public @UnknownNullability("only nullable for 1.19") ChatTypeDecoration getNarrationDecoration() {
return this.narrationDecoration;
}
@Override
public ResourceLocation getName() {
throw new UnsupportedOperationException();
public @Nullable NarrationPriority getNarrationPriority() {
return this.narrationPriority;
}
@Override
public int getId(ClientVersion version) {
throw new UnsupportedOperationException();
public boolean deepEquals(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;
if (!Objects.equals(this.narrationDecoration, that.narrationDecoration)) return false;
return this.narrationPriority == that.narrationPriority;
}
@Override
public boolean isRegistered() {
return false;
public int deepHashCode() {
return Objects.hash(super.hashCode(), this.chatDecoration, this.overlayDecoration, this.narrationDecoration, this.narrationPriority);
}
@Override
public String toString() {
return "StaticChatType{chatDecoration=" + this.chatDecoration + ", overlayDecoration=" + this.overlayDecoration + ", narrationDecoration=" + this.narrationDecoration + ", narrationPriority=" + this.narrationPriority + '}';
}
}
@@ -31,14 +31,13 @@ public class ChatMessageProcessorLegacy implements ChatMessageProcessor {
@Override
public ChatMessage readChatMessage(@NotNull PacketWrapper<?> wrapper) {
Component chatContent = wrapper.readComponent();
int id = wrapper.readByte();
ChatType type = ChatTypes.getById(wrapper.getServerVersion().toClientVersion(), id);
ChatType type = wrapper.readMappedEntity(ChatTypes.getRegistry());
return new ChatMessageLegacy(chatContent, type);
}
@Override
public void writeChatMessage(@NotNull PacketWrapper<?> wrapper, @NotNull ChatMessage data) {
wrapper.writeComponent(data.getChatContent());
wrapper.writeByte(data.getType().getId(wrapper.getServerVersion().toClientVersion()));
wrapper.writeMappedEntity(data.getType());
}
}
@@ -33,8 +33,7 @@ public class ChatMessageProcessor_v1_16 implements ChatMessageProcessor {
@Override
public ChatMessage readChatMessage(@NotNull PacketWrapper<?> wrapper) {
Component chatContent = wrapper.readComponent();
int id = wrapper.readByte();
ChatType type = ChatTypes.getById(wrapper.getServerVersion().toClientVersion(), id);
ChatType type = wrapper.readMappedEntity(ChatTypes.getRegistry());
UUID senderUUID = wrapper.readUUID();
return new ChatMessage_v1_16(chatContent, type, senderUUID);
}
@@ -42,7 +41,7 @@ public class ChatMessageProcessor_v1_16 implements ChatMessageProcessor {
@Override
public void writeChatMessage(@NotNull PacketWrapper<?> wrapper, @NotNull ChatMessage data) {
wrapper.writeComponent(data.getChatContent());
wrapper.writeByte(data.getType().getId(wrapper.getServerVersion().toClientVersion()));
wrapper.writeMappedEntity(data.getType());
wrapper.writeUUID(((ChatMessage_v1_16) data).getSenderUUID());
}
}
@@ -36,8 +36,7 @@ public class ChatMessageProcessor_v1_19 implements ChatMessageProcessor {
public ChatMessage readChatMessage(@NotNull PacketWrapper<?> wrapper) {
Component chatContent = wrapper.readComponent();
Component unsignedChatContent = wrapper.readOptional(PacketWrapper::readComponent);
int id = wrapper.readVarInt();
ChatType type = ChatTypes.getById(wrapper.getServerVersion().toClientVersion(), id);
ChatType type = wrapper.readMappedEntity(ChatTypes.getRegistry());
UUID senderUUID = wrapper.readUUID();
Component senderDisplayName = wrapper.readComponent();
@Nullable Component teamName = wrapper.readOptional(PacketWrapper::readComponent);
@@ -53,7 +52,7 @@ public class ChatMessageProcessor_v1_19 implements ChatMessageProcessor {
ChatMessage_v1_19 newData = (ChatMessage_v1_19) data;
wrapper.writeComponent(newData.getChatContent());
wrapper.writeOptional(newData.getUnsignedChatContent(), PacketWrapper::writeComponent);
wrapper.writeVarInt(newData.getType().getId(wrapper.getServerVersion().toClientVersion()));
wrapper.writeMappedEntity(newData.getType());
wrapper.writeUUID(newData.getSenderUUID());
wrapper.writeComponent(newData.getSenderDisplayName());
wrapper.writeOptional(newData.getTeamName(), PacketWrapper::writeComponent);
@@ -0,0 +1,146 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.color;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTFloat;
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
import com.github.retrooper.packetevents.protocol.nbt.NBTType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.MathUtil;
import org.jetbrains.annotations.Range;
public final class AlphaColor extends Color {
public static final AlphaColor WHITE = new AlphaColor(0xFFFFFFFF);
private final int alpha;
public AlphaColor(
@Range(from = 0L, to = 255L) int red,
@Range(from = 0L, to = 255L) int green,
@Range(from = 0L, to = 255L) int blue
) {
this(255, red, green, blue);
}
public AlphaColor(
@Range(from = 0L, to = 255L) int alpha,
@Range(from = 0L, to = 255L) int red,
@Range(from = 0L, to = 255L) int green,
@Range(from = 0L, to = 255L) int blue
) {
super(red, green, blue);
this.alpha = alpha;
}
public AlphaColor(
@Range(from = 0L, to = 1L) float red,
@Range(from = 0L, to = 1L) float green,
@Range(from = 0L, to = 1L) float blue
) {
this(1f, red, green, blue);
}
public AlphaColor(
@Range(from = 0L, to = 1L) float alpha,
@Range(from = 0L, to = 1L) float red,
@Range(from = 0L, to = 1L) float green,
@Range(from = 0L, to = 1L) float blue
) {
super(red, green, blue);
this.alpha = MathUtil.floor(alpha * 255f);
}
public AlphaColor(int rgb) {
this((rgb >> 24) & BIT_MASK,
(rgb >> 16) & BIT_MASK,
(rgb >> 8) & BIT_MASK,
rgb & BIT_MASK);
}
public static AlphaColor decode(NBT nbt, ClientVersion version) {
if (nbt instanceof NBTNumber) {
return new AlphaColor(((NBTNumber) nbt).getAsInt());
}
NBTList<?> list = (NBTList<?>) nbt;
float red = ((NBTNumber) list.getTag(0)).getAsFloat();
float green = ((NBTNumber) list.getTag(1)).getAsFloat();
float blue = ((NBTNumber) list.getTag(2)).getAsFloat();
float alpha = ((NBTNumber) list.getTag(3)).getAsFloat();
return new AlphaColor(alpha, red, green, blue);
}
public static NBT encode(AlphaColor color, ClientVersion version) {
if (version.isNewerThanOrEquals(ClientVersion.V_1_21_2)) {
return new NBTInt(color.asRGB());
}
NBTList<NBTFloat> list = new NBTList<>(NBTType.FLOAT, 4);
list.addTag(new NBTFloat(color.red));
list.addTag(new NBTFloat(color.green));
list.addTag(new NBTFloat(color.blue));
list.addTag(new NBTFloat(color.alpha));
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 withRed(@Range(from = 0L, to = 255L) int red) {
return new AlphaColor(this.alpha, red, this.green, this.blue);
}
@Override
public AlphaColor withGreen(@Range(from = 0L, to = 255L) int green) {
return new AlphaColor(this.alpha, this.red, green, this.blue);
}
@Override
public AlphaColor withBlue(@Range(from = 0L, to = 255L) int blue) {
return new AlphaColor(this.alpha, this.red, this.green, blue);
}
@Override
public int asRGB() {
return (this.alpha << 24) | (this.red << 16) | (this.green << 8) | this.blue;
}
public @Range(from = 0L, to = 255L) int alpha() {
return this.alpha;
}
@Override
public @Range(from = 0L, to = 255L) int red() {
return this.red;
}
@Override
public @Range(from = 0L, to = 255L) int green() {
return this.green;
}
@Override
public @Range(from = 0L, to = 255L) int blue() {
return this.blue;
}
}
@@ -18,15 +18,24 @@
package com.github.retrooper.packetevents.protocol.color;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTFloat;
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
import com.github.retrooper.packetevents.protocol.nbt.NBTType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.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;
public final class Color implements RGBLike {
public class Color implements RGBLike {
private static final int BIT_MASK = 0xFF;
protected static final int BIT_MASK = 0xFF;
private final int red, green, blue;
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;
@@ -34,10 +43,50 @@ public final class Color implements RGBLike {
this.blue = blue;
}
public Color(
@Range(from = 0L, to = 1L) float red,
@Range(from = 0L, to = 1L) float green,
@Range(from = 0L, to = 1L) float blue
) {
this(MathUtil.floor(red * 255f),
MathUtil.floor(green * 255f),
MathUtil.floor(blue * 255f));
}
public Color(int rgb) {
this((rgb >> 16) & BIT_MASK, (rgb >> 8) & BIT_MASK, rgb & BIT_MASK);
}
public static Color read(PacketWrapper<?> wrapper) {
return new Color(wrapper.readInt());
}
public static void write(PacketWrapper<?> wrapper, Color color) {
wrapper.writeInt(color.asRGB());
}
public static Color decode(NBT nbt, ClientVersion version) {
if (nbt instanceof NBTNumber) {
return new Color(((NBTNumber) nbt).getAsInt());
}
NBTList<?> list = (NBTList<?>) nbt;
float red = ((NBTNumber) list.getTag(0)).getAsFloat();
float green = ((NBTNumber) list.getTag(1)).getAsFloat();
float blue = ((NBTNumber) list.getTag(2)).getAsFloat();
return new Color(red, green, blue);
}
public static NBT encode(Color color, ClientVersion version) {
if (version.isNewerThanOrEquals(ClientVersion.V_1_21_2)) {
return new NBTInt(color.asRGB());
}
NBTList<NBTFloat> list = new NBTList<>(NBTType.FLOAT, 3);
list.addTag(new NBTFloat(color.red));
list.addTag(new NBTFloat(color.green));
list.addTag(new NBTFloat(color.blue));
return list;
}
public @NotNull Color withRed(@Range(from = 0L, to = 255L) int red) {
return new Color(red, green, blue);
}
@@ -51,9 +100,7 @@ public final class Color implements RGBLike {
}
public int asRGB() {
int rgb = red;
rgb = (rgb << 8) + green;
return (rgb << 8) + blue;
return (this.red << 16) | (this.green << 8) | this.blue;
}
@Override
@@ -70,4 +117,4 @@ public final class Color implements RGBLike {
public @Range(from = 0L, to = 255L) int blue() {
return blue;
}
}
}
@@ -23,6 +23,7 @@ import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
@@ -88,4 +89,22 @@ public class ComponentPredicate implements Predicate<IComponentMap> {
public void setRequiredComponents(List<ComponentValue<?>> requiredComponents) {
this.requiredComponents = requiredComponents;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ComponentPredicate)) return false;
ComponentPredicate that = (ComponentPredicate) obj;
return this.requiredComponents.equals(that.requiredComponents);
}
@Override
public int hashCode() {
return Objects.hashCode(this.requiredComponents);
}
@Override
public String toString() {
return "ComponentPredicate{requiredComponents=" + this.requiredComponents + '}';
}
}
@@ -19,11 +19,33 @@
package com.github.retrooper.packetevents.protocol.component;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import java.util.function.Function;
public interface ComponentType<T> extends MappedEntity {
T read(PacketWrapper<?> wrapper);
void write(PacketWrapper<?> wrapper, T content);
T decode(NBT nbt, ClientVersion version);
NBT encode(T value, ClientVersion version);
@ApiStatus.Internal
<Z> ComponentType<Z> legacyMap(Function<T, Z> mapper, Function<Z, T> unmapper);
interface Decoder<T> {
T decode(NBT nbt, ClientVersion version);
}
interface Encoder<T> {
NBT encode(T value, ClientVersion version);
}
}
@@ -31,21 +31,32 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemAdv
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemAttributeModifiers;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemBees;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemBlockStateProperties;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemConsumable;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemContainerContents;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemContainerLoot;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemCustomModelData;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemDamageResistant;
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;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemEnchantments;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemEquippable;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemFireworks;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemJukeboxPlayable;
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.ItemModel;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemPotionContents;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemProfile;
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.ItemTool;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemTooltipStyle;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemUseCooldown;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemUseRemainder;
import com.github.retrooper.packetevents.protocol.component.builtin.item.LodestoneTracker;
import com.github.retrooper.packetevents.protocol.component.builtin.item.PotDecorations;
import com.github.retrooper.packetevents.protocol.component.builtin.item.SuspiciousStewEffects;
@@ -56,85 +67,51 @@ import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.Dummy;
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Reader;
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Writer;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class ComponentTypes {
/**
* Contains all item data component types.
*
* @see EnchantEffectComponentTypes
*/
public final class ComponentTypes {
private static final Map<String, ComponentType<?>> COMPONENT_TYPE_MAP = new HashMap<>();
private static final Map<Byte, Map<Integer, ComponentType<?>>> COMPONENT_TYPE_ID_MAP = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_component_mappings");
private static final VersionedRegistry<ComponentType<?>> REGISTRY = new VersionedRegistry<>(
"data_component_type", "item/item_component_mappings");
private ComponentTypes() {
}
@ApiStatus.Internal
public static <T> ComponentType<T> define(String key) {
return define(key, null, null);
}
@ApiStatus.Internal
public static <T> ComponentType<T> define(String key, @Nullable Reader<T> reader, @Nullable Writer<T> writer) {
TypesBuilderData data = TYPES_BUILDER.define(key);
ComponentType<T> type = new ComponentType<T>() {
@Override
public T read(PacketWrapper<?> wrapper) {
return reader == null ? null : reader.apply(wrapper);
}
@Override
public void write(PacketWrapper<?> wrapper, T content) {
if (writer != null) {
writer.accept(wrapper, content);
}
}
@Override
public ResourceLocation getName() {
return data.getName();
}
@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ComponentType<?>) {
return this.getName().equals(((ComponentType<?>) obj).getName());
}
return false;
}
@Override
public String toString() {
return "Component[" + this.getName() + "]";
}
};
MappingHelper.registerMapping(TYPES_BUILDER, COMPONENT_TYPE_MAP, COMPONENT_TYPE_ID_MAP, type);
return type;
return REGISTRY.define(key, data -> new StaticComponentType<>(data, reader, writer));
}
public static VersionedRegistry<ComponentType<?>> getRegistry() {
return REGISTRY;
}
// with key
public static ComponentType<?> getByName(String name) {
return COMPONENT_TYPE_MAP.get(name);
return REGISTRY.getByName(name);
}
public static ComponentType<?> getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, ComponentType<?>> idMap = COMPONENT_TYPE_ID_MAP.get((byte) index);
return idMap.get(id);
return REGISTRY.getById(version, id);
}
// item component types
public static final ComponentType<NBTCompound> CUSTOM_DATA = define("custom_data",
// mojang wraps their "persistent" codec as a stream codec just here,
// so packetevents has to handle nbt strings
@@ -163,8 +140,14 @@ public class ComponentTypes {
ItemAdventurePredicate::read, ItemAdventurePredicate::write);
public static final ComponentType<ItemAttributeModifiers> ATTRIBUTE_MODIFIERS = define("attribute_modifiers",
ItemAttributeModifiers::read, ItemAttributeModifiers::write);
public static final ComponentType<Integer> CUSTOM_MODEL_DATA = define("custom_model_data",
PacketWrapper::readVarInt, PacketWrapper::writeVarInt);
public static final ComponentType<ItemCustomModelData> CUSTOM_MODEL_DATA_LISTS = define("custom_model_data",
ItemCustomModelData::read, ItemCustomModelData::write);
/**
* Rewritten in 1.21.4
*/
@Deprecated
public static final ComponentType<Integer> CUSTOM_MODEL_DATA = CUSTOM_MODEL_DATA_LISTS.legacyMap(
ItemCustomModelData::getLegacyId, ItemCustomModelData::new);
public static final ComponentType<Dummy> HIDE_ADDITIONAL_TOOLTIP = define("hide_additional_tooltip",
Dummy::dummyRead, Dummy::dummyWrite);
public static final ComponentType<Dummy> HIDE_TOOLTIP = define("hide_tooltip",
@@ -179,6 +162,10 @@ public class ComponentTypes {
Dummy::dummyReadNbt, Dummy::dummyWriteNbt);
public static final ComponentType<FoodProperties> FOOD = define("food",
FoodProperties::read, FoodProperties::write);
/**
* Has been migrated to #DAMAGE_RESISTANT with 1.21.2.
*/
@ApiStatus.Obsolete
public static final ComponentType<Dummy> FIRE_RESISTANT = define("fire_resistant",
Dummy::dummyRead, Dummy::dummyWrite);
public static final ComponentType<ItemTool> TOOL = define("tool",
@@ -254,22 +241,40 @@ public class ComponentTypes {
public static final ComponentType<ItemJukeboxPlayable> JUKEBOX_PLAYABLE = define("jukebox_playable",
ItemJukeboxPlayable::read, ItemJukeboxPlayable::write);
// added in 1.21.2
public static final ComponentType<ItemConsumable> CONSUMABLE = define("consumable",
ItemConsumable::read, ItemConsumable::write);
public static final ComponentType<ItemUseRemainder> USE_REMAINDER = define("use_remainder",
ItemUseRemainder::read, ItemUseRemainder::write);
public static final ComponentType<ItemUseCooldown> USE_COOLDOWN = define("use_cooldown",
ItemUseCooldown::read, ItemUseCooldown::write);
public static final ComponentType<ItemEnchantable> ENCHANTABLE = define("enchantable",
ItemEnchantable::read, ItemEnchantable::write);
public static final ComponentType<ItemRepairable> REPAIRABLE = define("repairable",
ItemRepairable::read, ItemRepairable::write);
public static final ComponentType<ItemModel> ITEM_MODEL = define("item_model",
ItemModel::read, ItemModel::write);
public static final ComponentType<ItemDamageResistant> DAMAGE_RESISTANT = define("damage_resistant",
ItemDamageResistant::read, ItemDamageResistant::write);
public static final ComponentType<ItemEquippable> EQUIPPABLE = define("equippable",
ItemEquippable::read, ItemEquippable::write);
public static final ComponentType<Dummy> GLIDER = define("glider",
Dummy::dummyRead, Dummy::dummyWrite);
public static final ComponentType<ItemDeathProtection> DEATH_PROTECTION = define("death_protection",
ItemDeathProtection::read, ItemDeathProtection::write);
public static final ComponentType<ItemTooltipStyle> TOOLTIP_STYLE = define("tooltip_style",
ItemTooltipStyle::read, ItemTooltipStyle::write);
/**
* Returns an immutable view of the component types.
*
* @return Component Types
*/
public static Collection<ComponentType<?>> values() {
return Collections.unmodifiableCollection(COMPONENT_TYPE_MAP.values());
return REGISTRY.getEntries();
}
static {
TYPES_BUILDER.unloadFileMappings();
REGISTRY.unloadMappings();
}
@FunctionalInterface
public interface Reader<T> extends Function<PacketWrapper<?>, T> {}
@FunctionalInterface
public interface Writer<T> extends BiConsumer<PacketWrapper<?>, T> {}
}
@@ -0,0 +1,120 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component;
import com.github.retrooper.packetevents.protocol.component.ComponentType.Decoder;
import com.github.retrooper.packetevents.protocol.component.ComponentType.Encoder;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
/**
* Contains all enchantment effect component types.
*
* @see ComponentTypes
*/
public final class EnchantEffectComponentTypes {
private static final VersionedRegistry<ComponentType<?>> REGISTRY = new VersionedRegistry<>(
"enchantment_effect_component_type", "enchantment/effect_component_type");
private EnchantEffectComponentTypes() {
}
@ApiStatus.Internal
public static <T> ComponentType<T> define(String key) {
return define(key, null, null);
}
@ApiStatus.Internal
public static <T> ComponentType<T> define(String key, @Nullable Decoder<T> reader, @Nullable Encoder<T> writer) {
return REGISTRY.define(key, data -> new StaticComponentType<>(data, reader, writer));
}
public static VersionedRegistry<ComponentType<?>> getRegistry() {
return REGISTRY;
}
// just pass everything through for now
public static ComponentType<NBT> DAMAGE_PROTECTION = define("damage_protection",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> DAMAGE_IMMUNITY = define("damage_immunity",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> DAMAGE = define("damage",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> SMASH_DAMAGE_PER_FALLEN_BLOCK = define("smash_damage_per_fallen_block",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> KNOCKBACK = define("knockback",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> ARMOR_EFFECTIVENESS = define("armor_effectiveness",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> POST_ATTACK = define("post_attack",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> HIT_BLOCK = define("hit_block",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> ITEM_DAMAGE = define("item_damage",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> ATTRIBUTES = define("attributes",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> EQUIPMENT_DROPS = define("equipment_drops",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> LOCATION_CHANGED = define("location_changed",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> TICK = define("tick",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> AMMO_USE = define("ammo_use",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PROJECTILE_PIERCING = define("projectile_piercing",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PROJECTILE_SPAWNED = define("projectile_spawned",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PROJECTILE_SPREAD = define("projectile_spread",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PROJECTILE_COUNT = define("projectile_count",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> TRIDENT_RETURN_ACCELERATION = define("trident_return_acceleration",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> FISHING_TIME_REDUCTION = define("fishing_time_reduction",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> FISHING_LUCK_BONUS = define("fishing_luck_bonus",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> BLOCK_EXPERIENCE = define("block_experience",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> MOB_EXPERIENCE = define("mob_experience",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> REPAIR_WITH_XP = define("repair_with_xp",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> CROSSBOW_CHARGE_TIME = define("crossbow_charge_time",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> CROSSBOW_CHARGING_SOUNDS = define("crossbow_charging_sounds",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> TRIDENT_SOUND = define("trident_sound",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PREVENT_EQUIPMENT_DROP = define("prevent_equipment_drop",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PREVENT_ARMOR_CHANGE = define("prevent_armor_change",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> TRIDENT_SPIN_ATTACK_STRENGTH = define("trident_spin_attack_strength",
(nbt, version) -> nbt, (val, version) -> val);
static {
REGISTRY.unloadMappings();
}
}
@@ -18,13 +18,44 @@
package com.github.retrooper.packetevents.protocol.component;
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 org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Optional;
public interface IComponentMap {
@SuppressWarnings("unchecked") // safe in this case
static StaticComponentMap decode(NBT nbt, ClientVersion version, IRegistry<? extends ComponentType<?>> registry) {
NBTCompound compound = (NBTCompound) nbt;
StaticComponentMap.Builder components = StaticComponentMap.builder();
for (Map.Entry<String, NBT> entry : compound.getTags().entrySet()) {
ComponentType<?> type = registry.getByName(entry.getKey());
if (type == null) {
throw new IllegalStateException("Unknown component type named " + entry.getKey() + " encountered");
}
Object value = type.decode(entry.getValue(), version);
components.set((ComponentType<? super Object>) type, value);
}
return components.build();
}
@SuppressWarnings("unchecked") // safe in this case
static NBT encode(StaticComponentMap components, ClientVersion version) {
NBTCompound compound = new NBTCompound();
for (Map.Entry<ComponentType<?>, ?> entry : components.getDelegate().entrySet()) {
String key = entry.getKey().getName().toString();
NBT value = ((ComponentType<? super Object>) entry.getKey()).encode(entry.getValue(), version);
compound.setTag(key, value);
}
return compound;
}
default <T> Optional<T> getOptional(ComponentType<T> type) {
return Optional.ofNullable(this.get(type));
}
@@ -96,6 +96,20 @@ public class PatchableComponentMap implements IComponentMap {
return this.patches;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof PatchableComponentMap)) return false;
PatchableComponentMap that = (PatchableComponentMap) obj;
if (!this.base.equals(that.base)) return false;
return this.patches.equals(that.patches);
}
@Override
public int hashCode() {
return Objects.hash(this.base, this.patches);
}
@Override
public String toString() {
return "PatchableComponentMap{base=" + this.base + ", patches=" + this.patches + '}';
@@ -22,16 +22,20 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemAtt
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemEnchantments;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemLore;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemRarity;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
public class StaticComponentMap implements IComponentMap {
public static final StaticComponentMap EMPTY = new StaticComponentMap(Collections.emptyMap());
@ApiStatus.Obsolete
public static final StaticComponentMap SHARED_ITEM_COMPONENTS = builder()
.set(ComponentTypes.MAX_STACK_SIZE, 64)
.set(ComponentTypes.LORE, ItemLore.EMPTY)
@@ -82,6 +86,24 @@ public class StaticComponentMap implements IComponentMap {
return this.empty;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof StaticComponentMap)) return false;
StaticComponentMap that = (StaticComponentMap) obj;
return this.delegate.equals(that.delegate);
}
@Override
public int hashCode() {
return Objects.hashCode(this.delegate);
}
@Override
public String toString() {
return "Components" + this.delegate;
}
public static class Builder {
private final Map<ComponentType<?>, Object> map = new HashMap<>();
@@ -93,6 +115,10 @@ public class StaticComponentMap implements IComponentMap {
return new StaticComponentMap(this.map);
}
public Builder setAll(StaticComponentMap.Builder map) {
return this.setAll(map.map);
}
public Builder setAll(StaticComponentMap map) {
return this.setAll(map.getDelegate());
}
@@ -0,0 +1,105 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
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.Nullable;
import java.util.function.Function;
public class StaticComponentType<T> extends AbstractMappedEntity implements ComponentType<T> {
private final @Nullable Reader<T> reader;
private final @Nullable Writer<T> writer;
private final @Nullable Decoder<T> decoder;
private final @Nullable Encoder<T> encoder;
public StaticComponentType(
@Nullable TypesBuilderData data,
@Nullable Reader<T> reader,
@Nullable Writer<T> writer
) {
this(data, reader, writer, null, null);
}
public StaticComponentType(
@Nullable TypesBuilderData data,
@Nullable Decoder<T> decoder,
@Nullable Encoder<T> encoder
) {
this(data, null, null, decoder, encoder);
}
public StaticComponentType(
@Nullable TypesBuilderData data,
@Nullable Reader<T> reader,
@Nullable Writer<T> writer,
@Nullable Decoder<T> decoder,
@Nullable Encoder<T> encoder
) {
super(data);
this.reader = reader;
this.writer = writer;
this.decoder = decoder;
this.encoder = encoder;
}
@Override
public T read(PacketWrapper<?> wrapper) {
return this.reader != null ? this.reader.apply(wrapper) : null;
}
@Override
public void write(PacketWrapper<?> wrapper, T content) {
if (this.writer != null) {
this.writer.accept(wrapper, content);
}
}
@Override
public T decode(NBT nbt, ClientVersion version) {
if (this.decoder != null) {
return this.decoder.decode(nbt, version);
}
throw new UnsupportedOperationException();
}
@Override
public NBT encode(T value, ClientVersion version) {
if (this.encoder != null) {
return this.encoder.encode(value, version);
}
throw new UnsupportedOperationException();
}
@Override
public <Z> ComponentType<Z> legacyMap(Function<T, Z> mapper, Function<Z, T> unmapper) {
Reader<Z> reader = this.reader != null ? wrapper -> mapper.apply(this.reader.apply(wrapper)) : null;
Writer<Z> writer = this.writer != null ? (wrapper, value) -> this.writer.accept(wrapper, unmapper.apply(value)) : null;
Decoder<Z> decoder = this.decoder != null ? (nbt, version) -> mapper.apply(this.decoder.decode(nbt, version)) : null;
Encoder<Z> encoder = this.encoder != null ? (value, version) -> this.encoder.encode(unmapper.apply(value), version) : null;
return new StaticComponentType<>(this.data, reader, writer, decoder, encoder);
}
}
@@ -80,7 +80,7 @@ public class BannerLayers {
public static Layer read(PacketWrapper<?> wrapper) {
BannerPattern pattern = wrapper.readMappedEntityOrDirect(
BannerPatterns::getById, BannerPattern::readDirect);
BannerPatterns.getRegistry(), BannerPattern::readDirect);
DyeColor color = wrapper.readEnum(DyeColor.values());
return new Layer(pattern, color);
}
@@ -22,8 +22,10 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.potion.PotionEffect;
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;
import java.util.Objects;
@@ -36,6 +38,17 @@ public class FoodProperties {
private List<PossibleEffect> effects;
private @Nullable ItemStack usingConvertsTo;
public FoodProperties(
int nutrition, float saturation, boolean canAlwaysEat
) {
this(nutrition, saturation, canAlwaysEat, 1.6f, Collections.emptyList());
}
/**
* <code>eatSeconds</code> and <code>effects</code>
* have been moved to {@link ItemConsumable} in 1.21.2
*/
@ApiStatus.Obsolete
public FoodProperties(
int nutrition, float saturation, boolean canAlwaysEat,
float eatSeconds, List<PossibleEffect> effects
@@ -43,6 +56,11 @@ public class FoodProperties {
this(nutrition, saturation, canAlwaysEat, eatSeconds, effects, null);
}
/**
* <code>eatSeconds</code>, <code>effects</code> and <code>usingConvertsTo</code>
* have been moved to {@link ItemConsumable} in 1.21.2
*/
@ApiStatus.Obsolete
public FoodProperties(
int nutrition, float saturation, boolean canAlwaysEat, float eatSeconds,
List<PossibleEffect> effects, @Nullable ItemStack usingConvertsTo
@@ -59,10 +77,13 @@ public class FoodProperties {
int nutrition = wrapper.readVarInt();
float saturation = wrapper.readFloat();
boolean canAlwaysEat = wrapper.readBoolean();
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2)) {
return new FoodProperties(nutrition, saturation, canAlwaysEat);
}
float eatSeconds = wrapper.readFloat();
List<PossibleEffect> effects = wrapper.readList(PossibleEffect::read);
ItemStack usingConvertsTo = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)
? wrapper.readOptional(PacketWrapper::readItemStack) : null;
List<PossibleEffect> effects = wrapper.readList(PossibleEffect::read);
return new FoodProperties(nutrition, saturation, canAlwaysEat, eatSeconds, effects, usingConvertsTo);
}
@@ -70,10 +91,12 @@ public class FoodProperties {
wrapper.writeVarInt(props.nutrition);
wrapper.writeFloat(props.saturation);
wrapper.writeBoolean(props.canAlwaysEat);
wrapper.writeFloat(props.eatSeconds);
wrapper.writeList(props.effects, PossibleEffect::write);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)) {
wrapper.writeOptional(props.usingConvertsTo, PacketWrapper::writeItemStack);
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_21_2)) {
wrapper.writeFloat(props.eatSeconds);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)) {
wrapper.writeOptional(props.usingConvertsTo, PacketWrapper::writeItemStack);
}
wrapper.writeList(props.effects, PossibleEffect::write);
}
}
@@ -101,30 +124,58 @@ public class FoodProperties {
this.canAlwaysEat = canAlwaysEat;
}
/**
* Has been moved to {@link ItemConsumable} in 1.21.2
*/
@ApiStatus.Obsolete
public float getEatSeconds() {
return this.eatSeconds;
}
/**
* Has been moved to {@link ItemConsumable} in 1.21.2
*/
@ApiStatus.Obsolete
public void setEatSeconds(float eatSeconds) {
this.eatSeconds = eatSeconds;
}
/**
* Has been moved to {@link ItemConsumable} in 1.21.2
*/
@ApiStatus.Obsolete
public void addEffect(PossibleEffect effect) {
this.effects.add(effect);
}
/**
* Has been moved to {@link ItemConsumable} in 1.21.2
*/
@ApiStatus.Obsolete
public List<PossibleEffect> getEffects() {
return this.effects;
}
/**
* Has been moved to {@link ItemConsumable} in 1.21.2
*/
@ApiStatus.Obsolete
public void setEffects(List<PossibleEffect> effects) {
this.effects = effects;
}
/**
* Has been moved to {@link ItemConsumable} in 1.21.2
*/
@ApiStatus.Obsolete
public @Nullable ItemStack getUsingConvertsTo() {
return this.usingConvertsTo;
}
/**
* Has been moved to {@link ItemConsumable} in 1.21.2
*/
@ApiStatus.Obsolete
public void setUsingConvertsTo(@Nullable ItemStack usingConvertsTo) {
this.usingConvertsTo = usingConvertsTo;
}
@@ -147,6 +198,10 @@ public class FoodProperties {
return Objects.hash(this.nutrition, this.saturation, this.canAlwaysEat, this.eatSeconds, this.effects, this.usingConvertsTo);
}
/**
* Has been moved to {@link ItemConsumable} in 1.21.2
*/
@ApiStatus.Obsolete
public static class PossibleEffect {
private PotionEffect effect;
@@ -104,8 +104,9 @@ public class ItemAdventurePredicate {
public static BlockPredicate read(PacketWrapper<?> wrapper) {
MappedEntitySet<StateType.Mapped> blocks = wrapper.readOptional(
ew -> MappedEntitySet.read(ew, StateTypes::getMappedById));
List<PropertyMatcher> properties = wrapper.readList(PropertyMatcher::read);
NBTCompound nbt = wrapper.readNBT();
List<PropertyMatcher> properties = wrapper.readOptional(
ew -> wrapper.readList(PropertyMatcher::read));
NBTCompound nbt = wrapper.readOptional(PacketWrapper::readNBT);
return new BlockPredicate(blocks, properties, nbt);
}
@@ -18,10 +18,15 @@
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.AttributeOperation;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes.PropertyModifier;
import net.kyori.adventure.util.Index;
import org.jetbrains.annotations.ApiStatus;
import java.util.Collections;
import java.util.List;
@@ -168,11 +173,16 @@ public class ItemAttributeModifiers {
public static class Modifier {
private UUID id;
private String name;
private UUID id; // removed in 1.21
private String name; // ResourceLocation since 1.21
private double value;
private AttributeOperation operation;
public Modifier(ResourceLocation name, double value, AttributeOperation operation) {
this(PropertyModifier.generateSemiUniqueId(name), name.toString(), value, operation);
}
@ApiStatus.Obsolete
public Modifier(UUID id, String name, double value, AttributeOperation operation) {
this.id = id;
this.name = name;
@@ -181,32 +191,56 @@ public class ItemAttributeModifiers {
}
public static Modifier read(PacketWrapper<?> wrapper) {
UUID id = wrapper.readUUID();
String name = wrapper.readString();
UUID id;
String name;
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)) {
ResourceLocation nameKey = wrapper.readIdentifier();
name = nameKey.toString();
id = PropertyModifier.generateSemiUniqueId(nameKey);
} else {
id = wrapper.readUUID();
name = wrapper.readString();
}
double value = wrapper.readDouble();
AttributeOperation operation = wrapper.readEnum(AttributeOperation.values());
return new Modifier(id, name, value, operation);
}
public static void write(PacketWrapper<?> wrapper, Modifier modifier) {
wrapper.writeUUID(modifier.id);
wrapper.writeString(modifier.name);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)) {
wrapper.writeIdentifier(new ResourceLocation(modifier.name));
} else {
wrapper.writeUUID(modifier.id);
wrapper.writeString(modifier.name);
}
wrapper.writeDouble(modifier.value);
wrapper.writeEnum(modifier.operation);
}
public ResourceLocation getNameKey() {
return new ResourceLocation(this.name);
}
public void setNameKey(ResourceLocation nameKey) {
this.name = nameKey.toString();
}
@ApiStatus.Obsolete
public UUID getId() {
return this.id;
}
@ApiStatus.Obsolete
public void setId(UUID id) {
this.id = id;
}
@ApiStatus.Obsolete
public String getName() {
return this.name;
}
@ApiStatus.Obsolete
public void setName(String name) {
this.name = name;
}
@@ -250,15 +284,29 @@ public class ItemAttributeModifiers {
}
public enum EquipmentSlotGroup {
ANY,
MAINHAND,
OFFHAND,
HAND,
FEET,
LEGS,
CHEST,
HEAD,
ARMOR,
BODY,
ANY("any"),
MAINHAND("mainhand"),
OFFHAND("offhand"),
HAND("hand"),
FEET("feet"),
LEGS("legs"),
CHEST("chest"),
HEAD("head"),
ARMOR("armor"),
BODY("body");
public static final Index<String, EquipmentSlotGroup> ID_INDEX = Index.create(
EquipmentSlotGroup.class, EquipmentSlotGroup::getId);
private final String id;
EquipmentSlotGroup(String id) {
this.id = id;
}
public String getId() {
return this.id;
}
}
}
@@ -0,0 +1,144 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables.ConsumeEffect;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.List;
import java.util.Objects;
public class ItemConsumable {
private float consumeSeconds;
private Animation animation;
private Sound sound;
private boolean consumeParticles;
private List<ConsumeEffect<?>> effects;
public ItemConsumable(
float consumeSeconds, Animation animation, Sound sound,
boolean consumeParticles, List<ConsumeEffect<?>> effects
) {
this.consumeSeconds = consumeSeconds;
this.animation = animation;
this.sound = sound;
this.consumeParticles = consumeParticles;
this.effects = effects;
}
public static ItemConsumable read(PacketWrapper<?> wrapper) {
float consumeSeconds = wrapper.readFloat();
Animation animation = wrapper.readEnum(Animation.values());
Sound sound = Sound.read(wrapper);
boolean consumeParticles = wrapper.readBoolean();
List<ConsumeEffect<?>> effects = wrapper.readList(ConsumeEffect::readFull);
return new ItemConsumable(consumeSeconds, animation, sound, consumeParticles, effects);
}
public static void write(PacketWrapper<?> wrapper, ItemConsumable consumable) {
wrapper.writeFloat(consumable.consumeSeconds);
wrapper.writeEnum(consumable.animation);
Sound.write(wrapper, consumable.sound);
wrapper.writeBoolean(consumable.consumeParticles);
wrapper.writeList(consumable.effects, ConsumeEffect::writeFull);
}
public float getConsumeSeconds() {
return this.consumeSeconds;
}
public void setConsumeSeconds(float consumeSeconds) {
this.consumeSeconds = consumeSeconds;
}
public Animation getAnimation() {
return this.animation;
}
public void setAnimation(Animation animation) {
this.animation = animation;
}
public Sound getSound() {
return this.sound;
}
public void setSound(Sound sound) {
this.sound = sound;
}
public boolean isConsumeParticles() {
return this.consumeParticles;
}
public void setConsumeParticles(boolean consumeParticles) {
this.consumeParticles = consumeParticles;
}
public List<ConsumeEffect<?>> getEffects() {
return this.effects;
}
public void setEffects(List<ConsumeEffect<?>> effects) {
this.effects = effects;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemConsumable)) return false;
ItemConsumable that = (ItemConsumable) obj;
if (Float.compare(that.consumeSeconds, this.consumeSeconds) != 0) return false;
if (this.consumeParticles != that.consumeParticles) return false;
if (this.animation != that.animation) return false;
if (!this.sound.equals(that.sound)) return false;
return this.effects.equals(that.effects);
}
@Override
public int hashCode() {
return Objects.hash(this.consumeSeconds, this.animation, this.sound, this.consumeParticles, this.effects);
}
@Override
public String toString() {
return "ItemConsumable{consumeSeconds=" + this.consumeSeconds + ", animation=" + this.animation + ", sound=" + this.sound + ", consumeParticles=" + this.consumeParticles + ", effects=" + this.effects + '}';
}
public enum Animation {
NONE,
EAT,
DRINK,
BLOCK,
BOW,
SPEAR,
CROSSBOW,
SPYGLASS,
TOOT_HORN,
BRUSH,
/**
* Added with 1.21.4
*/
BUNDLE,
;
}
}
@@ -0,0 +1,134 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.color.Color;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import java.util.ArrayList;
import java.util.List;
/**
* Custom model data was completely rewritten with 1.21.4.
* <p>
* Before 1.21.4, this used to be a single integer.<br/>
* With 1.21.4, this is now a holder of many elements.
* <p>
* If possible, use {@link com.github.retrooper.packetevents.protocol.component.ComponentTypes#ITEM_MODEL}
* instead for specifying which model an item should have.
* <p>
* When working with legacy versions, the first element in the {@link #floats}
* will represent the legacy single integer, just like Mojang is handling this.
*/
public class ItemCustomModelData {
private List<Float> floats;
private List<Boolean> flags;
private List<String> strings;
private List<Color> colors;
public ItemCustomModelData(List<Float> floats, List<Boolean> flags, List<String> strings, List<Color> colors) {
this.floats = floats;
this.flags = flags;
this.strings = strings;
this.colors = colors;
}
public ItemCustomModelData(int legacyId) {
this.floats = new ArrayList<>(1);
this.flags = new ArrayList<>(0);
this.strings = new ArrayList<>(0);
this.colors = new ArrayList<>(0);
this.setLegacyId(legacyId);
}
public static ItemCustomModelData read(PacketWrapper<?> wrapper) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_4)) {
return new ItemCustomModelData(
wrapper.readList(PacketWrapper::readFloat),
wrapper.readList(PacketWrapper::readBoolean),
wrapper.readList(PacketWrapper::readString),
wrapper.readList(Color::read));
} else {
return new ItemCustomModelData(wrapper.readVarInt());
}
}
public static void write(PacketWrapper<?> wrapper, ItemCustomModelData data) {
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_4)) {
wrapper.writeList(data.floats, PacketWrapper::writeFloat);
wrapper.writeList(data.flags, PacketWrapper::writeBoolean);
wrapper.writeList(data.strings, PacketWrapper::writeString);
wrapper.writeList(data.colors, Color::write);
} else {
wrapper.writeVarInt(data.getLegacyId());
}
}
public List<Float> getFloats() {
return this.floats;
}
public void setFloats(List<Float> floats) {
this.floats = floats;
}
public List<Boolean> getFlags() {
return this.flags;
}
public void setFlags(List<Boolean> flags) {
this.flags = flags;
}
public List<String> getStrings() {
return this.strings;
}
public void setStrings(List<String> strings) {
this.strings = strings;
}
public List<Color> getColors() {
return this.colors;
}
public void setColors(List<Color> colors) {
this.colors = colors;
}
@ApiStatus.Obsolete
public int getLegacyId() {
if (!this.floats.isEmpty()) {
return this.floats.get(0).intValue();
}
return 0;
}
@ApiStatus.Obsolete
public void setLegacyId(int legacyId) {
if (this.flags.isEmpty()) {
this.floats.add((float) legacyId);
} else {
this.floats.set(0, (float) legacyId);
}
}
}
@@ -0,0 +1,67 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
public class ItemDamageResistant {
private ResourceLocation typesTagKey;
public ItemDamageResistant(ResourceLocation typesTagKey) {
this.typesTagKey = typesTagKey;
}
public static ItemDamageResistant read(PacketWrapper<?> wrapper) {
return new ItemDamageResistant(wrapper.readIdentifier());
}
public static void write(PacketWrapper<?> wrapper, ItemDamageResistant resistant) {
wrapper.writeIdentifier(resistant.typesTagKey);
}
public ResourceLocation getTypesTagKey() {
return this.typesTagKey;
}
public void setTypesTagKey(ResourceLocation typesTagKey) {
this.typesTagKey = typesTagKey;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemDamageResistant)) return false;
ItemDamageResistant that = (ItemDamageResistant) obj;
return this.typesTagKey.equals(that.typesTagKey);
}
@Override
public int hashCode() {
return Objects.hashCode(this.typesTagKey);
}
@Override
public String toString() {
return "ItemDamageResistant{typesTagKey=" + this.typesTagKey + '}';
}
}
@@ -0,0 +1,69 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables.ConsumeEffect;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.List;
import java.util.Objects;
public class ItemDeathProtection {
private List<ConsumeEffect<?>> deathEffects;
public ItemDeathProtection(List<ConsumeEffect<?>> deathEffects) {
this.deathEffects = deathEffects;
}
public static ItemDeathProtection read(PacketWrapper<?> wrapper) {
List<ConsumeEffect<?>> deathEffects = wrapper.readList(ConsumeEffect::readFull);
return new ItemDeathProtection(deathEffects);
}
public static void write(PacketWrapper<?> wrapper, ItemDeathProtection deathProtection) {
wrapper.writeList(deathProtection.deathEffects, ConsumeEffect::writeFull);
}
public List<ConsumeEffect<?>> getDeathEffects() {
return this.deathEffects;
}
public void setDeathEffects(List<ConsumeEffect<?>> deathEffects) {
this.deathEffects = deathEffects;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemDeathProtection)) return false;
ItemDeathProtection that = (ItemDeathProtection) obj;
return this.deathEffects.equals(that.deathEffects);
}
@Override
public int hashCode() {
return Objects.hashCode(this.deathEffects);
}
@Override
public String toString() {
return "ItemDeathProtection{deathEffects=" + this.deathEffects + '}';
}
}
@@ -0,0 +1,67 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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 java.util.Objects;
public class ItemEnchantable {
private int value;
public ItemEnchantable(int value) {
this.value = value;
}
public static ItemEnchantable read(PacketWrapper<?> wrapper) {
int value = wrapper.readVarInt();
return new ItemEnchantable(value);
}
public static void write(PacketWrapper<?> wrapper, ItemEnchantable enchantable) {
wrapper.writeVarInt(enchantable.value);
}
public int getValue() {
return this.value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemEnchantable)) return false;
ItemEnchantable that = (ItemEnchantable) obj;
return this.value == that.value;
}
@Override
public int hashCode() {
return Objects.hashCode(this.value);
}
@Override
public String toString() {
return "ItemEnchantable{value=" + this.value + '}';
}
}
@@ -47,9 +47,8 @@ public class ItemEnchantments implements Iterable<Map.Entry<EnchantmentType, Int
}
public static ItemEnchantments read(PacketWrapper<?> wrapper) {
ClientVersion version = wrapper.getServerVersion().toClientVersion();
Map<EnchantmentType, Integer> enchantments = wrapper.readMap(
ew -> EnchantmentTypes.getById(version, ew.readVarInt()),
ew -> wrapper.readMappedEntity(EnchantmentTypes.getRegistry()),
PacketWrapper::readVarInt
);
boolean showInTooltip = wrapper.readBoolean();
@@ -0,0 +1,186 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.protocol.player.EquipmentSlot;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class ItemEquippable {
private EquipmentSlot slot;
private Sound equipSound;
private @Nullable ResourceLocation assetId;
private @Nullable ResourceLocation cameraOverlay;
private @Nullable MappedEntitySet<EntityType> allowedEntities;
private boolean dispensable;
private boolean swappable;
private boolean damageOnHurt;
public ItemEquippable(
EquipmentSlot slot,
Sound equipSound,
@Nullable ResourceLocation assetId,
@Nullable ResourceLocation cameraOverlay,
@Nullable MappedEntitySet<EntityType> allowedEntities,
boolean dispensable,
boolean swappable,
boolean damageOnHurt
) {
this.slot = slot;
this.equipSound = equipSound;
this.assetId = assetId;
this.cameraOverlay = cameraOverlay;
this.allowedEntities = allowedEntities;
this.dispensable = dispensable;
this.swappable = swappable;
this.damageOnHurt = damageOnHurt;
}
public static ItemEquippable read(PacketWrapper<?> wrapper) {
EquipmentSlot slot = wrapper.readEnum(EquipmentSlot.values());
Sound equipSound = Sound.read(wrapper);
ResourceLocation model = wrapper.readOptional(PacketWrapper::readIdentifier);
ResourceLocation cameraOverlay = wrapper.readOptional(PacketWrapper::readIdentifier);
MappedEntitySet<EntityType> allowedEntities = wrapper.readOptional(
ew -> MappedEntitySet.read(ew, EntityTypes::getById));
boolean dispensable = wrapper.readBoolean();
boolean swappable = wrapper.readBoolean();
boolean damageOnHurt = wrapper.readBoolean();
return new ItemEquippable(slot, equipSound, model,
cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt);
}
public static void write(PacketWrapper<?> wrapper, ItemEquippable equippable) {
wrapper.writeEnum(equippable.slot);
Sound.write(wrapper, equippable.equipSound);
wrapper.writeOptional(equippable.assetId, PacketWrapper::writeIdentifier);
wrapper.writeOptional(equippable.cameraOverlay, PacketWrapper::writeIdentifier);
wrapper.writeOptional(equippable.allowedEntities, MappedEntitySet::write);
wrapper.writeBoolean(equippable.dispensable);
wrapper.writeBoolean(equippable.swappable);
wrapper.writeBoolean(equippable.damageOnHurt);
}
public EquipmentSlot getSlot() {
return this.slot;
}
public void setSlot(EquipmentSlot slot) {
this.slot = slot;
}
public Sound getEquipSound() {
return this.equipSound;
}
public void setEquipSound(Sound equipSound) {
this.equipSound = equipSound;
}
public @Nullable ResourceLocation getAssetId() {
return this.assetId;
}
public void setAssetId(@Nullable ResourceLocation assetId) {
this.assetId = assetId;
}
public @Nullable ResourceLocation getCameraOverlay() {
return this.cameraOverlay;
}
public void setCameraOverlay(@Nullable ResourceLocation cameraOverlay) {
this.cameraOverlay = cameraOverlay;
}
public @Nullable MappedEntitySet<EntityType> getAllowedEntities() {
return this.allowedEntities;
}
public void setAllowedEntities(@Nullable MappedEntitySet<EntityType> allowedEntities) {
this.allowedEntities = allowedEntities;
}
public boolean isDispensable() {
return this.dispensable;
}
public void setDispensable(boolean dispensable) {
this.dispensable = dispensable;
}
public boolean isSwappable() {
return this.swappable;
}
public void setSwappable(boolean swappable) {
this.swappable = swappable;
}
public boolean isDamageOnHurt() {
return this.damageOnHurt;
}
public void setDamageOnHurt(boolean damageOnHurt) {
this.damageOnHurt = damageOnHurt;
}
@Deprecated
public @Nullable ResourceLocation getModel() {
return this.assetId;
}
@Deprecated
public void setModel(@Nullable ResourceLocation assetId) {
this.assetId = assetId;
}
@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.slot != that.slot) return false;
if (!Objects.equals(this.equipSound, that.equipSound)) return false;
if (!Objects.equals(this.assetId, that.assetId)) return false;
if (!Objects.equals(this.cameraOverlay, that.cameraOverlay)) return false;
return Objects.equals(this.allowedEntities, that.allowedEntities);
}
@Override
public int hashCode() {
return Objects.hash(this.slot, this.equipSound, this.assetId, this.cameraOverlay, this.allowedEntities, this.dispensable, this.swappable, this.damageOnHurt);
}
@Override
public String toString() {
return "ItemEquippable{slot=" + this.slot + ", equipSound=" + this.equipSound + ", model=" + this.assetId + ", cameraOverlay=" + this.cameraOverlay + ", allowedEntities=" + this.allowedEntities + ", dispensable=" + this.dispensable + ", swappable=" + this.swappable + ", damageOnHurt=" + this.damageOnHurt + '}';
}
}
@@ -18,6 +18,7 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.item.jukebox.IJukeboxSong;
import com.github.retrooper.packetevents.protocol.item.jukebox.JukeboxSong;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
@@ -27,7 +28,7 @@ import java.util.Objects;
public class ItemJukeboxPlayable {
private @Nullable JukeboxSong song;
private @Nullable IJukeboxSong song;
private @Nullable ResourceLocation songKey;
private boolean showInTooltip;
@@ -35,6 +36,14 @@ public class ItemJukeboxPlayable {
@Nullable JukeboxSong song,
@Nullable ResourceLocation songKey,
boolean showInTooltip
) {
this((IJukeboxSong) song, songKey, showInTooltip);
}
public ItemJukeboxPlayable(
@Nullable IJukeboxSong song,
@Nullable ResourceLocation songKey,
boolean showInTooltip
) {
if ((song == null) == (songKey == null)) {
throw new IllegalStateException("Illegal state of both song and "
@@ -47,10 +56,10 @@ public class ItemJukeboxPlayable {
}
public static ItemJukeboxPlayable read(PacketWrapper<?> wrapper) {
JukeboxSong song;
IJukeboxSong song;
ResourceLocation songKey;
if (wrapper.readBoolean()) {
song = JukeboxSong.read(wrapper);
song = IJukeboxSong.read(wrapper);
songKey = null;
} else {
song = null;
@@ -63,7 +72,7 @@ public class ItemJukeboxPlayable {
public static void write(PacketWrapper<?> wrapper, ItemJukeboxPlayable jukeboxPlayable) {
if (jukeboxPlayable.song != null) {
wrapper.writeBoolean(true);
JukeboxSong.write(wrapper, jukeboxPlayable.song);
IJukeboxSong.write(wrapper, jukeboxPlayable.song);
} else {
assert jukeboxPlayable.songKey != null;
wrapper.writeBoolean(false);
@@ -72,10 +81,26 @@ public class ItemJukeboxPlayable {
wrapper.writeBoolean(jukeboxPlayable.showInTooltip);
}
public @Nullable JukeboxSong getSong() {
public @Nullable IJukeboxSong getJukeboxSong() {
return this.song;
}
public void setJukeboxSong(@Nullable JukeboxSong song) {
this.song = song;
this.songKey = null;
}
@Deprecated
public @Nullable JukeboxSong getSong() {
if (this.song == null) {
return null;
} else if (this.song instanceof JukeboxSong) {
return (JukeboxSong) this.song;
}
return (JukeboxSong) this.song.copy(null);
}
@Deprecated
public void setSong(JukeboxSong song) {
this.song = song;
this.songKey = null;
@@ -0,0 +1,67 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
public class ItemModel {
private ResourceLocation modelLocation;
public ItemModel(ResourceLocation modelLocation) {
this.modelLocation = modelLocation;
}
public static ItemModel read(PacketWrapper<?> wrapper) {
return new ItemModel(wrapper.readIdentifier());
}
public static void write(PacketWrapper<?> wrapper, ItemModel model) {
wrapper.writeIdentifier(model.modelLocation);
}
public ResourceLocation getModelLocation() {
return this.modelLocation;
}
public void setModelLocation(ResourceLocation modelLocation) {
this.modelLocation = modelLocation;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemModel)) return false;
ItemModel itemModel = (ItemModel) obj;
return this.modelLocation.equals(itemModel.modelLocation);
}
@Override
public int hashCode() {
return Objects.hashCode(this.modelLocation);
}
@Override
public String toString() {
return "ItemModel{modelLocation=" + this.modelLocation + '}';
}
}
@@ -18,6 +18,7 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.potion.Potion;
import com.github.retrooper.packetevents.protocol.potion.PotionEffect;
import com.github.retrooper.packetevents.protocol.potion.Potions;
@@ -32,28 +33,44 @@ public class ItemPotionContents {
private @Nullable Potion potion;
private @Nullable Integer customColor;
private List<PotionEffect> customEffects;
private @Nullable String customName;
public ItemPotionContents(
@Nullable Potion potion,
@Nullable Integer customColor,
List<PotionEffect> customEffects
) {
this(potion, customColor, customEffects, null);
}
public ItemPotionContents(
@Nullable Potion potion,
@Nullable Integer customColor,
List<PotionEffect> customEffects,
@Nullable String customName
) {
this.potion = potion;
this.customColor = customColor;
this.customEffects = customEffects;
this.customName = customName;
}
public static ItemPotionContents read(PacketWrapper<?> wrapper) {
Potion potionId = wrapper.readOptional(ew -> ew.readMappedEntity(Potions::getById));
Integer customColor = wrapper.readOptional(PacketWrapper::readInt);
List<PotionEffect> customEffects = wrapper.readList(PotionEffect::read);
return new ItemPotionContents(potionId, customColor, customEffects);
String customName = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2)
? wrapper.readOptional(PacketWrapper::readString) : null;
return new ItemPotionContents(potionId, customColor, customEffects, customName);
}
public static void write(PacketWrapper<?> wrapper, ItemPotionContents contents) {
wrapper.writeOptional(contents.potion, PacketWrapper::writeMappedEntity);
wrapper.writeOptional(contents.customColor, PacketWrapper::writeInt);
wrapper.writeList(contents.customEffects, PotionEffect::write);
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2)) {
wrapper.writeOptional(contents.customName, PacketWrapper::writeString);
}
}
public @Nullable Potion getPotion() {
@@ -84,6 +101,14 @@ public class ItemPotionContents {
this.customEffects = customEffects;
}
public @Nullable String getCustomName() {
return this.customName;
}
public void setCustomName(@Nullable String customName) {
this.customName = customName;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
@@ -91,11 +116,12 @@ public class ItemPotionContents {
ItemPotionContents that = (ItemPotionContents) obj;
if (!Objects.equals(this.potion, that.potion)) return false;
if (!Objects.equals(this.customColor, that.customColor)) return false;
return this.customEffects.equals(that.customEffects);
if (!this.customEffects.equals(that.customEffects)) return false;
return Objects.equals(this.customName, that.customName);
}
@Override
public int hashCode() {
return Objects.hash(this.potion, this.customColor, this.customEffects);
return Objects.hash(this.potion, this.customColor, this.customEffects, this.customName);
}
}
@@ -18,9 +18,12 @@
package com.github.retrooper.packetevents.protocol.component.builtin.item;
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -33,12 +36,21 @@ public class ItemRecipes {
}
public static ItemRecipes read(PacketWrapper<?> wrapper) {
List<ResourceLocation> recipes = wrapper.readList(PacketWrapper::readIdentifier);
return new ItemRecipes(recipes);
NBTList<?> recipes = (NBTList<?>) wrapper.readNBTRaw();
List<ResourceLocation> recipeKeys = new ArrayList<>(recipes.size());
for (int i = 0; i < recipes.size(); i++) {
NBTString tag = (NBTString) recipes.getTag(i);
recipeKeys.add(new ResourceLocation(tag.getValue()));
}
return new ItemRecipes(recipeKeys);
}
public static void write(PacketWrapper<?> wrapper, ItemRecipes recipes) {
wrapper.writeList(recipes.recipes, PacketWrapper::writeIdentifier);
NBTList<NBTString> recipesTag = NBTList.createStringList();
for (ResourceLocation recipeKey : recipes.recipes) {
recipesTag.addTag(new NBTString(recipeKey.toString()));
}
wrapper.writeNBTRaw(recipesTag);
}
public void addRecipe(ResourceLocation recipeKey) {
@@ -0,0 +1,70 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
public class ItemRepairable {
private MappedEntitySet<ItemType> items;
public ItemRepairable(MappedEntitySet<ItemType> items) {
this.items = items;
}
public static ItemRepairable read(PacketWrapper<?> wrapper) {
MappedEntitySet<ItemType> items = MappedEntitySet.read(wrapper, ItemTypes.getRegistry());
return new ItemRepairable(items);
}
public static void write(PacketWrapper<?> wrapper, ItemRepairable repairable) {
MappedEntitySet.write(wrapper, repairable.items);
}
public MappedEntitySet<ItemType> getItems() {
return this.items;
}
public void setItems(MappedEntitySet<ItemType> items) {
this.items = items;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemRepairable)) return false;
ItemRepairable that = (ItemRepairable) obj;
return this.items.equals(that.items);
}
@Override
public int hashCode() {
return Objects.hashCode(this.items);
}
@Override
public String toString() {
return "ItemRepairable{items=" + this.items + '}';
}
}
@@ -0,0 +1,67 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
public class ItemTooltipStyle {
private ResourceLocation tooltipLoc;
public ItemTooltipStyle(ResourceLocation tooltipLoc) {
this.tooltipLoc = tooltipLoc;
}
public static ItemTooltipStyle read(PacketWrapper<?> wrapper) {
return new ItemTooltipStyle(wrapper.readIdentifier());
}
public static void write(PacketWrapper<?> wrapper, ItemTooltipStyle style) {
wrapper.writeIdentifier(style.tooltipLoc);
}
public ResourceLocation getTooltipLoc() {
return this.tooltipLoc;
}
public void setTooltipLoc(ResourceLocation tooltipLoc) {
this.tooltipLoc = tooltipLoc;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemTooltipStyle)) return false;
ItemTooltipStyle that = (ItemTooltipStyle) obj;
return this.tooltipLoc.equals(that.tooltipLoc);
}
@Override
public int hashCode() {
return Objects.hashCode(this.tooltipLoc);
}
@Override
public String toString() {
return "ItemTooltipStyle{tooltipLoc=" + this.tooltipLoc + '}';
}
}
@@ -0,0 +1,101 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetCooldown;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.Optional;
public class ItemUseCooldown {
private float seconds;
private Optional<ResourceLocation> cooldownGroup;
public ItemUseCooldown(float seconds, @Nullable ResourceLocation cooldownGroup) {
this(seconds, Optional.ofNullable(cooldownGroup));
}
public ItemUseCooldown(float seconds, Optional<ResourceLocation> cooldownGroup) {
this.seconds = seconds;
this.cooldownGroup = cooldownGroup;
}
public static ItemUseCooldown read(PacketWrapper<?> wrapper) {
float seconds = wrapper.readFloat();
ResourceLocation cooldownGroup = wrapper.readOptional(PacketWrapper::readIdentifier);
return new ItemUseCooldown(seconds, cooldownGroup);
}
public static void write(PacketWrapper<?> wrapper, ItemUseCooldown cooldown) {
wrapper.writeFloat(cooldown.seconds);
wrapper.writeOptional(cooldown.cooldownGroup.orElse(null), PacketWrapper::writeIdentifier);
}
public WrapperPlayServerSetCooldown buildWrapper(ItemStack fallbackStack) {
return this.buildWrapper(fallbackStack.getType());
}
public WrapperPlayServerSetCooldown buildWrapper(ItemType fallbackItem) {
int ticks = (int) (this.seconds * 20f);
return this.cooldownGroup
.map(resourceLocation -> new WrapperPlayServerSetCooldown(resourceLocation, ticks))
.orElseGet(() -> new WrapperPlayServerSetCooldown(fallbackItem, ticks));
}
public float getSeconds() {
return this.seconds;
}
public void setSeconds(float seconds) {
this.seconds = seconds;
}
public Optional<ResourceLocation> getCooldownGroup() {
return this.cooldownGroup;
}
public void setCooldownGroup(Optional<ResourceLocation> cooldownGroup) {
this.cooldownGroup = cooldownGroup;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemUseCooldown)) return false;
ItemUseCooldown that = (ItemUseCooldown) obj;
if (Float.compare(that.seconds, this.seconds) != 0) return false;
return this.cooldownGroup.equals(that.cooldownGroup);
}
@Override
public int hashCode() {
return Objects.hash(this.seconds, this.cooldownGroup);
}
@Override
public String toString() {
return "ItemUseCooldown{seconds=" + this.seconds + ", cooldownGroup=" + this.cooldownGroup + '}';
}
}
@@ -0,0 +1,68 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.ItemStack;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.Objects;
public class ItemUseRemainder {
private ItemStack target;
public ItemUseRemainder(ItemStack target) {
this.target = target;
}
public static ItemUseRemainder read(PacketWrapper<?> wrapper) {
ItemStack target = wrapper.readItemStack();
return new ItemUseRemainder(target);
}
public static void write(PacketWrapper<?> wrapper, ItemUseRemainder remainder) {
wrapper.writeItemStack(remainder.target);
}
public ItemStack getTarget() {
return this.target;
}
public void setTarget(ItemStack target) {
this.target = target;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ItemUseRemainder)) return false;
ItemUseRemainder that = (ItemUseRemainder) obj;
return this.target.equals(that.target);
}
@Override
public int hashCode() {
return Objects.hashCode(this.target);
}
@Override
public String toString() {
return "ItemUseRemainder{target=" + this.target + '}';
}
}
@@ -0,0 +1,109 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.entity;
// Created by booky10 in packetevents (02:12 21.10.2024)
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityPositionSync;
import java.util.Objects;
public final class EntityPositionData {
private Vector3d position;
private Vector3d deltaMovement;
private float yaw;
private float pitch;
public EntityPositionData(Vector3d position, Vector3d deltaMovement, float yaw, float pitch) {
this.position = position;
this.deltaMovement = deltaMovement;
this.yaw = yaw;
this.pitch = pitch;
}
public static EntityPositionData read(PacketWrapper<?> wrapper) {
Vector3d position = Vector3d.read(wrapper);
Vector3d deltaMovement = Vector3d.read(wrapper);
float yaw = wrapper.readFloat();
float pitch = wrapper.readFloat();
return new EntityPositionData(position, deltaMovement, yaw, pitch);
}
public static void write(PacketWrapper<?> wrapper, EntityPositionData positionData) {
Vector3d.write(wrapper, positionData.position);
Vector3d.write(wrapper, positionData.deltaMovement);
wrapper.writeFloat(positionData.yaw);
wrapper.writeFloat(positionData.pitch);
}
public Vector3d getPosition() {
return this.position;
}
public void setPosition(Vector3d position) {
this.position = position;
}
public Vector3d getDeltaMovement() {
return this.deltaMovement;
}
public void setDeltaMovement(Vector3d deltaMovement) {
this.deltaMovement = deltaMovement;
}
public float getYaw() {
return this.yaw;
}
public void setYaw(float yaw) {
this.yaw = yaw;
}
public float getPitch() {
return this.pitch;
}
public void setPitch(float pitch) {
this.pitch = pitch;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof EntityPositionData)) return false;
EntityPositionData that = (EntityPositionData) obj;
if (Float.compare(that.yaw, this.yaw) != 0) return false;
if (Float.compare(that.pitch, this.pitch) != 0) return false;
if (!this.position.equals(that.position)) return false;
return this.deltaMovement.equals(that.deltaMovement);
}
@Override
public int hashCode() {
return Objects.hash(this.position, this.deltaMovement, this.yaw, this.pitch);
}
@Override
public String toString() {
return "EntityPositionData{position=" + this.position + ", deltaMovement=" + this.deltaMovement + ", yaw=" + this.yaw + ", pitch=" + this.pitch + '}';
}
}
@@ -22,9 +22,14 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class EntityTypes {
private static final Map<String, EntityType> ENTITY_TYPE_MAP = new HashMap<>();
@@ -151,7 +156,13 @@ public class EntityTypes {
public static final EntityType BAT = define("bat", ABSTRACT_AMBIENT);
public static final EntityType BEE = define("bee", ABSTRACT_INSENTIENT);
public static final EntityType BLAZE = define("blaze", ABSTRACT_MONSTER);
/**
* <strong>WARNING:</strong> Does not exist itself anymore since 1.21.2
*/
public static final EntityType BOAT = define("boat", ENTITY);
/**
* <strong>WARNING:</strong> Does not exist itself anymore since 1.21.2
*/
public static final EntityType CHEST_BOAT = define("chest_boat", BOAT);
public static final EntityType CAT = define("cat", ABSTRACT_TAMEABLE_ANIMAL);
public static final EntityType CAMEL = define("camel", ABSTRACT_HORSE);
@@ -295,8 +306,37 @@ public class EntityTypes {
public static final EntityType BREEZE_WIND_CHARGE = define("breeze_wind_charge", ABSTRACT_WIND_CHARGE);
public static final EntityType OMINOUS_ITEM_SPAWNER = define("ominous_item_spawner", ENTITY);
// added with 1.21.2
public static final EntityType ACACIA_BOAT = define("acacia_boat", BOAT);
public static final EntityType ACACIA_CHEST_BOAT = define("acacia_chest_boat", CHEST_BOAT);
public static final EntityType BAMBOO_CHEST_RAFT = define("bamboo_chest_raft", CHEST_BOAT);
public static final EntityType BAMBOO_RAFT = define("bamboo_raft", BOAT);
public static final EntityType BIRCH_BOAT = define("birch_boat", BOAT);
public static final EntityType BIRCH_CHEST_BOAT = define("birch_chest_boat", CHEST_BOAT);
public static final EntityType CHERRY_BOAT = define("cherry_boat", BOAT);
public static final EntityType CHERRY_CHEST_BOAT = define("cherry_chest_boat", CHEST_BOAT);
public static final EntityType CREAKING = define("creaking", ABSTRACT_MONSTER);
/**
* Removed with 1.21.4
*/
@ApiStatus.Obsolete
public static final EntityType CREAKING_TRANSIENT = define("creaking_transient", CREAKING);
public static final EntityType DARK_OAK_BOAT = define("dark_oak_boat", BOAT);
public static final EntityType DARK_OAK_CHEST_BOAT = define("dark_oak_chest_boat", CHEST_BOAT);
public static final EntityType JUNGLE_BOAT = define("jungle_boat", BOAT);
public static final EntityType JUNGLE_CHEST_BOAT = define("jungle_chest_boat", CHEST_BOAT);
public static final EntityType MANGROVE_BOAT = define("mangrove_boat", BOAT);
public static final EntityType MANGROVE_CHEST_BOAT = define("mangrove_chest_boat", CHEST_BOAT);
public static final EntityType OAK_BOAT = define("oak_boat", BOAT);
public static final EntityType OAK_CHEST_BOAT = define("oak_chest_boat", CHEST_BOAT);
public static final EntityType PALE_OAK_BOAT = define("pale_oak_boat", BOAT);
public static final EntityType PALE_OAK_CHEST_BOAT = define("pale_oak_chest_boat", CHEST_BOAT);
public static final EntityType SPRUCE_BOAT = define("spruce_boat", BOAT);
public static final EntityType SPRUCE_CHEST_BOAT = define("spruce_chest_boat", CHEST_BOAT);
/**
* Returns an immutable view of the entity types.
*
* @return Entity Types
*/
public static Collection<EntityType> values() {
@@ -0,0 +1,106 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.entity.wolfvariant;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.protocol.world.biome.Biome;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class StaticWolfVariant extends AbstractMappedEntity implements WolfVariant {
private final ResourceLocation wildTexture;
private final ResourceLocation tameTexture;
private final ResourceLocation angryTexture;
private final MappedEntitySet<Biome> biomes;
public StaticWolfVariant(
ResourceLocation wildTexture,
ResourceLocation tameTexture,
ResourceLocation angryTexture,
MappedEntitySet<Biome> biomes
) {
this(null, wildTexture, tameTexture, angryTexture, biomes);
}
public StaticWolfVariant(
@Nullable TypesBuilderData data,
ResourceLocation wildTexture,
ResourceLocation tameTexture,
ResourceLocation angryTexture,
MappedEntitySet<Biome> biomes
) {
super(data);
this.wildTexture = wildTexture;
this.tameTexture = tameTexture;
this.angryTexture = angryTexture;
this.biomes = biomes;
}
@Override
public WolfVariant copy(@Nullable TypesBuilderData newData) {
return new StaticWolfVariant(newData, this.wildTexture, this.tameTexture, this.angryTexture, this.biomes);
}
@Override
public ResourceLocation getWildTexture() {
return this.wildTexture;
}
@Override
public ResourceLocation getTameTexture() {
return this.tameTexture;
}
@Override
public ResourceLocation getAngryTexture() {
return this.angryTexture;
}
@Override
public MappedEntitySet<Biome> getBiomes() {
return this.biomes;
}
@Override
public boolean deepEquals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof StaticWolfVariant)) return false;
if (!super.equals(obj)) return false;
StaticWolfVariant that = (StaticWolfVariant) obj;
if (!this.wildTexture.equals(that.wildTexture)) return false;
if (!this.tameTexture.equals(that.tameTexture)) return false;
if (!this.angryTexture.equals(that.angryTexture)) return false;
return this.biomes.equals(that.biomes);
}
@Override
public int deepHashCode() {
return Objects.hash(super.hashCode(), this.wildTexture, this.tameTexture, this.angryTexture, this.biomes);
}
@Override
public String toString() {
return "StaticWolfVariant{wildTexture=" + this.wildTexture + ", tameTexture=" + this.tameTexture + ", angryTexture=" + this.angryTexture + ", biomes=" + this.biomes + '}';
}
}
@@ -1,14 +1,63 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.entity.wolfvariant;
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
import com.github.retrooper.packetevents.protocol.mapper.DeepComparableEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
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.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.biome.Biome;
import com.github.retrooper.packetevents.protocol.world.biome.Biomes;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
public interface WolfVariant extends MappedEntity, CopyableEntity<WolfVariant>, DeepComparableEntity {
//TODO Finish Wolf-Variant class
public class WolfVariant {
private ResourceLocation wildId, tameId, angryId;
ResourceLocation getWildTexture();
public WolfVariant(ResourceLocation wildId, ResourceLocation tameId, ResourceLocation angryId) {
ResourceLocation getTameTexture();
ResourceLocation getAngryTexture();
MappedEntitySet<Biome> getBiomes();
static WolfVariant decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
NBTCompound compound = (NBTCompound) nbt;
ResourceLocation wildTexture = new ResourceLocation(compound.getStringTagValueOrThrow("wild_texture"));
ResourceLocation tameTexture = new ResourceLocation(compound.getStringTagValueOrThrow("tame_texture"));
ResourceLocation angryTexture = new ResourceLocation(compound.getStringTagValueOrThrow("angry_texture"));
MappedEntitySet<Biome> biomes = MappedEntitySet.decode(
compound.getTagOrThrow("biomes"), version, Biomes.getRegistry());
return new StaticWolfVariant(data, wildTexture, tameTexture, angryTexture, biomes);
}
static NBT encode(WolfVariant variant, ClientVersion version) {
NBTCompound compound = new NBTCompound();
compound.setTag("wild_texture", new NBTString(variant.getWildTexture().toString()));
compound.setTag("tame_texture", new NBTString(variant.getTameTexture().toString()));
compound.setTag("angry_texture", new NBTString(variant.getAngryTexture().toString()));
compound.setTag("biomes", MappedEntitySet.encode(variant.getBiomes(), version));
return compound;
}
}
@@ -0,0 +1,88 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.entity.wolfvariant;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.protocol.world.biome.Biome;
import com.github.retrooper.packetevents.protocol.world.biome.Biomes;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import org.jetbrains.annotations.ApiStatus;
import java.util.Arrays;
public final class WolfVariants {
private static final VersionedRegistry<WolfVariant> REGISTRY = new VersionedRegistry<>(
"wolf_variant", "entity/wolf_variant_mappings");
private WolfVariants() {
}
@ApiStatus.Internal
public static WolfVariant define(String key, MappedEntitySet<Biome> biomes) {
return define(key, "wolf_" + key, biomes);
}
@ApiStatus.Internal
public static WolfVariant define(String key, String assetId, MappedEntitySet<Biome> biomes) {
return define(key, ResourceLocation.minecraft("entity/wolf/" + assetId),
ResourceLocation.minecraft("entity/wolf/" + assetId + "_tame"),
ResourceLocation.minecraft("entity/wolf/" + assetId + "_angry"), biomes);
}
@ApiStatus.Internal
public static WolfVariant define(
String key,
ResourceLocation wildTexture,
ResourceLocation tameTexture,
ResourceLocation angryTexture,
MappedEntitySet<Biome> biomes
) {
return REGISTRY.define(key, data -> new StaticWolfVariant(
data, wildTexture, tameTexture, angryTexture, biomes));
}
public static VersionedRegistry<WolfVariant> getRegistry() {
return REGISTRY;
}
public static final WolfVariant PALE = define("pale", "wolf",
new MappedEntitySet<>(Arrays.asList(Biomes.TAIGA)));
public static final WolfVariant SPOTTED = define("spotted",
new MappedEntitySet<>(ResourceLocation.minecraft("is_savanna")));
public static final WolfVariant SNOWY = define("snowy",
new MappedEntitySet<>(Arrays.asList(Biomes.GROVE)));
public static final WolfVariant BLACK = define("black",
new MappedEntitySet<>(Arrays.asList(Biomes.OLD_GROWTH_PINE_TAIGA)));
public static final WolfVariant ASHEN = define("ashen",
new MappedEntitySet<>(Arrays.asList(Biomes.SNOWY_TAIGA)));
public static final WolfVariant RUSTY = define("rusty",
new MappedEntitySet<>(ResourceLocation.minecraft("is_jungle")));
public static final WolfVariant WOODS = define("woods",
new MappedEntitySet<>(Arrays.asList(Biomes.FOREST)));
public static final WolfVariant CHESTNUT = define("chestnut",
new MappedEntitySet<>(Arrays.asList(Biomes.OLD_GROWTH_SPRUCE_TAIGA)));
public static final WolfVariant STRIPED = define("striped",
new MappedEntitySet<>(ResourceLocation.minecraft("is_badlands")));
static {
REGISTRY.unloadMappings();
}
}
@@ -32,10 +32,12 @@ import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
import com.github.retrooper.packetevents.protocol.nbt.NBTShort;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.protocol.nbt.NBTType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -82,6 +84,54 @@ public class ItemStack {
updateCachedEmptyStatus();
}
public static ItemStack decode(NBT nbt, ClientVersion version) {
if (nbt instanceof NBTString) {
ResourceLocation itemName = new ResourceLocation(((NBTString) nbt).getValue());
return ItemStack.builder().type(ItemTypes.getByName(itemName.toString())).build();
}
NBTCompound compound = (NBTCompound) nbt;
ItemStack.Builder builder = ItemStack.builder();
ResourceLocation itemName = Optional.ofNullable(compound.getStringTagValueOrNull("id")).map(Optional::of)
.orElseGet(() -> Optional.ofNullable(compound.getStringTagValueOrNull("item")))
.map(ResourceLocation::new).orElseThrow(() -> new IllegalArgumentException(
"No item type specified: " + compound.getTags().keySet()));
builder.type(ItemTypes.getByName(itemName.toString()));
builder.nbt(compound.getCompoundTagOrNull("tag"));
Optional.ofNullable(compound.getNumberTagOrNull("Count")).map(Optional::of)
.orElseGet(() -> Optional.ofNullable(compound.getNumberTagOrNull("count")))
.map(NBTNumber::getAsInt).ifPresent(builder::amount);
// TODO components
return builder.build();
}
public static NBT encodeForParticle(ItemStack itemStack, ClientVersion version) {
if (version.isNewerThanOrEquals(ClientVersion.V_1_20_5)) {
boolean simple = itemStack.isEmpty()
|| itemStack.components == null
|| itemStack.components.getPatches().isEmpty();
if (simple) {
return new NBTString(itemStack.type.getName().toString());
}
}
NBTCompound compound = new NBTCompound();
compound.setTag("id", new NBTString(itemStack.type.getName().toString()));
if (version.isOlderThan(ClientVersion.V_1_20_5)) {
compound.setTag("Count", new NBTInt(itemStack.amount));
if (itemStack.nbt != null) {
compound.setTag("tag", itemStack.nbt);
}
}
// TODO components
return compound;
}
public int getMaxStackSize() {
return this.getComponentOr(MAX_STACK_SIZE,
// fallback to legacy specified max stack size
@@ -462,7 +512,7 @@ public class ItemStack {
int maxAmount = getType().getMaxAmount();
return "ItemStack[type=" + identifier + ", amount=" + amount + "/" + maxAmount
+ ", nbt tag names: " + (nbt != null ? nbt.getTagNames() : "[null]")
+ ", legacyData=" + legacyData + ", components=" + components + "]";
+ ", legacyData=" + legacyData + ", components=" + (components != null ? components.getPatches() : null) + "]";
}
}
@@ -19,54 +19,47 @@
package com.github.retrooper.packetevents.protocol.item.armormaterial;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import java.util.HashMap;
import java.util.Map;
public class ArmorMaterials {
/**
* This is named "equipment asset" in vanilla since 1.21.4,
* before this was also called "armor material" in vanilla.
*/
public final class ArmorMaterials {
private static final Map<String, ArmorMaterial> MATERIAL_MAP = new HashMap<>();
private static final Map<Byte, Map<Integer, ArmorMaterial>> MATERIAL_ID_MAP = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_armor_material_mappings");
// this isn't great, but it works
private static final Map<String, String> DFU = new HashMap<>();
public static ArmorMaterial define(String key) {
TypesBuilderData data = TYPES_BUILDER.define(key);
ArmorMaterial instrument = new ArmorMaterial() {
@Override
public ResourceLocation getName() {
return data.getName();
}
@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ArmorMaterial) {
return getName().equals(((ArmorMaterial) obj).getName());
}
return false;
}
};
MappingHelper.registerMapping(TYPES_BUILDER, MATERIAL_MAP, MATERIAL_ID_MAP, instrument);
return instrument;
static {
DFU.put("turtle", "minecraft:turtle_scute");
DFU.put("minecraft:turtle", "minecraft:turtle_scute");
DFU.put("armadillo", "minecraft:armadillo_scute");
DFU.put("minecraft:armadillo", "minecraft:armadillo_scute");
}
private static final VersionedRegistry<ArmorMaterial> REGISTRY = new VersionedRegistry<>(
"equipment_asset", "item/equipment_asset_mappings");
private ArmorMaterials() {
}
private static ArmorMaterial define(String name) {
return REGISTRY.define(name, StaticArmorMaterial::new);
}
public static VersionedRegistry<ArmorMaterial> getRegistry() {
return REGISTRY;
}
// with key
public static ArmorMaterial getByName(String name) {
return MATERIAL_MAP.get(name);
return REGISTRY.getByName(DFU.getOrDefault(name, name));
}
public static ArmorMaterial getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, ArmorMaterial> idMap = MATERIAL_ID_MAP.get((byte) index);
return idMap.get(id);
return REGISTRY.getById(version, id);
}
public static final ArmorMaterial LEATHER = define("leather");
@@ -75,16 +68,105 @@ public class ArmorMaterials {
public static final ArmorMaterial GOLD = define("gold");
public static final ArmorMaterial DIAMOND = define("diamond");
// Added with 1.13
public static final ArmorMaterial TURTLE = define("turtle");
/**
* Renamed from {@link #TURTLE} in 1.21.4
*/
public static final ArmorMaterial TURTLE_SCUTE = define("turtle_scute");
/**
* Added with 1.13, renamed to {@link #TURTLE_SCUTE} in 1.21.4
*/
@Deprecated
public static final ArmorMaterial TURTLE = TURTLE_SCUTE;
// Added with 1.16
/**
* Added with 1.16
*/
public static final ArmorMaterial NETHERITE = define("netherite");
// Added with 1.20.5
public static final ArmorMaterial ARMADILLO = define("armadillo");
/**
* Renamed from {@link #ARMADILLO} in 1.21.4
*/
public static final ArmorMaterial ARMADILLO_SCUTE = define("armadillo_scute");
/**
* Added with 1.20.5, renamed to {@link #ARMADILLO_SCUTE} in 1.21.4
*/
@Deprecated
public static final ArmorMaterial ARMADILLO = ARMADILLO_SCUTE;
/**
* Added with 1.21.4
*/
public static final ArmorMaterial ELYTRA = define("elytra");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial WHITE_CARPET = define("white_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial ORANGE_CARPET = define("orange_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial MAGENTA_CARPET = define("magenta_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial LIGHT_BLUE_CARPET = define("light_blue_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial YELLOW_CARPET = define("yellow_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial LIME_CARPET = define("lime_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial PINK_CARPET = define("pink_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial GRAY_CARPET = define("gray_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial LIGHT_GRAY_CARPET = define("light_gray_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial CYAN_CARPET = define("cyan_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial PURPLE_CARPET = define("purple_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial BLUE_CARPET = define("blue_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial BROWN_CARPET = define("brown_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial GREEN_CARPET = define("green_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial RED_CARPET = define("red_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial BLACK_CARPET = define("black_carpet");
/**
* Added with 1.21.4
*/
public static final ArmorMaterial TRADER_LLAMA = define("trader_llama");
static {
TYPES_BUILDER.unloadFileMappings();
REGISTRY.unloadMappings();
}
}
@@ -0,0 +1,30 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.armormaterial;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.Nullable;
public class StaticArmorMaterial extends AbstractMappedEntity implements ArmorMaterial {
public StaticArmorMaterial(@Nullable TypesBuilderData data) {
super(data);
}
}
@@ -18,11 +18,19 @@
package com.github.retrooper.packetevents.protocol.item.banner;
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
import com.github.retrooper.packetevents.protocol.mapper.DeepComparableEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
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.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.Nullable;
public interface BannerPattern extends MappedEntity {
public interface BannerPattern extends MappedEntity, CopyableEntity<BannerPattern>, DeepComparableEntity {
ResourceLocation getAssetId();
@@ -38,4 +46,18 @@ public interface BannerPattern extends MappedEntity {
wrapper.writeIdentifier(pattern.getAssetId());
wrapper.writeString(pattern.getTranslationKey());
}
static BannerPattern decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
NBTCompound compound = (NBTCompound) nbt;
ResourceLocation assetId = new ResourceLocation(compound.getStringTagValueOrThrow("asset_id"));
String translationKey = compound.getStringTagValueOrThrow("translation_key");
return new StaticBannerPattern(data, assetId, translationKey);
}
static NBT encode(BannerPattern bannerPattern, ClientVersion version) {
NBTCompound compound = new NBTCompound();
compound.setTag("asset_id", new NBTString(bannerPattern.getAssetId().toString()));
compound.setTag("translation_key", new NBTString(bannerPattern.getTranslationKey()));
return compound;
}
}
@@ -20,71 +20,42 @@ package com.github.retrooper.packetevents.protocol.item.banner;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import org.jetbrains.annotations.ApiStatus;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class BannerPatterns {
public final class BannerPatterns {
private static final Map<String, BannerPattern> PATTERN_TYPE_MAP = new HashMap<>();
private static final Map<Byte, Map<Integer, BannerPattern>> PATTERN_TYPE_ID_MAP = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_banner_pattern_mappings");
private static final VersionedRegistry<BannerPattern> REGISTRY = new VersionedRegistry<>(
"banner_pattern", "item/item_banner_pattern_mappings");
private BannerPatterns() {
}
@ApiStatus.Internal
public static BannerPattern define(String key) {
ResourceLocation assetId = ResourceLocation.minecraft(key);
String translationKey = "block.minecraft.banner." + key;
return define(key, assetId, translationKey);
}
@ApiStatus.Internal
public static BannerPattern define(String key, ResourceLocation assetId, String translationKey) {
TypesBuilderData data = TYPES_BUILDER.define(key);
BannerPattern pattern = new BannerPattern() {
@Override
public ResourceLocation getAssetId() {
return assetId;
}
@Override
public String getTranslationKey() {
return translationKey;
}
@Override
public ResourceLocation getName() {
return data.getName();
}
@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof BannerPattern) {
return getName().equals(((BannerPattern) obj).getName());
}
return false;
}
};
MappingHelper.registerMapping(TYPES_BUILDER, PATTERN_TYPE_MAP, PATTERN_TYPE_ID_MAP, pattern);
return pattern;
return REGISTRY.define(key, data ->
new StaticBannerPattern(data, assetId, translationKey));
}
public static VersionedRegistry<BannerPattern> getRegistry() {
return REGISTRY;
}
// with key
public static BannerPattern getByName(String name) {
return PATTERN_TYPE_MAP.get(name);
return REGISTRY.getByName(name);
}
public static BannerPattern getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, BannerPattern> idMap = PATTERN_TYPE_ID_MAP.get((byte) index);
return idMap.get(id);
return REGISTRY.getById(version, id);
}
public static final BannerPattern SQUARE_BOTTOM_LEFT = define("square_bottom_left");
@@ -135,13 +106,14 @@ public class BannerPatterns {
/**
* Returns an immutable view of the banner patterns.
*
* @return Banner Patterns
*/
public static Collection<BannerPattern> values() {
return Collections.unmodifiableCollection(PATTERN_TYPE_MAP.values());
return REGISTRY.getEntries();
}
static {
TYPES_BUILDER.unloadFileMappings();
REGISTRY.unloadMappings();
}
}
@@ -18,21 +18,33 @@
package com.github.retrooper.packetevents.protocol.item.banner;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class StaticBannerPattern implements BannerPattern {
public class StaticBannerPattern extends AbstractMappedEntity implements BannerPattern {
private final ResourceLocation assetId;
private final String translationKey;
public StaticBannerPattern(ResourceLocation assetId, String translationKey) {
this(null, assetId, translationKey);
}
public StaticBannerPattern(@Nullable TypesBuilderData data, ResourceLocation assetId, String translationKey) {
super(data);
this.assetId = assetId;
this.translationKey = translationKey;
}
@Override
public BannerPattern copy(@Nullable TypesBuilderData newData) {
return new StaticBannerPattern(newData, this.assetId, this.translationKey);
}
@Override
public ResourceLocation getAssetId() {
return this.assetId;
@@ -44,31 +56,22 @@ public class StaticBannerPattern implements BannerPattern {
}
@Override
public ResourceLocation getName() {
throw new UnsupportedOperationException();
}
@Override
public int getId(ClientVersion version) {
throw new UnsupportedOperationException();
}
@Override
public boolean isRegistered() {
return false;
}
@Override
public boolean equals(Object obj) {
public boolean deepEquals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof StaticBannerPattern)) return false;
if (!super.equals(obj)) return false;
StaticBannerPattern that = (StaticBannerPattern) obj;
if (!this.assetId.equals(that.assetId)) return false;
return this.translationKey.equals(that.translationKey);
}
@Override
public int hashCode() {
return Objects.hash(this.assetId, this.translationKey);
public int deepHashCode() {
return Objects.hash(super.hashCode(), this.assetId, this.translationKey);
}
@Override
public String toString() {
return "StaticBannerPattern{assetId=" + this.assetId + ", translationKey='" + this.translationKey + '\'' + '}';
}
}
@@ -0,0 +1,45 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
public abstract class ConsumeEffect<T extends ConsumeEffect<?>> {
protected final ConsumeEffectType<T> type;
protected ConsumeEffect(ConsumeEffectType<T> type) {
this.type = type;
}
public static ConsumeEffect<?> readFull(PacketWrapper<?> wrapper) {
ConsumeEffectType<?> type = wrapper.readMappedEntity(ConsumeEffectTypes.getRegistry());
return type.read(wrapper);
}
@SuppressWarnings("unchecked") // I hate generics
public static <T extends ConsumeEffect<?>> void writeFull(PacketWrapper<?> wrapper, ConsumeEffect<T> effect) {
wrapper.writeMappedEntity(effect.getType());
((ConsumeEffectType<ConsumeEffect<?>>) effect.getType()).write(wrapper, effect);
}
public ConsumeEffectType<T> getType() {
return this.type;
}
}
@@ -0,0 +1,29 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
public interface ConsumeEffectType<T extends ConsumeEffect<?>> extends MappedEntity {
T read(PacketWrapper<?> wrapper);
void write(PacketWrapper<?> wrapper, T effect);
}
@@ -0,0 +1,64 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables;
import com.github.retrooper.packetevents.protocol.item.consumables.builtin.ApplyEffectsConsumeEffect;
import com.github.retrooper.packetevents.protocol.item.consumables.builtin.ClearAllEffectsConsumeEffect;
import com.github.retrooper.packetevents.protocol.item.consumables.builtin.PlaySoundConsumeEffect;
import com.github.retrooper.packetevents.protocol.item.consumables.builtin.RemoveEffectsConsumeEffect;
import com.github.retrooper.packetevents.protocol.item.consumables.builtin.TeleportRandomlyConsumeEffect;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Reader;
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Writer;
import org.jetbrains.annotations.ApiStatus;
public final class ConsumeEffectTypes {
private static final VersionedRegistry<ConsumeEffectType<?>> REGISTRY = new VersionedRegistry<>(
"consume_effect_type", "item/consume_effect_type_mappings");
private ConsumeEffectTypes() {
}
@ApiStatus.Internal
public static <T extends ConsumeEffect<?>> ConsumeEffectType<T> define(
String name, Reader<T> reader, Writer<T> writer) {
return REGISTRY.define(name, data ->
new StaticConsumeEffectType<>(data, reader, writer));
}
public static final ConsumeEffectType<ApplyEffectsConsumeEffect> APPLY_EFFECTS = define(
"apply_effects", ApplyEffectsConsumeEffect::read, ApplyEffectsConsumeEffect::write);
public static final ConsumeEffectType<RemoveEffectsConsumeEffect> REMOVE_EFFECTS = define(
"remove_effects", RemoveEffectsConsumeEffect::read, RemoveEffectsConsumeEffect::write);
public static final ConsumeEffectType<ClearAllEffectsConsumeEffect> CLEAR_ALL_EFFECTS = define(
"clear_all_effects", ClearAllEffectsConsumeEffect::read, ClearAllEffectsConsumeEffect::write);
public static final ConsumeEffectType<TeleportRandomlyConsumeEffect> TELEPORT_RANDOMLY = define(
"teleport_randomly", TeleportRandomlyConsumeEffect::read, TeleportRandomlyConsumeEffect::write);
public static final ConsumeEffectType<PlaySoundConsumeEffect> PLAY_SOUND = define(
"play_sound", PlaySoundConsumeEffect::read, PlaySoundConsumeEffect::write);
public static VersionedRegistry<ConsumeEffectType<?>> getRegistry() {
return REGISTRY;
}
static {
REGISTRY.unloadMappings();
}
}
@@ -0,0 +1,52 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables;
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.Nullable;
public class StaticConsumeEffectType<T extends ConsumeEffect<?>> extends AbstractMappedEntity implements ConsumeEffectType<T> {
private final Reader<T> reader;
private final Writer<T> writer;
public StaticConsumeEffectType(
@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 effect) {
this.writer.accept(wrapper, effect);
}
}
@@ -0,0 +1,57 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables.builtin;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffect;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffectTypes;
import com.github.retrooper.packetevents.protocol.potion.PotionEffect;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.List;
public class ApplyEffectsConsumeEffect extends ConsumeEffect<ApplyEffectsConsumeEffect> {
private final List<PotionEffect> effects;
private final float probability;
public ApplyEffectsConsumeEffect(List<PotionEffect> effects, float probability) {
super(ConsumeEffectTypes.APPLY_EFFECTS);
this.effects = effects;
this.probability = probability;
}
public static ApplyEffectsConsumeEffect read(PacketWrapper<?> wrapper) {
List<PotionEffect> effects = wrapper.readList(PotionEffect::read);
float probability = wrapper.readFloat();
return new ApplyEffectsConsumeEffect(effects, probability);
}
public static void write(PacketWrapper<?> wrapper, ApplyEffectsConsumeEffect effect) {
wrapper.writeList(effect.effects, PotionEffect::write);
wrapper.writeFloat(effect.probability);
}
public List<PotionEffect> getEffects() {
return this.effects;
}
public float getProbability() {
return this.probability;
}
}
@@ -0,0 +1,41 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables.builtin;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffect;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffectType;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffectTypes;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
public class ClearAllEffectsConsumeEffect extends ConsumeEffect<ClearAllEffectsConsumeEffect> {
public static final ClearAllEffectsConsumeEffect INSTANCE = new ClearAllEffectsConsumeEffect();
private ClearAllEffectsConsumeEffect() {
super(ConsumeEffectTypes.CLEAR_ALL_EFFECTS);
}
public static ClearAllEffectsConsumeEffect read(PacketWrapper<?> ignoredWrapper) {
return INSTANCE;
}
public static void write(PacketWrapper<?> ignoredWrapper, ClearAllEffectsConsumeEffect ignoredEffect) {
// NO-OP
}
}
@@ -0,0 +1,47 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables.builtin;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffect;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffectTypes;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
public class PlaySoundConsumeEffect extends ConsumeEffect<PlaySoundConsumeEffect> {
private final Sound sound;
public PlaySoundConsumeEffect(Sound sound) {
super(ConsumeEffectTypes.PLAY_SOUND);
this.sound = sound;
}
public static PlaySoundConsumeEffect read(PacketWrapper<?> wrapper) {
Sound sound = Sound.read(wrapper);
return new PlaySoundConsumeEffect(sound);
}
public static void write(PacketWrapper<?> wrapper, PlaySoundConsumeEffect effect) {
Sound.write(wrapper, effect.sound);
}
public Sound getSound() {
return this.sound;
}
}
@@ -0,0 +1,49 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables.builtin;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffect;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffectTypes;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.protocol.potion.PotionType;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
public class RemoveEffectsConsumeEffect extends ConsumeEffect<RemoveEffectsConsumeEffect> {
private final MappedEntitySet<PotionType> effects;
public RemoveEffectsConsumeEffect(MappedEntitySet<PotionType> effects) {
super(ConsumeEffectTypes.REMOVE_EFFECTS);
this.effects = effects;
}
public static RemoveEffectsConsumeEffect read(PacketWrapper<?> wrapper) {
MappedEntitySet<PotionType> effects = MappedEntitySet.read(wrapper, PotionTypes::getById);
return new RemoveEffectsConsumeEffect(effects);
}
public static void write(PacketWrapper<?> wrapper, RemoveEffectsConsumeEffect effect) {
MappedEntitySet.write(wrapper, effect.effects);
}
public MappedEntitySet<PotionType> getEffects() {
return this.effects;
}
}
@@ -0,0 +1,46 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.consumables.builtin;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffect;
import com.github.retrooper.packetevents.protocol.item.consumables.ConsumeEffectTypes;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
public class TeleportRandomlyConsumeEffect extends ConsumeEffect<TeleportRandomlyConsumeEffect> {
private final float diameter;
public TeleportRandomlyConsumeEffect(float diameter) {
super(ConsumeEffectTypes.TELEPORT_RANDOMLY);
this.diameter = diameter;
}
public static TeleportRandomlyConsumeEffect read(PacketWrapper<?> wrapper) {
float diameter = wrapper.readFloat();
return new TeleportRandomlyConsumeEffect(diameter);
}
public static void write(PacketWrapper<?> wrapper, TeleportRandomlyConsumeEffect effect) {
wrapper.writeFloat(effect.diameter);
}
public float getDiameter() {
return this.diameter;
}
}
@@ -0,0 +1,78 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.enchantment;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import java.util.Objects;
public final class EnchantmentCost {
private final int base;
private final int perLevelAboveFirst;
public EnchantmentCost(int base, int perLevelAboveFirst) {
this.base = base;
this.perLevelAboveFirst = perLevelAboveFirst;
}
public static EnchantmentCost decode(NBT nbt, ClientVersion version) {
NBTCompound compound = (NBTCompound) nbt;
int base = compound.getNumberTagOrThrow("base").getAsInt();
int perLevelAboveFirst = compound.getNumberTagOrThrow("per_level_above_first").getAsInt();
return new EnchantmentCost(base, perLevelAboveFirst);
}
public static NBT encode(EnchantmentCost cost, ClientVersion version) {
NBTCompound compound = new NBTCompound();
compound.setTag("base", new NBTInt(cost.base));
compound.setTag("per_level_above_first", new NBTInt(cost.perLevelAboveFirst));
return compound;
}
public int getBase() {
return this.base;
}
public int getPerLevelAboveFirst() {
return this.perLevelAboveFirst;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof EnchantmentCost)) return false;
EnchantmentCost that = (EnchantmentCost) obj;
if (this.base != that.base) return false;
return this.perLevelAboveFirst == that.perLevelAboveFirst;
}
@Override
public int hashCode() {
return Objects.hash(this.base, this.perLevelAboveFirst);
}
@Override
public String toString() {
return "EnchantmentCost{base=" + this.base + ", perLevelAboveFirst=" + this.perLevelAboveFirst + '}';
}
}
@@ -0,0 +1,175 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.enchantment;
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemAttributeModifiers.EquipmentSlotGroup;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import static com.github.retrooper.packetevents.util.adventure.AdventureIndexUtil.indexValueOrThrow;
public final class EnchantmentDefinition {
private final MappedEntitySet<ItemType> supportedItems;
private final Optional<MappedEntitySet<ItemType>> primaryItems;
private final int weight;
private final int maxLevel;
private final EnchantmentCost minCost;
private final EnchantmentCost maxCost;
private final int anvilCost;
private final List<EquipmentSlotGroup> slots;
public EnchantmentDefinition(
MappedEntitySet<ItemType> supportedItems,
Optional<MappedEntitySet<ItemType>> primaryItems,
int weight, int maxLevel,
EnchantmentCost minCost, EnchantmentCost maxCost,
int anvilCost, List<EquipmentSlotGroup> slots
) {
this.supportedItems = supportedItems;
this.primaryItems = primaryItems;
this.weight = weight;
this.maxLevel = maxLevel;
this.minCost = minCost;
this.maxCost = maxCost;
this.anvilCost = anvilCost;
this.slots = slots;
}
public static EnchantmentDefinition decode(NBT nbt, ClientVersion version) {
NBTCompound compound = (NBTCompound) nbt;
MappedEntitySet<ItemType> supportedItems = MappedEntitySet.decode(
compound.getTagOrThrow("supported_items"), version, ItemTypes.getRegistry());
Optional<MappedEntitySet<ItemType>> primaryItems = Optional.ofNullable(compound.getTagOrNull("primary_items"))
.map(items -> MappedEntitySet.decode(items, version, ItemTypes.getRegistry()));
int weight = compound.getNumberTagOrThrow("weight").getAsInt();
int maxLevel = compound.getNumberTagOrThrow("max_level").getAsInt();
EnchantmentCost minCost = EnchantmentCost.decode(compound.getTagOrThrow("min_cost"), version);
EnchantmentCost maxCost = EnchantmentCost.decode(compound.getTagOrThrow("max_cost"), version);
int anvilCost = compound.getNumberTagOrThrow("anvil_cost").getAsInt();
NBT slotsTag = compound.getTagOrThrow("slots");
List<EquipmentSlotGroup> slots;
if (slotsTag instanceof NBTList<?>) {
NBTList<?> slotsTagList = (NBTList<?>) slotsTag;
slots = new ArrayList<>(slotsTagList.size());
for (NBT tag : slotsTagList.getTags()) {
String slotGroupId = ((NBTString) tag).getValue();
slots.add(indexValueOrThrow(EquipmentSlotGroup.ID_INDEX, slotGroupId));
}
} else {
String slotGroupId = ((NBTString) slotsTag).getValue();
EquipmentSlotGroup slotGroup = indexValueOrThrow(EquipmentSlotGroup.ID_INDEX, slotGroupId);
slots = Collections.singletonList(slotGroup);
}
return new EnchantmentDefinition(supportedItems, primaryItems, weight,
maxLevel, minCost, maxCost, anvilCost, slots);
}
public static NBT encode(EnchantmentDefinition definition, ClientVersion version) {
NBTList<NBTString> slotsTag = NBTList.createStringList();
for (EquipmentSlotGroup slot : definition.slots) {
slotsTag.addTag(new NBTString(slot.getId()));
}
NBTCompound compound = new NBTCompound();
compound.setTag("supported_items", MappedEntitySet.encode(
definition.supportedItems, version));
definition.primaryItems.ifPresent(set -> compound.setTag(
"primary_items", MappedEntitySet.encode(set, version)));
compound.setTag("weight", new NBTInt(definition.weight));
compound.setTag("max_level", new NBTInt(definition.maxLevel));
compound.setTag("min_cost", EnchantmentCost.encode(definition.minCost, version));
compound.setTag("max_cost", EnchantmentCost.encode(definition.maxCost, version));
compound.setTag("anvil_cost", new NBTInt(definition.anvilCost));
compound.setTag("slots", slotsTag);
return compound;
}
public MappedEntitySet<ItemType> getSupportedItems() {
return this.supportedItems;
}
public Optional<MappedEntitySet<ItemType>> getPrimaryItems() {
return this.primaryItems;
}
public int getWeight() {
return this.weight;
}
public int getMaxLevel() {
return this.maxLevel;
}
public EnchantmentCost getMinCost() {
return this.minCost;
}
public EnchantmentCost getMaxCost() {
return this.maxCost;
}
public int getAnvilCost() {
return this.anvilCost;
}
public List<EquipmentSlotGroup> getSlots() {
return this.slots;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof EnchantmentDefinition)) return false;
EnchantmentDefinition that = (EnchantmentDefinition) obj;
if (this.weight != that.weight) return false;
if (this.maxLevel != that.maxLevel) return false;
if (this.anvilCost != that.anvilCost) return false;
if (!this.supportedItems.equals(that.supportedItems)) return false;
if (!this.primaryItems.equals(that.primaryItems)) return false;
if (!this.minCost.equals(that.minCost)) return false;
if (!this.maxCost.equals(that.maxCost)) return false;
return this.slots.equals(that.slots);
}
@Override
public int hashCode() {
return Objects.hash(this.supportedItems, this.primaryItems, this.weight, this.maxLevel, this.minCost, this.maxCost, this.anvilCost, this.slots);
}
@Override
public String toString() {
return "EnchantmentDefinition{supportedItems=" + this.supportedItems + ", primaryItems=" + this.primaryItems + ", weight=" + this.weight + ", maxLevel=" + this.maxLevel + ", minCost=" + this.minCost + ", maxCost=" + this.maxCost + ", anvilCost=" + this.anvilCost + ", slots=" + this.slots + '}';
}
}
@@ -18,7 +18,57 @@
package com.github.retrooper.packetevents.protocol.item.enchantment.type;
import com.github.retrooper.packetevents.protocol.component.EnchantEffectComponentTypes;
import com.github.retrooper.packetevents.protocol.component.IComponentMap;
import com.github.retrooper.packetevents.protocol.component.StaticComponentMap;
import com.github.retrooper.packetevents.protocol.item.enchantment.EnchantmentDefinition;
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
import com.github.retrooper.packetevents.protocol.mapper.DeepComparableEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
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.adventure.AdventureSerializer;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
public interface EnchantmentType extends MappedEntity {
import java.util.Optional;
public interface EnchantmentType extends MappedEntity, CopyableEntity<EnchantmentType>, DeepComparableEntity {
Component getDescription();
EnchantmentDefinition getDefinition();
MappedEntitySet<EnchantmentType> getExclusiveSet();
StaticComponentMap getEffects();
static EnchantmentType decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
NBTCompound compound = (NBTCompound) nbt;
Component description = AdventureSerializer.fromNbt(compound.getTagOrThrow("description"));
EnchantmentDefinition definition = EnchantmentDefinition.decode(compound, version);
MappedEntitySet<EnchantmentType> exclusiveSet = Optional.ofNullable(compound.getTagOrNull("exclusive_set"))
.map(tag -> MappedEntitySet.decode(tag, version, EnchantmentTypes.getRegistry()))
.orElseGet(MappedEntitySet::createEmpty);
StaticComponentMap effects = Optional.ofNullable(compound.getTagOrNull("effects"))
.map(tag -> IComponentMap.decode(tag, version,
EnchantEffectComponentTypes.getRegistry()))
.orElse(StaticComponentMap.EMPTY);
return new StaticEnchantmentType(data, description, definition, exclusiveSet, effects);
}
static NBT encode(EnchantmentType type, ClientVersion version) {
NBTCompound compound = (NBTCompound) EnchantmentDefinition.encode(type.getDefinition(), version);
compound.setTag("description", AdventureSerializer.toNbt(type.getDescription()));
if (!type.getExclusiveSet().isEmpty()) {
compound.setTag("exclusive_set", MappedEntitySet.encode(type.getExclusiveSet(), version));
}
if (!type.getEffects().isEmpty()) {
compound.setTag("effects", IComponentMap.encode(type.getEffects(), version));
}
return compound;
}
}
@@ -18,17 +18,21 @@
package com.github.retrooper.packetevents.protocol.item.enchantment.type;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.serializer.SequentialNBTReader;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class EnchantmentTypes {
public final class EnchantmentTypes {
private static final Map<String, String> STRING_UPDATER = new HashMap<>();
@@ -37,47 +41,50 @@ public class EnchantmentTypes {
STRING_UPDATER.put("minecraft:sweeping", "minecraft:sweeping_edge");
}
private static final Map<String, EnchantmentType> ENCHANTMENT_TYPE_MAPPINGS = new HashMap<>();
private static final Map<Byte, Map<Integer, EnchantmentType>> ENCHANTMENT_TYPE_ID_MAPPINGS = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("enchantment/enchantment_type_mappings");
// load data from file, enchantment types are too complex to define in code here
private static final Map<ResourceLocation, NBTCompound> ENCHANTMENT_DATA;
public static EnchantmentType define(String key) {
TypesBuilderData data = TYPES_BUILDER.define(key);
EnchantmentType enchantmentType = new EnchantmentType() {
@Override
public ResourceLocation getName() {
return data.getName();
}
@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof EnchantmentType) {
return getName() == ((EnchantmentType) obj).getName();
static {
ENCHANTMENT_DATA = new HashMap<>();
try (SequentialNBTReader.Compound dataTag = MappingHelper.decompress("mappings/enchantment/enchantment_type_data")) {
while (dataTag.hasNext()) {
Map.Entry<String, NBT> entry = dataTag.next();
if (entry.getKey().equals("version")) {
continue; // skip version field
}
return false;
ResourceLocation enchantKey = new ResourceLocation(entry.getKey());
ENCHANTMENT_DATA.put(enchantKey, ((SequentialNBTReader.Compound) entry.getValue()).readFully());
}
};
MappingHelper.registerMapping(TYPES_BUILDER, ENCHANTMENT_TYPE_MAPPINGS, ENCHANTMENT_TYPE_ID_MAPPINGS, enchantmentType);
return enchantmentType;
} catch (IOException exception) {
throw new RuntimeException("Error while reading enchantment type data", exception);
}
}
@Nullable
public static EnchantmentType getByName(String name) {
private static final VersionedRegistry<EnchantmentType> REGISTRY = new VersionedRegistry<>(
"enchantment", "enchantment/enchantment_type_mappings");
@ApiStatus.Internal
public static EnchantmentType define(String key) {
return REGISTRY.define(key, data -> {
NBTCompound dataTag = ENCHANTMENT_DATA.get(data.getName());
if (dataTag == null) {
throw new IllegalArgumentException("Can't define enchantment " + data.getName() + ", no data found");
}
return EnchantmentType.decode(dataTag, ClientVersion.getLatest(), data);
});
}
public static VersionedRegistry<EnchantmentType> getRegistry() {
return REGISTRY;
}
public static @Nullable EnchantmentType getByName(String name) {
String fixedName = STRING_UPDATER.getOrDefault(name, name);
return ENCHANTMENT_TYPE_MAPPINGS.get(fixedName);
return REGISTRY.getByName(fixedName);
}
@Nullable
public static EnchantmentType getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, EnchantmentType> typeIdMap = ENCHANTMENT_TYPE_ID_MAPPINGS.get((byte) index);
return typeIdMap.get(id);
public static @Nullable EnchantmentType getById(ClientVersion version, int id) {
return REGISTRY.getById(version, id);
}
public static final EnchantmentType ALL_DAMAGE_PROTECTION = define("protection");
@@ -126,6 +133,7 @@ public class EnchantmentTypes {
public static final EnchantmentType WIND_BURST = define("wind_burst");
static {
TYPES_BUILDER.unloadFileMappings();
ENCHANTMENT_DATA.clear();
REGISTRY.unloadMappings();
}
}
@@ -0,0 +1,108 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.enchantment.type;
import com.github.retrooper.packetevents.protocol.component.StaticComponentMap;
import com.github.retrooper.packetevents.protocol.item.enchantment.EnchantmentDefinition;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class StaticEnchantmentType extends AbstractMappedEntity implements EnchantmentType {
private final Component description;
private final EnchantmentDefinition definition;
private final MappedEntitySet<EnchantmentType> exclusiveSet;
private final StaticComponentMap effects;
public StaticEnchantmentType(
Component description,
EnchantmentDefinition definition,
MappedEntitySet<EnchantmentType> exclusiveSet,
StaticComponentMap effects
) {
this(null, description, definition, exclusiveSet, effects);
}
public StaticEnchantmentType(
@Nullable TypesBuilderData data,
Component description,
EnchantmentDefinition definition,
MappedEntitySet<EnchantmentType> exclusiveSet,
StaticComponentMap effects
) {
super(data);
this.description = description;
this.definition = definition;
this.exclusiveSet = exclusiveSet;
this.effects = effects;
}
@Override
public EnchantmentType copy(@Nullable TypesBuilderData newData) {
return new StaticEnchantmentType(newData, this.description,
this.definition, this.exclusiveSet, this.effects);
}
@Override
public Component getDescription() {
return this.description;
}
@Override
public EnchantmentDefinition getDefinition() {
return this.definition;
}
@Override
public MappedEntitySet<EnchantmentType> getExclusiveSet() {
return this.exclusiveSet;
}
@Override
public StaticComponentMap getEffects() {
return this.effects;
}
@Override
public boolean deepEquals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof StaticEnchantmentType)) return false;
if (!super.equals(obj)) return false;
StaticEnchantmentType that = (StaticEnchantmentType) obj;
if (!this.description.equals(that.description)) return false;
if (!this.definition.equals(that.definition)) return false;
if (!this.exclusiveSet.equals(that.exclusiveSet)) return false;
return this.effects.equals(that.effects);
}
@Override
public int deepHashCode() {
return Objects.hash(super.hashCode(), this.description, this.definition, this.exclusiveSet, this.effects);
}
@Override
public String toString() {
return "StaticEnchantmentType{description=" + this.description + ", definition=" + this.definition + ", exclusiveSet=" + this.exclusiveSet + ", effects=" + this.effects + "}";
}
}
@@ -18,27 +18,51 @@
package com.github.retrooper.packetevents.protocol.item.instrument;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
import com.github.retrooper.packetevents.protocol.mapper.DeepComparableEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTFloat;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.util.MathUtil;
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
public interface Instrument extends MappedEntity {
public interface Instrument extends MappedEntity, CopyableEntity<Instrument>, DeepComparableEntity {
Sound getSound();
int getUseDuration();
float getUseSeconds();
/**
* Use duration measured in ticks
*/
default int getUseDuration() {
return MathUtil.floor(this.getUseSeconds() * 20);
}
float getRange();
Component getDescription();
static Instrument read(PacketWrapper<?> wrapper) {
return wrapper.readMappedEntityOrDirect(Instruments::getById, Instrument::readDirect);
return wrapper.readMappedEntityOrDirect(Instruments.getRegistry(), Instrument::readDirect);
}
static Instrument readDirect(PacketWrapper<?> wrapper) {
Sound sound = Sound.read(wrapper);
int useDuration = wrapper.readVarInt();
float useSeconds = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2)
? wrapper.readFloat() : wrapper.readVarInt() * 20f;
float range = wrapper.readFloat();
return new StaticInstrument(sound, useDuration, range);
Component description = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2)
? wrapper.readComponent() : Component.empty();
return new StaticInstrument(sound, useSeconds, range, description);
}
static void write(PacketWrapper<?> wrapper, Instrument instrument) {
@@ -47,7 +71,32 @@ public interface Instrument extends MappedEntity {
static void writeDirect(PacketWrapper<?> wrapper, Instrument instrument) {
Sound.write(wrapper, instrument.getSound());
wrapper.writeVarInt(instrument.getUseDuration());
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2)) {
wrapper.writeFloat(instrument.getUseSeconds());
} else {
wrapper.writeVarInt(instrument.getUseDuration());
}
wrapper.writeFloat(instrument.getRange());
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2)) {
wrapper.writeComponent(instrument.getDescription());
}
}
static Instrument decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
NBTCompound compound = (NBTCompound) nbt;
Sound sound = Sound.decode(compound.getTagOrThrow("sound_event"), version);
float useSeconds = compound.getNumberTagOrThrow("use_duration").getAsFloat();
float range = compound.getNumberTagOrThrow("range").getAsFloat();
Component description = AdventureSerializer.fromNbt(compound.getTagOrThrow("description"));
return new StaticInstrument(data, sound, useSeconds, range, description);
}
static NBT encode(Instrument instrument, ClientVersion version) {
NBTCompound compound = new NBTCompound();
compound.setTag("sound_event", Sound.encode(instrument.getSound(), version));
compound.setTag("use_duration", new NBTFloat(instrument.getUseSeconds()));
compound.setTag("range", new NBTFloat(instrument.getRange()));
compound.setTag("description", AdventureSerializer.toNbt(instrument.getDescription()));
return compound;
}
}
@@ -21,74 +21,40 @@ package com.github.retrooper.packetevents.protocol.item.instrument;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
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.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.ApiStatus;
import java.util.HashMap;
import java.util.Map;
public final class Instruments {
public class Instruments {
private static final VersionedRegistry<Instrument> REGISTRY = new VersionedRegistry<>(
"instrument", "item/item_instrument_mappings");
private static final Map<String, Instrument> INSTRUMENT_MAP = new HashMap<>();
private static final Map<Byte, Map<Integer, Instrument>> INSTRUMENT_ID_MAP = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_instrument_mappings");
private Instruments() {
}
public static Instrument define(String key, Sound sound) {
// vanilla defaults for goat horns
return define(key, sound, 140, 256f);
return define(key, sound, 20 * 7, 256f);
}
@ApiStatus.Internal
public static Instrument define(String key, Sound sound, int useDuration, float range) {
TypesBuilderData data = TYPES_BUILDER.define(key);
Instrument instrument = new Instrument() {
@Override
public Sound getSound() {
return sound;
}
@Override
public int getUseDuration() {
return useDuration;
}
@Override
public float getRange() {
return range;
}
@Override
public ResourceLocation getName() {
return data.getName();
}
@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Instrument) {
return getName().equals(((Instrument) obj).getName());
}
return false;
}
};
MappingHelper.registerMapping(TYPES_BUILDER, INSTRUMENT_MAP, INSTRUMENT_ID_MAP, instrument);
return instrument;
return REGISTRY.define(key, data -> new StaticInstrument(
data, sound, useDuration, range,
Component.translatable("instrument.minecraft." + key)));
}
public static VersionedRegistry<Instrument> getRegistry() {
return REGISTRY;
}
// with key
public static Instrument getByName(String name) {
return INSTRUMENT_MAP.get(name);
return REGISTRY.getByName(name);
}
public static Instrument getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, Instrument> idMap = INSTRUMENT_ID_MAP.get((byte) index);
return idMap.get(id);
return REGISTRY.getById(version, id);
}
public static final Instrument PONDER_GOAT_HORN = define("ponder_goat_horn", Sounds.ITEM_GOAT_HORN_SOUND_0);
@@ -101,6 +67,6 @@ public class Instruments {
public static final Instrument DREAM_GOAT_HORN = define("dream_goat_horn", Sounds.ITEM_GOAT_HORN_SOUND_7);
static {
TYPES_BUILDER.unloadFileMappings();
REGISTRY.unloadMappings();
}
}
@@ -18,22 +18,41 @@
package com.github.retrooper.packetevents.protocol.item.instrument;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class StaticInstrument implements Instrument {
public class StaticInstrument extends AbstractMappedEntity implements Instrument {
private final Sound sound;
private final int useDuration;
private final float useSeconds;
private final float range;
private final Component description;
@Deprecated // useDuration changed from ticks to seconds in 1.21.2
public StaticInstrument(Sound sound, int useDuration, float range) {
this(sound, useDuration * 20f, range, Component.empty());
}
public StaticInstrument(Sound sound, float useSeconds, float range, Component description) {
this(null, sound, useSeconds, range, description);
}
public StaticInstrument(@Nullable TypesBuilderData data, Sound sound, float useSeconds, float range, Component description) {
super(data);
this.sound = sound;
this.useDuration = useDuration;
this.useSeconds = useSeconds;
this.range = range;
this.description = description;
}
@Override
public Instrument copy(@Nullable TypesBuilderData newData) {
return new StaticInstrument(newData, this.sound, this.useSeconds, this.range, this.description);
}
@Override
@@ -42,8 +61,8 @@ public class StaticInstrument implements Instrument {
}
@Override
public int getUseDuration() {
return this.useDuration;
public float getUseSeconds() {
return this.useSeconds;
}
@Override
@@ -52,32 +71,24 @@ public class StaticInstrument implements Instrument {
}
@Override
public ResourceLocation getName() {
throw new UnsupportedOperationException();
public Component getDescription() {
return this.description;
}
@Override
public int getId(ClientVersion version) {
throw new UnsupportedOperationException();
}
@Override
public boolean isRegistered() {
return false;
}
@Override
public boolean equals(Object obj) {
public boolean deepEquals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof StaticInstrument)) return false;
if (!super.equals(obj)) return false;
StaticInstrument that = (StaticInstrument) obj;
if (this.useDuration != that.useDuration) return false;
if (this.useSeconds != that.useSeconds) return false;
if (Float.compare(that.range, this.range) != 0) return false;
return this.sound.equals(that.sound);
if (!this.sound.equals(that.sound)) return false;
return this.description.equals(that.description);
}
@Override
public int hashCode() {
return Objects.hash(this.sound, this.useDuration, this.range);
public int deepHashCode() {
return Objects.hash(super.hashCode(), this.sound, this.useSeconds, this.range, this.description);
}
}
@@ -0,0 +1,81 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.jukebox;
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
import com.github.retrooper.packetevents.protocol.mapper.DeepComparableEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTFloat;
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
public interface IJukeboxSong extends MappedEntity, CopyableEntity<IJukeboxSong>, DeepComparableEntity {
Sound getSound();
Component getDescription();
float getLengthInSeconds();
int getComparatorOutput();
static IJukeboxSong decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
NBTCompound compound = (NBTCompound) nbt;
Sound sound = Sound.decode(compound.getTagOrThrow("sound_event"), version);
Component description = AdventureSerializer.fromNbt(compound.getTagOrThrow("description"));
float length = compound.getNumberTagOrThrow("length_in_seconds").getAsFloat();
int comparator_output = compound.getNumberTagOrThrow("comparator_output").getAsInt();
return new JukeboxSong(data, sound, description, length, comparator_output);
}
static NBT encode(IJukeboxSong jukeboxSong, ClientVersion version) {
NBTCompound compound = new NBTCompound();
compound.setTag("sound_event", Sound.encode(jukeboxSong.getSound(), version));
compound.setTag("description", AdventureSerializer.toNbt(jukeboxSong.getDescription()));
compound.setTag("length_in_seconds", new NBTFloat(jukeboxSong.getLengthInSeconds()));
compound.setTag("comparator_output", new NBTInt(jukeboxSong.getComparatorOutput()));
return compound;
}
static IJukeboxSong read(PacketWrapper<?> wrapper) {
Sound sound = Sound.read(wrapper);
Component description = wrapper.readComponent();
float lengthInSeconds = wrapper.readFloat();
int comparatorOutput = wrapper.readVarInt();
return new JukeboxSong(null, sound, description, lengthInSeconds, comparatorOutput);
}
static void write(PacketWrapper<?> wrapper, IJukeboxSong song) {
Sound.write(wrapper, song.getSound());
wrapper.writeComponent(song.getDescription());
wrapper.writeFloat(song.getLengthInSeconds());
wrapper.writeVarInt(song.getComparatorOutput());
}
}
@@ -18,77 +18,94 @@
package com.github.retrooper.packetevents.protocol.item.jukebox;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.protocol.sound.Sound;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class JukeboxSong {
public class JukeboxSong extends AbstractMappedEntity implements IJukeboxSong {
private Sound sound;
private Component description;
private float lengthInSeconds;
private int comparatorOutput;
public JukeboxSong(Sound sound, Component description, float lengthInSeconds, int comparatorOutput) {
this(null, sound, description, lengthInSeconds, comparatorOutput);
}
public JukeboxSong(@Nullable TypesBuilderData data, Sound sound, Component description, float lengthInSeconds,
int comparatorOutput) {
super(data);
this.sound = sound;
this.description = description;
this.lengthInSeconds = lengthInSeconds;
this.comparatorOutput = comparatorOutput;
}
@Deprecated
public static JukeboxSong read(PacketWrapper<?> wrapper) {
Sound sound = Sound.read(wrapper);
Component description = wrapper.readComponent();
float lengthInSeconds = wrapper.readFloat();
int comparatorOutput = wrapper.readVarInt();
return new JukeboxSong(sound, description, lengthInSeconds, comparatorOutput);
return (JukeboxSong) IJukeboxSong.read(wrapper);
}
@Deprecated
public static void write(PacketWrapper<?> wrapper, JukeboxSong song) {
Sound.write(wrapper, song.sound);
wrapper.writeComponent(song.description);
wrapper.writeFloat(song.lengthInSeconds);
wrapper.writeVarInt(song.comparatorOutput);
IJukeboxSong.write(wrapper, song);
}
@Override
public IJukeboxSong copy(@Nullable TypesBuilderData newData) {
return new JukeboxSong(newData, sound, description, lengthInSeconds, comparatorOutput);
}
@Override
public Sound getSound() {
return this.sound;
}
@Deprecated
public void setSound(Sound sound) {
this.sound = sound;
}
@Override
public Component getDescription() {
return this.description;
}
@Deprecated
public void setDescription(Component description) {
this.description = description;
}
@Override
public float getLengthInSeconds() {
return this.lengthInSeconds;
}
@Deprecated
public void setLengthInSeconds(float lengthInSeconds) {
this.lengthInSeconds = lengthInSeconds;
}
@Override
public int getComparatorOutput() {
return this.comparatorOutput;
}
@Deprecated
public void setComparatorOutput(int comparatorOutput) {
this.comparatorOutput = comparatorOutput;
}
@Override
public boolean equals(Object obj) {
public boolean deepEquals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof JukeboxSong)) return false;
if (!super.equals(obj)) return false;
JukeboxSong that = (JukeboxSong) obj;
if (Float.compare(that.lengthInSeconds, this.lengthInSeconds) != 0) return false;
if (this.comparatorOutput != that.comparatorOutput) return false;
@@ -97,7 +114,12 @@ public class JukeboxSong {
}
@Override
public int hashCode() {
return Objects.hash(this.sound, this.description, this.lengthInSeconds, this.comparatorOutput);
public int deepHashCode() {
return Objects.hash(super.hashCode(), this.sound, this.description, this.lengthInSeconds, this.comparatorOutput);
}
@Override
public String toString() {
return "JukeboxSong{sound=" + this.sound + ", description=" + this.description + ", lengthInSeconds=" + this.lengthInSeconds + ", comparatorOutput=" + this.comparatorOutput + '}';
}
}
@@ -0,0 +1,96 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.jukebox;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
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.util.mappings.VersionedRegistry;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public class JukeboxSongs {
private static final VersionedRegistry<IJukeboxSong> REGISTRY = new VersionedRegistry<>("jukebox_song",
"item/item_jukebox_song_mappings");
private JukeboxSongs() {
}
private static String makeDescriptionId(String var0, @Nullable ResourceLocation var1) {
return var1 == null ? var0 + ".unregistered_sadface" :
var0 + "." + var1.getNamespace() + "." + var1.getKey().replace('/', '.');
}
@ApiStatus.Internal
public static IJukeboxSong define(String key, Sound sound, float lengthInSeconds, int comparatorOutput) {
return REGISTRY.define(key, data -> new JukeboxSong(data, sound,
Component.translatable(makeDescriptionId("jukebox_song", data.getName())), lengthInSeconds,
comparatorOutput));
}
public static VersionedRegistry<IJukeboxSong> getRegistry() {
return REGISTRY;
}
public static IJukeboxSong getByName(String name) {
return REGISTRY.getByName(name);
}
public static IJukeboxSong getById(ClientVersion version, int id) {
return REGISTRY.getById(version, id);
}
public static final IJukeboxSong THIRTEEN = define("13", Sounds.MUSIC_DISC_13, 178, 1);
public static final IJukeboxSong CAT = define("cat", Sounds.MUSIC_DISC_CAT, 185, 2);
public static final IJukeboxSong BLOCKS = define("blocks", Sounds.MUSIC_DISC_BLOCKS, 345, 3);
public static final IJukeboxSong CHIRP = define("chirp", Sounds.MUSIC_DISC_CHIRP, 185, 4);
public static final IJukeboxSong FAR = define("far", Sounds.MUSIC_DISC_FAR, 174, 5);
public static final IJukeboxSong MALL = define("mall", Sounds.MUSIC_DISC_MALL, 197, 6);
public static final IJukeboxSong MELLOHI = define("mellohi", Sounds.MUSIC_DISC_MELLOHI, 96, 7);
public static final IJukeboxSong STAL = define("stal", Sounds.MUSIC_DISC_STAL, 150, 8);
public static final IJukeboxSong STRAD = define("strad", Sounds.MUSIC_DISC_STRAD, 188, 9);
public static final IJukeboxSong WARD = define("ward", Sounds.MUSIC_DISC_WARD, 251, 10);
public static final IJukeboxSong ELEVEN = define("11", Sounds.MUSIC_DISC_11, 71, 11);
public static final IJukeboxSong WAIT = define("wait", Sounds.MUSIC_DISC_WAIT, 238, 12);
public static final IJukeboxSong PIGSTEP = define("pigstep", Sounds.MUSIC_DISC_PIGSTEP, 149, 13);
public static final IJukeboxSong OTHERSIDE = define("otherside", Sounds.MUSIC_DISC_OTHERSIDE, 195, 14);
public static final IJukeboxSong FIVE = define("5", Sounds.MUSIC_DISC_5, 178, 15);
public static final IJukeboxSong RELIC = define("relic", Sounds.MUSIC_DISC_RELIC, 218, 14);
public static final IJukeboxSong PRECIPICE = define("precipice", Sounds.MUSIC_DISC_PRECIPICE, 299, 13);
public static final IJukeboxSong CREATOR = define("creator", Sounds.MUSIC_DISC_CREATOR, 176, 12);
public static final IJukeboxSong CREATOR_MUSIC_BOX = define("creator_music_box", Sounds.MUSIC_DISC_CREATOR_MUSIC_BOX,
73, 11);
/**
* Returns an immutable view of the jukebox songs.
*
* @return Jukebox Songs
*/
public static Collection<IJukeboxSong> values() {
return REGISTRY.getEntries();
}
static {
REGISTRY.unloadMappings();
}
}
@@ -20,24 +20,17 @@ package com.github.retrooper.packetevents.protocol.item.mapdecoration;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static com.github.retrooper.packetevents.resources.ResourceLocation.minecraft;
public class MapDecorationTypes {
private static final Map<String, MapDecorationType> DECORATION_TYPE_MAP = new HashMap<>();
private static final Map<Byte, Map<Integer, MapDecorationType>> DECORATION_TYPE_ID_MAP = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_map_decoration_type_mappings");
private static final VersionedRegistry<MapDecorationType> REGISTRY =
new VersionedRegistry<>("map_decoration_type", "item/item_map_decoration_type_mappings");
public static MapDecorationType define(String key, boolean showOnItemFrame, boolean trackCount) {
return define(key, minecraft(key), showOnItemFrame, trackCount);
@@ -65,8 +58,7 @@ public class MapDecorationTypes {
boolean showOnItemFrame, int mapColor,
boolean explorationMapElement, boolean trackCount
) {
TypesBuilderData data = TYPES_BUILDER.define(key);
MapDecorationType potionType = new MapDecorationType() {
return REGISTRY.define(key, data -> new MapDecorationType() {
@Override
public ResourceLocation getAssetId() {
return assetId;
@@ -99,7 +91,7 @@ public class MapDecorationTypes {
@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
return data.getId(version);
}
@Override
@@ -109,23 +101,19 @@ public class MapDecorationTypes {
}
return false;
}
};
MappingHelper.registerMapping(TYPES_BUILDER, DECORATION_TYPE_MAP, DECORATION_TYPE_ID_MAP, potionType);
return potionType;
});
}
public static @Nullable MapDecorationType getByName(String name) {
return DECORATION_TYPE_MAP.get(name);
return REGISTRY.getByName(name);
}
public static @Nullable MapDecorationType getById(int id, ClientVersion version) {
return getById(version, id);
return REGISTRY.getById(version, id);
}
public static @Nullable MapDecorationType getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, MapDecorationType> idMap = DECORATION_TYPE_ID_MAP.get((byte) index);
return idMap.get(id);
return REGISTRY.getById(version, id);
}
// color constants used by vanilla
@@ -209,13 +197,14 @@ public class MapDecorationTypes {
/**
* Returns an immutable view of the map decoration types.
*
* @return Map Decoration Types
*/
public static Collection<MapDecorationType> values() {
return Collections.unmodifiableCollection(DECORATION_TYPE_MAP.values());
return REGISTRY.getEntries();
}
static {
TYPES_BUILDER.unloadFileMappings();
REGISTRY.unloadMappings();
}
}
@@ -20,15 +20,15 @@ package com.github.retrooper.packetevents.protocol.item.trimmaterial;
import com.github.retrooper.packetevents.protocol.item.armormaterial.ArmorMaterial;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Objects;
public class StaticTrimMaterial implements TrimMaterial {
public class StaticTrimMaterial extends AbstractMappedEntity implements TrimMaterial {
private final String assetName;
private final ItemType ingredient;
@@ -36,10 +36,34 @@ public class StaticTrimMaterial implements TrimMaterial {
private final Map<ArmorMaterial, String> overrideArmorMaterials;
private final Component description;
public StaticTrimMaterial(
String assetName, ItemType ingredient,
Map<ArmorMaterial, String> overrideArmorMaterials, Component description
) {
this(null, assetName, ingredient, FALLBACK_ITEM_MODEL_INDEX, overrideArmorMaterials, description);
}
public StaticTrimMaterial(
@Nullable TypesBuilderData data,
String assetName, ItemType ingredient,
Map<ArmorMaterial, String> overrideArmorMaterials, Component description
) {
this(data, assetName, ingredient, FALLBACK_ITEM_MODEL_INDEX, overrideArmorMaterials, description);
}
public StaticTrimMaterial(
String assetName, ItemType ingredient, float itemModelIndex,
Map<ArmorMaterial, String> overrideArmorMaterials, Component description
) {
this(null, assetName, ingredient, itemModelIndex, overrideArmorMaterials, description);
}
public StaticTrimMaterial(
@Nullable TypesBuilderData data,
String assetName, ItemType ingredient, float itemModelIndex,
Map<ArmorMaterial, String> overrideArmorMaterials, Component description
) {
super(data);
this.assetName = assetName;
this.ingredient = ingredient;
this.itemModelIndex = itemModelIndex;
@@ -48,18 +72,9 @@ public class StaticTrimMaterial implements TrimMaterial {
}
@Override
public ResourceLocation getName() {
throw new UnsupportedOperationException();
}
@Override
public int getId(ClientVersion version) {
throw new UnsupportedOperationException();
}
@Override
public boolean isRegistered() {
return false;
public TrimMaterial copy(@Nullable TypesBuilderData newData) {
return new StaticTrimMaterial(newData, this.assetName, this.ingredient, this.itemModelIndex,
this.overrideArmorMaterials, this.description);
}
@Override
@@ -88,19 +103,25 @@ public class StaticTrimMaterial implements TrimMaterial {
}
@Override
public boolean equals(Object obj) {
public boolean deepEquals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof StaticTrimMaterial)) return false;
StaticTrimMaterial material = (StaticTrimMaterial) obj;
if (Float.compare(material.itemModelIndex, this.itemModelIndex) != 0) return false;
if (!this.assetName.equals(material.assetName)) return false;
if (!this.ingredient.equals(material.ingredient)) return false;
if (!this.overrideArmorMaterials.equals(material.overrideArmorMaterials)) return false;
return this.description.equals(material.description);
if (!super.equals(obj)) return false;
StaticTrimMaterial that = (StaticTrimMaterial) obj;
if (Float.compare(that.itemModelIndex, this.itemModelIndex) != 0) return false;
if (!this.assetName.equals(that.assetName)) return false;
if (!this.ingredient.equals(that.ingredient)) return false;
if (!this.overrideArmorMaterials.equals(that.overrideArmorMaterials)) return false;
return this.description.equals(that.description);
}
@Override
public int hashCode() {
return Objects.hash(this.assetName, this.ingredient, this.itemModelIndex, this.overrideArmorMaterials, this.description);
public int deepHashCode() {
return Objects.hash(super.hashCode(), this.assetName, this.ingredient, this.itemModelIndex, this.overrideArmorMaterials, this.description);
}
@Override
public String toString() {
return "StaticTrimMaterial{assetName='" + this.assetName + '\'' + ", ingredient=" + this.ingredient + ", itemModelIndex=" + this.itemModelIndex + ", overrideArmorMaterials=" + this.overrideArmorMaterials + ", description=" + this.description + '}';
}
}
@@ -18,23 +18,42 @@
package com.github.retrooper.packetevents.protocol.item.trimmaterial;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.item.armormaterial.ArmorMaterial;
import com.github.retrooper.packetevents.protocol.item.armormaterial.ArmorMaterials;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
import com.github.retrooper.packetevents.protocol.mapper.DeepComparableEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTFloat;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public interface TrimMaterial extends MappedEntity {
public interface TrimMaterial extends MappedEntity, CopyableEntity<TrimMaterial>, DeepComparableEntity {
float FALLBACK_ITEM_MODEL_INDEX = 0f;
String getAssetName();
ItemType getIngredient();
/**
* Removed in 1.21.4
*/
@ApiStatus.Obsolete
float getItemModelIndex();
default @Nullable String getArmorMaterialOverride(ArmorMaterial armorMaterial) {
@@ -46,13 +65,14 @@ public interface TrimMaterial extends MappedEntity {
Component getDescription();
static TrimMaterial read(PacketWrapper<?> wrapper) {
return wrapper.readMappedEntityOrDirect(TrimMaterials::getById, TrimMaterial::readDirect);
return wrapper.readMappedEntityOrDirect(TrimMaterials.getRegistry(), TrimMaterial::readDirect);
}
static TrimMaterial readDirect(PacketWrapper<?> wrapper) {
String assetName = wrapper.readString();
ItemType ingredient = wrapper.readMappedEntity(ItemTypes::getById);
float itemModelIndex = wrapper.readFloat();
float itemModelIndex = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_4)
? FALLBACK_ITEM_MODEL_INDEX : wrapper.readFloat();
Map<ArmorMaterial, String> overrideArmorMaterials = wrapper.readMap(
ew -> ew.readMappedEntity(ArmorMaterials::getById),
PacketWrapper::readString);
@@ -67,9 +87,59 @@ public interface TrimMaterial extends MappedEntity {
static void writeDirect(PacketWrapper<?> wrapper, TrimMaterial material) {
wrapper.writeString(material.getAssetName());
wrapper.writeMappedEntity(material.getIngredient());
wrapper.writeFloat(material.getItemModelIndex());
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21_4)) {
wrapper.writeFloat(material.getItemModelIndex());
}
wrapper.writeMap(material.getOverrideArmorMaterials(),
PacketWrapper::writeMappedEntity, PacketWrapper::writeString);
wrapper.writeComponent(material.getDescription());
}
static TrimMaterial decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
NBTCompound compound = (NBTCompound) nbt;
String assetName = compound.getStringTagValueOrThrow("asset_name");
ItemType ingredient = ItemTypes.getByName(compound.getStringTagValueOrThrow("ingredient"));
float itemModelIndex = version.isNewerThanOrEquals(ClientVersion.V_1_21_4)
? FALLBACK_ITEM_MODEL_INDEX : compound.getNumberTagOrThrow("item_model_index").getAsFloat();
NBTCompound overrideArmorMaterialsTag = compound.getCompoundTagOrNull("override_armor_materials");
Map<ArmorMaterial, String> overrideArmorMaterials;
if (overrideArmorMaterialsTag != null) {
overrideArmorMaterials = new HashMap<>();
for (Map.Entry<String, NBT> entry : overrideArmorMaterialsTag.getTags().entrySet()) {
ArmorMaterial material = ArmorMaterials.getByName(entry.getKey());
String override = ((NBTString) entry.getValue()).getValue();
overrideArmorMaterials.put(material, override);
}
} else {
overrideArmorMaterials = Collections.emptyMap();
}
Component description = AdventureSerializer.fromNbt(((NBTCompound) nbt).getTagOrThrow("description"));
return new StaticTrimMaterial(data, assetName, ingredient, itemModelIndex, overrideArmorMaterials, description);
}
static NBT encode(TrimMaterial material, ClientVersion version) {
NBTCompound overrideArmorMaterialsTag;
if (!material.getOverrideArmorMaterials().isEmpty()) {
overrideArmorMaterialsTag = new NBTCompound();
for (Map.Entry<ArmorMaterial, String> entry : material.getOverrideArmorMaterials().entrySet()) {
String materialName = entry.getKey().getName().toString();
NBTString overrideTag = new NBTString(entry.getValue());
overrideArmorMaterialsTag.setTag(materialName, overrideTag);
}
} else {
overrideArmorMaterialsTag = null;
}
NBTCompound compound = new NBTCompound();
compound.setTag("asset_name", new NBTString(material.getAssetName()));
compound.setTag("ingredient", new NBTString(material.getIngredient().getName().toString()));
if (version.isNewerThanOrEquals(ClientVersion.V_1_21_4)) {
compound.setTag("item_model_index", new NBTFloat(material.getItemModelIndex()));
}
if (overrideArmorMaterialsTag != null) {
compound.setTag("override_armor_materials", overrideArmorMaterialsTag);
}
compound.setTag("description", AdventureSerializer.toNbt(material.getDescription()));
return compound;
}
}
@@ -24,25 +24,26 @@ import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.ApiStatus;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static net.kyori.adventure.text.Component.translatable;
import static net.kyori.adventure.text.format.TextColor.color;
public class TrimMaterials {
public final class TrimMaterials {
private static final Map<String, TrimMaterial> TRIM_MATERIAL_MAP = new HashMap<>();
private static final Map<Byte, Map<Integer, TrimMaterial>> TRIM_MATERIAL_ID_MAP = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_trim_material_mappings");
private static final VersionedRegistry<TrimMaterial> REGISTRY = new VersionedRegistry<>(
"trim_material", "item/item_trim_material_mappings");
private TrimMaterials() {
}
@ApiStatus.Internal
public static TrimMaterial define(String key, ItemType ingredient, float itemModelIndex, int color) {
// darken own armor material - if present
Map<ArmorMaterial, String> overrideArmorMaterials = new HashMap<>(2);
@@ -56,68 +57,25 @@ public class TrimMaterials {
return define(key, key, ingredient, itemModelIndex, overrideArmorMaterials, description);
}
@ApiStatus.Internal
public static TrimMaterial define(
String key, String assetName, ItemType ingredient, float itemModelIndex,
Map<ArmorMaterial, String> overrideArmorMaterials, Component description
) {
TypesBuilderData data = TYPES_BUILDER.define(key);
TrimMaterial material = new TrimMaterial() {
@Override
public String getAssetName() {
return assetName;
}
@Override
public ItemType getIngredient() {
return ingredient;
}
@Override
public float getItemModelIndex() {
return itemModelIndex;
}
@Override
public Map<ArmorMaterial, String> getOverrideArmorMaterials() {
return overrideArmorMaterials;
}
@Override
public Component getDescription() {
return description;
}
@Override
public ResourceLocation getName() {
return data.getName();
}
@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof TrimMaterial) {
return this.getName().equals(((TrimMaterial) obj).getName());
}
return false;
}
};
MappingHelper.registerMapping(TYPES_BUILDER, TRIM_MATERIAL_MAP, TRIM_MATERIAL_ID_MAP, material);
return material;
return REGISTRY.define(key, data ->
new StaticTrimMaterial(data, assetName, ingredient, itemModelIndex, overrideArmorMaterials, description));
}
public static VersionedRegistry<TrimMaterial> getRegistry() {
return REGISTRY;
}
// with key
public static TrimMaterial getByName(String name) {
return TRIM_MATERIAL_MAP.get(name);
return REGISTRY.getByName(name);
}
public static TrimMaterial getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, TrimMaterial> idMap = TRIM_MATERIAL_ID_MAP.get((byte) index);
return idMap.get(id);
return REGISTRY.getById(version, id);
}
// Added in 1.19.4
@@ -132,15 +90,19 @@ public class TrimMaterials {
public static final TrimMaterial QUARTZ = define("quartz", ItemTypes.QUARTZ, 0.1f, 0xE3D4C4);
public static final TrimMaterial REDSTONE = define("redstone", ItemTypes.REDSTONE, 0.4f, 0x971607);
// added with 1.21.4
public static final TrimMaterial RESIN = define("resin", ItemTypes.RESIN_BRICK, 0.11f, 0xFC7812);
/**
* Returns an immutable view of the trim materials.
*
* @return Trim Materials
*/
public static Collection<TrimMaterial> values() {
return Collections.unmodifiableCollection(TRIM_MATERIAL_MAP.values());
return REGISTRY.getEntries();
}
static {
TYPES_BUILDER.unloadFileMappings();
REGISTRY.unloadMappings();
}
}
@@ -19,13 +19,15 @@
package com.github.retrooper.packetevents.protocol.item.trimpattern;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class StaticTrimPattern implements TrimPattern {
public class StaticTrimPattern extends AbstractMappedEntity implements TrimPattern {
private final ResourceLocation assetId;
private final ItemType templateItem;
@@ -36,6 +38,15 @@ public class StaticTrimPattern implements TrimPattern {
ResourceLocation assetId, ItemType templateItem,
Component description, boolean decal
) {
this(null, assetId, templateItem, description, decal);
}
public StaticTrimPattern(
@Nullable TypesBuilderData data,
ResourceLocation assetId, ItemType templateItem,
Component description, boolean decal
) {
super(data);
this.assetId = assetId;
this.templateItem = templateItem;
this.description = description;
@@ -43,18 +54,9 @@ public class StaticTrimPattern implements TrimPattern {
}
@Override
public ResourceLocation getName() {
throw new UnsupportedOperationException();
}
@Override
public int getId(ClientVersion version) {
throw new UnsupportedOperationException();
}
@Override
public boolean isRegistered() {
return false;
public TrimPattern copy(@Nullable TypesBuilderData newData) {
return new StaticTrimPattern(newData, this.assetId,
this.templateItem, this.description, this.decal);
}
@Override
@@ -78,18 +80,24 @@ public class StaticTrimPattern implements TrimPattern {
}
@Override
public boolean equals(Object obj) {
public boolean deepEquals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof StaticTrimPattern)) return false;
StaticTrimPattern pattern = (StaticTrimPattern) obj;
if (this.decal != pattern.decal) return false;
if (!this.assetId.equals(pattern.assetId)) return false;
if (!this.templateItem.equals(pattern.templateItem)) return false;
return this.description.equals(pattern.description);
if (!super.equals(obj)) return false;
StaticTrimPattern that = (StaticTrimPattern) obj;
if (this.decal != that.decal) return false;
if (!this.assetId.equals(that.assetId)) return false;
if (!this.templateItem.equals(that.templateItem)) return false;
return this.description.equals(that.description);
}
@Override
public int hashCode() {
return Objects.hash(this.assetId, this.templateItem, this.description, this.decal);
public int deepHashCode() {
return Objects.hash(super.hashCode(), this.assetId, this.templateItem, this.description, this.decal);
}
@Override
public String toString() {
return "StaticTrimPattern{assetId=" + this.assetId + ", templateItem=" + this.templateItem + ", description=" + this.description + ", decal=" + this.decal + '}';
}
}
@@ -20,12 +20,22 @@ package com.github.retrooper.packetevents.protocol.item.trimpattern;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
import com.github.retrooper.packetevents.protocol.mapper.DeepComparableEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTByte;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
public interface TrimPattern extends MappedEntity {
public interface TrimPattern extends MappedEntity, CopyableEntity<TrimPattern>, DeepComparableEntity {
ResourceLocation getAssetId();
@@ -36,7 +46,7 @@ public interface TrimPattern extends MappedEntity {
boolean isDecal();
static TrimPattern read(PacketWrapper<?> wrapper) {
return wrapper.readMappedEntityOrDirect(TrimPatterns::getById, TrimPattern::readDirect);
return wrapper.readMappedEntityOrDirect(TrimPatterns.getRegistry(), TrimPattern::readDirect);
}
static TrimPattern readDirect(PacketWrapper<?> wrapper) {
@@ -57,4 +67,24 @@ public interface TrimPattern extends MappedEntity {
wrapper.writeComponent(pattern.getDescription());
wrapper.writeBoolean(pattern.isDecal());
}
static TrimPattern decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
NBTCompound compound = (NBTCompound) nbt;
ResourceLocation assetId = new ResourceLocation(compound.getStringTagValueOrThrow("asset_id"));
ItemType templateItem = ItemTypes.getByName(compound.getStringTagValueOrThrow("template_item"));
Component description = AdventureSerializer.fromNbt(compound.getTagOrThrow("description"));
boolean decal = version.isNewerThanOrEquals(ClientVersion.V_1_20_2) && compound.getBoolean("decal");
return new StaticTrimPattern(data, assetId, templateItem, description, decal);
}
static NBT encode(TrimPattern pattern, ClientVersion version) {
NBTCompound compound = new NBTCompound();
compound.setTag("asset_id", new NBTString(pattern.getAssetId().toString()));
compound.setTag("template_item", new NBTString(pattern.getTemplateItem().getName().toString()));
compound.setTag("description", AdventureSerializer.toNbt(pattern.getDescription()));
if (version.isNewerThanOrEquals(ClientVersion.V_1_20_2)) {
compound.setTag("decal", new NBTByte(pattern.isDecal()));
}
return compound;
}
}
@@ -22,20 +22,19 @@ import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.ApiStatus;
import java.util.HashMap;
import java.util.Map;
public final class TrimPatterns {
public class TrimPatterns {
private static final VersionedRegistry<TrimPattern> REGISTRY = new VersionedRegistry<>(
"trim_pattern", "item/item_trim_pattern_mappings");
private static final Map<String, TrimPattern> PATTERN_TYPE_MAP = new HashMap<>();
private static final Map<Byte, Map<Integer, TrimPattern>> PATTERN_TYPE_ID_MAP = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_trim_pattern_mappings");
private TrimPatterns() {
}
@ApiStatus.Internal
public static TrimPattern define(String key) {
ResourceLocation assetId = ResourceLocation.minecraft(key);
ItemType templateItem = ItemTypes.getByName(assetId + "_armor_trim_smithing_template");
@@ -44,63 +43,25 @@ public class TrimPatterns {
return define(key, assetId, templateItem, description, decal);
}
@ApiStatus.Internal
public static TrimPattern define(
String key, ResourceLocation assetId, ItemType templateItem,
Component description, boolean decal
) {
TypesBuilderData data = TYPES_BUILDER.define(key);
TrimPattern pattern = new TrimPattern() {
@Override
public ResourceLocation getAssetId() {
return assetId;
}
@Override
public ItemType getTemplateItem() {
return templateItem;
}
@Override
public Component getDescription() {
return description;
}
@Override
public boolean isDecal() {
return decal;
}
@Override
public ResourceLocation getName() {
return data.getName();
}
@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof TrimPattern) {
return this.getName().equals(((TrimPattern) obj).getName());
}
return false;
}
};
MappingHelper.registerMapping(TYPES_BUILDER, PATTERN_TYPE_MAP, PATTERN_TYPE_ID_MAP, pattern);
return pattern;
return REGISTRY.define(key, data ->
new StaticTrimPattern(data, assetId, templateItem, description, decal));
}
public static VersionedRegistry<TrimPattern> getRegistry() {
return REGISTRY;
}
// with key
public static TrimPattern getByName(String name) {
return PATTERN_TYPE_MAP.get(name);
return REGISTRY.getByName(name);
}
public static TrimPattern getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, TrimPattern> idMap = PATTERN_TYPE_ID_MAP.get((byte) index);
return idMap.get(id);
return REGISTRY.getById(version, id);
}
// Added in 1.19.4
@@ -128,6 +89,6 @@ public class TrimPatterns {
public static final TrimPattern FLOW = define("flow");
static {
TYPES_BUILDER.unloadFileMappings();
REGISTRY.unloadMappings();
}
}
@@ -18,30 +18,42 @@
package com.github.retrooper.packetevents.protocol.item.type;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.component.StaticComponentMap;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes.ItemAttribute;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
public interface ItemType extends MappedEntity {
int getMaxAmount();
int getMaxDurability();
boolean isMusicDisc();
default boolean isMusicDisc() {
return this.hasAttribute(ItemAttribute.MUSIC_DISC);
}
ItemType getCraftRemainder();
@Nullable
StateType getPlacedType();
Set<ItemTypes.ItemAttribute> getAttributes();
Set<ItemAttribute> getAttributes();
boolean hasAttribute(ItemTypes.ItemAttribute attribute);
default boolean hasAttribute(ItemAttribute attribute) {
return this.getAttributes().contains(attribute);
}
default StaticComponentMap getComponents() {
return this.getComponents(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
}
default StaticComponentMap getComponents(ClientVersion clientVersion) {
return StaticComponentMap.EMPTY;
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,136 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.item.type;
import com.github.retrooper.packetevents.protocol.component.StaticComponentMap;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes.ItemAttribute;
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.Nullable;
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
public class StaticItemType extends AbstractMappedEntity implements ItemType {
private final int maxAmount;
private final int maxDurability;
private final ItemType craftRemainder;
private final @Nullable StateType placedType;
private final Set<ItemAttribute> attributes;
private final Map<ClientVersion, StaticComponentMap> components;
StaticItemType(
TypesBuilderData data,
int maxAmount,
int maxDurability,
ItemType craftRemainder,
@Nullable StateType placedType,
Set<ItemAttribute> attributes
) {
super(data);
this.maxAmount = maxAmount;
this.maxDurability = maxDurability;
this.craftRemainder = craftRemainder;
this.placedType = placedType;
this.attributes = attributes;
this.components = new EnumMap<>(ClientVersion.class);
}
@Override
public int getMaxAmount() {
return this.maxAmount;
}
@Override
public int getMaxDurability() {
return this.maxDurability;
}
@Override
public ItemType getCraftRemainder() {
return this.craftRemainder;
}
@Override
public @Nullable StateType getPlacedType() {
return this.placedType;
}
@Override
public Set<ItemAttribute> getAttributes() {
return this.attributes;
}
@Override
public StaticComponentMap getComponents(ClientVersion version) {
if (!version.isRelease()) {
throw new IllegalArgumentException("Unsupported version for "
+ "getting components of " + this.getName() + ": " + version);
}
return this.components.getOrDefault(version, StaticComponentMap.SHARED_ITEM_COMPONENTS);
}
void setComponents(ClientVersion version, StaticComponentMap components) {
if (this.components.containsKey(version)) {
throw new IllegalStateException("Components are already defined for "
+ this.getName() + " in version " + version);
} else if (!version.isRelease()) {
throw new IllegalArgumentException("Unsupported version for "
+ "setting components of " + this.getName() + ": " + version);
}
this.components.put(version, components);
}
// internal, only used for checking wether
// component definition is present during startup
boolean hasComponents(ClientVersion version) {
return this.components.containsKey(version);
}
// fills holes in the base component mappings
void fillComponents() {
StaticComponentMap lastComponents = null;
for (ClientVersion version : ClientVersion.values()) {
if (!version.isRelease()) {
continue;
}
StaticComponentMap components = this.components.get(version);
if (components == null) {
if (lastComponents != null) {
this.components.put(version, lastComponents);
}
continue;
}
if (lastComponents == null) {
// also fill backwards
for (ClientVersion beforeVersion : ClientVersion.values()) {
if (beforeVersion == version) {
break;
}
this.components.put(beforeVersion, components);
}
}
lastComponents = components;
}
}
}
@@ -0,0 +1,84 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.mapper;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public abstract class AbstractMappedEntity implements MappedEntity {
protected final @Nullable TypesBuilderData data;
protected AbstractMappedEntity(@Nullable TypesBuilderData data) {
this.data = data;
}
public @Nullable TypesBuilderData getRegistryData() {
return this.data;
}
@Override
public ResourceLocation getName() {
if (this.data != null) {
return this.data.getName();
}
throw new UnsupportedOperationException();
}
@Override
public int getId(ClientVersion version) {
if (this.data != null) {
return this.data.getId(version);
}
throw new UnsupportedOperationException();
}
@Override
public boolean isRegistered() {
return this.data != null;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof AbstractMappedEntity)) return false;
AbstractMappedEntity that = (AbstractMappedEntity) obj;
if (this.data != null && that.data != null) {
return this.data.getName().equals(that.data.getName());
}
return false;
}
@Override
public int hashCode() {
if (this.data != null) {
return Objects.hashCode(this.data.getName());
}
return super.hashCode();
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "[" + (this.data == null ? this.hashCode() : this.data.getName()) + ']';
}
}
@@ -0,0 +1,27 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.mapper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import org.jetbrains.annotations.Nullable;
public interface CopyableEntity<T extends MappedEntity> {
T copy(@Nullable TypesBuilderData newData);
}
@@ -0,0 +1,26 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 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.mapper;
public interface DeepComparableEntity {
boolean deepEquals(Object obj);
int deepHashCode();
}
Loaded 100 of 436 files, more files were not shown because too many files have changed in this diff. Show more