Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab8faf358c | ||
|
|
243ce3c5dd | ||
|
|
d4762195f9 | ||
|
|
121e1615b6 | ||
|
|
350d33ae6f | ||
|
|
d4f7bced86 | ||
|
|
8037e659a8 | ||
|
|
28c7849252 | ||
|
|
cb277bf16a | ||
|
|
0612e1e188 | ||
|
|
7a9f83129e | ||
|
|
a17e5f13a7 | ||
|
|
02a565bf39 | ||
|
|
f1d7d5ac81 | ||
|
|
a1663f5a03 | ||
|
|
909492cfae | ||
|
|
a3b4cc21f5 | ||
|
|
402ebd729e | ||
|
|
349b5dc110 | ||
|
|
c778cc3368 | ||
|
|
26e5aab84e | ||
|
|
79da4e1bc4 | ||
|
|
51b550ca5e | ||
|
|
2877b74c42 | ||
|
|
c67d1a86c5 | ||
|
|
5cf9b34fd2 | ||
|
|
99acbe4960 | ||
|
|
2bf64b6107 | ||
|
|
4e86af8754 | ||
|
|
6bf639f18a | ||
|
|
9a7bb17459 | ||
|
|
6b84c683ee | ||
|
|
dc015dc457 | ||
|
|
fd7bc84cd5 | ||
|
|
9fd5b3b912 | ||
|
|
a2d259af58 | ||
|
|
6cc21a6d98 | ||
|
|
e105770dde | ||
|
|
68b7ee51dc | ||
|
|
a4a375f411 | ||
|
|
ae6b3d18a4 | ||
|
|
8763b0e77f | ||
|
|
2440b64981 | ||
|
|
ebe73587fe | ||
|
|
5b87ac4f61 | ||
|
|
d9a3f33199 | ||
|
|
9f44834514 | ||
|
|
314d4a2813 | ||
|
|
97fee0c898 | ||
|
|
bdc96a88cd | ||
|
|
af1691e6e5 | ||
|
|
e4058f7f15 | ||
|
|
7f0c922e10 | ||
|
|
453793eb60 | ||
|
|
015e7a4647 | ||
|
|
45c0c580f7 | ||
|
|
1c12a868c8 | ||
|
|
a3f22320d5 | ||
|
|
f4bb1dd8fc | ||
|
|
5203b3a376 | ||
|
|
fe66d743a9 | ||
|
|
1d1cf84c60 | ||
|
|
1c81aab994 | ||
|
|
52559f6fc8 | ||
|
|
06cc25bf23 | ||
|
|
86cf0d51ed | ||
|
|
5fbb052d6f | ||
|
|
b7021fcd1f | ||
|
|
64db7f13c6 | ||
|
|
20c9fdf634 | ||
|
|
a71035a157 | ||
|
|
b0002102e3 | ||
|
|
a3e65cfcbe | ||
|
|
edd9c5ce3d | ||
|
|
e918e6b10a | ||
|
|
f6c309fd18 | ||
|
|
322a99dbc4 | ||
|
|
6793dee0bc | ||
|
|
d33751dbb0 | ||
|
|
fa67de16a1 | ||
|
|
57fc21f411 | ||
|
|
9999ee3b4a | ||
|
|
4a90cadeb1 | ||
|
|
048903f33f | ||
|
|
3fa5eaf2a3 | ||
|
|
93bd6d5ac9 | ||
|
|
aa5535615c | ||
|
|
9ccd85178d | ||
|
|
14fd279c06 | ||
|
|
6df845324b | ||
|
|
c3f233ca61 | ||
|
|
ed4f018b34 | ||
|
|
ef4bc1c02e | ||
|
|
ca725b68a5 | ||
|
|
40f7463e93 | ||
|
|
7778768c30 | ||
|
|
6a6be44ab2 | ||
|
|
fe67c23ad4 | ||
|
|
c09348d4f7 | ||
|
|
e04cd2108f | ||
|
|
39f0dee9f1 | ||
|
|
9b9ae8d36c | ||
|
|
fc934195de | ||
|
|
6c4db8029b | ||
|
|
c4ce7b7a87 | ||
|
|
b751c63625 | ||
|
|
31ac149b42 | ||
|
|
2f45e9e469 | ||
|
|
7b152ff264 | ||
|
|
e9eb441a1c | ||
|
|
55c1093783 | ||
|
|
963ec4e978 | ||
|
|
26c30f46e7 | ||
|
|
c2cdafb17f | ||
|
|
22060a9889 | ||
|
|
e1a54099a4 | ||
|
|
3fa6a0f69a | ||
|
|
676cb6c3ce | ||
|
|
a3063f0bcb | ||
|
|
c1520401b6 | ||
|
|
d988d0c684 | ||
|
|
e2283d6f4e | ||
|
|
ea56cfde04 | ||
|
|
16733e587e | ||
|
|
b247807f0f | ||
|
|
679aea8181 | ||
|
|
f0d499a008 | ||
|
|
b5320f2ae7 | ||
|
|
0fd0821a93 | ||
|
|
c7c1b9da17 | ||
|
|
d67d307788 | ||
|
|
c057f18914 | ||
|
|
7a5b425dbb | ||
|
|
9b22739977 | ||
|
|
12e0869e0a | ||
|
|
0039ab8704 | ||
|
|
7da389db14 | ||
|
|
1f85797768 | ||
|
|
3c55703718 | ||
|
|
e3734c2d94 | ||
|
|
afc571e331 | ||
|
|
4549d07a6c | ||
|
|
acc220729b | ||
|
|
b27f64c3b1 | ||
|
|
1f7a09a561 | ||
|
|
f0b15c3f94 | ||
|
|
cc03d3029d | ||
|
|
ef2d24c5ff | ||
|
|
6a69d1bcb4 | ||
|
|
ea1e11d690 | ||
|
|
65b51fa6f5 | ||
|
|
dae31cedf6 | ||
|
|
6179f997c9 | ||
|
|
8cb083c29a | ||
|
|
7dd2434ea9 | ||
|
|
66ca952a1d | ||
|
|
d6fef1180f | ||
|
|
32451165ba | ||
|
|
2c806b2d4e | ||
|
|
a8dadfdfff | ||
|
|
4524b4289c | ||
|
|
67010e8f11 | ||
|
|
245ee7699a | ||
|
|
25dfb3c5b9 | ||
|
|
52709f279b | ||
|
|
13d6437638 | ||
|
|
7a3505070e | ||
|
|
7d79603d08 | ||
|
|
7890a8ae97 | ||
|
|
c73e149f43 | ||
|
|
2f72766aac | ||
|
|
43d915d09c | ||
|
|
3444b07f6a | ||
|
|
3cfb1c5b3e | ||
|
|
150736b170 | ||
|
|
1f325a36d6 | ||
|
|
bdc8f6ef82 | ||
|
|
d365e4b949 | ||
|
|
4f4a3ba87b | ||
|
|
7ceeaa5f3f | ||
|
|
6f968275c1 | ||
|
|
245b7a0d2a | ||
|
|
13b1007c1c | ||
|
|
c164908aac | ||
|
|
1dd28f124a | ||
|
|
149483ef21 | ||
|
|
0a689564ce | ||
|
|
facc6bc074 | ||
|
|
41224c9faf | ||
|
|
14548f5679 | ||
|
|
d31d0b2487 | ||
|
|
1366872acb | ||
|
|
40fcd23d87 | ||
|
|
ba7d09ee91 | ||
|
|
b0fa4eb3b7 | ||
|
|
a8bf163355 | ||
|
|
f81730c689 | ||
|
|
a830fe8b63 | ||
|
|
05c116271e | ||
|
|
a08f89813e | ||
|
|
87fa35dea0 | ||
|
|
4ed644313a | ||
|
|
9fdd1615bd | ||
|
|
4ab220f189 | ||
|
|
adef187685 | ||
|
|
0e5a443e9b | ||
|
|
4961ad6e8d | ||
|
|
e056f1ca0a | ||
|
|
9d43fd7a35 | ||
|
|
45bafb37fe | ||
|
|
3554f3c6ac | ||
|
|
10d4cf4a9d | ||
|
|
7a1621aa37 | ||
|
|
22a5e67c69 | ||
|
|
8737ba218a | ||
|
|
98e0a35f0c | ||
|
|
21500f3cab | ||
|
|
750d87937a | ||
|
|
f78ffc9a5c | ||
|
|
48b789d268 | ||
|
|
a765347cba | ||
|
|
21fe4c920d | ||
|
|
d35505b83a | ||
|
|
930d1370ce | ||
|
|
4f01b9b2d6 | ||
|
|
79ae548463 | ||
|
|
08120db4b4 | ||
|
|
11d2d979cc | ||
|
|
3822609afe | ||
|
|
dd057ca20f | ||
|
|
42403c9f51 | ||
|
|
9eb6b11fe0 | ||
|
|
8c02988330 | ||
|
|
fd7223a259 | ||
|
|
b22560852f | ||
|
|
3498720e8c | ||
|
|
457aed221b | ||
|
|
d6fb68d8e7 | ||
|
|
0e6c15eb8b | ||
|
|
485124bfef | ||
|
|
3517d1fd00 | ||
|
|
7d80f08e1c | ||
|
|
ff0af88299 | ||
|
|
ba08959d39 | ||
|
|
050aab96f7 | ||
|
|
afcdfae5a1 | ||
|
|
8908cce24f | ||
|
|
31447cb6cf | ||
|
|
884ab800f5 | ||
|
|
6e87103114 | ||
|
|
c3b8c213d3 | ||
|
|
33f50a0eb9 | ||
|
|
3f309bc92d | ||
|
|
8315b8d335 | ||
|
|
902c99aca2 | ||
|
|
f4fc20a1c8 | ||
|
|
0690c45558 | ||
|
|
699fd9ac02 | ||
|
|
b01db5ca2a | ||
|
|
4fdc9c67ad | ||
|
|
395ed0d58e | ||
|
|
bcad08260c | ||
|
|
06be6d52b2 | ||
|
|
7ec896b8b0 | ||
|
|
2717a94db5 | ||
|
|
2ea20e3d19 | ||
|
|
94d939ba67 | ||
|
|
620af0aec0 | ||
|
|
2299d82b92 | ||
|
|
25dbe61f64 | ||
|
|
ecd183156a | ||
|
|
3f0cb7e799 | ||
|
|
7b209c9733 | ||
|
|
dfd490afc8 | ||
|
|
92564a3a09 | ||
|
|
172cfceed7 |
No files matched your search
+1
-3
@@ -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]
|
||||
@@ -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,37 @@ 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
|
||||
@@ -1,33 +1,43 @@
|
||||
# packetevents
|
||||
<!--suppress HtmlDeprecatedAttribute -->
|
||||
<div align="center">
|
||||
<h2><i>packetevents</i></h2>
|
||||
<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>
|
||||
PacketEvents is emerging as a strong contender in the realm of Minecraft packet processing libraries. Designed to simplify packet manipulation while delivering high performance, this powerful tool aims to demystify the complexities of projects utilizing packets. Imbued with versatility, PacketEvents supports various platforms such as Spigot, BungeeCord, Velocity, and Fabric.
|
||||
|
||||
[](https://github.com/retrooper/packetevents/blob/2.0/LICENSE) [](https://github.com/retrooper/packetevents/actions) [](https://discord.gg/prqzNg9tRU)
|
||||
<h3>Resources</h3>
|
||||
|
||||
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.
|
||||
- [Read documentation](https://docs.packetevents.com/)
|
||||
- [Getting Started](https://docs.packetevents.com/getting-started)
|
||||
- [JavaDocs](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)
|
||||
|
||||
### 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)
|
||||
<h3>Sponsors</h3>
|
||||
|
||||
### Setup
|
||||
[How to Setup PacketEvents](https://github.com/retrooper/packetevents/wiki/Depending-on-pre%E2%80%90built-PacketEvents)
|
||||
<i>Thanks to the following sponsors for supporting this project:</i>
|
||||
|
||||
### Examples / How to use PacketEvents
|
||||
[Example repository](https://github.com/retrooper/packetevents-example)
|
||||
<a href="https://pebblehost.com"><img src="https://pebblehost.com/src/img/logos/main-old.png" width=150><br>
|
||||
|
||||
### Sponsorships
|
||||
[](https://www.ej-technologies.com/products/jprofiler/overview.html)
|
||||
<a href="https://www.ej-technologies.com"><img src="https://www.ej-technologies.com/images/product_banners/jprofiler_small.png"><br>
|
||||
|
||||
### Statistics
|
||||
PacketEvents optionally collects statistics using [bStats](https://bstats.org/)\
|
||||
Check out our [bStats page](https://bstats.org/plugin/bukkit/packetevents/11327)
|
||||
<a href="https://github.com/radstevee"><img src="https://github.com/radstevee.png" width="50px" alt="radstevee"/></a><br>
|
||||
|
||||
### 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)\
|
||||
<h3>Credits</h3>
|
||||
|
||||
<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/)
|
||||
@@ -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()
|
||||
@@ -47,7 +48,11 @@ mappingCompression {
|
||||
compress("block/legacy_block_mappings.json")
|
||||
compress("block/modern_block_mappings.json")
|
||||
|
||||
compress("enchantment/enchantment_type_data.json")
|
||||
|
||||
compress("stats/statistics.json")
|
||||
|
||||
compress("world/biome_data.json")
|
||||
}
|
||||
|
||||
with<JsonArrayCompressionStrategy> {
|
||||
@@ -60,13 +65,19 @@ 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/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")
|
||||
@@ -77,6 +88,7 @@ mappingCompression {
|
||||
|
||||
compress("sound/sound_mappings.json")
|
||||
|
||||
compress("world/biome_mappings.json")
|
||||
compress("world/world_position_source_mappings.json")
|
||||
}
|
||||
|
||||
@@ -88,6 +100,8 @@ mappingCompression {
|
||||
compress("entity/legacy_entity_type_mappings.json")
|
||||
|
||||
compress("item/item_type_mappings.json")
|
||||
|
||||
compress("world/dimension_type_mappings.json")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+9
-7
@@ -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();
|
||||
}
|
||||
@@ -39,11 +39,11 @@ import java.net.InetSocketAddress;
|
||||
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 +55,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 +92,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;
|
||||
@@ -133,8 +133,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 +213,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
|
||||
|
||||
+17
-84
@@ -26,31 +26,21 @@ 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.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 +82,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) {
|
||||
|
||||
+7
-4
@@ -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
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -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
|
||||
V_1_21(767), V_1_21_1(767),
|
||||
//TODO UPDATE Add server version constant
|
||||
ERROR(-1, true);
|
||||
|
||||
|
||||
@@ -19,17 +19,38 @@
|
||||
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.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> {
|
||||
|
||||
@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 +62,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+80
-40
@@ -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();
|
||||
}
|
||||
}
|
||||
+77
-17
@@ -18,41 +18,101 @@
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.chatDecoration, this.overlayDecoration, this.narrationDecoration, this.narrationPriority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered() {
|
||||
return false;
|
||||
public String toString() {
|
||||
return "StaticChatType{chatDecoration=" + this.chatDecoration + ", overlayDecoration=" + this.overlayDecoration + ", narrationDecoration=" + this.narrationDecoration + ", narrationPriority=" + this.narrationPriority + '}';
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -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());
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -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());
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -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);
|
||||
|
||||
+19
@@ -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 + '}';
|
||||
}
|
||||
}
|
||||
+16
@@ -19,6 +19,8 @@
|
||||
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;
|
||||
|
||||
public interface ComponentType<T> extends MappedEntity {
|
||||
@@ -26,4 +28,18 @@ 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);
|
||||
|
||||
interface Decoder<T> {
|
||||
|
||||
T decode(NBT nbt, ClientVersion version);
|
||||
}
|
||||
|
||||
interface Encoder<T> {
|
||||
|
||||
NBT encode(T value, ClientVersion version);
|
||||
}
|
||||
}
|
||||
+26
-66
@@ -56,85 +56,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
|
||||
@@ -260,16 +226,10 @@ public class ComponentTypes {
|
||||
* @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> {}
|
||||
}
|
||||
+120
@@ -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();
|
||||
}
|
||||
}
|
||||
+31
@@ -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));
|
||||
}
|
||||
|
||||
+14
@@ -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 + '}';
|
||||
|
||||
+19
@@ -27,6 +27,7 @@ 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 {
|
||||
@@ -82,6 +83,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 "StaticComponentMap{empty=" + this.empty + ", delegate=" + this.delegate + '}';
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final Map<ComponentType<?>, Object> map = new HashMap<>();
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
|
||||
+3
-2
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+64
-16
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -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();
|
||||
|
||||
+30
-5
@@ -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;
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 + '}';
|
||||
}
|
||||
}
|
||||
+53
-5
@@ -1,14 +1,62 @@
|
||||
/*
|
||||
* 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.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> {
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
+88
@@ -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
|
||||
|
||||
+22
-1
@@ -18,11 +18,18 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.banner;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
|
||||
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> {
|
||||
|
||||
ResourceLocation getAssetId();
|
||||
|
||||
@@ -38,4 +45,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;
|
||||
}
|
||||
}
|
||||
+21
-49
@@ -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();
|
||||
}
|
||||
}
|
||||
+22
-21
@@ -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;
|
||||
@@ -43,32 +55,21 @@ public class StaticBannerPattern implements BannerPattern {
|
||||
return this.translationKey;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.assetId, this.translationKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.assetId, this.translationKey);
|
||||
public String toString() {
|
||||
return "StaticBannerPattern{assetId=" + this.assetId + ", translationKey='" + this.translationKey + '\'' + '}';
|
||||
}
|
||||
}
|
||||
+78
@@ -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 + '}';
|
||||
}
|
||||
}
|
||||
+175
@@ -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 + '}';
|
||||
}
|
||||
}
|
||||
+50
-1
@@ -18,7 +18,56 @@
|
||||
|
||||
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.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> {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
+45
-37
@@ -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();
|
||||
}
|
||||
}
|
||||
+106
@@ -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.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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 + "}";
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.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> {
|
||||
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());
|
||||
}
|
||||
}
|
||||
+35
-15
@@ -18,77 +18,93 @@
|
||||
|
||||
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;
|
||||
@@ -96,8 +112,12 @@ public class JukeboxSong {
|
||||
return this.description.equals(that.description);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.sound, this.description, this.lengthInSeconds, this.comparatorOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.sound, this.description, this.lengthInSeconds, this.comparatorOutput);
|
||||
public String toString() {
|
||||
return "JukeboxSong{sound=" + this.sound + ", description=" + this.description + ", lengthInSeconds=" + this.lengthInSeconds + ", comparatorOutput=" + this.comparatorOutput + '}';
|
||||
}
|
||||
}
|
||||
+96
@@ -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();
|
||||
}
|
||||
}
|
||||
+29
-25
@@ -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;
|
||||
@@ -40,6 +40,15 @@ public class StaticTrimMaterial implements TrimMaterial {
|
||||
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 +57,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
|
||||
@@ -87,20 +87,24 @@ public class StaticTrimMaterial implements TrimMaterial {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.assetName, this.ingredient, this.itemModelIndex, this.overrideArmorMaterials, this.description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.assetName, this.ingredient, this.itemModelIndex, this.overrideArmorMaterials, this.description);
|
||||
public String toString() {
|
||||
return "StaticTrimMaterial{assetName='" + this.assetName + '\'' + ", ingredient=" + this.ingredient + ", itemModelIndex=" + this.itemModelIndex + ", overrideArmorMaterials=" + this.overrideArmorMaterials + ", description=" + this.description + '}';
|
||||
}
|
||||
}
|
||||
+57
-2
@@ -22,14 +22,24 @@ import com.github.retrooper.packetevents.protocol.item.armormaterial.ArmorMateri
|
||||
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.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.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> {
|
||||
|
||||
String getAssetName();
|
||||
|
||||
@@ -46,7 +56,7 @@ 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) {
|
||||
@@ -72,4 +82,49 @@ public interface TrimMaterial extends MappedEntity {
|
||||
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 = 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()));
|
||||
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;
|
||||
}
|
||||
}
|
||||
+21
-62
@@ -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
|
||||
@@ -134,13 +92,14 @@ public class TrimMaterials {
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
+29
-23
@@ -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
|
||||
@@ -77,19 +79,23 @@ public class StaticTrimPattern implements TrimPattern {
|
||||
return this.decal;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.assetId, this.templateItem, this.description, this.decal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.assetId, this.templateItem, this.description, this.decal);
|
||||
public String toString() {
|
||||
return "StaticTrimPattern{assetId=" + this.assetId + ", templateItem=" + this.templateItem + ", description=" + this.description + ", decal=" + this.decal + '}';
|
||||
}
|
||||
}
|
||||
+31
-2
@@ -20,12 +20,21 @@ 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.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> {
|
||||
|
||||
ResourceLocation getAssetId();
|
||||
|
||||
@@ -36,7 +45,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 +66,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;
|
||||
}
|
||||
}
|
||||
+18
-57
@@ -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();
|
||||
}
|
||||
}
|
||||
+21
-25
@@ -45,9 +45,7 @@ import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
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.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -87,14 +85,15 @@ import static com.github.retrooper.packetevents.protocol.component.ComponentType
|
||||
import static com.github.retrooper.packetevents.protocol.component.ComponentTypes.WRITABLE_BOOK_CONTENT;
|
||||
|
||||
public class ItemTypes {
|
||||
private static final Map<String, ItemType> ITEM_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<Byte, Map<Integer, ItemType>> ITEM_TYPE_ID_MAP = new HashMap<>();
|
||||
|
||||
private static final VersionedRegistry<ItemType> REGISTRY = new VersionedRegistry<>(
|
||||
"item", "item/item_type_mappings");
|
||||
private static final Map<StateType, ItemType> HELD_TO_PLACED_MAP = new HashMap<>();
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_type_mappings");
|
||||
|
||||
private static final UUID TOOL_MODIFIER_ATTACK_DAMAGE_UUID = UUID.fromString("cb3f55d3-645c-4f38-a497-9c13a33db5cf");
|
||||
private static final UUID TOOL_MODIFIER_ATTACK_SPEED_UUID = UUID.fromString("fa233e1c-4180-4865-b01b-bcce9785aca3");
|
||||
|
||||
// <editor-fold desc="item type definitions" defaultstate="collapsed">
|
||||
public static final ItemType GILDED_BLACKSTONE = builder("gilded_blackstone").setMaxAmount(64).setPlacedType(StateTypes.GILDED_BLACKSTONE).build();
|
||||
public static final ItemType NETHER_BRICK_SLAB = builder("nether_brick_slab").setMaxAmount(64).setPlacedType(StateTypes.NETHER_BRICK_SLAB).build();
|
||||
public static final ItemType ANDESITE_SLAB = builder("andesite_slab").setMaxAmount(64).setPlacedType(StateTypes.ANDESITE_SLAB).build();
|
||||
@@ -1488,8 +1487,15 @@ public class ItemTypes {
|
||||
@Deprecated
|
||||
public static final ItemType POTTERY_SHARD_SKULL = builder("POTTERY_SHARD_SKULL").setMaxAmount(64).build();
|
||||
|
||||
// </editor-fold>
|
||||
|
||||
|
||||
public static VersionedRegistry<ItemType> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
public static Collection<ItemType> values() {
|
||||
return ITEM_TYPE_MAP.values();
|
||||
return REGISTRY.getEntries();
|
||||
}
|
||||
|
||||
public static Builder builder(String key) {
|
||||
@@ -1516,10 +1522,7 @@ public class ItemTypes {
|
||||
}
|
||||
StaticComponentMap components = mapBuilder.build();
|
||||
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
ItemType type = new ItemType() {
|
||||
private final int[] ids = data.getData();
|
||||
|
||||
return REGISTRY.define(key, data -> new ItemType() {
|
||||
@Override
|
||||
public int getMaxAmount() {
|
||||
return maxAmount;
|
||||
@@ -1537,8 +1540,7 @@ public class ItemTypes {
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
return ids[index];
|
||||
return data.getId(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1579,21 +1581,15 @@ public class ItemTypes {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, ITEM_TYPE_MAP, ITEM_TYPE_ID_MAP, type);
|
||||
return type;
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ItemType getByName(String name) {
|
||||
return ITEM_TYPE_MAP.get(name);
|
||||
public static @Nullable ItemType getByName(String name) {
|
||||
return REGISTRY.getByName(name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ItemType getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, ItemType> typeIdMap = ITEM_TYPE_ID_MAP.get((byte) index);
|
||||
return typeIdMap.getOrDefault(id, ItemTypes.AIR);
|
||||
public static @Nullable ItemType getById(ClientVersion version, int id) {
|
||||
return REGISTRY.getById(version, id);
|
||||
}
|
||||
|
||||
public static ItemType getTypePlacingState(StateType type) {
|
||||
@@ -1662,6 +1658,6 @@ public class ItemTypes {
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
+27
@@ -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);
|
||||
}
|
||||
+69
@@ -18,13 +18,18 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.mapper;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
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.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.IRegistry;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
@@ -54,6 +59,10 @@ public class MappedEntitySet<T> {
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public static <Z extends MappedEntity> MappedEntitySet<Z> createEmpty() {
|
||||
return new MappedEntitySet<>(new ArrayList<>(0));
|
||||
}
|
||||
|
||||
public static <Z extends MappedEntity> MappedEntitySet<Z> read(
|
||||
PacketWrapper<?> wrapper, BiFunction<ClientVersion, Integer, Z> getter) {
|
||||
int count = wrapper.readVarInt() - 1;
|
||||
@@ -80,4 +89,64 @@ public class MappedEntitySet<T> {
|
||||
wrapper.writeMappedEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
public static <Z extends MappedEntity> MappedEntitySet<Z> decode(
|
||||
NBT nbt, ClientVersion version, IRegistry<Z> registry) {
|
||||
if (nbt instanceof NBTString) {
|
||||
String tagName = ((NBTString) nbt).getValue();
|
||||
ResourceLocation tagKey = new ResourceLocation(tagName);
|
||||
return new MappedEntitySet<>(tagKey);
|
||||
}
|
||||
NBTList<?> listTag = (NBTList<?>) nbt;
|
||||
List<Z> list = new ArrayList<>(listTag.size());
|
||||
for (NBT tag : listTag.getTags()) {
|
||||
ResourceLocation tagKey = new ResourceLocation(((NBTString) tag).getValue());
|
||||
list.add(registry.getByName(tagKey));
|
||||
}
|
||||
return new MappedEntitySet<>(list);
|
||||
}
|
||||
|
||||
public static <Z extends MappedEntity> NBT encode(MappedEntitySet<Z> set, ClientVersion version) {
|
||||
if (set.tagKey != null) {
|
||||
return new NBTString(set.tagKey.toString());
|
||||
}
|
||||
|
||||
assert set.entities != null; // can't be null, verified in ctor
|
||||
NBTList<NBTString> listTag = NBTList.createStringList();
|
||||
for (Z entity : set.entities) {
|
||||
listTag.addTag(new NBTString(entity.getName().toString()));
|
||||
}
|
||||
return listTag;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.entities != null && this.entities.isEmpty();
|
||||
}
|
||||
|
||||
public @Nullable ResourceLocation getTagKey() {
|
||||
return this.tagKey;
|
||||
}
|
||||
|
||||
public @Nullable List<T> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof MappedEntitySet)) return false;
|
||||
MappedEntitySet<?> that = (MappedEntitySet<?>) obj;
|
||||
if (!Objects.equals(this.tagKey, that.tagKey)) return false;
|
||||
return Objects.equals(this.entities, that.entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.tagKey, this.entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MappedEntitySet{tagKey=" + this.tagKey + ", entities=" + this.entities + '}';
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,10 @@ public class NBTByte extends NBTNumber {
|
||||
this((byte) (value ? 1 : 0));
|
||||
}
|
||||
|
||||
public boolean getAsBool() {
|
||||
return this.value != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType<NBTByte> getType() {
|
||||
return NBTType.BYTE;
|
||||
|
||||
@@ -1,32 +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.nbt;
|
||||
|
||||
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class NBTLimiter {
|
||||
public interface NBTLimiter {
|
||||
|
||||
private final int max;
|
||||
@Nullable
|
||||
private Object byteBuf;
|
||||
private int bytes;
|
||||
int DEFAULT_MAX_SIZE = 2097152;
|
||||
|
||||
public NBTLimiter() {
|
||||
this.max = Integer.MAX_VALUE;
|
||||
static NBTLimiter noop() {
|
||||
return new NBTLimiter() {
|
||||
@Override
|
||||
public void increment(int amount) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkReadability(int length) {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public NBTLimiter(@NotNull Object byteBuf) {
|
||||
this.byteBuf = byteBuf;
|
||||
this.max = 2097152;
|
||||
static NBTLimiter forBuffer(final @NotNull Object byteBuf) {
|
||||
return forBuffer(byteBuf, DEFAULT_MAX_SIZE);
|
||||
}
|
||||
|
||||
public void increment(int amount) {
|
||||
bytes += amount;
|
||||
static NBTLimiter forBuffer(final @NotNull Object byteBuf, final int max) {
|
||||
return new NBTLimiter() {
|
||||
private int bytes;
|
||||
|
||||
if (bytes > max) throw new IllegalArgumentException("NBT size limit reached (" + bytes + "/" + max + ")");
|
||||
@Override
|
||||
public void increment(int amount) {
|
||||
bytes += amount;
|
||||
|
||||
if (bytes > max) throw new IllegalArgumentException("NBT size limit reached (" + bytes + "/" + max + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkReadability(int length) {
|
||||
if (length > ByteBufHelper.readableBytes(byteBuf)) throw new IllegalArgumentException("Length is too large: " + length + ", readable: " + ByteBufHelper.readableBytes(byteBuf));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void checkReadability(int length) {
|
||||
if(byteBuf != null && length > ByteBufHelper.readableBytes(byteBuf)) throw new IllegalArgumentException("Length is too large: " + length + ", readable: " + ByteBufHelper.readableBytes(byteBuf));
|
||||
}
|
||||
void increment(int amount);
|
||||
|
||||
void checkReadability(int length);
|
||||
|
||||
}
|
||||
+5
-1
@@ -150,7 +150,11 @@ public class NBTCodec {
|
||||
//PacketEvents end
|
||||
|
||||
public static NBT readNBTFromBuffer(Object byteBuf, ServerVersion serverVersion) {
|
||||
NBTLimiter limiter = new NBTLimiter(byteBuf);
|
||||
NBTLimiter limiter = NBTLimiter.forBuffer(byteBuf);
|
||||
return readNBTFromBuffer(byteBuf, serverVersion, limiter);
|
||||
}
|
||||
|
||||
public static NBT readNBTFromBuffer(Object byteBuf, ServerVersion serverVersion, NBTLimiter limiter) {
|
||||
if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_8)) {
|
||||
try {
|
||||
final boolean named = serverVersion.isOlderThan(ServerVersion.V_1_20_2);
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.nbt.serializer;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTLimiter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface NBTReader<T extends NBT, IN> {
|
||||
|
||||
default T deserializeTag(NBTLimiter limiter, IN from) throws IOException {
|
||||
return deserializeTag(limiter, from, true);
|
||||
}
|
||||
|
||||
T deserializeTag(NBTLimiter limiter, IN from, boolean named) throws IOException;
|
||||
|
||||
}
|
||||
+9
-15
@@ -27,7 +27,7 @@ import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class NBTSerializer<IN, OUT> {
|
||||
public class NBTSerializer<IN, OUT> implements NBTReader<NBT, IN>, NBTWriter<NBT, OUT> {
|
||||
|
||||
protected final IdReader<IN> idReader;
|
||||
protected final IdWriter<OUT> idWriter;
|
||||
@@ -47,10 +47,7 @@ public class NBTSerializer<IN, OUT> {
|
||||
this.nameWriter = nameWriter;
|
||||
}
|
||||
|
||||
public NBT deserializeTag(NBTLimiter limiter, IN from) throws IOException {
|
||||
return deserializeTag(limiter, from, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT deserializeTag(NBTLimiter limiter, IN from, boolean named) throws IOException {
|
||||
NBTType<?> type = readTagType(limiter, from);
|
||||
if (type == NBTType.END) {
|
||||
@@ -62,10 +59,7 @@ public class NBTSerializer<IN, OUT> {
|
||||
return readTag(limiter, from, type);
|
||||
}
|
||||
|
||||
public void serializeTag(OUT to, NBT tag) throws IOException {
|
||||
serializeTag(to, tag, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeTag(OUT to, NBT tag, boolean named) throws IOException {
|
||||
NBTType<?> type = tag.getType();
|
||||
writeTagType(to, type);
|
||||
@@ -95,7 +89,7 @@ public class NBTSerializer<IN, OUT> {
|
||||
typeWriters.put(type, typeWriter);
|
||||
}
|
||||
|
||||
protected NBTType<?> readTagType(NBTLimiter limiter, IN from) throws IOException {
|
||||
NBTType<?> readTagType(NBTLimiter limiter, IN from) throws IOException {
|
||||
int id = idReader.readId(limiter, from);
|
||||
NBTType<?> type = idToType.get(id);
|
||||
if (type == null) {
|
||||
@@ -104,11 +98,11 @@ public class NBTSerializer<IN, OUT> {
|
||||
return type;
|
||||
}
|
||||
|
||||
protected String readTagName(NBTLimiter limiter, IN from) throws IOException {
|
||||
String readTagName(NBTLimiter limiter, IN from) throws IOException {
|
||||
return nameReader.readName(limiter, from);
|
||||
}
|
||||
|
||||
protected NBT readTag(NBTLimiter limiter, IN from, NBTType<?> type) throws IOException {
|
||||
NBT readTag(NBTLimiter limiter, IN from, NBTType<?> type) throws IOException {
|
||||
TagReader<IN, ? extends NBT> f = typeReaders.get(type);
|
||||
if (f == null) {
|
||||
throw new IOException(MessageFormat.format("No reader registered for nbt type {0}", type));
|
||||
@@ -116,7 +110,7 @@ public class NBTSerializer<IN, OUT> {
|
||||
return f.readTag(limiter, from);
|
||||
}
|
||||
|
||||
protected void writeTagType(OUT stream, NBTType<?> type) throws IOException {
|
||||
void writeTagType(OUT stream, NBTType<?> type) throws IOException {
|
||||
int id = typeToId.getOrDefault(type, -1);
|
||||
if (id == -1) {
|
||||
throw new IOException(MessageFormat.format("Unknown nbt type {0}", type));
|
||||
@@ -124,12 +118,12 @@ public class NBTSerializer<IN, OUT> {
|
||||
idWriter.writeId(stream, id);
|
||||
}
|
||||
|
||||
protected void writeTagName(OUT stream, String name) throws IOException {
|
||||
void writeTagName(OUT stream, String name) throws IOException {
|
||||
nameWriter.writeName(stream, name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void writeTag(OUT stream, NBT tag) throws IOException {
|
||||
void writeTag(OUT stream, NBT tag) throws IOException {
|
||||
TagWriter<OUT, NBT> f = (TagWriter<OUT, NBT>) typeWriters.get(tag.getType());
|
||||
if (f == null) {
|
||||
throw new IOException(MessageFormat.format("No writer registered for nbt type {0}", tag.getType()));
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.nbt.serializer;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface NBTWriter<T extends NBT, OUT> {
|
||||
|
||||
default void serializeTag(OUT to, T tag) throws IOException {
|
||||
serializeTag(to, tag, true);
|
||||
}
|
||||
|
||||
void serializeTag(OUT to, NBT tag, boolean named) throws IOException;
|
||||
|
||||
}
|
||||
+698
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
* 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.nbt.serializer;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public final class SequentialNBTReader implements NBTReader<NBT, DataInputStream> {
|
||||
|
||||
public static final SequentialNBTReader INSTANCE = new SequentialNBTReader();
|
||||
|
||||
private static final Map<NBTType<?>, TagSkip> TAG_SKIPS = new HashMap<>(16);
|
||||
private static final Map<NBTType<?>, TagBinaryReader> TAG_BINARY_READERS = new HashMap<>(16);
|
||||
|
||||
@Override
|
||||
public NBT deserializeTag(NBTLimiter limiter, DataInputStream from, boolean named) throws IOException {
|
||||
NBTType<?> type = DefaultNBTSerializer.INSTANCE.readTagType(limiter, from);
|
||||
|
||||
if (named) {
|
||||
// skip name
|
||||
int len = from.readUnsignedShort();
|
||||
from.skipBytes(len);
|
||||
}
|
||||
|
||||
NBT nbt;
|
||||
if (type == NBTType.COMPOUND) {
|
||||
nbt = new Compound(from, limiter, () -> {});
|
||||
} else if (type == NBTType.LIST) {
|
||||
nbt = new List(from, limiter, () -> {});
|
||||
} else {
|
||||
nbt = DefaultNBTSerializer.INSTANCE.readTag(limiter, from, type);
|
||||
}
|
||||
|
||||
return nbt;
|
||||
}
|
||||
|
||||
private static void checkReadable(NBT lastRead) {
|
||||
if (lastRead == null) return;
|
||||
if (lastRead instanceof Iterator && ((Iterator<NBT>) lastRead).hasNext()) {
|
||||
throw new IllegalStateException("Previous nbt has not been read completely");
|
||||
}
|
||||
}
|
||||
|
||||
public static class Compound extends NBT implements Iterator<Map.Entry<String, NBT>>, Iterable<Map.Entry<String, NBT>>, Skippable, Closeable {
|
||||
|
||||
private final DataInputStream stream;
|
||||
private final NBTLimiter limiter;
|
||||
private final Runnable onComplete;
|
||||
private NBTType<?> nextType;
|
||||
private NBT lastRead;
|
||||
private boolean hasReadType;
|
||||
|
||||
private Compound(DataInputStream stream, NBTLimiter limiter, Runnable onComplete) {
|
||||
this.stream = stream;
|
||||
this.limiter = limiter;
|
||||
this.onComplete = onComplete;
|
||||
limiter.increment(48);
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType<?> getType() {
|
||||
return NBTType.COMPOUND;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return this == other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT copy() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
checkReadable(lastRead);
|
||||
if (!hasReadType) {
|
||||
try {
|
||||
nextType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, stream);
|
||||
hasReadType = true;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return nextType != NBTType.END;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<String, NBT> next() {
|
||||
if (!hasNext()) {
|
||||
throw new IllegalStateException("No more elements in compound");
|
||||
}
|
||||
|
||||
try {
|
||||
hasReadType = false;
|
||||
|
||||
String name = DefaultNBTSerializer.INSTANCE.readTagName(limiter, stream);
|
||||
|
||||
if (nextType == NBTType.COMPOUND) {
|
||||
lastRead = new Compound(stream, limiter, this::runCompleted);
|
||||
} else if (nextType == NBTType.LIST) {
|
||||
lastRead = new List(stream, limiter, this::runCompleted);
|
||||
} else {
|
||||
lastRead = DefaultNBTSerializer.INSTANCE.readTag(limiter, stream, nextType);
|
||||
runCompleted();
|
||||
}
|
||||
limiter.increment(36);
|
||||
|
||||
return new AbstractMap.SimpleEntry<>(name, lastRead);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void runCompleted() {
|
||||
if (!hasNext()) {
|
||||
onComplete.run();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, NBT>> iterator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skip() {
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return;
|
||||
|
||||
try {
|
||||
int len = stream.readUnsignedShort();
|
||||
stream.skipBytes(len);
|
||||
|
||||
TAG_SKIPS.get(nextType).skip(limiter, stream);
|
||||
limiter.increment(36);
|
||||
|
||||
TAG_SKIPS.get(NBTType.COMPOUND).skip(limiter, stream);
|
||||
|
||||
hasReadType = true;
|
||||
nextType = NBTType.END;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skipOne() {
|
||||
checkReadable(lastRead);
|
||||
|
||||
if (!hasNext()) return;
|
||||
|
||||
try {
|
||||
int len = stream.readUnsignedShort();
|
||||
stream.skipBytes(len);
|
||||
|
||||
TAG_SKIPS.get(nextType).skip(limiter, stream);
|
||||
limiter.increment(36);
|
||||
hasReadType = false;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
public NBTCompound readFully() {
|
||||
try {
|
||||
// skip last read
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return new NBTCompound();
|
||||
|
||||
NBTCompound compound = new NBTCompound();
|
||||
|
||||
// we have read a tag type, so we can start reading the tag
|
||||
do {
|
||||
String name = DefaultNBTSerializer.INSTANCE.readTagName(limiter, stream);
|
||||
NBT nbt = DefaultNBTSerializer.INSTANCE.readTag(limiter, stream, nextType);
|
||||
limiter.increment(36);
|
||||
compound.setTag(name, nbt);
|
||||
} while ((nextType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, stream)) != NBTType.END);
|
||||
|
||||
hasReadType = true;
|
||||
runCompleted();
|
||||
return compound;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] readFullyAsBytes() {
|
||||
try {
|
||||
// skip last read
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return new byte[] { 10, 0 }; // empty compound
|
||||
|
||||
try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(bytes)) {
|
||||
out.write(10); // compound type
|
||||
|
||||
do {
|
||||
out.write(DefaultNBTSerializer.INSTANCE.typeToId.get(nextType));
|
||||
|
||||
// name
|
||||
byte[] name = TAG_BINARY_READERS.get(NBTType.STRING).read(NBTLimiter.noop(), stream);
|
||||
limiter.increment(name.length * 2 + 28);
|
||||
out.write(name);
|
||||
|
||||
// nbt
|
||||
byte[] nbt = TAG_BINARY_READERS.get(nextType).read(limiter, stream);
|
||||
limiter.increment(36);
|
||||
|
||||
out.write(nbt);
|
||||
} while ((nextType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, stream)) != NBTType.END);
|
||||
|
||||
out.write(0);
|
||||
hasReadType = true;
|
||||
runCompleted();
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static class List extends NBT implements Iterator<NBT>, Iterable<NBT>, Skippable, Closeable {
|
||||
|
||||
private final DataInputStream stream;
|
||||
private final NBTLimiter limiter;
|
||||
private final Runnable onComplete;
|
||||
private final NBTType<?> listType;
|
||||
private NBT lastRead;
|
||||
public int remaining;
|
||||
|
||||
private List(DataInputStream stream, NBTLimiter limiter, Runnable onComplete) {
|
||||
this.stream = stream;
|
||||
this.limiter = limiter;
|
||||
this.onComplete = onComplete;
|
||||
limiter.increment(37);
|
||||
try {
|
||||
this.listType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, stream);
|
||||
this.remaining = stream.readInt();
|
||||
limiter.increment(remaining * 4);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType<?> getType() {
|
||||
return NBTType.LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return this == other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT copy() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return remaining > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT next() {
|
||||
checkReadable(lastRead);
|
||||
if (!hasNext()) {
|
||||
throw new IllegalStateException("No more elements in list");
|
||||
}
|
||||
|
||||
try {
|
||||
remaining--;
|
||||
if (listType == NBTType.COMPOUND) {
|
||||
lastRead = new Compound(stream, limiter, this::runCompleted);
|
||||
} else if (listType == NBTType.LIST) {
|
||||
lastRead = new List(stream, limiter, this::runCompleted);
|
||||
} else {
|
||||
lastRead = DefaultNBTSerializer.INSTANCE.readTag(limiter, stream, listType);
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
return lastRead;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void runCompleted() {
|
||||
if (!hasNext()) {
|
||||
onComplete.run();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<NBT> iterator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skip() {
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return;
|
||||
|
||||
try {
|
||||
TagSkip typeSkip = TAG_SKIPS.get(listType);
|
||||
for (int i = 0; i < remaining; i++) {
|
||||
typeSkip.skip(limiter, stream);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
remaining = 0;
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skipOne() {
|
||||
checkReadable(lastRead);
|
||||
|
||||
if (!hasNext()) return;
|
||||
|
||||
try {
|
||||
TAG_SKIPS.get(listType).skip(limiter, stream);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
remaining--;
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
public NBTList<NBT> readFully() {
|
||||
try {
|
||||
// skip last read
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return new NBTList<>((NBTType<NBT>) listType, 0);
|
||||
|
||||
NBTList<NBT> list = new NBTList<>((NBTType<NBT>) listType, remaining);
|
||||
for (int i = 0; i < remaining; i++) {
|
||||
list.addTag(DefaultNBTSerializer.INSTANCE.readTag(limiter, stream, listType));
|
||||
}
|
||||
|
||||
remaining = 0;
|
||||
runCompleted();
|
||||
return list;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] readFullyAsBinary() {
|
||||
try {
|
||||
// skip last read
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return new byte[] { 9 };
|
||||
|
||||
byte[] array = null;
|
||||
for (int i = 0; i < remaining; i++) {
|
||||
byte[] element = TAG_BINARY_READERS.get(listType).read(limiter, stream);
|
||||
|
||||
if (array == null) {
|
||||
array = new byte[2 + Integer.BYTES + remaining * element.length]; // all the remaining child tags will be of same size
|
||||
array[0] = 9; // list tag
|
||||
array[1] = DefaultNBTSerializer.INSTANCE.typeToId.get(listType).byteValue();
|
||||
|
||||
// write length
|
||||
array[2] = (byte) (remaining >>> 24);
|
||||
array[3] = (byte) (remaining >>> 16);
|
||||
array[4] = (byte) (remaining >>> 8);
|
||||
array[5] = (byte) remaining;
|
||||
}
|
||||
|
||||
System.arraycopy(element, 0, array, 1 + Integer.BYTES + i * element.length, element.length);
|
||||
}
|
||||
|
||||
remaining = 0;
|
||||
runCompleted();
|
||||
return array;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
interface Skippable {
|
||||
void skip();
|
||||
|
||||
void skipOne();
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface TagSkip {
|
||||
void skip(NBTLimiter limiter, DataInput in) throws IOException;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface TagBinaryReader {
|
||||
byte[] read(NBTLimiter limiter, DataInput in) throws IOException;
|
||||
}
|
||||
|
||||
static {
|
||||
TAG_SKIPS.put(NBTType.BYTE, (limiter, in) -> {
|
||||
limiter.increment(9);
|
||||
in.skipBytes(Byte.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.SHORT, (limiter, in) -> {
|
||||
limiter.increment(10);
|
||||
in.skipBytes(Short.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.INT, (limiter, in) -> {
|
||||
limiter.increment(12);
|
||||
in.skipBytes(Integer.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.LONG, (limiter, in) -> {
|
||||
limiter.increment(16);
|
||||
in.skipBytes(Long.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.FLOAT, (limiter, in) -> {
|
||||
limiter.increment(12);
|
||||
in.skipBytes(Float.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.DOUBLE, (limiter, in) -> {
|
||||
limiter.increment(16);
|
||||
in.skipBytes(Double.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.BYTE_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
int length = in.readInt();
|
||||
|
||||
limiter.checkReadability(length);
|
||||
limiter.increment(length);
|
||||
|
||||
in.skipBytes(length);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.STRING, (limiter, in) -> {
|
||||
limiter.increment(36);
|
||||
int length = in.readUnsignedShort();
|
||||
limiter.increment(length * 2);
|
||||
in.skipBytes(length);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.LIST, (limiter, in) -> {
|
||||
limiter.increment(37);
|
||||
NBTType<?> listType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, in);
|
||||
int length = in.readInt();
|
||||
limiter.increment(length * 4);
|
||||
for (int i = 0; i < length; i++) {
|
||||
TAG_SKIPS.get(listType).skip(limiter, in);
|
||||
}
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.COMPOUND, (limiter, in) -> {
|
||||
limiter.increment(48);
|
||||
NBTType<?> valueType;
|
||||
while ((valueType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, in)) != NBTType.END) {
|
||||
int utfLen = in.readUnsignedShort();
|
||||
in.skipBytes(utfLen);
|
||||
limiter.increment(36);
|
||||
TAG_SKIPS.get(valueType).skip(limiter, in);
|
||||
}
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.INT_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
int length = in.readInt();
|
||||
|
||||
limiter.checkReadability(length * 4);
|
||||
limiter.increment(length * 4);
|
||||
|
||||
in.skipBytes(length * Integer.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.LONG_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
int length = in.readInt();
|
||||
|
||||
limiter.checkReadability(length * 8);
|
||||
limiter.increment(length * 8);
|
||||
|
||||
in.skipBytes(length * Long.BYTES);
|
||||
});
|
||||
|
||||
TAG_BINARY_READERS.put(NBTType.BYTE, (limiter, in) -> {
|
||||
limiter.increment(9);
|
||||
return new byte[] { in.readByte() };
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.SHORT, (limiter, in) -> {
|
||||
limiter.increment(10);
|
||||
return new byte[] { in.readByte(), in.readByte() };
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.INT, (limiter, in) -> {
|
||||
limiter.increment(12);
|
||||
byte[] bytes = new byte[Integer.BYTES];
|
||||
in.readFully(bytes);
|
||||
return bytes;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.LONG, (limiter, in) -> {
|
||||
limiter.increment(16);
|
||||
byte[] bytes = new byte[Long.BYTES];
|
||||
in.readFully(bytes);
|
||||
return bytes;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.FLOAT, (limiter, in) -> {
|
||||
limiter.increment(12);
|
||||
byte[] bytes = new byte[Float.BYTES];
|
||||
in.readFully(bytes);
|
||||
return bytes;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.DOUBLE, (limiter, in) -> {
|
||||
limiter.increment(16);
|
||||
byte[] bytes = new byte[Double.BYTES];
|
||||
in.readFully(bytes);
|
||||
return bytes;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.BYTE_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
byte[] length = new byte[Integer.BYTES];
|
||||
in.readFully(length);
|
||||
int len = bytesToInt(length);
|
||||
|
||||
if (len >= 1 << 24)
|
||||
throw new IllegalArgumentException("Byte array length is too large: " + len);
|
||||
|
||||
limiter.checkReadability(len);
|
||||
limiter.increment(len);
|
||||
|
||||
byte[] array = new byte[Integer.BYTES + len];
|
||||
System.arraycopy(length, 0, array, 0, Integer.BYTES);
|
||||
in.readFully(array, Integer.BYTES, len);
|
||||
return array;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.STRING, (limiter, in) -> {
|
||||
limiter.increment(36);
|
||||
byte[] length = new byte[Short.BYTES];
|
||||
in.readFully(length);
|
||||
// read len
|
||||
short signedVal = (short) ((length[0] & 0xFF) << 8 | (length[1] & 0xFF));
|
||||
int len = signedVal >= 0 ? signedVal : 0x10000 + signedVal;
|
||||
|
||||
limiter.increment(len * 2);
|
||||
|
||||
byte[] array = new byte[Short.BYTES + len];
|
||||
System.arraycopy(length, 0, array, 0, Short.BYTES);
|
||||
in.readFully(array, Short.BYTES, len);
|
||||
return array;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.LIST, (limiter, in) -> {
|
||||
limiter.increment(37);
|
||||
byte type = in.readByte();
|
||||
NBTType<? extends NBT> nbtType = DefaultNBTSerializer.INSTANCE.idToType.get((int) type);
|
||||
|
||||
byte[] length = new byte[Integer.BYTES];
|
||||
in.readFully(length);
|
||||
int len = bytesToInt(length);
|
||||
|
||||
limiter.increment(len * 4);
|
||||
|
||||
byte[] array = null;
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte[] element = TAG_BINARY_READERS.get(nbtType).read(limiter, in);
|
||||
|
||||
if (array == null) {
|
||||
array = new byte[1 + Integer.BYTES + len * element.length]; // all the remaining child tags will be of same size
|
||||
array[0] = type;
|
||||
System.arraycopy(length, 0, array, 1, Integer.BYTES);
|
||||
}
|
||||
|
||||
System.arraycopy(element, 0, array, 1 + Integer.BYTES + i * element.length, element.length);
|
||||
}
|
||||
return array;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.COMPOUND, (limiter, in) -> {
|
||||
limiter.increment(48);
|
||||
try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(bytes)) {
|
||||
byte type;
|
||||
while ((type = in.readByte()) != 0) {
|
||||
out.writeByte(type);
|
||||
|
||||
// name
|
||||
byte[] name = TAG_BINARY_READERS.get(NBTType.STRING).read(NBTLimiter.noop(), in);
|
||||
limiter.increment(name.length * 2 + 28);
|
||||
out.write(name);
|
||||
|
||||
// nbt
|
||||
byte[] nbt = TAG_BINARY_READERS.get(DefaultNBTSerializer.INSTANCE.idToType.get((int) type)).read(limiter, in);
|
||||
limiter.increment(36);
|
||||
|
||||
out.write(nbt);
|
||||
}
|
||||
|
||||
out.write(0); // end
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.INT_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
byte[] length = new byte[Integer.BYTES];
|
||||
in.readFully(length);
|
||||
int len = bytesToInt(length);
|
||||
|
||||
limiter.checkReadability(len * 4);
|
||||
limiter.increment(len * 4);
|
||||
|
||||
byte[] array = new byte[Integer.BYTES + len * Integer.BYTES];
|
||||
System.arraycopy(length, 0, array, 0, Integer.BYTES);
|
||||
in.readFully(array, Integer.BYTES, len * Integer.BYTES);
|
||||
return array;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.LONG_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
byte[] length = new byte[Integer.BYTES];
|
||||
in.readFully(length);
|
||||
int len = bytesToInt(length);
|
||||
|
||||
limiter.checkReadability(len * 8);
|
||||
limiter.increment(len * 8);
|
||||
|
||||
byte[] array = new byte[Integer.BYTES + len * Long.BYTES];
|
||||
System.arraycopy(length, 0, array, 0, Integer.BYTES);
|
||||
in.readFully(array, Integer.BYTES, len * Long.BYTES);
|
||||
return array;
|
||||
});
|
||||
}
|
||||
|
||||
private static int bytesToInt(byte[] bytes) {
|
||||
return ((bytes[0] & 0xFF) << 24) |
|
||||
((bytes[1] & 0xFF) << 16) |
|
||||
((bytes[2] & 0xFF) << 8 ) |
|
||||
((bytes[3] & 0xFF));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,9 +18,14 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.particle;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.particle.data.ParticleData;
|
||||
import com.github.retrooper.packetevents.protocol.particle.type.ParticleType;
|
||||
import com.github.retrooper.packetevents.protocol.particle.type.ParticleTypes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class Particle<T extends ParticleData> {
|
||||
@@ -48,6 +53,24 @@ public class Particle<T extends ParticleData> {
|
||||
particle.getType().writeData(wrapper, particle.data);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Particle<?> decode(NBT nbt, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
NBT typeTag = compound.getTagOrThrow("type");
|
||||
ParticleType<?> type = typeTag instanceof NBTNumber
|
||||
? ParticleTypes.getById(version, ((NBTNumber) typeTag).getAsInt())
|
||||
: ParticleTypes.getByName(((NBTString) typeTag).getValue());
|
||||
ParticleData data = type.decodeData(compound, version);
|
||||
return new Particle<>((ParticleType<? super ParticleData>) type, data);
|
||||
}
|
||||
|
||||
public static <T extends ParticleData> NBT encode(Particle<T> particle, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("type", new NBTString(particle.type.getName().toString()));
|
||||
particle.type.encodeData(particle.getData(), version, compound);
|
||||
return compound;
|
||||
}
|
||||
|
||||
public ParticleType<T> getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
+16
-6
@@ -19,11 +19,13 @@
|
||||
package com.github.retrooper.packetevents.protocol.particle.data;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class ParticleBlockStateData extends ParticleData implements LegacyConvertible {
|
||||
|
||||
private WrappedBlockState blockState;
|
||||
|
||||
public ParticleBlockStateData(WrappedBlockState blockState) {
|
||||
@@ -42,11 +44,9 @@ public class ParticleBlockStateData extends ParticleData implements LegacyConver
|
||||
int blockID;
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
|
||||
blockID = wrapper.readVarInt();
|
||||
}
|
||||
else if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
|
||||
} else if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
|
||||
blockID = wrapper.readInt();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
blockID = wrapper.readVarInt();
|
||||
}
|
||||
return new ParticleBlockStateData(WrappedBlockState.getByGlobalId(wrapper.getServerVersion()
|
||||
@@ -56,12 +56,22 @@ public class ParticleBlockStateData extends ParticleData implements LegacyConver
|
||||
public static void write(PacketWrapper<?> wrapper, ParticleBlockStateData data) {
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
|
||||
wrapper.writeVarInt(data.getBlockState().getGlobalId());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
wrapper.writeInt(data.getBlockState().getGlobalId());
|
||||
}
|
||||
}
|
||||
|
||||
public static ParticleBlockStateData decode(NBTCompound compound, ClientVersion version) {
|
||||
String key = version.isNewerThanOrEquals(ClientVersion.V_1_20_5) ? "block_state" : "value";
|
||||
WrappedBlockState state = WrappedBlockState.decode(compound.getTagOrThrow(key), version);
|
||||
return new ParticleBlockStateData(state);
|
||||
}
|
||||
|
||||
public static void encode(ParticleBlockStateData data, ClientVersion version, NBTCompound compound) {
|
||||
String key = version.isNewerThanOrEquals(ClientVersion.V_1_20_5) ? "block_state" : "value";
|
||||
compound.setTag(key, WrappedBlockState.encode(data.blockState, version));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
|
||||
+35
@@ -19,8 +19,16 @@
|
||||
package com.github.retrooper.packetevents.protocol.particle.data;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
import static com.github.retrooper.packetevents.protocol.particle.data.ParticleDustData.decodeColor;
|
||||
import static com.github.retrooper.packetevents.util.MathUtil.floor;
|
||||
|
||||
public class ParticleColorData extends ParticleData {
|
||||
|
||||
private int color;
|
||||
@@ -40,6 +48,33 @@ public class ParticleColorData extends ParticleData {
|
||||
}
|
||||
}
|
||||
|
||||
public static ParticleColorData decode(NBTCompound compound, ClientVersion version) {
|
||||
int argb;
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_20_5)) {
|
||||
NBT colorTag = compound.getTagOrThrow("color");
|
||||
if (colorTag instanceof NBTNumber) {
|
||||
argb = ((NBTNumber) colorTag).getAsInt();
|
||||
} else {
|
||||
float[] color = decodeColor(colorTag);
|
||||
assert color.length == 4; // required by vanilla protocol
|
||||
argb = (floor(color[0] * 255f) << 24)
|
||||
| (floor(color[1] * 255f) << 16)
|
||||
| (floor(color[2] * 255f) << 8)
|
||||
| floor(color[3] * 255f);
|
||||
}
|
||||
} else {
|
||||
// no data to decode for <1.20.5
|
||||
argb = 0xFFFFFFFF;
|
||||
}
|
||||
return new ParticleColorData(argb);
|
||||
}
|
||||
|
||||
public static void encode(ParticleColorData data, ClientVersion version, NBTCompound compound) {
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_20_5)) {
|
||||
compound.setTag("color", new NBTInt(data.color));
|
||||
}
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return this.color;
|
||||
}
|
||||
|
||||
+35
@@ -20,9 +20,15 @@ package com.github.retrooper.packetevents.protocol.particle.data;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.color.Color;
|
||||
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.util.Vector3f;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
import static com.github.retrooper.packetevents.protocol.particle.data.ParticleDustData.decodeColor;
|
||||
import static com.github.retrooper.packetevents.protocol.particle.data.ParticleDustData.encodeColor;
|
||||
|
||||
public class ParticleDustColorTransitionData extends ParticleData {
|
||||
//0.01 - 4
|
||||
private float scale;
|
||||
@@ -49,6 +55,10 @@ public class ParticleDustColorTransitionData extends ParticleData {
|
||||
this.endBlue = endBlue;
|
||||
}
|
||||
|
||||
public ParticleDustColorTransitionData(float scale, float[] startRGB, float[] endRGB) {
|
||||
this(scale, startRGB[0], startRGB[1], startRGB[2], endRGB[0], endRGB[1], endRGB[2]);
|
||||
}
|
||||
|
||||
public ParticleDustColorTransitionData(float scale, Vector3f startRGB, Vector3f endRGB) {
|
||||
this(scale, startRGB.getX(), startRGB.getY(), startRGB.getZ(), endRGB.getX(), endRGB.getY(), endRGB.getZ());
|
||||
}
|
||||
@@ -145,6 +155,31 @@ public class ParticleDustColorTransitionData extends ParticleData {
|
||||
}
|
||||
}
|
||||
|
||||
public static ParticleDustColorTransitionData decode(NBTCompound compound, ClientVersion version) {
|
||||
String fromColorKey = "from_color";
|
||||
String toColorKey = "to_color";
|
||||
if (version.isOlderThan(ClientVersion.V_1_20_5)) {
|
||||
fromColorKey = "fromColor";
|
||||
toColorKey = "toColor";
|
||||
}
|
||||
float[] fromColor = decodeColor(compound.getTagOrThrow(fromColorKey));
|
||||
float[] toColor = decodeColor(compound.getTagOrThrow(toColorKey));
|
||||
float scale = compound.getNumberTagOrThrow("scale").getAsFloat();
|
||||
return new ParticleDustColorTransitionData(scale, fromColor, toColor);
|
||||
}
|
||||
|
||||
public static void encode(ParticleDustColorTransitionData data, ClientVersion version, NBTCompound compound) {
|
||||
String fromColorKey = "from_color";
|
||||
String toColorKey = "to_color";
|
||||
if (version.isOlderThan(ClientVersion.V_1_20_5)) {
|
||||
fromColorKey = "fromColor";
|
||||
toColorKey = "toColor";
|
||||
}
|
||||
compound.setTag(fromColorKey, encodeColor(null, data.startRed, data.startGreen, data.startBlue));
|
||||
compound.setTag(toColorKey, encodeColor(null, data.endRed, data.endGreen, data.endBlue));
|
||||
compound.setTag("scale", new NBTFloat(data.scale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
|
||||
+73
@@ -19,8 +19,20 @@
|
||||
package com.github.retrooper.packetevents.protocol.particle.data;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.color.Color;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTByteArray;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTFloat;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTIntArray;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTLongArray;
|
||||
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.Vector3f;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ParticleDustData extends ParticleData {
|
||||
//0.01 - 4
|
||||
@@ -38,6 +50,10 @@ public class ParticleDustData extends ParticleData {
|
||||
this.blue = blue;
|
||||
}
|
||||
|
||||
public ParticleDustData(float scale, float[] rgb) {
|
||||
this(scale, rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
public ParticleDustData(float scale, Vector3f rgb) {
|
||||
this(scale, rgb.getX(), rgb.getY(), rgb.getZ());
|
||||
}
|
||||
@@ -93,6 +109,63 @@ public class ParticleDustData extends ParticleData {
|
||||
wrapper.writeFloat(data.getScale());
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static float[] decodeColor(NBT tag) {
|
||||
// I hate how nbt works
|
||||
if (tag instanceof NBTList<?>) {
|
||||
NBTList<?> colorTagList = (NBTList<?>) tag;
|
||||
float first = ((NBTNumber) colorTagList.getTag(0)).getAsFloat();
|
||||
float second = ((NBTNumber) colorTagList.getTag(1)).getAsFloat();
|
||||
float third = ((NBTNumber) colorTagList.getTag(2)).getAsFloat();
|
||||
if (colorTagList.size() > 3) {
|
||||
float fourth = ((NBTNumber) colorTagList.getTag(3)).getAsFloat();
|
||||
return new float[]{first, second, third, fourth}; // ARGB
|
||||
}
|
||||
return new float[]{first, second, third}; // RGB
|
||||
} else if (tag instanceof NBTByteArray) {
|
||||
byte[] colors = ((NBTByteArray) tag).getValue();
|
||||
return colors.length > 3
|
||||
? new float[]{colors[0], colors[1], colors[2], colors[3]}
|
||||
: new float[]{colors[0], colors[1], colors[2]};
|
||||
} else if (tag instanceof NBTIntArray) {
|
||||
int[] colors = ((NBTIntArray) tag).getValue();
|
||||
return colors.length > 3
|
||||
? new float[]{colors[0], colors[1], colors[2], colors[3]}
|
||||
: new float[]{colors[0], colors[1], colors[2]};
|
||||
} else if (tag instanceof NBTLongArray) {
|
||||
long[] colors = ((NBTLongArray) tag).getValue();
|
||||
return colors.length > 3
|
||||
? new float[]{colors[0], colors[1], colors[2], colors[3]}
|
||||
: new float[]{colors[0], colors[1], colors[2]};
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported color nbt tag: " + tag);
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static NBT encodeColor(@Nullable Float alpha, float red, float green, float blue) {
|
||||
NBTList<NBTFloat> nbtList = new NBTList<>(NBTType.FLOAT,
|
||||
alpha == null ? 3 : 4);
|
||||
if (alpha != null) {
|
||||
nbtList.addTag(new NBTFloat(alpha));
|
||||
}
|
||||
nbtList.addTag(new NBTFloat(red));
|
||||
nbtList.addTag(new NBTFloat(green));
|
||||
nbtList.addTag(new NBTFloat(blue));
|
||||
return nbtList;
|
||||
}
|
||||
|
||||
public static ParticleDustData decode(NBTCompound compound, ClientVersion version) {
|
||||
NBT colorNBT = compound.getTagOrNull("color");
|
||||
float[] color = decodeColor(colorNBT);
|
||||
float scale = compound.getNumberTagOrThrow("scale").getAsFloat();
|
||||
return new ParticleDustData(scale, color);
|
||||
}
|
||||
|
||||
public static void encode(ParticleDustData data, ClientVersion version, NBTCompound compound) {
|
||||
compound.setTag("color", encodeColor(null, data.red, data.green, data.blue));
|
||||
compound.setTag("scale", new NBTFloat(data.scale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
|
||||
+13
-2
@@ -21,6 +21,7 @@ package com.github.retrooper.packetevents.protocol.particle.data;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
@@ -42,8 +43,7 @@ public class ParticleItemStackData extends ParticleData implements LegacyConvert
|
||||
public static ParticleItemStackData read(PacketWrapper<?> wrapper) {
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
|
||||
return new ParticleItemStackData(wrapper.readItemStack());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return new ParticleItemStackData(ItemStack.builder()
|
||||
.type(ItemTypes.getById(wrapper.getClientVersion(), wrapper.readVarInt()))
|
||||
.build());
|
||||
@@ -54,6 +54,17 @@ public class ParticleItemStackData extends ParticleData implements LegacyConvert
|
||||
wrapper.writeItemStack(data.getItemStack());
|
||||
}
|
||||
|
||||
public static ParticleItemStackData decode(NBTCompound compound, ClientVersion version) {
|
||||
String key = version.isNewerThanOrEquals(ClientVersion.V_1_20_5) ? "item" : "value";
|
||||
ItemStack stack = ItemStack.decode(compound.getTagOrThrow(key), version);
|
||||
return new ParticleItemStackData(stack);
|
||||
}
|
||||
|
||||
public static void encode(ParticleItemStackData data, ClientVersion version, NBTCompound compound) {
|
||||
String key = version.isNewerThanOrEquals(ClientVersion.V_1_20_5) ? "item" : "value";
|
||||
compound.setTag(key, ItemStack.encodeForParticle(data.itemStack, version));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
|
||||
+12
@@ -1,5 +1,8 @@
|
||||
package com.github.retrooper.packetevents.protocol.particle.data;
|
||||
|
||||
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.wrapper.PacketWrapper;
|
||||
|
||||
public class ParticleSculkChargeData extends ParticleData {
|
||||
@@ -26,6 +29,15 @@ public class ParticleSculkChargeData extends ParticleData {
|
||||
wrapper.writeFloat(data.getRoll());
|
||||
}
|
||||
|
||||
public static ParticleSculkChargeData decode(NBTCompound compound, ClientVersion version) {
|
||||
float roll = compound.getNumberTagOrThrow("roll").getAsFloat();
|
||||
return new ParticleSculkChargeData(roll);
|
||||
}
|
||||
|
||||
public static void encode(ParticleSculkChargeData data, ClientVersion version, NBTCompound compound) {
|
||||
compound.setTag("roll", new NBTFloat(data.roll));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
|
||||
+12
@@ -1,5 +1,8 @@
|
||||
package com.github.retrooper.packetevents.protocol.particle.data;
|
||||
|
||||
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 com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class ParticleShriekData extends ParticleData {
|
||||
@@ -26,6 +29,15 @@ public class ParticleShriekData extends ParticleData {
|
||||
wrapper.writeVarInt(data.getDelay());
|
||||
}
|
||||
|
||||
public static ParticleShriekData decode(NBTCompound compound, ClientVersion version) {
|
||||
int delay = compound.getNumberTagOrThrow("delay").getAsInt();
|
||||
return new ParticleShriekData(delay);
|
||||
}
|
||||
|
||||
public static void encode(ParticleShriekData data, ClientVersion version, NBTCompound compound) {
|
||||
compound.setTag("delay", new NBTInt(data.delay));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
|
||||
+23
@@ -21,6 +21,9 @@ package com.github.retrooper.packetevents.protocol.particle.data;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTIntArray;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.positionsource.PositionSource;
|
||||
import com.github.retrooper.packetevents.protocol.world.positionsource.PositionSourceType;
|
||||
@@ -152,6 +155,26 @@ public class ParticleVibrationData extends ParticleData {
|
||||
wrapper.writeVarInt(data.getTicks());
|
||||
}
|
||||
|
||||
public static ParticleVibrationData decode(NBTCompound compound, ClientVersion version) {
|
||||
Vector3i origin = version.isNewerThanOrEquals(ClientVersion.V_1_19) ? null :
|
||||
new Vector3i(compound.getTagOfTypeOrThrow("origin", NBTIntArray.class).getValue());
|
||||
PositionSource destination = PositionSource.decode(compound.getCompoundTagOrThrow("destination"), version);
|
||||
int arrivalInTicks = compound.getNumberTagOrThrow("arrival_in_ticks").getAsInt();
|
||||
return new ParticleVibrationData(origin, destination, arrivalInTicks);
|
||||
}
|
||||
|
||||
public static void encode(ParticleVibrationData data, ClientVersion version, NBTCompound compound) {
|
||||
if (version.isOlderThan(ClientVersion.V_1_19)) {
|
||||
Vector3i startPos = data.getStartingPosition();
|
||||
if (startPos != null) {
|
||||
compound.setTag("origin", new NBTIntArray(
|
||||
new int[]{startPos.x, startPos.y, startPos.z}));
|
||||
}
|
||||
}
|
||||
compound.setTag("destination", PositionSource.encode(data.source, version));
|
||||
compound.setTag("arrival_in_ticks", new NBTInt(data.ticks));
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete
|
||||
public Vector3i getStartingPosition() {
|
||||
return this.startingPosition;
|
||||
|
||||
+6
@@ -19,7 +19,9 @@
|
||||
package com.github.retrooper.packetevents.protocol.particle.type;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.particle.data.ParticleData;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -31,6 +33,10 @@ public interface ParticleType<T extends ParticleData> extends MappedEntity {
|
||||
|
||||
void writeData(PacketWrapper<?> wrapper, T data);
|
||||
|
||||
T decodeData(NBTCompound compound, ClientVersion version);
|
||||
|
||||
void encodeData(T data, ClientVersion version, NBTCompound compound);
|
||||
|
||||
@Deprecated
|
||||
default Function<PacketWrapper<?>, ParticleData> readDataFunction() {
|
||||
return this::readData;
|
||||
|
||||
+72
-15
@@ -18,6 +18,7 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.particle.type;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.particle.data.ParticleBlockStateData;
|
||||
import com.github.retrooper.packetevents.protocol.particle.data.ParticleColorData;
|
||||
import com.github.retrooper.packetevents.protocol.particle.data.ParticleData;
|
||||
@@ -33,6 +34,9 @@ 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.wrapper.PacketWrapper;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Reader;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Writer;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -47,13 +51,17 @@ public class ParticleTypes {
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("particle/particle_type_mappings");
|
||||
|
||||
public static ParticleType<ParticleData> define(String key) {
|
||||
return define(key, wrapper -> ParticleData.emptyData(), null);
|
||||
return define(
|
||||
key,
|
||||
wrapper -> ParticleData.emptyData(), null,
|
||||
(nbt, version) -> ParticleData.emptyData(), null
|
||||
);
|
||||
}
|
||||
|
||||
public static <T extends ParticleData> ParticleType<T> define(
|
||||
String key,
|
||||
PacketWrapper.Reader<T> reader,
|
||||
@Nullable PacketWrapper.Writer<T> writer
|
||||
Reader<T> reader, @Nullable Writer<T> writer,
|
||||
Decoder<T> decoder, @Nullable Encoder<T> encoder
|
||||
) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
ParticleType<T> particleType = new ParticleType<T>() {
|
||||
@@ -67,7 +75,21 @@ public class ParticleTypes {
|
||||
if (writer != null) {
|
||||
writer.accept(wrapper, data);
|
||||
} else if (!data.isEmpty()) {
|
||||
throw new UnsupportedOperationException("Trying to serialize non-empty data for " + this.getName());
|
||||
throw new UnsupportedOperationException("Trying to write non-empty data for " + this.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T decodeData(NBTCompound compound, ClientVersion version) {
|
||||
return decoder.decode(compound, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeData(T data, ClientVersion version, NBTCompound compound) {
|
||||
if (encoder != null) {
|
||||
encoder.encode(data, version, compound);
|
||||
} else if (!data.isEmpty()) {
|
||||
throw new UnsupportedOperationException("Trying to encode non-empty data for " + this.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,8 +129,12 @@ public class ParticleTypes {
|
||||
@Deprecated // Removed in 1.20.5
|
||||
public static final ParticleType<ParticleData> AMBIENT_ENTITY_EFFECT = define("ambient_entity_effect");
|
||||
public static final ParticleType<ParticleData> ANGRY_VILLAGER = define("angry_villager");
|
||||
public static final ParticleType<ParticleBlockStateData> BLOCK = define("block", ParticleBlockStateData::read, ParticleBlockStateData::write);
|
||||
public static final ParticleType<ParticleBlockStateData> BLOCK_MARKER = define("block_marker", ParticleBlockStateData::read, ParticleBlockStateData::write);
|
||||
public static final ParticleType<ParticleBlockStateData> BLOCK = define("block",
|
||||
ParticleBlockStateData::read, ParticleBlockStateData::write,
|
||||
ParticleBlockStateData::decode, ParticleBlockStateData::encode);
|
||||
public static final ParticleType<ParticleBlockStateData> BLOCK_MARKER = define("block_marker",
|
||||
ParticleBlockStateData::read, ParticleBlockStateData::write,
|
||||
ParticleBlockStateData::decode, ParticleBlockStateData::encode);
|
||||
public static final ParticleType<ParticleData> BUBBLE = define("bubble");
|
||||
public static final ParticleType<ParticleData> CLOUD = define("cloud");
|
||||
public static final ParticleType<ParticleData> CRIT = define("crit");
|
||||
@@ -119,23 +145,33 @@ public class ParticleTypes {
|
||||
public static final ParticleType<ParticleData> LANDING_LAVA = define("landing_lava");
|
||||
public static final ParticleType<ParticleData> DRIPPING_WATER = define("dripping_water");
|
||||
public static final ParticleType<ParticleData> FALLING_WATER = define("falling_water");
|
||||
public static final ParticleType<ParticleDustData> DUST = define("dust", ParticleDustData::read, ParticleDustData::write);
|
||||
public static final ParticleType<ParticleDustColorTransitionData> DUST_COLOR_TRANSITION = define("dust_color_transition", ParticleDustColorTransitionData::read, ParticleDustColorTransitionData::write);
|
||||
public static final ParticleType<ParticleDustData> DUST = define("dust",
|
||||
ParticleDustData::read, ParticleDustData::write,
|
||||
ParticleDustData::decode, ParticleDustData::encode);
|
||||
public static final ParticleType<ParticleDustColorTransitionData> DUST_COLOR_TRANSITION = define("dust_color_transition",
|
||||
ParticleDustColorTransitionData::read, ParticleDustColorTransitionData::write,
|
||||
ParticleDustColorTransitionData::decode, ParticleDustColorTransitionData::encode);
|
||||
public static final ParticleType<ParticleData> EFFECT = define("effect");
|
||||
public static final ParticleType<ParticleData> ELDER_GUARDIAN = define("elder_guardian");
|
||||
public static final ParticleType<ParticleData> ENCHANTED_HIT = define("enchanted_hit");
|
||||
public static final ParticleType<ParticleData> ENCHANT = define("enchant");
|
||||
public static final ParticleType<ParticleData> END_ROD = define("end_rod");
|
||||
public static final ParticleType<ParticleColorData> ENTITY_EFFECT = define("entity_effect", ParticleColorData::read, ParticleColorData::write);
|
||||
public static final ParticleType<ParticleColorData> ENTITY_EFFECT = define("entity_effect",
|
||||
ParticleColorData::read, ParticleColorData::write,
|
||||
ParticleColorData::decode, ParticleColorData::encode);
|
||||
public static final ParticleType<ParticleData> EXPLOSION_EMITTER = define("explosion_emitter");
|
||||
public static final ParticleType<ParticleData> EXPLOSION = define("explosion");
|
||||
public static final ParticleType<ParticleData> SONIC_BOOM = define("sonic_boom");
|
||||
public static final ParticleType<ParticleBlockStateData> FALLING_DUST = define("falling_dust", ParticleBlockStateData::read, ParticleBlockStateData::write);
|
||||
public static final ParticleType<ParticleBlockStateData> FALLING_DUST = define("falling_dust",
|
||||
ParticleBlockStateData::read, ParticleBlockStateData::write,
|
||||
ParticleBlockStateData::decode, ParticleBlockStateData::encode);
|
||||
public static final ParticleType<ParticleData> FIREWORK = define("firework");
|
||||
public static final ParticleType<ParticleData> FISHING = define("fishing");
|
||||
public static final ParticleType<ParticleData> FLAME = define("flame");
|
||||
public static final ParticleType<ParticleData> SCULK_SOUL = define("sculk_soul");
|
||||
public static final ParticleType<ParticleSculkChargeData> SCULK_CHARGE = define("sculk_charge", ParticleSculkChargeData::read, ParticleSculkChargeData::write);
|
||||
public static final ParticleType<ParticleSculkChargeData> SCULK_CHARGE = define("sculk_charge",
|
||||
ParticleSculkChargeData::read, ParticleSculkChargeData::write,
|
||||
ParticleSculkChargeData::decode, ParticleSculkChargeData::encode);
|
||||
public static final ParticleType<ParticleData> SCULK_CHARGE_POP = define("sculk_charge_pop");
|
||||
public static final ParticleType<ParticleData> SOUL_FIRE_FLAME = define("soul_fire_flame");
|
||||
public static final ParticleType<ParticleData> SOUL = define("soul");
|
||||
@@ -144,8 +180,12 @@ public class ParticleTypes {
|
||||
public static final ParticleType<ParticleData> COMPOSTER = define("composter");
|
||||
public static final ParticleType<ParticleData> HEART = define("heart");
|
||||
public static final ParticleType<ParticleData> INSTANT_EFFECT = define("instant_effect");
|
||||
public static final ParticleType<ParticleItemStackData> ITEM = define("item", ParticleItemStackData::read, ParticleItemStackData::write);
|
||||
public static final ParticleType<ParticleVibrationData> VIBRATION = define("vibration", ParticleVibrationData::read, ParticleVibrationData::write);
|
||||
public static final ParticleType<ParticleItemStackData> ITEM = define("item",
|
||||
ParticleItemStackData::read, ParticleItemStackData::write,
|
||||
ParticleItemStackData::decode, ParticleItemStackData::encode);
|
||||
public static final ParticleType<ParticleVibrationData> VIBRATION = define("vibration",
|
||||
ParticleVibrationData::read, ParticleVibrationData::write,
|
||||
ParticleVibrationData::decode, ParticleVibrationData::encode);
|
||||
public static final ParticleType<ParticleData> ITEM_SLIME = define("item_slime");
|
||||
public static final ParticleType<ParticleData> ITEM_SNOWBALL = define("item_snowball");
|
||||
public static final ParticleType<ParticleData> LARGE_SMOKE = define("large_smoke");
|
||||
@@ -197,7 +237,9 @@ public class ParticleTypes {
|
||||
public static final ParticleType<ParticleData> WAX_OFF = define("wax_off");
|
||||
public static final ParticleType<ParticleData> ELECTRIC_SPARK = define("electric_spark");
|
||||
public static final ParticleType<ParticleData> SCRAPE = define("scrape");
|
||||
public static final ParticleType<ParticleShriekData> SHRIEK = define("shriek", ParticleShriekData::read, ParticleShriekData::write);
|
||||
public static final ParticleType<ParticleShriekData> SHRIEK = define("shriek",
|
||||
ParticleShriekData::read, ParticleShriekData::write,
|
||||
ParticleShriekData::decode, ParticleShriekData::encode);
|
||||
//Added in 1.19.3, BUT REMOVED in 1.20, replaced with CHERRY_LEAVES
|
||||
public static final ParticleType<ParticleData> DRIPPING_CHERRY_LEAVES = define("dripping_cherry_leaves");
|
||||
public static final ParticleType<ParticleData> FALLING_CHERRY_LEAVES = define("falling_cherry_leaves");
|
||||
@@ -224,13 +266,16 @@ public class ParticleTypes {
|
||||
public static final ParticleType<ParticleData> ITEM_COBWEB = define("item_cobweb");
|
||||
public static final ParticleType<ParticleData> TRIAL_SPAWNER_DETECTION_OMINOUS = define("trial_spawner_detection_ominous");
|
||||
public static final ParticleType<ParticleData> VAULT_CONNECTION = define("vault_connection");
|
||||
public static final ParticleType<ParticleBlockStateData> DUST_PILLAR = define("dust_pillar", ParticleBlockStateData::read, ParticleBlockStateData::write);
|
||||
public static final ParticleType<ParticleBlockStateData> DUST_PILLAR = define("dust_pillar",
|
||||
ParticleBlockStateData::read, ParticleBlockStateData::write,
|
||||
ParticleBlockStateData::decode, ParticleBlockStateData::encode);
|
||||
public static final ParticleType<ParticleData> OMINOUS_SPAWNING = define("ominous_spawning");
|
||||
public static final ParticleType<ParticleData> RAID_OMEN = define("raid_omen");
|
||||
public static final ParticleType<ParticleData> TRIAL_OMEN = define("trial_omen");
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the particle types.
|
||||
*
|
||||
* @return Particle Types
|
||||
*/
|
||||
public static Collection<ParticleType<?>> values() {
|
||||
@@ -240,4 +285,16 @@ public class ParticleTypes {
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@FunctionalInterface
|
||||
public interface Decoder<T> {
|
||||
T decode(NBTCompound compound, ClientVersion version);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@FunctionalInterface
|
||||
public interface Encoder<T> {
|
||||
void encode(T value, ClientVersion version, NBTCompound compound);
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -95,7 +95,10 @@ public enum ClientVersion {
|
||||
* 1.20.5 and 1.20.6 have the same protocol version.
|
||||
*/
|
||||
V_1_20_5(766),
|
||||
|
||||
|
||||
/**
|
||||
* 1.21 and 1.21.1 have the same protocol version.
|
||||
*/
|
||||
V_1_21(767),
|
||||
//TODO UPDATE Add new protocol version field
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2022 retrooper and contributors
|
||||
* 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
|
||||
@@ -30,7 +30,12 @@ import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage_v1_16
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
|
||||
import com.github.retrooper.packetevents.protocol.world.Dimension;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionTypes;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
|
||||
import com.github.retrooper.packetevents.util.mappings.IRegistry;
|
||||
import com.github.retrooper.packetevents.util.mappings.IRegistryHolder;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChatMessage;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerCloseWindow;
|
||||
@@ -40,23 +45,25 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSe
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSystemChatMessage;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerTitle;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class User {
|
||||
public class User implements IRegistryHolder {
|
||||
|
||||
private final Object channel;
|
||||
private ConnectionState decoderState;
|
||||
private ConnectionState encoderState;
|
||||
private ClientVersion clientVersion;
|
||||
private final UserProfile profile;
|
||||
private int entityId = -1;
|
||||
private int minWorldHeight = 0;
|
||||
private int totalWorldHeight = 256;
|
||||
private List<NBTCompound> worldNBT;
|
||||
private Dimension dimension = new Dimension(0);
|
||||
|
||||
private DimensionType dimensionType = DimensionTypes.OVERWORLD;
|
||||
private final Map<ResourceLocation, IRegistry<?>> registries = new HashMap<>();
|
||||
|
||||
public User(Object channel,
|
||||
ConnectionState connectionState, ClientVersion clientVersion,
|
||||
@@ -68,6 +75,17 @@ public class User {
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Override
|
||||
public @Nullable IRegistry<?> getRegistry(ResourceLocation registryKey, ClientVersion version) {
|
||||
return this.registries.get(registryKey);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public void putRegistry(IRegistry<?> registry) {
|
||||
this.registries.put(registry.getRegistryKey(), registry);
|
||||
}
|
||||
|
||||
public Object getChannel() {
|
||||
return channel;
|
||||
}
|
||||
@@ -249,116 +267,105 @@ public class User {
|
||||
|
||||
//TODO sendTitle that is cross-version
|
||||
|
||||
// dimension type related methods
|
||||
|
||||
public int getMinWorldHeight() {
|
||||
return minWorldHeight;
|
||||
return this.getMinWorldHeight(null);
|
||||
}
|
||||
|
||||
public void setMinWorldHeight(int minWorldHeight) {
|
||||
this.minWorldHeight = minWorldHeight;
|
||||
public int getMinWorldHeight(@Nullable ClientVersion version) {
|
||||
if (version == null) {
|
||||
version = PacketEvents.getAPI().getInjector().isProxy() ? this.getClientVersion() :
|
||||
PacketEvents.getAPI().getServerManager().getVersion().toClientVersion();
|
||||
}
|
||||
return this.dimensionType.getMinY(version);
|
||||
}
|
||||
|
||||
public int getTotalWorldHeight() {
|
||||
return totalWorldHeight;
|
||||
return this.getTotalWorldHeight(null);
|
||||
}
|
||||
|
||||
public int getTotalWorldHeight(@Nullable ClientVersion version) {
|
||||
if (version == null) {
|
||||
version = PacketEvents.getAPI().getInjector().isProxy() ? this.getClientVersion() :
|
||||
PacketEvents.getAPI().getServerManager().getVersion().toClientVersion();
|
||||
}
|
||||
return this.dimensionType.getHeight(version);
|
||||
}
|
||||
|
||||
public DimensionType getDimensionType() {
|
||||
return this.dimensionType;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public void setDimensionType(DimensionType dimensionType) {
|
||||
this.dimensionType = dimensionType;
|
||||
}
|
||||
|
||||
// legacy dimension type related methods
|
||||
|
||||
@Deprecated
|
||||
public void setMinWorldHeight(int minWorldHeight) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setTotalWorldHeight(int totalWorldHeight) {
|
||||
this.totalWorldHeight = totalWorldHeight;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void switchDimensionType(ServerVersion version, Dimension dimension) {
|
||||
NBTCompound dimensionData = this.getWorldNBT(dimension);
|
||||
if (dimensionData != null) {
|
||||
NBTCompound worldNBT = dimensionData.getCompoundTagOrNull("element");
|
||||
if (worldNBT != null) {
|
||||
this.setMinWorldHeight(worldNBT.getNumberTagOrNull("min_y").getAsInt());
|
||||
this.setTotalWorldHeight(worldNBT.getNumberTagOrNull("height").getAsInt());
|
||||
return;
|
||||
} else {
|
||||
this.setDefaultWorldHeights(version, dimension);
|
||||
}
|
||||
}
|
||||
if (version.isOlderThan(ServerVersion.V_1_20_5)
|
||||
|| this.clientVersion.isOlderThan(ClientVersion.V_1_20_5)) {
|
||||
// hide this warning on 1.20.5, as the server does no longer send
|
||||
// vanilla datapack dimension type contents
|
||||
//
|
||||
// this 1.20.5 feature can be fully worked around with by clearing the
|
||||
// known packs sent by the client to the server durings config phase
|
||||
PacketEvents.getAPI().getLogger().warning(
|
||||
"No data was sent for dimension " + dimensionData + " to " + this.getName());
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setDefaultWorldHeights(ServerVersion version, Dimension dimension) {
|
||||
boolean extended = version.isNewerThanOrEquals(ServerVersion.V_1_18)
|
||||
&& "minecraft:overworld".equals(this.getWorldName(dimension));
|
||||
this.setDefaultWorldHeights(extended);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setDefaultWorldHeights(boolean extended) {
|
||||
this.minWorldHeight = extended ? -64 : 0;
|
||||
this.totalWorldHeight = extended ? 256 + 128 : 256;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setWorldNBT(NBTList<NBTCompound> worldNBT) {
|
||||
this.worldNBT = worldNBT.getTags();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Dimension getDimension() {
|
||||
return dimension;
|
||||
return Dimension.fromDimensionType(this.dimensionType, this, null);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setDimension(Dimension dimension) {
|
||||
this.dimension = dimension;
|
||||
this.dimensionType = dimension.asDimensionType(this, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public NBTCompound getWorldNBT(String worldName) {
|
||||
if (worldNBT == null) {
|
||||
return null;
|
||||
}
|
||||
for (NBTCompound compound : worldNBT) {
|
||||
if (compound.getStringTagOrNull("name").getValue().equals(worldName)) {
|
||||
return compound;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@Deprecated
|
||||
public @Nullable NBTCompound getWorldNBT(String worldName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public @Nullable NBTCompound getWorldNBT(int worldId) {
|
||||
if (this.worldNBT == null) {
|
||||
return null;
|
||||
}
|
||||
for (NBTCompound element : this.worldNBT) {
|
||||
if (element.getNumberTagOrNull("id").getAsInt() == worldId) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public @Nullable NBTCompound getWorldNBT(Dimension dimension) {
|
||||
String dimensionName = dimension.getDimensionName();
|
||||
if (!dimensionName.isEmpty()) {
|
||||
return this.getWorldNBT(dimensionName);
|
||||
}
|
||||
return this.getWorldNBT(dimension.getId());
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public @Nullable String getWorldName(int worldId) {
|
||||
if (this.worldNBT == null) {
|
||||
return null;
|
||||
}
|
||||
for (NBTCompound element : this.worldNBT) {
|
||||
if (element.getNumberTagOrNull("id").getAsInt() == worldId) {
|
||||
return element.getStringTagValueOrNull("name");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public @Nullable String getWorldName(Dimension dimension) {
|
||||
String dimensionName = dimension.getDimensionName();
|
||||
return dimensionName.isEmpty() ? this.getWorldName(dimension.getId()) : dimensionName;
|
||||
@Deprecated
|
||||
public String getWorldName(Dimension dimension) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -32,6 +32,7 @@ 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.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -152,8 +153,8 @@ public class RecipeSerializers {
|
||||
CookedRecipeData::read, CookedRecipeData::write, RecipeType.CAMPFIRE_COOKING);
|
||||
public static final RecipeSerializer<StoneCuttingRecipeData> STONECUTTING = define("stonecutting",
|
||||
StoneCuttingRecipeData::read, StoneCuttingRecipeData::write, RecipeType.STONECUTTING);
|
||||
@Deprecated
|
||||
public static final RecipeSerializer<SmithingRecipeData> SMITHING = define("smithing_transform",
|
||||
@ApiStatus.Obsolete
|
||||
public static final RecipeSerializer<SmithingRecipeData> SMITHING = define("smithing",
|
||||
ew -> SmithingRecipeData.read(ew, true),
|
||||
(ew, data) -> SmithingRecipeData.write(ew, data, true),
|
||||
RecipeType.SMITHING);
|
||||
|
||||
@@ -19,10 +19,18 @@
|
||||
package com.github.retrooper.packetevents.protocol.sound;
|
||||
|
||||
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.NBTNumber;
|
||||
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.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface Sound extends MappedEntity {
|
||||
|
||||
ResourceLocation getSoundId();
|
||||
@@ -48,4 +56,27 @@ public interface Sound extends MappedEntity {
|
||||
wrapper.writeIdentifier(sound.getSoundId());
|
||||
wrapper.writeOptional(sound.getRange(), PacketWrapper::writeFloat);
|
||||
}
|
||||
|
||||
static Sound decode(NBT nbt, ClientVersion version) {
|
||||
if (nbt instanceof NBTString) {
|
||||
return Sounds.getByNameOrCreate(((NBTString) nbt).getValue());
|
||||
}
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
ResourceLocation soundId = new ResourceLocation(((NBTCompound) nbt).getStringTagValueOrThrow("sound_id"));
|
||||
Float range = Optional.ofNullable(compound.getNumberTagOrNull("range"))
|
||||
.map(NBTNumber::getAsFloat).orElse(null);
|
||||
return new StaticSound(soundId, range);
|
||||
}
|
||||
|
||||
static NBT encode(Sound sound, ClientVersion version) {
|
||||
if (sound.isRegistered()) {
|
||||
return new NBTString(sound.getName().toString());
|
||||
}
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("sound_id", new NBTString(sound.getSoundId().toString()));
|
||||
if (sound.getRange() != null) {
|
||||
compound.setTag("range", new NBTFloat(sound.getRange()));
|
||||
}
|
||||
return compound;
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,14 @@ public class Sounds {
|
||||
return soundType;
|
||||
}
|
||||
|
||||
public static Sound getByNameOrCreate(String name) {
|
||||
Sound builtinSound = getByName(name);
|
||||
if (builtinSound == null) {
|
||||
return new StaticSound(new ResourceLocation(name), null);
|
||||
}
|
||||
return builtinSound;
|
||||
}
|
||||
|
||||
public static @Nullable Sound getByName(String name) {
|
||||
return SOUND_TYPE_MAP.get(name);
|
||||
}
|
||||
|
||||
+36
-27
@@ -21,12 +21,13 @@ package com.github.retrooper.packetevents.protocol.stats;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.serializer.SequentialNBTReader;
|
||||
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
|
||||
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -43,38 +44,46 @@ public class Statistics {
|
||||
|
||||
if (version.isOlderThan(ServerVersion.V_1_12_2)) {
|
||||
|
||||
NBTCompound mapping = MappingHelper.decompress("mappings/stats/statistics");
|
||||
try (final SequentialNBTReader.Compound mapping = MappingHelper.decompress("mappings/stats/statistics")) {
|
||||
mapping.skipOne(); //Skip version
|
||||
|
||||
if (version.isOlderThanOrEquals(ServerVersion.V_1_8_3)) {
|
||||
mapping = mapping.getCompoundTagOrThrow("V_1_8");
|
||||
} else {
|
||||
mapping = mapping.getCompoundTagOrThrow("V_1_12");
|
||||
}
|
||||
if (version.isOlderThanOrEquals(ServerVersion.V_1_8_3)) {
|
||||
mapping.skipOne(); // Skip to version 1.8
|
||||
}
|
||||
|
||||
for (Map.Entry<String, NBT> entry : mapping.getTags().entrySet()) {
|
||||
Component value = AdventureSerializer.parseComponent(((NBTString) entry.getValue()).getValue());
|
||||
SequentialNBTReader.Compound toLoad = (SequentialNBTReader.Compound) mapping.next();
|
||||
|
||||
Statistic statistic = new Statistic() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return entry.getKey();
|
||||
}
|
||||
for (Map.Entry<String, NBT> entry : toLoad) {
|
||||
String value = ((NBTString) entry.getValue()).getValue();
|
||||
Statistic statistic = new Statistic() {
|
||||
private Component cachedDisplay;
|
||||
|
||||
@Override
|
||||
public Component display() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Statistic) {
|
||||
return ((Statistic) obj).getId().equals(this.getId());
|
||||
@Override
|
||||
public String getId() {
|
||||
return entry.getKey();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
STATISTIC_MAP.put(entry.getKey(), statistic);
|
||||
@Override
|
||||
public Component display() {
|
||||
if (cachedDisplay == null) {
|
||||
cachedDisplay = AdventureSerializer.parseComponent(value);
|
||||
}
|
||||
return cachedDisplay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Statistic) {
|
||||
return ((Statistic) obj).getId().equals(this.getId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
STATISTIC_MAP.put(entry.getKey(), statistic);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Cannot load statistics mappings", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,21 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.world;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
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.player.User;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionTypeRef;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionTypes;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.IRegistry;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @deprecated use {@link com.github.retrooper.packetevents.protocol.world.dimension.DimensionType instead}
|
||||
*/
|
||||
@Deprecated
|
||||
public class Dimension {
|
||||
private int id;
|
||||
private NBTCompound attributes;
|
||||
@@ -40,6 +52,68 @@ public class Dimension {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Dimension(int id, NBTCompound attributes) {
|
||||
this.id = id;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public static Dimension fromDimensionTypeRef(DimensionTypeRef ref) {
|
||||
if (ref instanceof DimensionTypeRef.NameRef) {
|
||||
Dimension dimension = new Dimension(0);
|
||||
dimension.setDimensionName(ref.getName().toString());
|
||||
return dimension;
|
||||
} else if (ref instanceof DimensionTypeRef.IdRef) {
|
||||
return new Dimension(ref.getId());
|
||||
} else if (ref instanceof DimensionTypeRef.DataRef) {
|
||||
return new Dimension((NBTCompound) ref.getData());
|
||||
} else if (ref instanceof DimensionTypeRef.DirectRef) {
|
||||
return fromDimensionType(((DimensionTypeRef.DirectRef) ref).getDimensionType(),
|
||||
null, ((DimensionTypeRef.DirectRef) ref).getVersion());
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported DimensionTypeRef implementation: " + ref);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dimension fromDimensionType(
|
||||
com.github.retrooper.packetevents.protocol.world.dimension.DimensionType dimensionType,
|
||||
@Nullable User user, @Nullable ClientVersion version
|
||||
) {
|
||||
if (version == null) {
|
||||
version = user != null && PacketEvents.getAPI().getInjector().isProxy() ? user.getClientVersion() :
|
||||
PacketEvents.getAPI().getServerManager().getVersion().toClientVersion();
|
||||
}
|
||||
NBTCompound encodedType = (NBTCompound) com.github.retrooper.packetevents.protocol.world.dimension.DimensionType.encode(dimensionType, version);
|
||||
return new Dimension(dimensionType.getId(version), encodedType);
|
||||
}
|
||||
|
||||
public DimensionTypeRef asDimensionTypeRef() {
|
||||
if (this.attributes == null) {
|
||||
return new DimensionTypeRef.IdRef(this.id);
|
||||
} else if (this.attributes.size() > 1) {
|
||||
// seems to contain more than just "effects"
|
||||
return new DimensionTypeRef.DataRef(this.attributes);
|
||||
} else {
|
||||
ResourceLocation dimensionName = new ResourceLocation(this.getDimensionName());
|
||||
return new DimensionTypeRef.NameRef(dimensionName);
|
||||
}
|
||||
}
|
||||
|
||||
public com.github.retrooper.packetevents.protocol.world.dimension.DimensionType asDimensionType(
|
||||
@Nullable User user, @Nullable ClientVersion version) {
|
||||
IRegistry<com.github.retrooper.packetevents.protocol.world.dimension.DimensionType> registry = user != null
|
||||
? user.getRegistryOr(DimensionTypes.getRegistry()) : DimensionTypes.getRegistry();
|
||||
String dimName = this.getDimensionName();
|
||||
if (!dimName.isEmpty()) {
|
||||
return registry.getByName(new ResourceLocation(dimName));
|
||||
}
|
||||
if (version == null) {
|
||||
version = user != null && PacketEvents.getAPI().getInjector().isProxy() ? user.getClientVersion() :
|
||||
PacketEvents.getAPI().getServerManager().getVersion().toClientVersion();
|
||||
}
|
||||
return registry.getById(version, this.id);
|
||||
}
|
||||
|
||||
public String getDimensionName() {
|
||||
return getAttributes().getStringTagValueOrDefault("effects", "");
|
||||
}
|
||||
|
||||
+7
-2
@@ -18,6 +18,7 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.world;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -36,9 +37,13 @@ public class WorldBlockPosition {
|
||||
this.blockPosition = new Vector3i(x, y, z);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public WorldBlockPosition(@NotNull Dimension dimension, @NotNull Vector3i blockPosition) {
|
||||
this.world = new ResourceLocation(dimension.getDimensionName());
|
||||
this.blockPosition = blockPosition;
|
||||
this(new ResourceLocation(dimension.getDimensionName()), blockPosition);
|
||||
}
|
||||
|
||||
public WorldBlockPosition(@NotNull DimensionType dimensionType, @NotNull Vector3i blockPosition) {
|
||||
this(dimensionType.getName(), blockPosition);
|
||||
}
|
||||
|
||||
public ResourceLocation getWorld() {
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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.world.biome;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
|
||||
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.NBTFloat;
|
||||
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 net.kyori.adventure.util.Index;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.github.retrooper.packetevents.util.adventure.AdventureIndexUtil.indexValueOrThrow;
|
||||
|
||||
public interface Biome extends MappedEntity, CopyableEntity<Biome> {
|
||||
|
||||
boolean hasPrecipitation();
|
||||
|
||||
@ApiStatus.Obsolete(since = "1.19.3")
|
||||
Precipitation getPrecipitation();
|
||||
|
||||
float getTemperature();
|
||||
|
||||
TemperatureModifier getTemperatureModifier();
|
||||
|
||||
float getDownfall();
|
||||
|
||||
@ApiStatus.Obsolete(since = "1.19")
|
||||
@Nullable Category getCategory();
|
||||
|
||||
@ApiStatus.Obsolete(since = "1.18")
|
||||
@Nullable Float getDepth();
|
||||
|
||||
@ApiStatus.Obsolete(since = "1.18")
|
||||
@Nullable Float getScale();
|
||||
|
||||
BiomeEffects getEffects();
|
||||
|
||||
static Biome decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
float temperature = compound.getNumberTagOrThrow("temperature").getAsFloat();
|
||||
TemperatureModifier temperatureModifier =
|
||||
Optional.ofNullable(compound.getStringTagValueOrNull("temperature_modifier"))
|
||||
.map(id -> indexValueOrThrow(TemperatureModifier.ID_INDEX, id))
|
||||
.orElse(TemperatureModifier.NONE);
|
||||
float downfall = compound.getNumberTagOrThrow("downfall").getAsFloat();
|
||||
boolean precipitation = version.isNewerThan(ClientVersion.V_1_19_3) ? compound.getBoolean("has_precipitation") :
|
||||
indexValueOrThrow(Precipitation.ID_INDEX, compound.getStringTagValueOrThrow("precipitation")) != Precipitation.NONE;
|
||||
BiomeEffects effects = BiomeEffects.decode(compound.getTagOrThrow("effects"), version);
|
||||
|
||||
// removed with 1.19
|
||||
Category category = version.isNewerThanOrEquals(ClientVersion.V_1_19) ? null :
|
||||
indexValueOrThrow(Category.ID_INDEX, compound.getStringTagValueOrThrow("category"));
|
||||
Float depth = version.isNewerThanOrEquals(ClientVersion.V_1_18) ? null :
|
||||
compound.getNumberTagOrThrow("depth").getAsFloat();
|
||||
Float scale = version.isNewerThanOrEquals(ClientVersion.V_1_18) ? null :
|
||||
compound.getNumberTagOrThrow("scale").getAsFloat();
|
||||
|
||||
return new StaticBiome(data, precipitation, temperature, temperatureModifier, downfall,
|
||||
category, depth, scale, effects);
|
||||
}
|
||||
|
||||
static NBT encode(Biome biome, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
if (version.isNewerThan(ClientVersion.V_1_19_3)) {
|
||||
compound.setTag("has_precipitation", new NBTByte(biome.hasPrecipitation()));
|
||||
} else {
|
||||
compound.setTag("precipitation", new NBTString(biome.getPrecipitation().getId()));
|
||||
}
|
||||
compound.setTag("temperature", new NBTFloat(biome.getTemperature()));
|
||||
if (biome.getTemperatureModifier() != TemperatureModifier.NONE) {
|
||||
compound.setTag("temperature_modifier", new NBTString(biome.getTemperatureModifier().getId()));
|
||||
}
|
||||
compound.setTag("downfall", new NBTFloat(biome.getDownfall()));
|
||||
if (version.isOlderThan(ClientVersion.V_1_19)) {
|
||||
if (biome.getCategory() != null) {
|
||||
compound.setTag("category", new NBTString(biome.getCategory().getId()));
|
||||
}
|
||||
if (version.isOlderThan(ClientVersion.V_1_18)) {
|
||||
if (biome.getDepth() != null) {
|
||||
compound.setTag("depth", new NBTFloat(biome.getDepth()));
|
||||
}
|
||||
if (biome.getScale() != null) {
|
||||
compound.setTag("scale", new NBTFloat(biome.getScale()));
|
||||
}
|
||||
}
|
||||
}
|
||||
compound.setTag("effects", BiomeEffects.encode(biome.getEffects(), version));
|
||||
return compound;
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete(since = "1.19")
|
||||
enum Category {
|
||||
|
||||
NONE("none"),
|
||||
TAIGA("taiga"),
|
||||
EXTREME_HILLS("extreme_hills"),
|
||||
JUNGLE("jungle"),
|
||||
MESA("mesa"),
|
||||
PLAINS("plains"),
|
||||
SAVANNA("savanna"),
|
||||
ICY("icy"),
|
||||
THE_END("the_end"),
|
||||
BEACH("beach"),
|
||||
FOREST("forest"),
|
||||
OCEAN("ocean"),
|
||||
DESERT("desert"),
|
||||
RIVER("river"),
|
||||
SWAMP("swamp"),
|
||||
MUSHROOM("mushroom"),
|
||||
NETHER("nether"),
|
||||
UNDERGROUND("underground"),
|
||||
MOUNTAIN("mountain");
|
||||
|
||||
public static final Index<String, Category> ID_INDEX = Index.create(Category.class,
|
||||
Category::getId);
|
||||
private final String id;
|
||||
|
||||
Category(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete(since = "1.19.3")
|
||||
enum Precipitation {
|
||||
NONE("none"),
|
||||
RAIN("rain"),
|
||||
SNOW("snow");
|
||||
|
||||
public static final Index<String, Precipitation> ID_INDEX = Index.create(Precipitation.class,
|
||||
Precipitation::getId);
|
||||
private final String id;
|
||||
|
||||
Precipitation(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
enum TemperatureModifier {
|
||||
|
||||
NONE("none"),
|
||||
FROZEN("frozen");
|
||||
|
||||
public static final Index<String, TemperatureModifier> ID_INDEX = Index.create(
|
||||
TemperatureModifier.class, TemperatureModifier::getId);
|
||||
|
||||
private final String id;
|
||||
|
||||
TemperatureModifier(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
+432
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* 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.world.biome;
|
||||
|
||||
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.NBTDouble;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTFloat;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.particle.Particle;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.sound.Sound;
|
||||
import net.kyori.adventure.util.Index;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
import static com.github.retrooper.packetevents.util.adventure.AdventureIndexUtil.indexValueOrThrow;
|
||||
|
||||
public class BiomeEffects {
|
||||
|
||||
private final int fogColor;
|
||||
private final int waterColor;
|
||||
private final int waterFogColor;
|
||||
private final int skyColor;
|
||||
private final OptionalInt foliageColor;
|
||||
private final OptionalInt grassColor;
|
||||
private final GrassColorModifier grassColorModifier;
|
||||
private final Optional<ParticleSettings> particle;
|
||||
private final Optional<Sound> ambientSound;
|
||||
private final Optional<MoodSettings> moodSound;
|
||||
private final Optional<AdditionsSettings> additionsSound;
|
||||
private final Optional<MusicSettings> music;
|
||||
|
||||
public BiomeEffects(
|
||||
int fogColor, int waterColor, int waterFogColor, int skyColor,
|
||||
OptionalInt foliageColor, OptionalInt grassColor,
|
||||
GrassColorModifier grassColorModifier,
|
||||
Optional<ParticleSettings> particle,
|
||||
Optional<Sound> ambientSound,
|
||||
Optional<MoodSettings> moodSound,
|
||||
Optional<AdditionsSettings> additionsSound,
|
||||
Optional<MusicSettings> music
|
||||
) {
|
||||
this.fogColor = fogColor;
|
||||
this.waterColor = waterColor;
|
||||
this.waterFogColor = waterFogColor;
|
||||
this.skyColor = skyColor;
|
||||
this.foliageColor = foliageColor;
|
||||
this.grassColor = grassColor;
|
||||
this.grassColorModifier = grassColorModifier;
|
||||
this.particle = particle;
|
||||
this.ambientSound = ambientSound;
|
||||
this.moodSound = moodSound;
|
||||
this.additionsSound = additionsSound;
|
||||
this.music = music;
|
||||
}
|
||||
|
||||
public static BiomeEffects decode(NBT nbt, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
int fogColor = compound.getNumberTagOrThrow("fog_color").getAsInt();
|
||||
int waterColor = compound.getNumberTagOrThrow("water_color").getAsInt();
|
||||
int waterFogColor = compound.getNumberTagOrThrow("water_fog_color").getAsInt();
|
||||
int skyColor = compound.getNumberTagOrThrow("sky_color").getAsInt();
|
||||
OptionalInt foliageColor = Optional.ofNullable(compound.getNumberTagOrNull("foliage_color"))
|
||||
.map(NBTNumber::getAsInt).map(OptionalInt::of).orElseGet(OptionalInt::empty);
|
||||
OptionalInt grassColor = Optional.ofNullable(compound.getNumberTagOrNull("grass_color"))
|
||||
.map(NBTNumber::getAsInt).map(OptionalInt::of).orElseGet(OptionalInt::empty);
|
||||
GrassColorModifier grassColorModifier = Optional.ofNullable(compound.getStringTagValueOrNull("grass_color_modifier"))
|
||||
.map(id -> indexValueOrThrow(GrassColorModifier.ID_INDEX, id)).orElse(GrassColorModifier.NONE);
|
||||
Optional<ParticleSettings> particle = Optional.ofNullable(compound.getTagOrNull("particle"))
|
||||
.map(tag -> ParticleSettings.decode(tag, version));
|
||||
Optional<Sound> ambientSound = Optional.ofNullable(compound.getTagOrNull("ambient_sound"))
|
||||
.map(tag -> Sound.decode(tag, version));
|
||||
Optional<MoodSettings> moodSound = Optional.ofNullable(compound.getTagOrNull("mood_sound"))
|
||||
.map(tag -> MoodSettings.decode(tag, version));
|
||||
Optional<AdditionsSettings> additionsSound = Optional.ofNullable(compound.getTagOrNull("additions_sound"))
|
||||
.map(tag -> AdditionsSettings.decode(tag, version));
|
||||
Optional<MusicSettings> music = Optional.ofNullable(compound.getTagOrNull("music"))
|
||||
.map(tag -> MusicSettings.decode(tag, version));
|
||||
return new BiomeEffects(fogColor, waterColor, waterFogColor, skyColor, foliageColor, grassColor,
|
||||
grassColorModifier, particle, ambientSound, moodSound, additionsSound, music);
|
||||
}
|
||||
|
||||
public static NBT encode(BiomeEffects effects, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("fog_color", new NBTInt(effects.fogColor));
|
||||
compound.setTag("water_color", new NBTInt(effects.waterColor));
|
||||
compound.setTag("water_fog_color", new NBTInt(effects.waterFogColor));
|
||||
compound.setTag("sky_color", new NBTInt(effects.skyColor));
|
||||
effects.foliageColor.ifPresent(color ->
|
||||
compound.setTag("foliage_color", new NBTInt(color)));
|
||||
effects.grassColor.ifPresent(color ->
|
||||
compound.setTag("grass_color", new NBTInt(color)));
|
||||
if (effects.grassColorModifier != GrassColorModifier.NONE) {
|
||||
compound.setTag("grass_color_modifier", new NBTString(effects.grassColorModifier.getId()));
|
||||
}
|
||||
effects.particle.ifPresent(settings -> compound.setTag(
|
||||
"particle", ParticleSettings.encode(settings, version)));
|
||||
effects.ambientSound.ifPresent(sound -> compound.setTag(
|
||||
"ambient_sound", Sound.encode(sound, version)));
|
||||
effects.moodSound.ifPresent(sound -> compound.setTag(
|
||||
"mood_sound", MoodSettings.encode(sound, version)));
|
||||
effects.additionsSound.ifPresent(sound -> compound.setTag(
|
||||
"additions_sound", AdditionsSettings.encode(sound, version)));
|
||||
effects.music.ifPresent(music -> compound.setTag(
|
||||
"music", MusicSettings.encode(music, version)));
|
||||
return compound;
|
||||
}
|
||||
|
||||
public int getFogColor() {
|
||||
return this.fogColor;
|
||||
}
|
||||
|
||||
public int getWaterColor() {
|
||||
return this.waterColor;
|
||||
}
|
||||
|
||||
public int getWaterFogColor() {
|
||||
return this.waterFogColor;
|
||||
}
|
||||
|
||||
public int getSkyColor() {
|
||||
return this.skyColor;
|
||||
}
|
||||
|
||||
public OptionalInt getFoliageColor() {
|
||||
return this.foliageColor;
|
||||
}
|
||||
|
||||
public OptionalInt getGrassColor() {
|
||||
return this.grassColor;
|
||||
}
|
||||
|
||||
public GrassColorModifier getGrassColorModifier() {
|
||||
return this.grassColorModifier;
|
||||
}
|
||||
|
||||
public Optional<ParticleSettings> getParticle() {
|
||||
return this.particle;
|
||||
}
|
||||
|
||||
public Optional<Sound> getAmbientSound() {
|
||||
return this.ambientSound;
|
||||
}
|
||||
|
||||
public Optional<MoodSettings> getMoodSound() {
|
||||
return this.moodSound;
|
||||
}
|
||||
|
||||
public Optional<MusicSettings> getMusic() {
|
||||
return this.music;
|
||||
}
|
||||
|
||||
public Optional<AdditionsSettings> getAdditionsSound() {
|
||||
return this.additionsSound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof BiomeEffects)) return false;
|
||||
BiomeEffects that = (BiomeEffects) obj;
|
||||
if (this.fogColor != that.fogColor) return false;
|
||||
if (this.waterColor != that.waterColor) return false;
|
||||
if (this.waterFogColor != that.waterFogColor) return false;
|
||||
if (this.skyColor != that.skyColor) return false;
|
||||
if (!this.foliageColor.equals(that.foliageColor)) return false;
|
||||
if (!this.grassColor.equals(that.grassColor)) return false;
|
||||
if (this.grassColorModifier != that.grassColorModifier) return false;
|
||||
if (!this.particle.equals(that.particle)) return false;
|
||||
if (!this.ambientSound.equals(that.ambientSound)) return false;
|
||||
if (!this.moodSound.equals(that.moodSound)) return false;
|
||||
if (!this.additionsSound.equals(that.additionsSound)) return false;
|
||||
return this.music.equals(that.music);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.fogColor, this.waterColor, this.waterFogColor, this.skyColor, this.foliageColor, this.grassColor, this.grassColorModifier, this.particle, this.ambientSound, this.moodSound, this.additionsSound, this.music);
|
||||
}
|
||||
|
||||
public enum GrassColorModifier {
|
||||
|
||||
NONE("none"),
|
||||
DARK_FOREST("dark_forest"),
|
||||
SWAMP("swamp");
|
||||
|
||||
public static final Index<String, GrassColorModifier> ID_INDEX = Index.create(
|
||||
GrassColorModifier.class, GrassColorModifier::getId);
|
||||
|
||||
private final String id;
|
||||
|
||||
GrassColorModifier(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ParticleSettings {
|
||||
|
||||
private final Particle<?> particle;
|
||||
private final float probability;
|
||||
|
||||
public ParticleSettings(Particle<?> particle, float probability) {
|
||||
this.particle = particle;
|
||||
this.probability = probability;
|
||||
}
|
||||
|
||||
public static ParticleSettings decode(NBT nbt, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
Particle<?> particle = Particle.decode(compound.getTagOrNull("options"), version);
|
||||
float probability = compound.getNumberTagOrThrow("probability").getAsFloat();
|
||||
return new ParticleSettings(particle, probability);
|
||||
}
|
||||
|
||||
public static NBT encode(ParticleSettings settings, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("options", Particle.encode(settings.particle, version));
|
||||
compound.setTag("probability", new NBTFloat(settings.probability));
|
||||
return compound;
|
||||
}
|
||||
|
||||
public Particle<?> getParticle() {
|
||||
return this.particle;
|
||||
}
|
||||
|
||||
public float getProbability() {
|
||||
return this.probability;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class MoodSettings {
|
||||
|
||||
private final Sound sound;
|
||||
private final int tickDelay;
|
||||
private final int blockSearchExtent;
|
||||
private final double soundOffset;
|
||||
|
||||
public MoodSettings(Sound sound, int tickDelay, int blockSearchExtent, double soundOffset) {
|
||||
this.sound = sound;
|
||||
this.tickDelay = tickDelay;
|
||||
this.blockSearchExtent = blockSearchExtent;
|
||||
this.soundOffset = soundOffset;
|
||||
}
|
||||
|
||||
public static MoodSettings decode(NBT nbt, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
Sound sound = Sound.decode(compound.getTagOrThrow("sound"), version);
|
||||
int tickDelay = compound.getNumberTagOrThrow("tick_delay").getAsInt();
|
||||
int blockSearchExtent = compound.getNumberTagOrThrow("block_search_extent").getAsInt();
|
||||
double soundOffset = compound.getNumberTagOrThrow("offset").getAsDouble();
|
||||
return new MoodSettings(sound, tickDelay, blockSearchExtent, soundOffset);
|
||||
}
|
||||
|
||||
public static NBT encode(MoodSettings settings, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("sound", Sound.encode(settings.sound, version));
|
||||
compound.setTag("tick_delay", new NBTInt(settings.tickDelay));
|
||||
compound.setTag("block_search_extent", new NBTInt(settings.blockSearchExtent));
|
||||
compound.setTag("offset", new NBTDouble(settings.soundOffset));
|
||||
return compound;
|
||||
}
|
||||
|
||||
public Sound getSound() {
|
||||
return this.sound;
|
||||
}
|
||||
|
||||
public int getTickDelay() {
|
||||
return this.tickDelay;
|
||||
}
|
||||
|
||||
public int getBlockSearchExtent() {
|
||||
return this.blockSearchExtent;
|
||||
}
|
||||
|
||||
public double getSoundOffset() {
|
||||
return this.soundOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof MoodSettings)) return false;
|
||||
MoodSettings that = (MoodSettings) obj;
|
||||
if (this.tickDelay != that.tickDelay) return false;
|
||||
if (this.blockSearchExtent != that.blockSearchExtent) return false;
|
||||
if (Double.compare(that.soundOffset, this.soundOffset) != 0) return false;
|
||||
return this.sound.equals(that.sound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.sound, this.tickDelay, this.blockSearchExtent, this.soundOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class AdditionsSettings {
|
||||
|
||||
private final Sound sound;
|
||||
private final double tickChance;
|
||||
|
||||
public AdditionsSettings(Sound sound, double tickChance) {
|
||||
this.sound = sound;
|
||||
this.tickChance = tickChance;
|
||||
}
|
||||
|
||||
public static AdditionsSettings decode(NBT nbt, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
Sound sound = Sound.decode(compound.getTagOrThrow("sound"), version);
|
||||
double tickChance = compound.getNumberTagOrThrow("tick_chance").getAsDouble();
|
||||
return new AdditionsSettings(sound, tickChance);
|
||||
}
|
||||
|
||||
public static NBT encode(AdditionsSettings settings, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("sound", Sound.encode(settings.sound, version));
|
||||
compound.setTag("tick_chance", new NBTDouble(settings.tickChance));
|
||||
return compound;
|
||||
}
|
||||
|
||||
public Sound getSound() {
|
||||
return this.sound;
|
||||
}
|
||||
|
||||
public double getTickChance() {
|
||||
return this.tickChance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof AdditionsSettings)) return false;
|
||||
AdditionsSettings that = (AdditionsSettings) obj;
|
||||
if (Double.compare(that.tickChance, this.tickChance) != 0) return false;
|
||||
return this.sound.equals(that.sound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.sound, this.tickChance);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class MusicSettings {
|
||||
|
||||
private final Sound sound;
|
||||
private final int minDelay;
|
||||
private final int maxDelay;
|
||||
private final boolean replaceMusic;
|
||||
|
||||
public MusicSettings(Sound sound, int minDelay, int maxDelay, boolean replaceMusic) {
|
||||
this.sound = sound;
|
||||
this.minDelay = minDelay;
|
||||
this.maxDelay = maxDelay;
|
||||
this.replaceMusic = replaceMusic;
|
||||
}
|
||||
|
||||
public static MusicSettings decode(NBT nbt, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
Sound sound = Sound.decode(compound.getTagOrThrow("sound"), version);
|
||||
int minDelay = compound.getNumberTagOrThrow("min_delay").getAsInt();
|
||||
int maxDelay = compound.getNumberTagOrThrow("max_delay").getAsInt();
|
||||
boolean replaceMusic = compound.getBoolean("replace_current_music");
|
||||
return new MusicSettings(sound, minDelay, maxDelay, replaceMusic);
|
||||
}
|
||||
|
||||
public static NBT encode(MusicSettings settings, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("sound", Sound.encode(settings.sound, version));
|
||||
compound.setTag("min_delay", new NBTInt(settings.minDelay));
|
||||
compound.setTag("max_delay", new NBTInt(settings.maxDelay));
|
||||
compound.setTag("replace_current_music", new NBTByte(settings.replaceMusic));
|
||||
return compound;
|
||||
}
|
||||
|
||||
public Sound getSound() {
|
||||
return this.sound;
|
||||
}
|
||||
|
||||
public int getMinDelay() {
|
||||
return this.minDelay;
|
||||
}
|
||||
|
||||
public int getMaxDelay() {
|
||||
return this.maxDelay;
|
||||
}
|
||||
|
||||
public boolean isReplaceMusic() {
|
||||
return this.replaceMusic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof MusicSettings)) return false;
|
||||
MusicSettings that = (MusicSettings) obj;
|
||||
if (this.minDelay != that.minDelay) return false;
|
||||
if (this.maxDelay != that.maxDelay) return false;
|
||||
if (this.replaceMusic != that.replaceMusic) return false;
|
||||
return this.sound.equals(that.sound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.sound, this.minDelay, this.maxDelay, this.replaceMusic);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.world.biome;
|
||||
|
||||
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.VersionedRegistry;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class Biomes {
|
||||
|
||||
private static final VersionedRegistry<Biome> REGISTRY = new VersionedRegistry<>(
|
||||
"worldgen/biome", "world/biome_mappings");
|
||||
|
||||
// load data from file, biomes are too complex to define in code here
|
||||
private static final Map<ResourceLocation, NBTCompound> BIOME_DATA;
|
||||
|
||||
static {
|
||||
BIOME_DATA = new HashMap<>();
|
||||
try (SequentialNBTReader.Compound dataTag = MappingHelper.decompress("mappings/world/biome_data")) {
|
||||
while (dataTag.hasNext()) {
|
||||
Map.Entry<String, NBT> entry = dataTag.next();
|
||||
if (entry.getKey().equals("version")) {
|
||||
continue; // skip version field
|
||||
}
|
||||
ResourceLocation biomeKey = new ResourceLocation(entry.getKey());
|
||||
BIOME_DATA.put(biomeKey, ((SequentialNBTReader.Compound) entry.getValue()).readFully());
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
throw new RuntimeException("Error while reading biome data", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private Biomes() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static Biome define(String key) {
|
||||
return REGISTRY.define(key, data -> {
|
||||
NBTCompound dataTag = BIOME_DATA.get(data.getName());
|
||||
if (dataTag == null) {
|
||||
throw new IllegalArgumentException("Can't define biome " + data.getName() + ", no data found");
|
||||
}
|
||||
return Biome.decode(dataTag, ClientVersion.getLatest(), data);
|
||||
});
|
||||
}
|
||||
|
||||
public static VersionedRegistry<Biome> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
public static final Biome BADLANDS = define("badlands");
|
||||
public static final Biome BAMBOO_JUNGLE = define("bamboo_jungle");
|
||||
public static final Biome BASALT_DELTAS = define("basalt_deltas");
|
||||
public static final Biome BEACH = define("beach");
|
||||
public static final Biome BIRCH_FOREST = define("birch_forest");
|
||||
public static final Biome CHERRY_GROVE = define("cherry_grove");
|
||||
public static final Biome COLD_OCEAN = define("cold_ocean");
|
||||
public static final Biome CRIMSON_FOREST = define("crimson_forest");
|
||||
public static final Biome DARK_FOREST = define("dark_forest");
|
||||
public static final Biome DEEP_COLD_OCEAN = define("deep_cold_ocean");
|
||||
public static final Biome DEEP_DARK = define("deep_dark");
|
||||
public static final Biome DEEP_FROZEN_OCEAN = define("deep_frozen_ocean");
|
||||
public static final Biome DEEP_LUKEWARM_OCEAN = define("deep_lukewarm_ocean");
|
||||
public static final Biome DEEP_OCEAN = define("deep_ocean");
|
||||
public static final Biome DESERT = define("desert");
|
||||
public static final Biome DRIPSTONE_CAVES = define("dripstone_caves");
|
||||
public static final Biome END_BARRENS = define("end_barrens");
|
||||
public static final Biome END_HIGHLANDS = define("end_highlands");
|
||||
public static final Biome END_MIDLANDS = define("end_midlands");
|
||||
public static final Biome ERODED_BADLANDS = define("eroded_badlands");
|
||||
public static final Biome FLOWER_FOREST = define("flower_forest");
|
||||
public static final Biome FOREST = define("forest");
|
||||
public static final Biome FROZEN_OCEAN = define("frozen_ocean");
|
||||
public static final Biome FROZEN_PEAKS = define("frozen_peaks");
|
||||
public static final Biome FROZEN_RIVER = define("frozen_river");
|
||||
public static final Biome GROVE = define("grove");
|
||||
public static final Biome ICE_SPIKES = define("ice_spikes");
|
||||
public static final Biome JAGGED_PEAKS = define("jagged_peaks");
|
||||
public static final Biome JUNGLE = define("jungle");
|
||||
public static final Biome LUKEWARM_OCEAN = define("lukewarm_ocean");
|
||||
public static final Biome LUSH_CAVES = define("lush_caves");
|
||||
public static final Biome MANGROVE_SWAMP = define("mangrove_swamp");
|
||||
public static final Biome MEADOW = define("meadow");
|
||||
public static final Biome MUSHROOM_FIELDS = define("mushroom_fields");
|
||||
public static final Biome NETHER_WASTES = define("nether_wastes");
|
||||
public static final Biome OCEAN = define("ocean");
|
||||
public static final Biome OLD_GROWTH_BIRCH_FOREST = define("old_growth_birch_forest");
|
||||
public static final Biome OLD_GROWTH_PINE_TAIGA = define("old_growth_pine_taiga");
|
||||
public static final Biome OLD_GROWTH_SPRUCE_TAIGA = define("old_growth_spruce_taiga");
|
||||
public static final Biome PLAINS = define("plains");
|
||||
public static final Biome RIVER = define("river");
|
||||
public static final Biome SAVANNA = define("savanna");
|
||||
public static final Biome SAVANNA_PLATEAU = define("savanna_plateau");
|
||||
public static final Biome SMALL_END_ISLANDS = define("small_end_islands");
|
||||
public static final Biome SNOWY_BEACH = define("snowy_beach");
|
||||
public static final Biome SNOWY_PLAINS = define("snowy_plains");
|
||||
public static final Biome SNOWY_SLOPES = define("snowy_slopes");
|
||||
public static final Biome SNOWY_TAIGA = define("snowy_taiga");
|
||||
public static final Biome SOUL_SAND_VALLEY = define("soul_sand_valley");
|
||||
public static final Biome SPARSE_JUNGLE = define("sparse_jungle");
|
||||
public static final Biome STONY_PEAKS = define("stony_peaks");
|
||||
public static final Biome STONY_SHORE = define("stony_shore");
|
||||
public static final Biome SUNFLOWER_PLAINS = define("sunflower_plains");
|
||||
public static final Biome SWAMP = define("swamp");
|
||||
public static final Biome TAIGA = define("taiga");
|
||||
public static final Biome THE_END = define("the_end");
|
||||
public static final Biome THE_VOID = define("the_void");
|
||||
public static final Biome WARM_OCEAN = define("warm_ocean");
|
||||
public static final Biome WARPED_FOREST = define("warped_forest");
|
||||
public static final Biome WINDSWEPT_FOREST = define("windswept_forest");
|
||||
public static final Biome WINDSWEPT_GRAVELLY_HILLS = define("windswept_gravelly_hills");
|
||||
public static final Biome WINDSWEPT_HILLS = define("windswept_hills");
|
||||
public static final Biome WINDSWEPT_SAVANNA = define("windswept_savanna");
|
||||
public static final Biome WOODED_BADLANDS = define("wooded_badlands");
|
||||
|
||||
static {
|
||||
BIOME_DATA.clear();
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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.world.biome;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class StaticBiome extends AbstractMappedEntity implements Biome {
|
||||
|
||||
private final boolean precipitation;
|
||||
private final float temperature;
|
||||
private final TemperatureModifier temperatureModifier;
|
||||
private final float downfall;
|
||||
private final @Nullable Category category;
|
||||
private final @Nullable Float depth;
|
||||
private final @Nullable Float scale;
|
||||
private final BiomeEffects effects;
|
||||
|
||||
public StaticBiome(
|
||||
boolean precipitation, float temperature, TemperatureModifier temperatureModifier,
|
||||
float downfall, BiomeEffects effects
|
||||
) {
|
||||
this(null, precipitation, temperature, temperatureModifier, downfall, effects);
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete
|
||||
public StaticBiome(@Nullable TypesBuilderData data, Precipitation precipitation, float temperature,
|
||||
TemperatureModifier temperatureModifier, float downfall, BiomeEffects effects) {
|
||||
this(data, precipitation != Precipitation.NONE, temperature, temperatureModifier, downfall, effects);
|
||||
}
|
||||
|
||||
public StaticBiome(
|
||||
@Nullable TypesBuilderData data, boolean precipitation,
|
||||
float temperature, TemperatureModifier temperatureModifier,
|
||||
float downfall, BiomeEffects effects
|
||||
) {
|
||||
this(data, precipitation, temperature, temperatureModifier,
|
||||
downfall, null, null, null, effects);
|
||||
}
|
||||
|
||||
public StaticBiome(
|
||||
boolean precipitation, float temperature, TemperatureModifier temperatureModifier,
|
||||
float downfall, @Nullable Category category, @Nullable Float depth,
|
||||
@Nullable Float scale, BiomeEffects effects
|
||||
) {
|
||||
this(null, precipitation, temperature, temperatureModifier, downfall,
|
||||
category, depth, scale, effects);
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete
|
||||
public StaticBiome(@Nullable TypesBuilderData data, Precipitation precipitation, float temperature,
|
||||
TemperatureModifier temperatureModifier, float downfall, @Nullable Category category,
|
||||
@Nullable Float depth, @Nullable Float scale, BiomeEffects effects) {
|
||||
this(data, precipitation != Precipitation.NONE, temperature, temperatureModifier,
|
||||
downfall, category, depth, scale, effects);
|
||||
}
|
||||
|
||||
public StaticBiome(
|
||||
@Nullable TypesBuilderData data, boolean precipitation,
|
||||
float temperature, TemperatureModifier temperatureModifier,
|
||||
float downfall, @Nullable Category category, @Nullable Float depth,
|
||||
@Nullable Float scale, BiomeEffects effects
|
||||
) {
|
||||
super(data);
|
||||
this.precipitation = precipitation;
|
||||
this.temperature = temperature;
|
||||
this.temperatureModifier = temperatureModifier;
|
||||
this.downfall = downfall;
|
||||
this.category = category;
|
||||
this.depth = depth;
|
||||
this.scale = scale;
|
||||
this.effects = effects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome copy(@Nullable TypesBuilderData newData) {
|
||||
return new StaticBiome(newData, this.precipitation, this.temperature, this.temperatureModifier,
|
||||
this.downfall, this.category, this.depth, this.scale, this.effects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrecipitation() {
|
||||
return this.precipitation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Precipitation getPrecipitation() {
|
||||
if (!this.hasPrecipitation()) {
|
||||
return Precipitation.NONE;
|
||||
}
|
||||
switch (this.getTemperatureModifier()) {
|
||||
case NONE:
|
||||
return Precipitation.RAIN;
|
||||
case FROZEN:
|
||||
return Precipitation.SNOW;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTemperature() {
|
||||
return this.temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemperatureModifier getTemperatureModifier() {
|
||||
return this.temperatureModifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDownfall() {
|
||||
return this.downfall;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Category getCategory() {
|
||||
return this.category;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Float getDepth() {
|
||||
return this.depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Float getScale() {
|
||||
return this.scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeEffects getEffects() {
|
||||
return this.effects;
|
||||
}
|
||||
|
||||
public boolean deepEquals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof StaticBiome)) return false;
|
||||
if (!super.equals(obj)) return false;
|
||||
StaticBiome that = (StaticBiome) obj;
|
||||
if (this.precipitation != that.precipitation) return false;
|
||||
if (Float.compare(that.temperature, this.temperature) != 0) return false;
|
||||
if (Float.compare(that.downfall, this.downfall) != 0) return false;
|
||||
if (this.temperatureModifier != that.temperatureModifier) return false;
|
||||
if (this.category != that.category) return false;
|
||||
if (!Objects.equals(this.depth, that.depth)) return false;
|
||||
if (!Objects.equals(this.scale, that.scale)) return false;
|
||||
return this.effects.equals(that.effects);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.precipitation, this.temperature,
|
||||
this.temperatureModifier, this.downfall, this.category, this.depth, this.scale, this.effects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StaticBiome{precipitation=" + this.precipitation + ", temperature=" + this.temperature + ", temperatureModifier=" + this.temperatureModifier + ", downfall=" + this.downfall + ", category=" + this.category + ", depth=" + this.depth + ", scale=" + this.scale + ", effects=" + this.effects + '}';
|
||||
}
|
||||
}
|
||||
+19
-4
@@ -20,14 +20,12 @@ package com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_16;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.stream.NetStreamInput;
|
||||
import com.github.retrooper.packetevents.protocol.stream.NetStreamOutput;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.NibbleArray3d;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.palette.DataPalette;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.palette.PaletteType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
|
||||
public class Chunk_v1_9 implements BaseChunk {
|
||||
private static final int AIR = 0;
|
||||
@@ -56,7 +54,8 @@ public class Chunk_v1_9 implements BaseChunk {
|
||||
}
|
||||
|
||||
if (isSixteen) {
|
||||
dataPalette = DataPalette.read(in, PaletteType.CHUNK);
|
||||
// singleton palette got added with 1.18 which isn't supported by this chunk section implementation
|
||||
dataPalette = DataPalette.read(in, PaletteType.CHUNK, false);
|
||||
} else {
|
||||
dataPalette = DataPalette.readLegacy(in);
|
||||
}
|
||||
@@ -117,4 +116,20 @@ public class Chunk_v1_9 implements BaseChunk {
|
||||
// 1.14+, we can rely on the value
|
||||
return this.blockCount == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public NibbleArray3d getSkyLight() {
|
||||
return this.skyLight;
|
||||
}
|
||||
|
||||
public void setSkyLight(NibbleArray3d skyLight) {
|
||||
this.skyLight = skyLight;
|
||||
}
|
||||
|
||||
public NibbleArray3d getBlockLight() {
|
||||
return this.blockLight;
|
||||
}
|
||||
|
||||
public void setBlockLight(NibbleArray3d blockLight) {
|
||||
this.blockLight = blockLight;
|
||||
}
|
||||
}
|
||||
+17
-8
@@ -55,8 +55,12 @@ public class DataPalette {
|
||||
}
|
||||
|
||||
public static DataPalette read(NetStreamInput in, PaletteType paletteType) {
|
||||
return read(in, paletteType, true);
|
||||
}
|
||||
|
||||
public static DataPalette read(NetStreamInput in, PaletteType paletteType, boolean allowSingletonPalette) {
|
||||
int bitsPerEntry = in.readByte();
|
||||
Palette palette = readPalette(paletteType, bitsPerEntry, in);
|
||||
Palette palette = readPalette(paletteType, bitsPerEntry, in, allowSingletonPalette);
|
||||
BitStorage storage;
|
||||
if (!(palette instanceof SingletonPalette)) {
|
||||
int length = in.readVarInt();
|
||||
@@ -94,7 +98,7 @@ public class DataPalette {
|
||||
|
||||
public static DataPalette readLegacy(NetStreamInput in) {
|
||||
int bitsPerEntry = in.readByte() & 0xff;
|
||||
Palette palette = readPalette(PaletteType.CHUNK, bitsPerEntry, in);
|
||||
Palette palette = readPalette(PaletteType.CHUNK, bitsPerEntry, in, false);
|
||||
BaseStorage storage;
|
||||
if (!(palette instanceof SingletonPalette)) {
|
||||
int length = in.readVarInt();
|
||||
@@ -108,7 +112,7 @@ public class DataPalette {
|
||||
|
||||
public int get(int x, int y, int z) {
|
||||
if (storage != null) {
|
||||
int id = this.storage.get(index(x, y, z));
|
||||
int id = this.storage.get(index(this.paletteType, x, y, z));
|
||||
return this.palette.idToState(id);
|
||||
} else {
|
||||
return this.palette.idToState(0);
|
||||
@@ -126,7 +130,7 @@ public class DataPalette {
|
||||
}
|
||||
|
||||
if (this.storage != null) {
|
||||
int index = index(x, y, z);
|
||||
int index = index(this.paletteType, x, y, z);
|
||||
int curr = this.storage.get(index);
|
||||
|
||||
this.storage.set(index, id);
|
||||
@@ -137,11 +141,16 @@ public class DataPalette {
|
||||
}
|
||||
}
|
||||
|
||||
private static Palette readPalette(PaletteType paletteType, int bitsPerEntry, NetStreamInput in) {
|
||||
private static Palette readPalette(
|
||||
PaletteType paletteType,
|
||||
int bitsPerEntry,
|
||||
NetStreamInput in,
|
||||
boolean allowSingletonPalette
|
||||
) {
|
||||
if (bitsPerEntry > paletteType.getMaxBitsPerEntry()) {
|
||||
return new GlobalPalette();
|
||||
}
|
||||
if (bitsPerEntry == 0) {
|
||||
if (bitsPerEntry == 0 && allowSingletonPalette) {
|
||||
return new SingletonPalette(in);
|
||||
}
|
||||
if (bitsPerEntry <= paletteType.getMinBitsPerEntry()) {
|
||||
@@ -186,7 +195,7 @@ public class DataPalette {
|
||||
}
|
||||
}
|
||||
|
||||
private static int index(int x, int y, int z) {
|
||||
return y << 8 | z << 4 | x;
|
||||
private static int index(PaletteType paletteType, int x, int y, int z) {
|
||||
return (y << paletteType.getBitShift() | z) << paletteType.getBitShift() | x;
|
||||
}
|
||||
}
|
||||
+9
-3
@@ -19,16 +19,18 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.chunk.palette;
|
||||
|
||||
public enum PaletteType {
|
||||
BIOME(1, 3, 64),
|
||||
CHUNK(4, 8, 4096);
|
||||
BIOME(1, 3, 2, 64),
|
||||
CHUNK(4, 8, 4, 4096);
|
||||
|
||||
private final int minBitsPerEntry;
|
||||
private final int maxBitsPerEntry;
|
||||
private final int bitShift;
|
||||
private final int storageSize;
|
||||
|
||||
PaletteType(int minBitsPerEntry, int maxBitsPerEntry, int storageSize) {
|
||||
PaletteType(int minBitsPerEntry, int maxBitsPerEntry, int bitShift, int storageSize) {
|
||||
this.minBitsPerEntry = minBitsPerEntry;
|
||||
this.maxBitsPerEntry = maxBitsPerEntry;
|
||||
this.bitShift = bitShift;
|
||||
this.storageSize = storageSize;
|
||||
}
|
||||
|
||||
@@ -40,6 +42,10 @@ public enum PaletteType {
|
||||
return minBitsPerEntry;
|
||||
}
|
||||
|
||||
public int getBitShift() {
|
||||
return bitShift;
|
||||
}
|
||||
|
||||
public int getStorageSize() {
|
||||
return storageSize;
|
||||
}
|
||||
|
||||
+19
-1
@@ -21,9 +21,27 @@ package com.github.retrooper.packetevents.protocol.world.chunk.reader;
|
||||
import com.github.retrooper.packetevents.protocol.stream.NetStreamInput;
|
||||
import com.github.retrooper.packetevents.protocol.world.Dimension;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public interface ChunkReader {
|
||||
BaseChunk[] read(Dimension dimension, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight, boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn);
|
||||
|
||||
@Deprecated
|
||||
default BaseChunk[] read(
|
||||
Dimension dimension, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight,
|
||||
boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn
|
||||
) {
|
||||
DimensionType dimensionType = dimension.asDimensionType(null, null);
|
||||
return this.read(dimensionType, set, sevenExtendedMask, fullChunk,
|
||||
hasSkyLight, checkForSky, chunkSize, data, dataIn);
|
||||
}
|
||||
|
||||
default BaseChunk[] read(
|
||||
DimensionType dimensionType, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight,
|
||||
boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn
|
||||
) {
|
||||
Dimension dimension = Dimension.fromDimensionType(dimensionType, null, null);
|
||||
return this.read(dimension, set, sevenExtendedMask, fullChunk, hasSkyLight, checkForSky, chunkSize, data, dataIn);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -19,16 +19,16 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.chunk.reader.impl;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.stream.NetStreamInput;
|
||||
import com.github.retrooper.packetevents.protocol.world.Dimension;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_16.Chunk_v1_9;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.reader.ChunkReader;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public class ChunkReader_v1_16 implements ChunkReader {
|
||||
@Override
|
||||
public BaseChunk[] read(Dimension dimension, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight, boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn) {
|
||||
public BaseChunk[] read(DimensionType dimensionType, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight, boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn) {
|
||||
BaseChunk[] chunks = new BaseChunk[chunkSize];
|
||||
|
||||
for (int index = 0; index < chunks.length; ++index) {
|
||||
|
||||
+2
-2
@@ -19,16 +19,16 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.chunk.reader.impl;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.stream.NetStreamInput;
|
||||
import com.github.retrooper.packetevents.protocol.world.Dimension;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v_1_18.Chunk_v1_18;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.reader.ChunkReader;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public class ChunkReader_v1_18 implements ChunkReader {
|
||||
@Override
|
||||
public BaseChunk[] read(Dimension dimension, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight, boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn) {
|
||||
public BaseChunk[] read(DimensionType dimensionType, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight, boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn) {
|
||||
BaseChunk[] chunks = new BaseChunk[chunkSize];
|
||||
|
||||
for (int index = 0; index < chunkSize; ++index) {
|
||||
|
||||
+2
-2
@@ -19,19 +19,19 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.chunk.reader.impl;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.stream.NetStreamInput;
|
||||
import com.github.retrooper.packetevents.protocol.world.Dimension;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.ByteArray3d;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.NetworkChunkData;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.NibbleArray3d;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_7.Chunk_v1_7;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.reader.ChunkReader;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public class ChunkReader_v1_7 implements ChunkReader {
|
||||
@Override
|
||||
public BaseChunk[] read(Dimension dimension, BitSet primarySet, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight, boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn) {
|
||||
public BaseChunk[] read(DimensionType dimensionType, BitSet primarySet, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight, boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn) {
|
||||
Chunk_v1_7[] chunks = new Chunk_v1_7[16];
|
||||
int pos = 0;
|
||||
int expected = 0;
|
||||
|
||||
+2
-2
@@ -19,13 +19,13 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.chunk.reader.impl;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.stream.NetStreamInput;
|
||||
import com.github.retrooper.packetevents.protocol.world.Dimension;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.NetworkChunkData;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.NibbleArray3d;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.ShortArray3d;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_8.Chunk_v1_8;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.reader.ChunkReader;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
@@ -35,7 +35,7 @@ import java.util.BitSet;
|
||||
public class ChunkReader_v1_8 implements ChunkReader {
|
||||
|
||||
@Override
|
||||
public BaseChunk[] read(Dimension dimension, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight, boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn) {
|
||||
public BaseChunk[] read(DimensionType dimensionType, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasSkyLight, boolean checkForSky, int chunkSize, byte[] data, NetStreamInput dataIn) {
|
||||
Chunk_v1_8[] chunks = new Chunk_v1_8[16];
|
||||
int pos = 0;
|
||||
int expected = fullChunk ? 256 : 0; // 256 if full chunk for the biome data, always sent if full chunk
|
||||
|
||||
+2
-2
@@ -19,17 +19,17 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.chunk.reader.impl;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.stream.NetStreamInput;
|
||||
import com.github.retrooper.packetevents.protocol.world.Dimension;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_16.Chunk_v1_9;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.reader.ChunkReader;
|
||||
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public class ChunkReader_v1_9 implements ChunkReader {
|
||||
|
||||
@Override
|
||||
public BaseChunk[] read(Dimension dimension, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasBlockLight, boolean hasSkyLight, int chunkSize, byte[] data, NetStreamInput dataIn) {
|
||||
public BaseChunk[] read(DimensionType dimensionType, BitSet set, BitSet sevenExtendedMask, boolean fullChunk, boolean hasBlockLight, boolean hasSkyLight, int chunkSize, byte[] data, NetStreamInput dataIn) {
|
||||
BaseChunk[] chunks = new BaseChunk[chunkSize];
|
||||
|
||||
for (int index = 0; index < chunks.length; ++index) {
|
||||
|
||||
Loaded 100 of 212 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user