Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3400877958 | ||
|
|
b5a2c0ac29 | ||
|
|
c43dd6425a | ||
|
|
8b643ae238 | ||
|
|
b07461340e | ||
|
|
4cec8fe549 | ||
|
|
55ea059640 | ||
|
|
5429e80f66 | ||
|
|
16c71fad14 | ||
|
|
d27a97c322 | ||
|
|
59ccfa89db | ||
|
|
b6f25939be | ||
|
|
d19406edf4 | ||
|
|
0702ff3716 | ||
|
|
4577c5a948 | ||
|
|
d073f716f9 | ||
|
|
5051c31bea | ||
|
|
eb2d91745a | ||
|
|
9d40bc506e | ||
|
|
0fa3be1ce2 | ||
|
|
acecdb57f4 | ||
|
|
33d3a72d4d | ||
|
|
2ce1fc1e79 | ||
|
|
63b9e27ebf | ||
|
|
8093481f08 | ||
|
|
629871fcb5 | ||
|
|
d2d9135c45 | ||
|
|
bf5c3e90b3 | ||
|
|
d100fd54de | ||
|
|
c8137956f1 | ||
|
|
e7739bac22 | ||
|
|
5c9cfcb25d | ||
|
|
4364d7a646 | ||
|
|
0ba826f578 | ||
|
|
3e21b7d384 | ||
|
|
b934d7361d | ||
|
|
4047bafc6a | ||
|
|
27de28476e | ||
|
|
e5dfb84a53 | ||
|
|
2b3c77b6b8 | ||
|
|
16294ccc63 | ||
|
|
9ae2cd0538 | ||
|
|
30492a7b1f | ||
|
|
ecce9d8c4e | ||
|
|
448f7be2ae | ||
|
|
4e3c45bc7e | ||
|
|
ccd3fd4b7b | ||
|
|
5003d578c7 | ||
|
|
881a66740f | ||
|
|
c9ae98814c | ||
|
|
ee2c562c9e | ||
|
|
cbd38ea581 | ||
|
|
983b27d071 | ||
|
|
b2a827e97b | ||
|
|
a709e5f746 | ||
|
|
c1f482dd35 | ||
|
|
269ca7ad43 | ||
|
|
594f8cdc6e | ||
|
|
187041bd47 | ||
|
|
68eb537b66 | ||
|
|
b18884a5b3 | ||
|
|
061d1c25e8 | ||
|
|
b1a881bfab | ||
|
|
e68dbe4155 | ||
|
|
60e33ef0a3 | ||
|
|
eac72687cb | ||
|
|
d205d83f61 | ||
|
|
61969bf9df | ||
|
|
ed9ff0c5da | ||
|
|
371ec62571 | ||
|
|
4eaf000dea | ||
|
|
97ca0007fc | ||
|
|
ece10d66c1 | ||
|
|
420a658b0a | ||
|
|
48fbb745e0 | ||
|
|
24d78ef500 | ||
|
|
a1123cdf67 | ||
|
|
cd3d3b17b1 | ||
|
|
1f2de8a566 | ||
|
|
74f4d65356 | ||
|
|
2be8692661 | ||
|
|
5021eebd55 | ||
|
|
124e59ba70 | ||
|
|
301adfb28f | ||
|
|
8d80725cf7 | ||
|
|
7aa429988b | ||
|
|
1cbd15e797 | ||
|
|
802c707902 | ||
|
|
17d5e3f711 | ||
|
|
7a342a8c21 | ||
|
|
a4e9a2cd06 | ||
|
|
4abc4a7403 | ||
|
|
2a364895cf | ||
|
|
ff56e81136 | ||
|
|
371fcff23a | ||
|
|
abe5b9f75a | ||
|
|
2c36b5ad9f | ||
|
|
0436b8cb6a | ||
|
|
2fb967ec04 | ||
|
|
aafc45d70d | ||
|
|
3e25fa641c | ||
|
|
3f3c6ba2e1 | ||
|
|
3175ef85c4 | ||
|
|
e876b1c95f | ||
|
|
be2094a21f | ||
|
|
95fdebfb08 | ||
|
|
5662c7ea9c | ||
|
|
b8587a2487 | ||
|
|
1411fd09b9 | ||
|
|
604a48e2dd | ||
|
|
f091ab69bc | ||
|
|
e22db21f72 | ||
|
|
24000fd837 | ||
|
|
87275458bb | ||
|
|
faac9cd83d | ||
|
|
887a9fa959 | ||
|
|
d716309e34 | ||
|
|
92603a382b | ||
|
|
88c788f654 | ||
|
|
bdb429a0b4 | ||
|
|
0c2e09bc7b | ||
|
|
131a66220f | ||
|
|
7e2c6726e0 | ||
|
|
882e7b57f9 | ||
|
|
990a19585f | ||
|
|
c2f7c92ed4 | ||
|
|
08b420ffb4 | ||
|
|
d9a821e44e | ||
|
|
2e39d61d53 | ||
|
|
bb9bd91970 | ||
|
|
a789d9ec83 | ||
|
|
524cf896c3 | ||
|
|
5190d71bc8 | ||
|
|
29dd1cdc03 | ||
|
|
cbe517e994 | ||
|
|
5175ed9733 | ||
|
|
26ddcfde2a | ||
|
|
e17eb7987f | ||
|
|
6cc2ac81df | ||
|
|
12d16144c0 | ||
|
|
f4fc034d51 | ||
|
|
42c6df480c | ||
|
|
c591335dd4 | ||
|
|
d93e01cca1 | ||
|
|
b666a1a62c | ||
|
|
fcdac76ba9 | ||
|
|
3e33d38518 | ||
|
|
46dd4be1d3 | ||
|
|
809517f04b | ||
|
|
f53e73ed9a | ||
|
|
a7e1852af4 | ||
|
|
95ac9d8633 | ||
|
|
8034de3ec3 | ||
|
|
ee6aac43d4 | ||
|
|
2fef51f3d4 | ||
|
|
f27ead56c7 | ||
|
|
317853fd8e | ||
|
|
db8a4184f8 | ||
|
|
95543c7033 | ||
|
|
306f1598e0 | ||
|
|
5a26451880 | ||
|
|
9384187f06 | ||
|
|
5e414bae58 | ||
|
|
990dfc279f | ||
|
|
27ec0876cb | ||
|
|
c3853614c5 | ||
|
|
67855eda8a | ||
|
|
e2ed78e81d | ||
|
|
80ae2de524 | ||
|
|
af3c440526 | ||
|
|
8bac60f2db | ||
|
|
6d0d1df82e | ||
|
|
44eba1fbdc | ||
|
|
7ca7eaa346 | ||
|
|
fb93dde220 | ||
|
|
4f9f58f76f | ||
|
|
4c2ee57f8d | ||
|
|
345db7d3f6 | ||
|
|
ab6df11274 | ||
|
|
71ed30e2a9 | ||
|
|
cbfccafce7 | ||
|
|
2888afa999 | ||
|
|
9c4d7cb933 | ||
|
|
baec4bdd00 | ||
|
|
a00ae8f52c | ||
|
|
b973820c59 | ||
|
|
5fbf597d20 | ||
|
|
cc8bb89ee5 | ||
|
|
1f0792f854 | ||
|
|
6b7ebc2162 | ||
|
|
596a961b05 | ||
|
|
9586d8da29 | ||
|
|
8391c11a7f | ||
|
|
51de60ab4f | ||
|
|
5d14703492 | ||
|
|
d3968b15db | ||
|
|
990cc38b67 | ||
|
|
df0d135a72 | ||
|
|
18ac4937b6 | ||
|
|
531cef241a | ||
|
|
e5353800e7 | ||
|
|
21dfaceb22 | ||
|
|
c13454a255 | ||
|
|
4f4f5f0578 | ||
|
|
02544cd0f5 | ||
|
|
3ed09a3834 | ||
|
|
28749faa44 | ||
|
|
2dbbdcc5d4 | ||
|
|
291266c4bd | ||
|
|
411693611a | ||
|
|
98c36ff39f | ||
|
|
1e69b33d4f | ||
|
|
ae2c6cdc4b | ||
|
|
3104885fb5 | ||
|
|
081868571b | ||
|
|
6a3b18aff9 | ||
|
|
c4caba57bd | ||
|
|
c9f3eb32aa | ||
|
|
1dad678f98 | ||
|
|
4f579f59c3 | ||
|
|
3352f25ede | ||
|
|
0378141ac4 | ||
|
|
9dbb877455 | ||
|
|
ee382176c5 | ||
|
|
b3d9c1f10f | ||
|
|
a51ce059e5 | ||
|
|
126bf406ce | ||
|
|
b476d51910 | ||
|
|
02e9f7f901 | ||
|
|
0cf411c4de | ||
|
|
37e2317a5f | ||
|
|
415550b354 | ||
|
|
3b5099f940 | ||
|
|
34605f3d72 | ||
|
|
8e5eab8bd1 | ||
|
|
8cde415712 | ||
|
|
c5189d2788 | ||
|
|
e550924b38 | ||
|
|
27d7495f65 | ||
|
|
7477483f15 | ||
|
|
7e064f453a | ||
|
|
f7e58de863 | ||
|
|
7a135fe0f5 | ||
|
|
8336f1c0ab | ||
|
|
2648f8538d | ||
|
|
6893216ed2 | ||
|
|
b6f944ad57 | ||
|
|
969f032607 | ||
|
|
daed712bf7 | ||
|
|
835952a7d2 | ||
|
|
d272f8d19e | ||
|
|
8cb8ad7388 | ||
|
|
6793fcb928 | ||
|
|
86ea24d3ee | ||
|
|
69f9c4f500 | ||
|
|
3d869f7dfc | ||
|
|
92d716d78e | ||
|
|
8a7f086fdf | ||
|
|
58f6a77287 | ||
|
|
04110da6f1 | ||
|
|
81e5a50b8a | ||
|
|
dfb6787322 | ||
|
|
6b03502307 | ||
|
|
499d2eea6c | ||
|
|
fdf1942553 | ||
|
|
9e9b9abb14 | ||
|
|
92397b2e4a | ||
|
|
154b789b48 | ||
|
|
0cee676a69 | ||
|
|
387f4661e8 | ||
|
|
c261e1d467 | ||
|
|
b43a76e682 | ||
|
|
6efb6f59b1 | ||
|
|
9f27a49358 | ||
|
|
5001b21e7a | ||
|
|
24446c61e0 | ||
|
|
d03ed48409 | ||
|
|
840153bc98 | ||
|
|
f3ee112a4e | ||
|
|
1634eed6e7 | ||
|
|
6e7dbf13e3 | ||
|
|
d60c661d3d | ||
|
|
cd0f1bb241 | ||
|
|
dd46140147 | ||
|
|
337d35f1d8 | ||
|
|
6ad2d61dd3 | ||
|
|
1d6e737611 | ||
|
|
01e161d37e | ||
|
|
bbb3e47a50 | ||
|
|
09ab2ff82b | ||
|
|
a59a8e116c | ||
|
|
9adfa831bf | ||
|
|
3a4daec265 | ||
|
|
de87ca203e | ||
|
|
9957cb3de9 | ||
|
|
2ac60d7055 | ||
|
|
87c2ca3c07 | ||
|
|
1f1b1aabd1 | ||
|
|
e2865ce4be | ||
|
|
f53f182090 | ||
|
|
2ec7771a8a | ||
|
|
75320ef583 |
No files matched your search
@@ -13,10 +13,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up JDK 17
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'adopt'
|
||||
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import com.github.retrooper.MappingCompressionTask
|
||||
|
||||
// papermc repo + disableAutoTargetJvm needed for mockbukkit
|
||||
repositories {
|
||||
maven { url 'https://repo.papermc.io/repository/maven-public/' }
|
||||
}
|
||||
|
||||
java {
|
||||
disableAutoTargetJvm()
|
||||
sourceSets {
|
||||
main {
|
||||
resources {
|
||||
srcDirs += ["$buildDir.canonicalPath/mappings/generated"]
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
resources {
|
||||
srcDirs += ["$buildDir.canonicalPath/mappings/generated"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(adventureDependencies)
|
||||
|
||||
testImplementation(adventureDependencies)
|
||||
testImplementation(project(":netty-common"))
|
||||
testImplementation("com.github.seeseemelk:MockBukkit-v1.20:3.9.0")
|
||||
testImplementation("org.slf4j:slf4j-simple:2.0.7")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.0")
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
task generateMapping(type: MappingCompressionTask) {
|
||||
mappingsDir = rootDir.toPath().resolve("mappings")
|
||||
outDir = project.buildDir.toPath().resolve("mappings/generated/assets/mappings")
|
||||
outputs.upToDateWhen {
|
||||
def gen_modified = project.buildDir.toPath().resolve("mappings/generated/assets/mappings").toFile().lastModified()
|
||||
def list = []
|
||||
project.rootProject.projectDir.toPath().resolve("mappings").toFile().eachFileRecurse(groovy.io.FileType.FILES) { file ->
|
||||
list << file
|
||||
}
|
||||
|
||||
for (File file : list) {
|
||||
if (file.lastModified() > gen_modified) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
tasks.processResources.dependsOn(generateMapping)
|
||||
@@ -0,0 +1,138 @@
|
||||
import com.github.retrooper.compression.strategy.JsonArrayCompressionStrategy
|
||||
import com.github.retrooper.compression.strategy.JsonObjectCompressionStrategy
|
||||
import com.github.retrooper.compression.strategy.JsonToNbtStrategy
|
||||
import com.github.retrooper.excludeAdventure
|
||||
|
||||
plugins {
|
||||
packetevents.`shadow-conventions`
|
||||
packetevents.`library-conventions`
|
||||
`mapping-compression`
|
||||
`pe-version`
|
||||
}
|
||||
|
||||
// papermc repo + disableAutoTargetJvm needed for mockbukkit
|
||||
repositories {
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
}
|
||||
|
||||
java {
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnlyApi(libs.bundles.adventure)
|
||||
implementation(libs.adventure.api)
|
||||
api(project(":patch:adventure-text-serializer-gson", "shadow")) {
|
||||
excludeAdventure()
|
||||
}
|
||||
api(libs.adventure.text.serializer.legacy) {
|
||||
excludeAdventure()
|
||||
}
|
||||
compileOnly(libs.gson)
|
||||
|
||||
testImplementation(libs.bundles.adventure)
|
||||
testImplementation(project(":patch:adventure-text-serializer-gson"))
|
||||
testImplementation(libs.adventure.text.serializer.legacy)
|
||||
testImplementation(project(":netty-common"))
|
||||
testImplementation(testlibs.mockbukkit)
|
||||
testImplementation(testlibs.slf4j)
|
||||
testImplementation(testlibs.bundles.junit)
|
||||
}
|
||||
|
||||
mappingCompression {
|
||||
mappingDirectory = rootDir.resolve("mappings")
|
||||
outDirectory = project.layout.buildDirectory.dir("mappings/generated/assets/mappings")
|
||||
|
||||
with<JsonToNbtStrategy> {
|
||||
compress("block/legacy_block_mappings.json")
|
||||
compress("block/modern_block_mappings.json")
|
||||
|
||||
compress("stats/statistics.json")
|
||||
}
|
||||
|
||||
with<JsonArrayCompressionStrategy> {
|
||||
compress("attribute/attribute_mappings.json")
|
||||
|
||||
compress("block/block_entity_type_mappings.json")
|
||||
compress("block/block_type_mappings.json")
|
||||
|
||||
compress("chat/chat_type_mappings.json")
|
||||
|
||||
compress("command/argument_parser_mappings.json")
|
||||
|
||||
compress("entity/entity_data_type_mappings.json")
|
||||
compress("entity/painting_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_map_decoration_type_mappings.json")
|
||||
compress("item/item_potion_mappings.json")
|
||||
compress("item/item_trim_material_mappings.json")
|
||||
compress("item/item_trim_pattern_mappings.json")
|
||||
compress("item/recipe_serializer_mappings.json")
|
||||
|
||||
compress("particle/particle_type_mappings.json")
|
||||
|
||||
compress("sound/sound_mappings.json")
|
||||
|
||||
compress("world/world_position_source_mappings.json")
|
||||
}
|
||||
|
||||
with<JsonObjectCompressionStrategy> {
|
||||
compress("enchantment/enchantment_type_mappings.json")
|
||||
|
||||
compress("entity/entity_effect_mappings.json")
|
||||
compress("entity/entity_type_mappings.json")
|
||||
compress("entity/legacy_entity_type_mappings.json")
|
||||
|
||||
compress("item/item_type_mappings.json")
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
javadoc {
|
||||
setDestinationDir(file("${project.layout.buildDirectory.asFile.get()}/docs/javadoc"))
|
||||
options {
|
||||
(this as CoreJavadocOptions).addBooleanOption("Xdoclint:none", true)
|
||||
}
|
||||
mustRunAfter(generateVersionsFile)
|
||||
}
|
||||
|
||||
sourcesJar {
|
||||
mustRunAfter(generateVersionsFile)
|
||||
}
|
||||
|
||||
withType<JavaCompile> {
|
||||
dependsOn(generateVersionsFile)
|
||||
}
|
||||
|
||||
processResources {
|
||||
dependsOn(compressMappings)
|
||||
from(project.layout.buildDirectory.dir("mappings/generated").get())
|
||||
}
|
||||
|
||||
generateVersionsFile {
|
||||
packageName = "com.github.retrooper.packetevents.util"
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
exclude {
|
||||
val path = it.path
|
||||
path.startsWith("net/kyori") && !path.startsWith("net/kyori/adventure/text/serializer") && !path.startsWith("net/kyori/option")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
named<MavenPublication>("shadow") {
|
||||
artifact(tasks["javadocJar"])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,8 @@ import com.github.retrooper.packetevents.netty.NettyManager;
|
||||
import com.github.retrooper.packetevents.settings.PacketEventsSettings;
|
||||
import com.github.retrooper.packetevents.util.LogManager;
|
||||
import com.github.retrooper.packetevents.util.PEVersion;
|
||||
//Note: The PEVersions class is generated. Refer to PEVersionTask.kt
|
||||
import com.github.retrooper.packetevents.util.PEVersions;
|
||||
import com.github.retrooper.packetevents.util.updatechecker.UpdateChecker;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
@@ -35,11 +37,9 @@ 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 final Logger LOGGER = Logger.getLogger(PacketEventsAPI.class.getName());
|
||||
private static final LogManager LOG_MANAGER = new LogManager();
|
||||
//TODO UPDATE
|
||||
private static final PEVersion VERSION = new PEVersion(2, 3, 0);
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(PacketEventsAPI.class.getName());
|
||||
|
||||
public EventManager getEventManager() {
|
||||
return EVENT_MANAGER;
|
||||
}
|
||||
@@ -53,7 +53,8 @@ public abstract class PacketEventsAPI<T> {
|
||||
}
|
||||
|
||||
public PEVersion getVersion() {
|
||||
return VERSION;
|
||||
//Note: The PEVersions class is generated by the auto-version task. Refer to PEVersionTask.kt
|
||||
return PEVersions.CURRENT;
|
||||
}
|
||||
|
||||
public Logger getLogger() {
|
||||
|
||||
@@ -23,7 +23,7 @@ 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;
|
||||
|
||||
public class EventManager {
|
||||
@@ -82,7 +82,7 @@ public class EventManager {
|
||||
public PacketListenerCommon registerListener(PacketListenerCommon listener) {
|
||||
Set<PacketListenerCommon> listenerSet = listenersMap.get(listener.getPriority());
|
||||
if (listenerSet == null) {
|
||||
listenerSet = ConcurrentHashMap.newKeySet();
|
||||
listenerSet = new CopyOnWriteArraySet<>();
|
||||
}
|
||||
listenerSet.add(listener);
|
||||
listenersMap.put(listener.getPriority(), listenerSet);
|
||||
|
||||
+31
-7
@@ -100,9 +100,21 @@ public class InternalPacketListener extends PacketListenerAbstract {
|
||||
NBTCompound registryDataTag = registryData.getRegistryData();
|
||||
NBTList<NBTCompound> list = null;
|
||||
if (registryDataTag != null) { // <1.20.5
|
||||
list = registryDataTag
|
||||
.getCompoundTagOrNull(DIMENSION_TYPE_REGISTRY_KEY.toString())
|
||||
.getCompoundListTagOrNull("value");
|
||||
//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);
|
||||
@@ -137,10 +149,22 @@ public class InternalPacketListener extends PacketListenerAbstract {
|
||||
// Store world data
|
||||
NBTCompound dimensionCodec = joinGame.getDimensionCodec();
|
||||
if (dimensionCodec != null) {
|
||||
NBTList<NBTCompound> list = dimensionCodec
|
||||
.getCompoundTagOrNull(DIMENSION_TYPE_REGISTRY_KEY.toString())
|
||||
.getCompoundListTagOrNull("value");
|
||||
user.setWorldNBT(list);
|
||||
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
|
||||
|
||||
@@ -49,6 +49,7 @@ 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),
|
||||
//TODO UPDATE Add server version constant
|
||||
ERROR(-1, true);
|
||||
|
||||
|
||||
+3
@@ -24,8 +24,11 @@ public interface ByteBufAllocationOperator {
|
||||
Object copiedBuffer(byte[] bytes);
|
||||
|
||||
Object buffer();
|
||||
Object buffer(int initialCapacity);
|
||||
|
||||
Object directBuffer();
|
||||
Object directBuffer(int initialCapacity);
|
||||
|
||||
Object compositeBuffer();
|
||||
Object compositeBuffer(int maxNumComponents);
|
||||
}
|
||||
@@ -103,6 +103,14 @@ public class ByteBufHelper {
|
||||
PacketEvents.getAPI().getNettyManager().getByteBufOperator().writeShort(buffer, value);
|
||||
}
|
||||
|
||||
public static int readMedium(Object buffer) {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufOperator().readMedium(buffer);
|
||||
}
|
||||
|
||||
public static void writeMedium(Object buffer, int value) {
|
||||
PacketEvents.getAPI().getNettyManager().getByteBufOperator().writeMedium(buffer, value);
|
||||
}
|
||||
|
||||
public static int readInt(Object buffer) {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufOperator().readInt(buffer);
|
||||
}
|
||||
|
||||
+6
-6
@@ -42,27 +42,27 @@ public class ByteBufInputStream extends InputStream implements DataInput {
|
||||
this(buffer, ByteBufHelper.readableBytes(buffer), releaseOnClose);
|
||||
}
|
||||
|
||||
public ByteBufInputStream(Object buffer, int length, boolean releaseOnClose) {
|
||||
public ByteBufInputStream(Object buffer, int maxLength, boolean releaseOnClose) {
|
||||
this.lineBuf = new StringBuilder();
|
||||
if (buffer == null) {
|
||||
throw new NullPointerException("buffer");
|
||||
} else if (length < 0) {
|
||||
} else if (maxLength < 0) {
|
||||
if (releaseOnClose) {
|
||||
ByteBufHelper.release(buffer);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("length: " + length);
|
||||
} else if (length > ByteBufHelper.readableBytes(buffer)) {
|
||||
throw new IllegalArgumentException("maxLength: " + maxLength);
|
||||
} else if (ByteBufHelper.readableBytes(buffer) > maxLength) {
|
||||
if (releaseOnClose) {
|
||||
ByteBufHelper.release(buffer);
|
||||
}
|
||||
|
||||
throw new IndexOutOfBoundsException("Too many bytes to be read - Needs " + length + ", maximum is " + ByteBufHelper.readableBytes(buffer));
|
||||
throw new IndexOutOfBoundsException("Too many bytes to be read - Found " + ByteBufHelper.readableBytes(buffer) + ", maximum is " + maxLength);
|
||||
} else {
|
||||
this.releaseOnClose = releaseOnClose;
|
||||
this.buffer = buffer;
|
||||
this.startIndex = ByteBufHelper.readerIndex(buffer);
|
||||
this.endIndex = this.startIndex + length;
|
||||
this.endIndex = this.startIndex + ByteBufHelper.readableBytes(buffer);
|
||||
ByteBufHelper.markReaderIndex(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,14 @@ public interface ByteBufOperator {
|
||||
|
||||
byte readByte(Object buffer);
|
||||
short readShort(Object buffer);
|
||||
int readMedium(Object buffer);
|
||||
int readInt(Object buffer);
|
||||
long readUnsignedInt(Object buffer);
|
||||
long readLong(Object buffer);
|
||||
|
||||
void writeByte(Object buffer, int value);
|
||||
void writeShort(Object buffer, int value);
|
||||
void writeMedium(Object buffer, int value);
|
||||
void writeInt(Object buffer, int value);
|
||||
void writeLong(Object buffer, long value);
|
||||
|
||||
|
||||
+12
@@ -40,4 +40,16 @@ public class UnpooledByteBufAllocationHelper {
|
||||
public static Object compositeBuffer() {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().compositeBuffer();
|
||||
}
|
||||
|
||||
public static Object buffer(int initialCapacity) {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().buffer(initialCapacity);
|
||||
}
|
||||
|
||||
public static Object directBuffer(int initialCapacity) {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().directBuffer(initialCapacity);
|
||||
}
|
||||
|
||||
public static Object compositeBuffer(int maxNumComponents) {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().compositeBuffer(maxNumComponents);
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -89,7 +89,7 @@ public class Attributes {
|
||||
// Added in 1.20.2
|
||||
public static final Attribute GENERIC_MAX_ABSORPTION = define("generic.max_absorption");
|
||||
|
||||
// added in 1.20.5
|
||||
// Added in 1.20.5
|
||||
public static final Attribute PLAYER_BLOCK_BREAK_SPEED = define("player.block_break_speed");
|
||||
public static final Attribute PLAYER_BLOCK_INTERACTION_RANGE = define("player.block_interaction_range");
|
||||
public static final Attribute PLAYER_ENTITY_INTERACTION_RANGE = define("player.entity_interaction_range");
|
||||
@@ -100,6 +100,17 @@ public class Attributes {
|
||||
public static final Attribute GENERIC_SCALE = define("generic.scale");
|
||||
public static final Attribute GENERIC_STEP_HEIGHT = define("generic.step_height");
|
||||
|
||||
// Added in 1.21
|
||||
public static final Attribute GENERIC_BURNING_TIME = define("generic.burning_time");
|
||||
public static final Attribute GENERIC_EXPLOSION_KNOCKBACK_RESISTANCE = define("generic.explosion_knockback_resistance");
|
||||
public static final Attribute PLAYER_MINING_EFFICIENCY = define("player.mining_efficiency");
|
||||
public static final Attribute GENERIC_MOVEMENT_EFFICIENCY = define("generic.movement_efficiency");
|
||||
public static final Attribute GENERIC_OXYGEN_BONUS = define("generic.oxygen_bonus");
|
||||
public static final Attribute PLAYER_SNEAKING_SPEED = define("player.sneaking_speed");
|
||||
public static final Attribute PLAYER_SUBMERGED_MINING_SPEED = define("player.submerged_mining_speed");
|
||||
public static final Attribute PLAYER_SWEEPING_DAMAGE_RATIO = define("player.sweeping_damage_ratio");
|
||||
public static final Attribute GENERIC_WATER_MOVEMENT_EFFICIENCY = define("generic.water_movement_efficiency");
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
@@ -18,8 +18,32 @@
|
||||
|
||||
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.MappedEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface ChatType extends MappedEntity {
|
||||
|
||||
ChatTypeDecoration getChatDecoration();
|
||||
|
||||
ChatTypeDecoration getNarrationDecoration();
|
||||
|
||||
static ChatType readDirect(PacketWrapper<?> wrapper) {
|
||||
ChatTypeDecoration chatDecoration = ChatTypeDecoration.read(wrapper);
|
||||
ChatTypeDecoration narrationDecoration = ChatTypeDecoration.read(wrapper);
|
||||
return new StaticChatType(chatDecoration, narrationDecoration);
|
||||
}
|
||||
|
||||
static void writeDirect(PacketWrapper<?> wrapper, ChatType chatType) {
|
||||
ChatTypeDecoration.write(wrapper, chatType.getChatDecoration());
|
||||
ChatTypeDecoration.write(wrapper, chatType.getNarrationDecoration());
|
||||
}
|
||||
|
||||
class Bound extends ChatMessage_v1_19_1.ChatTypeBoundNetwork {
|
||||
public Bound(ChatType type, Component name, @Nullable Component targetName) {
|
||||
super(type, name, targetName);
|
||||
}
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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.chat;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage_v1_19_1;
|
||||
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.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 org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.Parameter.*;
|
||||
import static java.util.Arrays.asList;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||
import static net.kyori.adventure.text.format.Style.empty;
|
||||
import static net.kyori.adventure.text.format.Style.style;
|
||||
import static net.kyori.adventure.text.format.TextDecoration.ITALIC;
|
||||
|
||||
public class ChatTypeDecoration {
|
||||
|
||||
private final String translationKey;
|
||||
private final List<Parameter> parameters;
|
||||
private final Style style;
|
||||
|
||||
public ChatTypeDecoration(String translationKey, List<Parameter> parameters, Style style) {
|
||||
this.translationKey = translationKey;
|
||||
this.parameters = Collections.unmodifiableList(new ArrayList<>(parameters));
|
||||
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()));
|
||||
Style style = wrapper.readStyle();
|
||||
return new ChatTypeDecoration(translationKey, parameters, style);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, ChatTypeDecoration decoration) {
|
||||
wrapper.writeString(decoration.translationKey);
|
||||
wrapper.writeList(decoration.parameters, PacketWrapper::writeEnum);
|
||||
wrapper.writeStyle(decoration.style);
|
||||
}
|
||||
|
||||
public static ChatTypeDecoration withSender(String translationKey) {
|
||||
return new ChatTypeDecoration(translationKey, asList(SENDER, CONTENT), empty());
|
||||
}
|
||||
|
||||
public static ChatTypeDecoration incomingDirectMessage(String translationKey) {
|
||||
return new ChatTypeDecoration(translationKey, asList(SENDER, CONTENT),
|
||||
style(GRAY, ITALIC));
|
||||
}
|
||||
|
||||
public static ChatTypeDecoration outgoingDirectMessage(String translationKey) {
|
||||
return new ChatTypeDecoration(translationKey, asList(TARGET, CONTENT),
|
||||
style(GRAY, ITALIC));
|
||||
}
|
||||
|
||||
public static ChatTypeDecoration teamMessage(String translationKey) {
|
||||
return new ChatTypeDecoration(translationKey, asList(TARGET, SENDER, CONTENT), empty());
|
||||
}
|
||||
|
||||
public Component decorate(Component component, ChatType.Bound chatType) {
|
||||
ComponentLike[] components = new ComponentLike[this.parameters.size()];
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
Parameter parameter = this.parameters.get(i);
|
||||
components[i] = parameter.selector.apply(component, chatType);
|
||||
}
|
||||
return Component.translatable(this.translationKey, null, this.style, components);
|
||||
}
|
||||
|
||||
public String getTranslationKey() {
|
||||
return this.translationKey;
|
||||
}
|
||||
|
||||
public List<Parameter> getParameters() {
|
||||
return this.parameters;
|
||||
}
|
||||
|
||||
public Style getStyle() {
|
||||
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);
|
||||
|
||||
private final BiFunction<Component, ChatType.Bound, Component> selector;
|
||||
|
||||
Parameter(BiFunction<Component, ChatType.Bound, Component> selector) {
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Parameter valueByName(String name) {
|
||||
try {
|
||||
return valueOf(name);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,18 +24,44 @@ 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 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 {
|
||||
|
||||
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");
|
||||
|
||||
public static ChatType define(String key) {
|
||||
return define(key, withSender("chat.type.text"));
|
||||
}
|
||||
|
||||
public static ChatType define(String key, ChatTypeDecoration chatDeco) {
|
||||
return define(key, chatDeco, withSender("chat.type.text.narrate"));
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -61,12 +87,21 @@ public class ChatTypes {
|
||||
}
|
||||
|
||||
public static final ChatType CHAT = define("chat");
|
||||
public static final ChatType SAY_COMMAND = define("say_command");
|
||||
public static final ChatType MSG_COMMAND_INCOMING = define("msg_command_incoming");
|
||||
public static final ChatType MSG_COMMAND_OUTGOING = define("msg_command_outgoing");
|
||||
public static final ChatType TEAM_MSG_COMMAND_INCOMING = define("team_msg_command_incoming");
|
||||
public static final ChatType TEAM_MSG_COMMAND_OUTGOING = define("team_msg_command_outgoing");
|
||||
public static final ChatType EMOTE_COMMAND = define("emote_command");
|
||||
public static final ChatType SAY_COMMAND = define("say_command",
|
||||
withSender("chat.type.announcement"));
|
||||
public static final ChatType MSG_COMMAND_INCOMING = define("msg_command_incoming",
|
||||
incomingDirectMessage("commands.message.display.incoming"));
|
||||
public static final ChatType MSG_COMMAND_OUTGOING = define("msg_command_outgoing",
|
||||
outgoingDirectMessage("commands.message.display.outgoing"));
|
||||
public static final ChatType TEAM_MSG_COMMAND_INCOMING = define("team_msg_command_incoming",
|
||||
teamMessage("chat.type.team.text"));
|
||||
public static final ChatType TEAM_MSG_COMMAND_OUTGOING = define("team_msg_command_outgoing",
|
||||
teamMessage("chat.type.team.sent"));
|
||||
public static final ChatType EMOTE_COMMAND = define("emote_command",
|
||||
withSender("chat.type.emote"),
|
||||
withSender("chat.type.emote"));
|
||||
|
||||
// added by CraftBukkit for a few versions
|
||||
public static final ChatType RAW = define("raw");
|
||||
|
||||
@Deprecated
|
||||
@@ -78,6 +113,14 @@ public class ChatTypes {
|
||||
@Deprecated
|
||||
public static final ChatType TEAM_MSG_COMMAND = define("team_msg_command");
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the chat types.
|
||||
* @return Chat Types
|
||||
*/
|
||||
public static Collection<ChatType> values() {
|
||||
return Collections.unmodifiableCollection(CHAT_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.chat;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.protocol.chat.Parsers.Parser;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -26,20 +27,33 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Node {
|
||||
|
||||
private byte flags;
|
||||
private List<Integer> children;
|
||||
private int redirectNodeIndex;
|
||||
private Optional<String> name;
|
||||
private Optional<Integer> parserID;
|
||||
private Optional<Parser> parser;
|
||||
private Optional<List<Object>> properties;
|
||||
private Optional<ResourceLocation> suggestionsType;
|
||||
|
||||
public Node(byte flags, List<Integer> children, int redirectNodeIndex, @Nullable String name, @Nullable Integer parserID, @Nullable List<Object> properties, @Nullable ResourceLocation suggestionsType) {
|
||||
public Node(
|
||||
byte flags, List<Integer> children, int redirectNodeIndex, @Nullable String name,
|
||||
@Nullable Integer parserID, @Nullable List<Object> properties, @Nullable ResourceLocation suggestionsType
|
||||
) {
|
||||
this(flags, children, redirectNodeIndex, name, parserID == null ? null : Parsers.getById(
|
||||
PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), parserID),
|
||||
properties, suggestionsType);
|
||||
}
|
||||
|
||||
public Node(
|
||||
byte flags, List<Integer> children, int redirectNodeIndex, @Nullable String name, @Nullable Parser parser,
|
||||
@Nullable List<Object> properties, @Nullable ResourceLocation suggestionsType
|
||||
) {
|
||||
this.flags = flags;
|
||||
this.children = children;
|
||||
this.redirectNodeIndex = redirectNodeIndex;
|
||||
this.name = Optional.ofNullable(name);
|
||||
this.parserID = Optional.ofNullable(parserID);
|
||||
this.parser = Optional.ofNullable(parser);
|
||||
this.properties = Optional.ofNullable(properties);
|
||||
this.suggestionsType = Optional.ofNullable(suggestionsType);
|
||||
}
|
||||
@@ -76,12 +90,22 @@ public class Node {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Optional<Parser> getParser() {
|
||||
return this.parser;
|
||||
}
|
||||
|
||||
public void setParser(Optional<Parser> parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
public Optional<Integer> getParserID() {
|
||||
return parserID;
|
||||
return this.parser.map(parser -> parser.getId(PacketEvents.getAPI()
|
||||
.getServerManager().getVersion().toClientVersion()));
|
||||
}
|
||||
|
||||
public void setParserID(Optional<Integer> parserID) {
|
||||
this.parserID = parserID;
|
||||
this.parser = parserID.map(id -> Parsers.getById(PacketEvents.getAPI()
|
||||
.getServerManager().getVersion().toClientVersion(), id));
|
||||
}
|
||||
|
||||
public Optional<List<Object>> getProperties() {
|
||||
|
||||
@@ -151,7 +151,9 @@ public class Parsers {
|
||||
public static final Parser COMPONENT = define("component", null, null);
|
||||
public static final Parser STYLE = define("style", null, null);
|
||||
public static final Parser MESSAGE = define("message", null, null);
|
||||
public static final Parser NBT = define("nbt", null, null);
|
||||
public static final Parser NBT_COMPOUND_TAG = define("nbt_compound_tag", null, null);
|
||||
@Deprecated
|
||||
public static final Parser NBT = NBT_COMPOUND_TAG;
|
||||
public static final Parser NBT_TAG = define("nbt_tag", null, null);
|
||||
public static final Parser NBT_PATH = define("nbt_path", null, null);
|
||||
public static final Parser OBJECTIVE = define("objective", null, null);
|
||||
@@ -170,10 +172,13 @@ public class Parsers {
|
||||
public static final Parser ITEM_SLOT = define("item_slot", null, null);
|
||||
public static final Parser ITEM_SLOTS = define("item_slots", null, null);
|
||||
public static final Parser RESOURCE_LOCATION = define("resource_location", null, null);
|
||||
public static final Parser MOB_EFFECT = define("mob_effect", null, null);
|
||||
public static final Parser FUNCTION = define("function", null, null);
|
||||
public static final Parser ENTITY_ANCHOR = define("entity_anchor", null, null);
|
||||
public static final Parser INT_RANGE = define("int_range", null, null);
|
||||
public static final Parser FLOAT_RANGE = define("float_range", null, null);
|
||||
public static final Parser ITEM_ENCHANTMENT = define("item_enchantment", null, null);
|
||||
public static final Parser ENTITY_SUMMON = define("entity_summon", null, null);
|
||||
public static final Parser DIMENSION = define("dimension", null, null);
|
||||
public static final Parser GAMEMODE = define("gamemode", null, null);
|
||||
public static final Parser TIME = define("time",
|
||||
|
||||
+4
-4
@@ -2,9 +2,9 @@ package com.github.retrooper.packetevents.protocol.chat;
|
||||
|
||||
public class SignedCommandArgument {
|
||||
private String argument;
|
||||
private byte[] signature;
|
||||
private MessageSignature signature;
|
||||
|
||||
public SignedCommandArgument(String argument, byte[] signature) {
|
||||
public SignedCommandArgument(String argument, MessageSignature signature) {
|
||||
this.argument = argument;
|
||||
this.signature = signature;
|
||||
}
|
||||
@@ -17,11 +17,11 @@ public class SignedCommandArgument {
|
||||
this.argument = argument;
|
||||
}
|
||||
|
||||
public byte[] getSignature() {
|
||||
public MessageSignature getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(byte[] signature) {
|
||||
public void setSignature(MessageSignature signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.chat;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
|
||||
public class StaticChatType implements ChatType {
|
||||
|
||||
private final ChatTypeDecoration chatDecoration;
|
||||
private final ChatTypeDecoration narrationDecoration;
|
||||
|
||||
public StaticChatType(ChatTypeDecoration chatDecoration, ChatTypeDecoration narrationDecoration) {
|
||||
this.chatDecoration = chatDecoration;
|
||||
this.narrationDecoration = narrationDecoration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatTypeDecoration getChatDecoration() {
|
||||
return this.chatDecoration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatTypeDecoration getNarrationDecoration() {
|
||||
return this.narrationDecoration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+32
-10
@@ -30,7 +30,7 @@ import java.util.UUID;
|
||||
public class ChatMessage_v1_19_1 extends ChatMessage_v1_16 {
|
||||
private String plainContent;
|
||||
private @Nullable Component unsignedChatContent;
|
||||
private ChatTypeBoundNetwork chatType;
|
||||
private ChatType.Bound chatFormatting;
|
||||
private byte @Nullable [] previousSignature;
|
||||
private byte[] signature;
|
||||
private Instant timestamp;
|
||||
@@ -40,15 +40,15 @@ public class ChatMessage_v1_19_1 extends ChatMessage_v1_16 {
|
||||
|
||||
public ChatMessage_v1_19_1(String plainContent, Component decoratedChatContent,
|
||||
@Nullable Component unsignedChatContent,
|
||||
UUID senderUUID, ChatTypeBoundNetwork chatType,
|
||||
UUID senderUUID, ChatType.Bound chatFormatting,
|
||||
byte @Nullable [] previousSignature, byte[] signature,
|
||||
Instant timestamp, long salt,
|
||||
LastSeenMessages lastSeenMessages,
|
||||
FilterMask filterMask) {
|
||||
super(decoratedChatContent, chatType.getType(), senderUUID);
|
||||
super(decoratedChatContent, chatFormatting.getType(), senderUUID);
|
||||
this.plainContent = plainContent;
|
||||
this.unsignedChatContent = unsignedChatContent;
|
||||
this.chatType = chatType;
|
||||
this.chatFormatting = chatFormatting;
|
||||
this.previousSignature = previousSignature;
|
||||
this.signature = signature;
|
||||
this.timestamp = timestamp;
|
||||
@@ -79,20 +79,38 @@ public class ChatMessage_v1_19_1 extends ChatMessage_v1_16 {
|
||||
|
||||
@Override
|
||||
public ChatType getType() {
|
||||
return chatType.getType();
|
||||
return chatFormatting.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(ChatType type) {
|
||||
chatType.setType(type);
|
||||
chatFormatting.setType(type);
|
||||
}
|
||||
|
||||
public ChatTypeBoundNetwork getChatType() {
|
||||
return chatType;
|
||||
public ChatType.Bound getChatFormatting() {
|
||||
return chatFormatting;
|
||||
}
|
||||
|
||||
public void setChatType(ChatTypeBoundNetwork type) {
|
||||
this.chatType = type;
|
||||
public void setChatFormatting(ChatType.Bound chatFormatting) {
|
||||
this.chatFormatting = chatFormatting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the chat formatting. Please refer to {@link ChatMessage_v1_19_1#getChatFormatting}
|
||||
* @return chat formatting which contains the actual chat type.
|
||||
*/
|
||||
@Deprecated
|
||||
public ChatType.Bound getChatType() {
|
||||
return chatFormatting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chat formatting. Please refer to {@link ChatMessage_v1_19_1#setChatFormatting}
|
||||
* @param chatFormatting formatting which contains the actual chat type.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setChatType(ChatType.Bound chatFormatting) {
|
||||
this.chatFormatting = chatFormatting;
|
||||
}
|
||||
|
||||
public byte @Nullable [] getPreviousSignature() {
|
||||
@@ -143,6 +161,10 @@ public class ChatMessage_v1_19_1 extends ChatMessage_v1_16 {
|
||||
this.filterMask = filterMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Please refer to {@link com.github.retrooper.packetevents.protocol.chat.ChatType.Bound}
|
||||
*/
|
||||
@Deprecated
|
||||
public static class ChatTypeBoundNetwork {
|
||||
private ChatType type;
|
||||
private Component name;
|
||||
|
||||
+28
-8
@@ -1,5 +1,6 @@
|
||||
package com.github.retrooper.packetevents.protocol.chat.message;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.chat.ChatType;
|
||||
import com.github.retrooper.packetevents.protocol.chat.LastSeenMessages;
|
||||
import com.github.retrooper.packetevents.protocol.chat.filter.FilterMask;
|
||||
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
|
||||
@@ -19,10 +20,10 @@ public class ChatMessage_v1_19_3 extends ChatMessage_v1_16 {
|
||||
LastSeenMessages.Packed lastSeenMessagesPacked;
|
||||
@Nullable Component unsignedChatContent;
|
||||
FilterMask filterMask;
|
||||
ChatMessage_v1_19_1.ChatTypeBoundNetwork chatType;
|
||||
ChatType.Bound chatFormatting;
|
||||
|
||||
public ChatMessage_v1_19_3(UUID senderUUID, int index, byte[] signature, String plainContent, Instant timestamp, long salt, LastSeenMessages.Packed lastSeenMessagesPacked, @Nullable Component unsignedChatContent, FilterMask filterMask, ChatMessage_v1_19_1.ChatTypeBoundNetwork chatType) {
|
||||
super(Component.text(plainContent), chatType.getType(), senderUUID);
|
||||
public ChatMessage_v1_19_3(UUID senderUUID, int index, byte[] signature, String plainContent, Instant timestamp, long salt, LastSeenMessages.Packed lastSeenMessagesPacked, @Nullable Component unsignedChatContent, FilterMask filterMask, ChatType.Bound chatFormatting) {
|
||||
super(Component.text(plainContent), chatFormatting.getType(), senderUUID);
|
||||
this.index = index;
|
||||
this.signature = signature;
|
||||
this.plainContent = plainContent;
|
||||
@@ -31,7 +32,7 @@ public class ChatMessage_v1_19_3 extends ChatMessage_v1_16 {
|
||||
this.lastSeenMessagesPacked = lastSeenMessagesPacked;
|
||||
this.unsignedChatContent = unsignedChatContent;
|
||||
this.filterMask = filterMask;
|
||||
this.chatType = chatType;
|
||||
this.chatFormatting = chatFormatting;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
@@ -109,11 +110,30 @@ public class ChatMessage_v1_19_3 extends ChatMessage_v1_16 {
|
||||
this.filterMask = filterMask;
|
||||
}
|
||||
|
||||
public ChatMessage_v1_19_1.ChatTypeBoundNetwork getChatType() {
|
||||
return chatType;
|
||||
|
||||
public ChatType.Bound getChatFormatting() {
|
||||
return chatFormatting;
|
||||
}
|
||||
|
||||
public void setChatType(ChatMessage_v1_19_1.ChatTypeBoundNetwork chatType) {
|
||||
this.chatType = chatType;
|
||||
public void setChatFormatting(ChatType.Bound chatFormatting) {
|
||||
this.chatFormatting = chatFormatting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the chat formatting. Please refer to {@link ChatMessage_v1_19_3#getChatFormatting}
|
||||
* @return chat formatting which contains the actual chat type.
|
||||
*/
|
||||
@Deprecated
|
||||
public ChatType.Bound getChatType() {
|
||||
return chatFormatting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chat formatting. Please refer to {@link ChatMessage_v1_19_3#setChatFormatting}
|
||||
* @param chatFormatting formatting which contains the actual chat type.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setChatType(ChatType.Bound chatFormatting) {
|
||||
this.chatFormatting = chatFormatting;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -50,8 +50,8 @@ public class ChatMessageProcessor_v1_19_1 implements ChatMessageProcessor {
|
||||
LastSeenMessages lastSeenMessages = wrapper.readLastSeenMessages();
|
||||
Component unsignedChatContent = wrapper.readOptional(PacketWrapper::readComponent);
|
||||
FilterMask filterMask = wrapper.readFilterMask();
|
||||
ChatMessage_v1_19_1.ChatTypeBoundNetwork chatType = wrapper.readChatTypeBoundNetwork();
|
||||
return new ChatMessage_v1_19_1(plainContent, chatContent, unsignedChatContent, senderUUID, chatType,
|
||||
ChatType.Bound chatFormatting = wrapper.readChatTypeBoundNetwork();
|
||||
return new ChatMessage_v1_19_1(plainContent, chatContent, unsignedChatContent, senderUUID, chatFormatting,
|
||||
previousSignature, signature, timestamp, salt, lastSeenMessages, filterMask);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,6 @@ public class ChatMessageProcessor_v1_19_1 implements ChatMessageProcessor {
|
||||
wrapper.writeLastSeenMessages(newData.getLastSeenMessages());
|
||||
wrapper.writeOptional(newData.getUnsignedChatContent(), PacketWrapper::writeComponent);
|
||||
wrapper.writeFilterMask(newData.getFilterMask());
|
||||
wrapper.writeChatTypeBoundNetwork(newData.getChatType());
|
||||
wrapper.writeChatTypeBoundNetwork(newData.getChatFormatting());
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
package com.github.retrooper.packetevents.protocol.chat.message.reader.impl;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.chat.ChatType;
|
||||
import com.github.retrooper.packetevents.protocol.chat.LastSeenMessages;
|
||||
import com.github.retrooper.packetevents.protocol.chat.filter.FilterMask;
|
||||
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage;
|
||||
@@ -25,7 +26,7 @@ public class ChatMessageProcessor_v1_19_3 implements ChatMessageProcessor {
|
||||
LastSeenMessages.Packed lastSeenMessagesPacked = wrapper.readLastSeenMessagesPacked();
|
||||
Component unsignedChatContent = wrapper.readOptional(PacketWrapper::readComponent);
|
||||
FilterMask filterMask = wrapper.readFilterMask();
|
||||
ChatMessage_v1_19_1.ChatTypeBoundNetwork chatType = wrapper.readChatTypeBoundNetwork();
|
||||
ChatType.Bound chatType = wrapper.readChatTypeBoundNetwork();
|
||||
|
||||
return new ChatMessage_v1_19_3(senderUUID, index, signature, plainContent, timestamp, salt, lastSeenMessagesPacked, unsignedChatContent, filterMask, chatType);
|
||||
}
|
||||
@@ -42,6 +43,6 @@ public class ChatMessageProcessor_v1_19_3 implements ChatMessageProcessor {
|
||||
wrapper.writeLastSeenMessagesPacked(newData.getLastSeenMessagesPacked());
|
||||
wrapper.writeOptional(newData.getUnsignedChatContent().orElse(null), PacketWrapper::writeComponent);
|
||||
wrapper.writeFilterMask(newData.getFilterMask());
|
||||
wrapper.writeChatTypeBoundNetwork(newData.getChatType());
|
||||
wrapper.writeChatTypeBoundNetwork(newData.getChatFormatting());
|
||||
}
|
||||
}
|
||||
+20
-1
@@ -23,6 +23,7 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.ArmorTr
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.BannerLayers;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.BundleContents;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ChargedProjectiles;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.CustomData;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.DebugStickState;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.FireworkExplosion;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.FoodProperties;
|
||||
@@ -35,6 +36,7 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemCon
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemDyeColor;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemEnchantments;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemFireworks;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemJukeboxPlayable;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemLock;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemLore;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemMapDecorations;
|
||||
@@ -61,6 +63,8 @@ import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
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;
|
||||
@@ -132,7 +136,9 @@ public class ComponentTypes {
|
||||
|
||||
// item component types
|
||||
public static final ComponentType<NBTCompound> CUSTOM_DATA = define("custom_data",
|
||||
PacketWrapper::readNBT, PacketWrapper::writeNBT);
|
||||
// mojang wraps their "persistent" codec as a stream codec just here,
|
||||
// so packetevents has to handle nbt strings
|
||||
CustomData::read, CustomData::write);
|
||||
public static final ComponentType<Integer> MAX_STACK_SIZE = define("max_stack_size",
|
||||
PacketWrapper::readVarInt, PacketWrapper::writeVarInt);
|
||||
public static final ComponentType<Integer> MAX_DAMAGE = define("max_damage",
|
||||
@@ -244,6 +250,19 @@ public class ComponentTypes {
|
||||
public static final ComponentType<ItemContainerLoot> CONTAINER_LOOT = define("container_loot",
|
||||
ItemContainerLoot::read, ItemContainerLoot::write);
|
||||
|
||||
// added in 1.21
|
||||
public static final ComponentType<ItemJukeboxPlayable> JUKEBOX_PLAYABLE = define("jukebox_playable",
|
||||
ItemJukeboxPlayable::read, ItemJukeboxPlayable::write);
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the component types.
|
||||
*
|
||||
* @return Component Types
|
||||
*/
|
||||
public static Collection<ComponentType<?>> values() {
|
||||
return Collections.unmodifiableCollection(COMPONENT_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
+5
@@ -87,4 +87,9 @@ public class ArmorTrim {
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.material, this.pattern, this.showInTooltip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArmorTrim{material=" + this.material + ", pattern=" + this.pattern + ", showInTooltip=" + this.showInTooltip + '}';
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.component.builtin.item;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class CustomData {
|
||||
|
||||
private CustomData() {
|
||||
}
|
||||
|
||||
public static NBTCompound read(PacketWrapper<?> wrapper) {
|
||||
NBT nbt = wrapper.readNBTRaw();
|
||||
if (nbt instanceof NBTCompound) {
|
||||
return (NBTCompound) nbt;
|
||||
}
|
||||
if (nbt instanceof NBTString) {
|
||||
// TODO: parse nbt string
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported custom data nbt type: " + nbt.getType());
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, NBTCompound compound) {
|
||||
wrapper.writeNBT(compound);
|
||||
}
|
||||
}
|
||||
+33
-4
@@ -18,8 +18,11 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.component.builtin.item;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.potion.PotionEffect;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -31,13 +34,25 @@ public class FoodProperties {
|
||||
private boolean canAlwaysEat;
|
||||
private float eatSeconds;
|
||||
private List<PossibleEffect> effects;
|
||||
private @Nullable ItemStack usingConvertsTo;
|
||||
|
||||
public FoodProperties(int nutrition, float saturation, boolean canAlwaysEat, float eatSeconds, List<PossibleEffect> effects) {
|
||||
public FoodProperties(
|
||||
int nutrition, float saturation, boolean canAlwaysEat,
|
||||
float eatSeconds, List<PossibleEffect> effects
|
||||
) {
|
||||
this(nutrition, saturation, canAlwaysEat, eatSeconds, effects, null);
|
||||
}
|
||||
|
||||
public FoodProperties(
|
||||
int nutrition, float saturation, boolean canAlwaysEat, float eatSeconds,
|
||||
List<PossibleEffect> effects, @Nullable ItemStack usingConvertsTo
|
||||
) {
|
||||
this.nutrition = nutrition;
|
||||
this.saturation = saturation;
|
||||
this.canAlwaysEat = canAlwaysEat;
|
||||
this.eatSeconds = eatSeconds;
|
||||
this.effects = effects;
|
||||
this.usingConvertsTo = usingConvertsTo;
|
||||
}
|
||||
|
||||
public static FoodProperties read(PacketWrapper<?> wrapper) {
|
||||
@@ -46,7 +61,9 @@ public class FoodProperties {
|
||||
boolean canAlwaysEat = wrapper.readBoolean();
|
||||
float eatSeconds = wrapper.readFloat();
|
||||
List<PossibleEffect> effects = wrapper.readList(PossibleEffect::read);
|
||||
return new FoodProperties(nutrition, saturation, canAlwaysEat, eatSeconds, effects);
|
||||
ItemStack usingConvertsTo = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)
|
||||
? wrapper.readOptional(PacketWrapper::readItemStack) : null;
|
||||
return new FoodProperties(nutrition, saturation, canAlwaysEat, eatSeconds, effects, usingConvertsTo);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, FoodProperties props) {
|
||||
@@ -55,6 +72,9 @@ public class FoodProperties {
|
||||
wrapper.writeBoolean(props.canAlwaysEat);
|
||||
wrapper.writeFloat(props.eatSeconds);
|
||||
wrapper.writeList(props.effects, PossibleEffect::write);
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)) {
|
||||
wrapper.writeOptional(props.usingConvertsTo, PacketWrapper::writeItemStack);
|
||||
}
|
||||
}
|
||||
|
||||
public int getNutrition() {
|
||||
@@ -101,6 +121,14 @@ public class FoodProperties {
|
||||
this.effects = effects;
|
||||
}
|
||||
|
||||
public @Nullable ItemStack getUsingConvertsTo() {
|
||||
return this.usingConvertsTo;
|
||||
}
|
||||
|
||||
public void setUsingConvertsTo(@Nullable ItemStack usingConvertsTo) {
|
||||
this.usingConvertsTo = usingConvertsTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
@@ -110,12 +138,13 @@ public class FoodProperties {
|
||||
if (Float.compare(that.saturation, this.saturation) != 0) return false;
|
||||
if (this.canAlwaysEat != that.canAlwaysEat) return false;
|
||||
if (Float.compare(that.eatSeconds, this.eatSeconds) != 0) return false;
|
||||
return this.effects.equals(that.effects);
|
||||
if (!this.effects.equals(that.effects)) return false;
|
||||
return Objects.equals(this.usingConvertsTo, that.usingConvertsTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.nutrition, this.saturation, this.canAlwaysEat, this.eatSeconds, this.effects);
|
||||
return Objects.hash(this.nutrition, this.saturation, this.canAlwaysEat, this.eatSeconds, this.effects, this.usingConvertsTo);
|
||||
}
|
||||
|
||||
public static class PossibleEffect {
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.component.builtin.item;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.item.jukebox.JukeboxSong;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ItemJukeboxPlayable {
|
||||
|
||||
private @Nullable JukeboxSong song;
|
||||
private @Nullable ResourceLocation songKey;
|
||||
private boolean showInTooltip;
|
||||
|
||||
public ItemJukeboxPlayable(
|
||||
@Nullable JukeboxSong song,
|
||||
@Nullable ResourceLocation songKey,
|
||||
boolean showInTooltip
|
||||
) {
|
||||
if ((song == null) == (songKey == null)) {
|
||||
throw new IllegalStateException("Illegal state of both song and "
|
||||
+ "song key combined: " + song + " / " + songKey);
|
||||
}
|
||||
|
||||
this.song = song;
|
||||
this.songKey = songKey;
|
||||
this.showInTooltip = showInTooltip;
|
||||
}
|
||||
|
||||
public static ItemJukeboxPlayable read(PacketWrapper<?> wrapper) {
|
||||
JukeboxSong song;
|
||||
ResourceLocation songKey;
|
||||
if (wrapper.readBoolean()) {
|
||||
song = JukeboxSong.read(wrapper);
|
||||
songKey = null;
|
||||
} else {
|
||||
song = null;
|
||||
songKey = wrapper.readIdentifier();
|
||||
}
|
||||
boolean showInTooltip = wrapper.readBoolean();
|
||||
return new ItemJukeboxPlayable(song, songKey, showInTooltip);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, ItemJukeboxPlayable jukeboxPlayable) {
|
||||
if (jukeboxPlayable.song != null) {
|
||||
wrapper.writeBoolean(true);
|
||||
JukeboxSong.write(wrapper, jukeboxPlayable.song);
|
||||
} else {
|
||||
assert jukeboxPlayable.songKey != null;
|
||||
wrapper.writeBoolean(false);
|
||||
wrapper.writeIdentifier(jukeboxPlayable.songKey);
|
||||
}
|
||||
wrapper.writeBoolean(jukeboxPlayable.showInTooltip);
|
||||
}
|
||||
|
||||
public @Nullable JukeboxSong getSong() {
|
||||
return this.song;
|
||||
}
|
||||
|
||||
public void setSong(JukeboxSong song) {
|
||||
this.song = song;
|
||||
this.songKey = null;
|
||||
}
|
||||
|
||||
public @Nullable ResourceLocation getSongKey() {
|
||||
return this.songKey;
|
||||
}
|
||||
|
||||
public void setSongKey(ResourceLocation songKey) {
|
||||
this.song = null;
|
||||
this.songKey = songKey;
|
||||
}
|
||||
|
||||
public boolean isShowInTooltip() {
|
||||
return this.showInTooltip;
|
||||
}
|
||||
|
||||
public void setShowInTooltip(boolean showInTooltip) {
|
||||
this.showInTooltip = showInTooltip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof ItemJukeboxPlayable)) return false;
|
||||
ItemJukeboxPlayable that = (ItemJukeboxPlayable) obj;
|
||||
if (this.showInTooltip != that.showInTooltip) return false;
|
||||
if (!Objects.equals(this.song, that.song)) return false;
|
||||
return Objects.equals(this.songKey, that.songKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.song, this.songKey, this.showInTooltip);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -122,7 +122,7 @@ public class ItemMapDecorations {
|
||||
compound.setTag("type", new NBTString(decoration.type.getName().toString()));
|
||||
compound.setTag("x", new NBTDouble(decoration.x));
|
||||
compound.setTag("z", new NBTDouble(decoration.z));
|
||||
compound.setTag("float", new NBTFloat(decoration.rotation));
|
||||
compound.setTag("rotation", new NBTFloat(decoration.rotation));
|
||||
}
|
||||
|
||||
public MapDecorationType getType() {
|
||||
|
||||
+21
-10
@@ -27,6 +27,7 @@ import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
|
||||
public class PotDecorations {
|
||||
@@ -36,8 +37,13 @@ public class PotDecorations {
|
||||
private @Nullable ItemType right;
|
||||
private @Nullable ItemType front;
|
||||
|
||||
private PotDecorations(Queue<ItemType> items) {
|
||||
this(items.poll(), items.poll(), items.poll(), items.poll());
|
||||
private PotDecorations(Queue<Optional<ItemType>> items) {
|
||||
this(
|
||||
items.isEmpty() ? null : items.remove().orElse(null),
|
||||
items.isEmpty() ? null : items.remove().orElse(null),
|
||||
items.isEmpty() ? null : items.remove().orElse(null),
|
||||
items.isEmpty() ? null : items.remove().orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
public PotDecorations(
|
||||
@@ -52,23 +58,28 @@ public class PotDecorations {
|
||||
this.front = front;
|
||||
}
|
||||
|
||||
private List<ItemType> asList() {
|
||||
return Arrays.asList(this.back, this.left, this.right, this.front);
|
||||
private List<Optional<ItemType>> asList() {
|
||||
return Arrays.asList(
|
||||
Optional.ofNullable(this.back),
|
||||
Optional.ofNullable(this.left),
|
||||
Optional.ofNullable(this.right),
|
||||
Optional.ofNullable(this.front)
|
||||
);
|
||||
}
|
||||
|
||||
private static @Nullable ItemType readItem(PacketWrapper<?> wrapper) {
|
||||
private static Optional<ItemType> readItem(PacketWrapper<?> wrapper) {
|
||||
ItemType type = wrapper.readMappedEntity(ItemTypes::getById);
|
||||
return type == ItemTypes.BRICK ? null : type;
|
||||
return type == ItemTypes.BRICK ? Optional.empty() : Optional.of(type);
|
||||
}
|
||||
|
||||
public static PotDecorations read(PacketWrapper<?> wrapper) {
|
||||
Queue<ItemType> items = wrapper.<ItemType, Queue<ItemType>>readCollection(
|
||||
ArrayDeque::new, PotDecorations::readItem);
|
||||
Queue<Optional<ItemType>> items = wrapper.<Optional<ItemType>, Queue<Optional<ItemType>>>
|
||||
readCollection(ArrayDeque::new, PotDecorations::readItem);
|
||||
return new PotDecorations(items);
|
||||
}
|
||||
|
||||
private static void writeItem(PacketWrapper<?> wrapper, @Nullable ItemType type) {
|
||||
wrapper.writeMappedEntity(type == null ? ItemTypes.BRICK : type);
|
||||
private static void writeItem(PacketWrapper<?> wrapper, Optional<ItemType> type) {
|
||||
wrapper.writeMappedEntity(type.orElse(ItemTypes.BRICK));
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, PotDecorations decorations) {
|
||||
|
||||
+9
-5
@@ -39,11 +39,7 @@ import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -210,6 +206,14 @@ public class EntityDataTypes {
|
||||
public static final EntityDataType<Integer> WOLF_VARIANT =
|
||||
define("wolf_variant_type", readIntDeserializer(), writeIntSerializer());
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the entity-data types.
|
||||
* @return Entity-Data Types
|
||||
*/
|
||||
public static Collection<EntityDataType<?>> values() {
|
||||
return Collections.unmodifiableCollection(ENTITY_DATA_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
public static EntityDataType<?> getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, EntityDataType<?>> typeIdMap = ENTITY_DATA_TYPE_ID_MAP.get((byte) index);
|
||||
|
||||
+9
-3
@@ -24,9 +24,7 @@ import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
|
||||
public class EntityTypes {
|
||||
private static final Map<String, EntityType> ENTITY_TYPE_MAP = new HashMap<>();
|
||||
@@ -297,6 +295,14 @@ public class EntityTypes {
|
||||
public static final EntityType BREEZE_WIND_CHARGE = define("breeze_wind_charge", ABSTRACT_WIND_CHARGE);
|
||||
public static final EntityType OMINOUS_ITEM_SPAWNER = define("ominous_item_spawner", ENTITY);
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the entity types.
|
||||
* @return Entity Types
|
||||
*/
|
||||
public static Collection<EntityType> values() {
|
||||
return Collections.unmodifiableCollection(ENTITY_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
LEGACY_TYPES_BUILDER.unloadFileMappings();
|
||||
|
||||
+10
@@ -20,6 +20,8 @@ package com.github.retrooper.packetevents.protocol.entity.villager.type;
|
||||
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -62,4 +64,12 @@ public class VillagerTypes {
|
||||
public static final VillagerType SNOW = define(4, "minecraft:snow");
|
||||
public static final VillagerType SWAMP = define(5, "minecraft:swamp");
|
||||
public static final VillagerType TAIGA = define(6, "minecraft:taiga");
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the villager types.
|
||||
* @return Villager Types
|
||||
*/
|
||||
public static Collection<VillagerType> values() {
|
||||
return Collections.unmodifiableCollection(VILLAGER_TYPE_MAP.values());
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.github.retrooper.packetevents.protocol.entity.wolfvariant;
|
||||
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
//TODO Finish Wolf-Variant class
|
||||
public class WolfVariant {
|
||||
private ResourceLocation wildId, tameId, angryId;
|
||||
|
||||
public WolfVariant(ResourceLocation wildId, ResourceLocation tameId, ResourceLocation angryId) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,14 @@ package com.github.retrooper.packetevents.protocol.item;
|
||||
import com.github.retrooper.packetevents.protocol.component.ComponentType;
|
||||
import com.github.retrooper.packetevents.protocol.component.ComponentTypes;
|
||||
import com.github.retrooper.packetevents.protocol.component.PatchableComponentMap;
|
||||
import com.github.retrooper.packetevents.protocol.component.StaticComponentMap;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemEnchantments;
|
||||
import com.github.retrooper.packetevents.protocol.item.enchantment.Enchantment;
|
||||
import com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentType;
|
||||
import com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentTypes;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
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;
|
||||
@@ -273,17 +275,15 @@ public class ItemStack {
|
||||
}
|
||||
|
||||
// check for components
|
||||
Optional<ItemEnchantments> optEnchantments = this.getComponent(ENCHANTMENTS);
|
||||
Optional<ItemEnchantments> optStoredEnchantments = this.getComponent(STORED_ENCHANTMENTS);
|
||||
if (optEnchantments.isPresent() || optStoredEnchantments.isPresent()) {
|
||||
ItemEnchantments enchantments = optEnchantments.orElse(ItemEnchantments.EMPTY);
|
||||
ItemEnchantments storedEnchantments = optStoredEnchantments.orElse(ItemEnchantments.EMPTY);
|
||||
ItemEnchantments enchantmentsComp = this.getComponentOr(ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
ItemEnchantments storedEnchantmentsComp = this.getComponentOr(STORED_ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
if (!enchantmentsComp.isEmpty() || !storedEnchantmentsComp.isEmpty()) {
|
||||
List<Enchantment> enchantmentsList = new ArrayList<>(
|
||||
enchantments.getEnchantmentCount() + storedEnchantments.getEnchantmentCount());
|
||||
for (Map.Entry<EnchantmentType, Integer> enchantment : enchantments) {
|
||||
enchantmentsComp.getEnchantmentCount() + storedEnchantmentsComp.getEnchantmentCount());
|
||||
for (Map.Entry<EnchantmentType, Integer> enchantment : enchantmentsComp) {
|
||||
enchantmentsList.add(new Enchantment(enchantment.getKey(), enchantment.getValue()));
|
||||
}
|
||||
for (Map.Entry<EnchantmentType, Integer> enchantment : storedEnchantments) {
|
||||
for (Map.Entry<EnchantmentType, Integer> enchantment : storedEnchantmentsComp) {
|
||||
enchantmentsList.add(new Enchantment(enchantment.getKey(), enchantment.getValue()));
|
||||
}
|
||||
return enchantmentsList;
|
||||
@@ -320,16 +320,16 @@ public class ItemStack {
|
||||
}
|
||||
|
||||
// check for components
|
||||
Optional<ItemEnchantments> optEnchantments = this.getComponent(ENCHANTMENTS);
|
||||
if (optEnchantments.isPresent()) {
|
||||
int level = optEnchantments.get().getEnchantmentLevel(enchantment);
|
||||
ItemEnchantments enchantmentsComp = this.getComponentOr(ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
if (!enchantmentsComp.isEmpty()) {
|
||||
int level = enchantmentsComp.getEnchantmentLevel(enchantment);
|
||||
if (level > 0) {
|
||||
return level;
|
||||
}
|
||||
}
|
||||
Optional<ItemEnchantments> optStoredEnchantments = this.getComponent(STORED_ENCHANTMENTS);
|
||||
if (optStoredEnchantments.isPresent()) {
|
||||
int level = optStoredEnchantments.get().getEnchantmentLevel(enchantment);
|
||||
ItemEnchantments storedEnchantmentsComp = this.getComponentOr(STORED_ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
if (!storedEnchantmentsComp.isEmpty()) {
|
||||
int level = storedEnchantmentsComp.getEnchantmentLevel(enchantment);
|
||||
if (level > 0) {
|
||||
return level;
|
||||
}
|
||||
@@ -496,11 +496,28 @@ public class ItemStack {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder nbt(String key, NBT tag) {
|
||||
if (this.nbt == null) {
|
||||
this.nbt = new NBTCompound();
|
||||
}
|
||||
this.nbt.setTag(key, tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder components(@Nullable PatchableComponentMap components) {
|
||||
this.components = components;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder component(ComponentType<T> type, @Nullable T value) {
|
||||
if (this.components == null) {
|
||||
this.components = new PatchableComponentMap(this.type == null
|
||||
? StaticComponentMap.SHARED_ITEM_COMPONENTS : this.type.getComponents());
|
||||
}
|
||||
this.components.set(type, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder legacyData(int legacyData) {
|
||||
this.legacyData = legacyData;
|
||||
return this;
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public class ArmorMaterials {
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return TYPES_BUILDER.getDataIndex(version);
|
||||
return MappingHelper.getId(version, TYPES_BUILDER, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+15
-1
@@ -24,6 +24,8 @@ 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 java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -59,7 +61,7 @@ public class BannerPatterns {
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return TYPES_BUILDER.getDataIndex(version);
|
||||
return MappingHelper.getId(version, TYPES_BUILDER, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,6 +129,18 @@ public class BannerPatterns {
|
||||
public static final BannerPattern PIGLIN = define("piglin");
|
||||
public static final BannerPattern DIAGONAL_LEFT = define("diagonal_left");
|
||||
|
||||
// Added with 1.21
|
||||
public static final BannerPattern FLOW = define("flow");
|
||||
public static final BannerPattern GUSTER = define("guster");
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the banner patterns.
|
||||
* @return Banner Patterns
|
||||
*/
|
||||
public static Collection<BannerPattern> values() {
|
||||
return Collections.unmodifiableCollection(PATTERN_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.sound.Sound;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class JukeboxSong {
|
||||
|
||||
private Sound sound;
|
||||
private Component description;
|
||||
private float lengthInSeconds;
|
||||
private int comparatorOutput;
|
||||
|
||||
public JukeboxSong(Sound sound, Component description, float lengthInSeconds, int comparatorOutput) {
|
||||
this.sound = sound;
|
||||
this.description = description;
|
||||
this.lengthInSeconds = lengthInSeconds;
|
||||
this.comparatorOutput = comparatorOutput;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public Sound getSound() {
|
||||
return this.sound;
|
||||
}
|
||||
|
||||
public void setSound(Sound sound) {
|
||||
this.sound = sound;
|
||||
}
|
||||
|
||||
public Component getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(Component description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public float getLengthInSeconds() {
|
||||
return this.lengthInSeconds;
|
||||
}
|
||||
|
||||
public void setLengthInSeconds(float lengthInSeconds) {
|
||||
this.lengthInSeconds = lengthInSeconds;
|
||||
}
|
||||
|
||||
public int getComparatorOutput() {
|
||||
return this.comparatorOutput;
|
||||
}
|
||||
|
||||
public void setComparatorOutput(int comparatorOutput) {
|
||||
this.comparatorOutput = comparatorOutput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof JukeboxSong)) return false;
|
||||
JukeboxSong that = (JukeboxSong) obj;
|
||||
if (Float.compare(that.lengthInSeconds, this.lengthInSeconds) != 0) return false;
|
||||
if (this.comparatorOutput != that.comparatorOutput) return false;
|
||||
if (!this.sound.equals(that.sound)) return false;
|
||||
return this.description.equals(that.description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.sound, this.description, this.lengthInSeconds, this.comparatorOutput);
|
||||
}
|
||||
}
|
||||
+14
@@ -25,6 +25,8 @@ import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -117,6 +119,10 @@ public class MapDecorationTypes {
|
||||
}
|
||||
|
||||
public static @Nullable MapDecorationType getById(int id, ClientVersion version) {
|
||||
return getById(version, id);
|
||||
}
|
||||
|
||||
public static @Nullable MapDecorationType getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, MapDecorationType> idMap = DECORATION_TYPE_ID_MAP.get((byte) index);
|
||||
return idMap.get(id);
|
||||
@@ -201,6 +207,14 @@ public class MapDecorationTypes {
|
||||
public static final MapDecorationType TRIAL_CHAMBERS = define("trial_chambers",
|
||||
true, COPPER_COLOR, true, false);
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the map decoration types.
|
||||
* @return Map Decoration Types
|
||||
*/
|
||||
public static Collection<MapDecorationType> values() {
|
||||
return Collections.unmodifiableCollection(DECORATION_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
+18
-8
@@ -29,6 +29,8 @@ import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -37,8 +39,8 @@ import static net.kyori.adventure.text.format.TextColor.color;
|
||||
|
||||
public class TrimMaterials {
|
||||
|
||||
private static final Map<String, TrimMaterial> PATTERN_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<Byte, Map<Integer, TrimMaterial>> PATTERN_TYPE_ID_MAP = new HashMap<>();
|
||||
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");
|
||||
|
||||
public static TrimMaterial define(String key, ItemType ingredient, float itemModelIndex, int color) {
|
||||
@@ -59,7 +61,7 @@ public class TrimMaterials {
|
||||
Map<ArmorMaterial, String> overrideArmorMaterials, Component description
|
||||
) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
TrimMaterial pattern = new TrimMaterial() {
|
||||
TrimMaterial material = new TrimMaterial() {
|
||||
@Override
|
||||
public String getAssetName() {
|
||||
return assetName;
|
||||
@@ -92,7 +94,7 @@ public class TrimMaterials {
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return TYPES_BUILDER.getDataIndex(version);
|
||||
return MappingHelper.getId(version, TYPES_BUILDER, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,18 +105,18 @@ public class TrimMaterials {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, PATTERN_TYPE_MAP, PATTERN_TYPE_ID_MAP, pattern);
|
||||
return pattern;
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, TRIM_MATERIAL_MAP, TRIM_MATERIAL_ID_MAP, material);
|
||||
return material;
|
||||
}
|
||||
|
||||
// with key
|
||||
public static TrimMaterial getByName(String name) {
|
||||
return PATTERN_TYPE_MAP.get(name);
|
||||
return TRIM_MATERIAL_MAP.get(name);
|
||||
}
|
||||
|
||||
public static TrimMaterial getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, TrimMaterial> idMap = PATTERN_TYPE_ID_MAP.get((byte) index);
|
||||
Map<Integer, TrimMaterial> idMap = TRIM_MATERIAL_ID_MAP.get((byte) index);
|
||||
return idMap.get(id);
|
||||
}
|
||||
|
||||
@@ -130,6 +132,14 @@ public class TrimMaterials {
|
||||
public static final TrimMaterial QUARTZ = define("quartz", ItemTypes.QUARTZ, 0.1f, 0xE3D4C4);
|
||||
public static final TrimMaterial REDSTONE = define("redstone", ItemTypes.REDSTONE, 0.4f, 0x971607);
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the trim materials.
|
||||
* @return Trim Materials
|
||||
*/
|
||||
public static Collection<TrimMaterial> values() {
|
||||
return Collections.unmodifiableCollection(TRIM_MATERIAL_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ public class TrimPatterns {
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return TYPES_BUILDER.getDataIndex(version);
|
||||
return MappingHelper.getId(version, TYPES_BUILDER, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+14
-9
@@ -1385,14 +1385,14 @@ public class ItemTypes {
|
||||
public static final ItemType WAXED_EXPOSED_CHISELED_COPPER = builder("waxed_exposed_chiseled_copper").setMaxAmount(64).setPlacedType(StateTypes.WAXED_EXPOSED_CHISELED_COPPER).build();
|
||||
public static final ItemType WAXED_WEATHERED_CHISELED_COPPER = builder("waxed_weathered_chiseled_copper").setMaxAmount(64).setPlacedType(StateTypes.WAXED_WEATHERED_CHISELED_COPPER).build();
|
||||
public static final ItemType WAXED_OXIDIZED_CHISELED_COPPER = builder("waxed_oxidized_chiseled_copper").setMaxAmount(64).setPlacedType(StateTypes.WAXED_OXIDIZED_CHISELED_COPPER).build();
|
||||
public static final ItemType COPPER_DOOR = builder("copper_door").setMaxAmount(64).setPlacedType(StateTypes.COPPER_DOOR).build();
|
||||
public static final ItemType EXPOSED_COPPER_DOOR = builder("exposed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.EXPOSED_COPPER_DOOR).build();
|
||||
public static final ItemType WEATHERED_COPPER_DOOR = builder("weathered_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WEATHERED_COPPER_DOOR).build();
|
||||
public static final ItemType OXIDIZED_COPPER_DOOR = builder("oxidized_copper_door").setMaxAmount(64).setPlacedType(StateTypes.OXIDIZED_COPPER_DOOR).build();
|
||||
public static final ItemType WAXED_COPPER_DOOR = builder("waxed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_COPPER_DOOR).build();
|
||||
public static final ItemType WAXED_EXPOSED_COPPER_DOOR = builder("waxed_exposed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_EXPOSED_COPPER_DOOR).build();
|
||||
public static final ItemType WAXED_WEATHERED_COPPER_DOOR = builder("waxed_weathered_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_WEATHERED_COPPER_DOOR).build();
|
||||
public static final ItemType WAXED_OXIDIZED_COPPER_DOOR = builder("waxed_oxidized_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_OXIDIZED_COPPER_DOOR).build();
|
||||
public static final ItemType COPPER_DOOR = builder("copper_door").setMaxAmount(64).setPlacedType(StateTypes.COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType EXPOSED_COPPER_DOOR = builder("exposed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.EXPOSED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType WEATHERED_COPPER_DOOR = builder("weathered_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WEATHERED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType OXIDIZED_COPPER_DOOR = builder("oxidized_copper_door").setMaxAmount(64).setPlacedType(StateTypes.OXIDIZED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType WAXED_COPPER_DOOR = builder("waxed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType WAXED_EXPOSED_COPPER_DOOR = builder("waxed_exposed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_EXPOSED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType WAXED_WEATHERED_COPPER_DOOR = builder("waxed_weathered_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_WEATHERED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType WAXED_OXIDIZED_COPPER_DOOR = builder("waxed_oxidized_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_OXIDIZED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType COPPER_TRAPDOOR = builder("copper_trapdoor").setMaxAmount(64).setPlacedType(StateTypes.COPPER_TRAPDOOR).build();
|
||||
public static final ItemType EXPOSED_COPPER_TRAPDOOR = builder("exposed_copper_trapdoor").setMaxAmount(64).setPlacedType(StateTypes.EXPOSED_COPPER_TRAPDOOR).build();
|
||||
public static final ItemType WEATHERED_COPPER_TRAPDOOR = builder("weathered_copper_trapdoor").setMaxAmount(64).setPlacedType(StateTypes.WEATHERED_COPPER_TRAPDOOR).build();
|
||||
@@ -1429,7 +1429,7 @@ public class ItemTypes {
|
||||
public static final ItemType HEAVY_CORE = builder("heavy_core").setMaxAmount(64).setPlacedType(StateTypes.HEAVY_CORE).build();
|
||||
public static final ItemType BOGGED_SPAWN_EGG = builder("bogged_spawn_egg").setMaxAmount(64).build();
|
||||
public static final ItemType WIND_CHARGE = builder("wind_charge").setMaxAmount(64).build();
|
||||
public static final ItemType MACE = builder("mace").setMaxAmount(1).setMaxDurability(250).setComponent(DAMAGE, 0).setComponent(ATTRIBUTE_MODIFIERS, new ItemAttributeModifiers(Arrays.asList(new ItemAttributeModifiers.ModifierEntry(Attributes.GENERIC_ATTACK_DAMAGE, new ItemAttributeModifiers.Modifier(TOOL_MODIFIER_ATTACK_DAMAGE_UUID, "Weapon modifier", 6.0d, AttributeOperation.ADDITION), ItemAttributeModifiers.EquipmentSlotGroup.MAINHAND), new ItemAttributeModifiers.ModifierEntry(Attributes.GENERIC_ATTACK_SPEED, new ItemAttributeModifiers.Modifier(TOOL_MODIFIER_ATTACK_SPEED_UUID, "Weapon modifier", -2.4d, AttributeOperation.ADDITION), ItemAttributeModifiers.EquipmentSlotGroup.MAINHAND)), true)).setComponent(TOOL, new ItemTool(Collections.emptyList(), 1.0f, 2)).build();
|
||||
public static final ItemType MACE = builder("mace").setMaxAmount(1).setMaxDurability(500).setComponent(DAMAGE, 0).setComponent(ATTRIBUTE_MODIFIERS, new ItemAttributeModifiers(Arrays.asList(new ItemAttributeModifiers.ModifierEntry(Attributes.GENERIC_ATTACK_DAMAGE, new ItemAttributeModifiers.Modifier(TOOL_MODIFIER_ATTACK_DAMAGE_UUID, "Weapon modifier", 5.0d, AttributeOperation.ADDITION), ItemAttributeModifiers.EquipmentSlotGroup.MAINHAND), new ItemAttributeModifiers.ModifierEntry(Attributes.GENERIC_ATTACK_SPEED, new ItemAttributeModifiers.Modifier(TOOL_MODIFIER_ATTACK_SPEED_UUID, "Weapon modifier", -3.5d, AttributeOperation.ADDITION), ItemAttributeModifiers.EquipmentSlotGroup.MAINHAND)), true)).setComponent(TOOL, new ItemTool(Collections.emptyList(), 1.0f, 2)).build();
|
||||
public static final ItemType FLOW_BANNER_PATTERN = builder("flow_banner_pattern").setMaxAmount(1).build();
|
||||
public static final ItemType GUSTER_BANNER_PATTERN = builder("guster_banner_pattern").setMaxAmount(1).build();
|
||||
public static final ItemType FLOW_ARMOR_TRIM_SMITHING_TEMPLATE = builder("flow_armor_trim_smithing_template").setMaxAmount(64).build();
|
||||
@@ -1442,6 +1442,11 @@ public class ItemTypes {
|
||||
public static final ItemType OMINOUS_BOTTLE = builder("ominous_bottle").setMaxAmount(64).setAttributes(ItemAttribute.EDIBLE).setComponent(FOOD, new FoodProperties(1, 0.2f, false, 1.6f, Collections.emptyList())).setComponent(OMINOUS_BOTTLE_AMPLIFIER, 0).build();
|
||||
public static final ItemType BREEZE_ROD = builder("breeze_rod").setMaxAmount(64).build();
|
||||
|
||||
// 1.21 items
|
||||
public static final ItemType MUSIC_DISC_CREATOR = builder("music_disc_creator").setMaxAmount(1).setAttributes(ItemAttribute.MUSIC_DISC).setComponent(RARITY, ItemRarity.RARE).build();
|
||||
public static final ItemType MUSIC_DISC_CREATOR_MUSIC_BOX = builder("music_disc_creator_music_box").setMaxAmount(1).setAttributes(ItemAttribute.MUSIC_DISC).setComponent(RARITY, ItemRarity.RARE).build();
|
||||
public static final ItemType MUSIC_DISC_PRECIPICE = builder("music_disc_precipice").setMaxAmount(1).setAttributes(ItemAttribute.MUSIC_DISC).setComponent(RARITY, ItemRarity.RARE).build();
|
||||
|
||||
/**
|
||||
* @deprecated Burning furnace shows up as a missing texture, removed in 1.9
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
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 {
|
||||
|
||||
private final int max;
|
||||
@Nullable
|
||||
private Object byteBuf;
|
||||
private int bytes;
|
||||
|
||||
public NBTLimiter() {
|
||||
this.max = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public NBTLimiter(@NotNull Object byteBuf) {
|
||||
this.byteBuf = byteBuf;
|
||||
this.max = 2097152;
|
||||
}
|
||||
|
||||
public void increment(int amount) {
|
||||
bytes += amount;
|
||||
|
||||
if (bytes > max) throw new IllegalArgumentException("NBT size limit reached (" + bytes + "/" + max + ")");
|
||||
}
|
||||
|
||||
public void checkReadability(int length) {
|
||||
if(byteBuf != null && length > ByteBufHelper.readableBytes(byteBuf)) throw new IllegalArgumentException("Length is too large: " + length + ", readable: " + ByteBufHelper.readableBytes(byteBuf));
|
||||
}
|
||||
}
|
||||
@@ -27,14 +27,21 @@ import java.util.Objects;
|
||||
public class NBTList<T extends NBT> extends NBT {
|
||||
|
||||
protected final NBTType<T> type;
|
||||
protected final List<T> tags = new ArrayList<>();
|
||||
protected final List<T> tags;
|
||||
|
||||
public NBTList(NBTType<T> type) {
|
||||
this.type = type;
|
||||
this.tags = new ArrayList<>();
|
||||
}
|
||||
|
||||
public NBTList(NBTType<T> type, int size) {
|
||||
this.type = type;
|
||||
this.tags = new ArrayList<>(size);
|
||||
}
|
||||
|
||||
public NBTList(NBTType<T> type, List<T> tags) {
|
||||
this.type = type;
|
||||
this.tags = new ArrayList<>();
|
||||
this.tags.addAll(tags);
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -37,6 +37,7 @@ import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class NBTCodec {
|
||||
|
||||
//PacketEvents start: JSON -> NBT conversion method
|
||||
@Deprecated
|
||||
public static NBT jsonToNBT(JsonElement element) {
|
||||
@@ -149,11 +150,12 @@ public class NBTCodec {
|
||||
//PacketEvents end
|
||||
|
||||
public static NBT readNBTFromBuffer(Object byteBuf, ServerVersion serverVersion) {
|
||||
NBTLimiter limiter = new NBTLimiter(byteBuf);
|
||||
if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_8)) {
|
||||
try {
|
||||
final boolean named = serverVersion.isOlderThan(ServerVersion.V_1_20_2);
|
||||
return DefaultNBTSerializer.INSTANCE.deserializeTag(
|
||||
new ByteBufInputStream(byteBuf), named);
|
||||
limiter, new ByteBufInputStream(byteBuf), named);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -167,7 +169,7 @@ public class NBTCodec {
|
||||
Object slicedBuffer = ByteBufHelper.readSlice(byteBuf, length);
|
||||
try (DataInputStream stream = new DataInputStream(
|
||||
new GZIPInputStream(new ByteBufInputStream(slicedBuffer)))) {
|
||||
return DefaultNBTSerializer.INSTANCE.deserializeTag(stream);
|
||||
return DefaultNBTSerializer.INSTANCE.deserializeTag(limiter, stream);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
|
||||
+131
-57
@@ -31,20 +31,61 @@ public class DefaultNBTSerializer extends NBTSerializer<DataInput, DataOutput> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public DefaultNBTSerializer() {
|
||||
super(DataInput::readByte, DataOutput::writeByte, DataInput::readUTF, DataOutput::writeUTF);
|
||||
registerType(NBTType.END, 0, stream -> NBTEnd.INSTANCE, (stream, tag) -> {
|
||||
super(
|
||||
(limiter, dataInput) -> {
|
||||
limiter.increment(1);
|
||||
return dataInput.readByte();
|
||||
},
|
||||
DataOutput::writeByte,
|
||||
(limiter, dataInput) -> {
|
||||
String name = dataInput.readUTF();
|
||||
limiter.increment(name.length() * 2 + 28);
|
||||
return name;
|
||||
},
|
||||
DataOutput::writeUTF
|
||||
);
|
||||
registerType(NBTType.END, 0, (limiter, stream) -> {
|
||||
limiter.increment(8);
|
||||
return NBTEnd.INSTANCE;
|
||||
}, (stream, tag) -> {
|
||||
});
|
||||
registerType(NBTType.BYTE, 1, stream -> new NBTByte(stream.readByte()), (stream, tag) -> stream.writeByte(tag.getAsByte()));
|
||||
registerType(NBTType.SHORT, 2, stream -> new NBTShort(stream.readShort()), (stream, tag) -> stream.writeShort(tag.getAsShort()));
|
||||
registerType(NBTType.INT, 3, stream -> new NBTInt(stream.readInt()), (stream, tag) -> stream.writeInt(tag.getAsInt()));
|
||||
registerType(NBTType.LONG, 4, stream -> new NBTLong(stream.readLong()), (stream, tag) -> stream.writeLong(tag.getAsLong()));
|
||||
registerType(NBTType.FLOAT, 5, stream -> new NBTFloat(stream.readFloat()), (stream, tag) -> stream.writeFloat(tag.getAsFloat()));
|
||||
registerType(NBTType.DOUBLE, 6, stream -> new NBTDouble(stream.readDouble()), (stream, tag) -> stream.writeDouble(tag.getAsDouble()));
|
||||
registerType(NBTType.STRING, 8, stream -> new NBTString(stream.readUTF()), (stream, tag) -> stream.writeUTF(tag.getValue()));
|
||||
registerType(NBTType.BYTE, 1, (limiter, stream) -> {
|
||||
limiter.increment(9);
|
||||
return new NBTByte(stream.readByte());
|
||||
}, (stream, tag) -> stream.writeByte(tag.getAsByte()));
|
||||
registerType(NBTType.SHORT, 2, (limiter, stream) -> {
|
||||
limiter.increment(10);
|
||||
return new NBTShort(stream.readShort());
|
||||
}, (stream, tag) -> stream.writeShort(tag.getAsShort()));
|
||||
registerType(NBTType.INT, 3, (limiter, stream) -> {
|
||||
limiter.increment(12);
|
||||
return new NBTInt(stream.readInt());
|
||||
}, (stream, tag) -> stream.writeInt(tag.getAsInt()));
|
||||
registerType(NBTType.LONG, 4, (limiter, stream) -> {
|
||||
limiter.increment(16);
|
||||
return new NBTLong(stream.readLong());
|
||||
}, (stream, tag) -> stream.writeLong(tag.getAsLong()));
|
||||
registerType(NBTType.FLOAT, 5, (limiter, stream) -> {
|
||||
limiter.increment(12);
|
||||
return new NBTFloat(stream.readFloat());
|
||||
}, (stream, tag) -> stream.writeFloat(tag.getAsFloat()));
|
||||
registerType(NBTType.DOUBLE, 6, (limiter, stream) -> {
|
||||
limiter.increment(16);
|
||||
return new NBTDouble(stream.readDouble());
|
||||
}, (stream, tag) -> stream.writeDouble(tag.getAsDouble()));
|
||||
registerType(
|
||||
NBTType.BYTE_ARRAY, 7,
|
||||
stream -> {
|
||||
byte[] array = new byte[stream.readInt()];
|
||||
(limiter, stream) -> {
|
||||
limiter.increment(24);
|
||||
int length = stream.readInt();
|
||||
|
||||
if (length >= 1 << 24)
|
||||
throw new IllegalArgumentException("Byte array length is too large: " + length);
|
||||
|
||||
limiter.checkReadability(length);
|
||||
limiter.increment(length);
|
||||
|
||||
byte[] array = new byte[length];
|
||||
stream.readFully(array);
|
||||
return new NBTByteArray(array);
|
||||
},
|
||||
@@ -54,10 +95,76 @@ public class DefaultNBTSerializer extends NBTSerializer<DataInput, DataOutput> {
|
||||
stream.write(array);
|
||||
}
|
||||
);
|
||||
registerType(NBTType.STRING, 8, (limiter, stream) -> {
|
||||
limiter.increment(36);
|
||||
String string = stream.readUTF();
|
||||
limiter.increment(string.length() * 2);
|
||||
return new NBTString(string);
|
||||
}, (stream, tag) -> stream.writeUTF(tag.getValue()));
|
||||
registerType(
|
||||
NBTType.LIST, 9,
|
||||
(limiter, stream) -> {
|
||||
limiter.increment(37);
|
||||
|
||||
NBTType<? extends NBT> valueType = readTagType(limiter, stream);
|
||||
int size = stream.readInt();
|
||||
|
||||
if ((valueType == NBTType.END) && (size > 0)) {
|
||||
throw new IllegalStateException("Missing nbt list values tag type");
|
||||
}
|
||||
limiter.increment(4 * size);
|
||||
NBTList<NBT> list = new NBTList<>((NBTType<NBT>) valueType, size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.addTag(readTag(limiter, stream, valueType));
|
||||
}
|
||||
return list;
|
||||
},
|
||||
(stream, tag) -> {
|
||||
writeTagType(stream, tag.getTagsType());
|
||||
stream.writeInt(tag.size());
|
||||
for (NBT value : ((List<NBT>) tag.getTags())) {
|
||||
writeTag(stream, value);
|
||||
}
|
||||
}
|
||||
);
|
||||
registerType(
|
||||
NBTType.COMPOUND, 10,
|
||||
(limiter, stream) -> {
|
||||
limiter.increment(48);
|
||||
|
||||
NBTCompound compound = new NBTCompound();
|
||||
NBTType<?> valueType;
|
||||
while ((valueType = readTagType(limiter, stream)) != NBTType.END) {
|
||||
String name = readTagName(limiter, stream);
|
||||
NBT nbt = readTag(limiter, stream, valueType);
|
||||
if(!compound.getTags().containsKey(name)) limiter.increment(36);
|
||||
compound.setTag(name, nbt);
|
||||
}
|
||||
return compound;
|
||||
},
|
||||
(stream, tag) -> {
|
||||
for (Entry<String, NBT> entry : tag.getTags().entrySet()) {
|
||||
NBT value = entry.getValue();
|
||||
writeTagType(stream, value.getType());
|
||||
writeTagName(stream, entry.getKey());
|
||||
writeTag(stream, value);
|
||||
}
|
||||
writeTagType(stream, NBTType.END);
|
||||
}
|
||||
);
|
||||
registerType(
|
||||
NBTType.INT_ARRAY, 11,
|
||||
stream -> {
|
||||
int[] array = new int[stream.readInt()];
|
||||
(limiter, stream) -> {
|
||||
limiter.increment(24);
|
||||
int length = stream.readInt();
|
||||
|
||||
if (length >= 1 << 24)
|
||||
throw new IllegalArgumentException("Int array length is too large: " + length);
|
||||
|
||||
limiter.checkReadability(length * 4);
|
||||
limiter.increment(length * 4);
|
||||
|
||||
int[] array = new int[length];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = stream.readInt();
|
||||
}
|
||||
@@ -73,8 +180,17 @@ public class DefaultNBTSerializer extends NBTSerializer<DataInput, DataOutput> {
|
||||
);
|
||||
registerType(
|
||||
NBTType.LONG_ARRAY, 12,
|
||||
stream -> {
|
||||
long[] array = new long[stream.readInt()];
|
||||
(limiter, stream) -> {
|
||||
limiter.increment(24);
|
||||
int length = stream.readInt();
|
||||
|
||||
if (length >= 1 << 24)
|
||||
throw new IllegalArgumentException("Long array length is too large: " + length);
|
||||
|
||||
limiter.checkReadability(length * 8);
|
||||
limiter.increment(length * 8);
|
||||
|
||||
long[] array = new long[length];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = stream.readLong();
|
||||
}
|
||||
@@ -88,48 +204,6 @@ public class DefaultNBTSerializer extends NBTSerializer<DataInput, DataOutput> {
|
||||
}
|
||||
}
|
||||
);
|
||||
registerType(
|
||||
NBTType.COMPOUND, 10,
|
||||
stream -> {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
NBTType<?> valueType = null;
|
||||
while ((valueType = readTagType(stream)) != NBTType.END) {
|
||||
compound.setTag(readTagName(stream), readTag(stream, valueType));
|
||||
}
|
||||
return compound;
|
||||
},
|
||||
(stream, tag) -> {
|
||||
for (Entry<String, NBT> entry : tag.getTags().entrySet()) {
|
||||
NBT value = entry.getValue();
|
||||
writeTagType(stream, value.getType());
|
||||
writeTagName(stream, entry.getKey());
|
||||
writeTag(stream, value);
|
||||
}
|
||||
writeTagType(stream, NBTType.END);
|
||||
}
|
||||
);
|
||||
registerType(
|
||||
NBTType.LIST, 9,
|
||||
stream -> {
|
||||
NBTType<? extends NBT> valueType = readTagType(stream);
|
||||
int size = stream.readInt();
|
||||
if ((valueType == NBTType.END) && (size > 0)) {
|
||||
throw new IllegalStateException("Missing nbt list values tag type");
|
||||
}
|
||||
NBTList<NBT> list = new NBTList<>((NBTType<NBT>) valueType);
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.addTag(readTag(stream, valueType));
|
||||
}
|
||||
return list;
|
||||
},
|
||||
(stream, tag) -> {
|
||||
writeTagType(stream, tag.getTagsType());
|
||||
stream.writeInt(tag.size());
|
||||
for (NBT value : ((List<NBT>) tag.getTags())) {
|
||||
writeTag(stream, value);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+16
-15
@@ -19,6 +19,7 @@
|
||||
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 com.github.retrooper.packetevents.protocol.nbt.NBTType;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -46,19 +47,19 @@ public class NBTSerializer<IN, OUT> {
|
||||
this.nameWriter = nameWriter;
|
||||
}
|
||||
|
||||
public NBT deserializeTag(IN from) throws IOException {
|
||||
return deserializeTag(from, true);
|
||||
public NBT deserializeTag(NBTLimiter limiter, IN from) throws IOException {
|
||||
return deserializeTag(limiter, from, true);
|
||||
}
|
||||
|
||||
public NBT deserializeTag(IN from, boolean named) throws IOException {
|
||||
NBTType<?> type = readTagType(from);
|
||||
public NBT deserializeTag(NBTLimiter limiter, IN from, boolean named) throws IOException {
|
||||
NBTType<?> type = readTagType(limiter, from);
|
||||
if (type == NBTType.END) {
|
||||
return null;
|
||||
}
|
||||
if (named) {
|
||||
readTagName(from);
|
||||
readTagName(limiter, from);
|
||||
}
|
||||
return readTag(from, type);
|
||||
return readTag(limiter, from, type);
|
||||
}
|
||||
|
||||
public void serializeTag(OUT to, NBT tag) throws IOException {
|
||||
@@ -94,8 +95,8 @@ public class NBTSerializer<IN, OUT> {
|
||||
typeWriters.put(type, typeWriter);
|
||||
}
|
||||
|
||||
protected NBTType<?> readTagType(IN from) throws IOException {
|
||||
int id = idReader.readId(from);
|
||||
protected NBTType<?> readTagType(NBTLimiter limiter, IN from) throws IOException {
|
||||
int id = idReader.readId(limiter, from);
|
||||
NBTType<?> type = idToType.get(id);
|
||||
if (type == null) {
|
||||
throw new IOException(MessageFormat.format("Unknown nbt type id {0}", id));
|
||||
@@ -103,16 +104,16 @@ public class NBTSerializer<IN, OUT> {
|
||||
return type;
|
||||
}
|
||||
|
||||
protected String readTagName(IN from) throws IOException {
|
||||
return nameReader.readName(from);
|
||||
protected String readTagName(NBTLimiter limiter, IN from) throws IOException {
|
||||
return nameReader.readName(limiter, from);
|
||||
}
|
||||
|
||||
protected NBT readTag(IN from, NBTType<?> type) throws IOException {
|
||||
protected 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));
|
||||
}
|
||||
return f.readTag(from);
|
||||
return f.readTag(limiter, from);
|
||||
}
|
||||
|
||||
protected void writeTagType(OUT stream, NBTType<?> type) throws IOException {
|
||||
@@ -138,7 +139,7 @@ public class NBTSerializer<IN, OUT> {
|
||||
|
||||
@FunctionalInterface
|
||||
protected interface IdReader<T> {
|
||||
int readId(T from) throws IOException;
|
||||
int readId(NBTLimiter limiter, T from) throws IOException;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
@@ -148,7 +149,7 @@ public class NBTSerializer<IN, OUT> {
|
||||
|
||||
@FunctionalInterface
|
||||
protected interface NameReader<T> {
|
||||
String readName(T from) throws IOException;
|
||||
String readName(NBTLimiter limiter, T from) throws IOException;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
@@ -158,7 +159,7 @@ public class NBTSerializer<IN, OUT> {
|
||||
|
||||
@FunctionalInterface
|
||||
protected interface TagReader<IN, T extends NBT> {
|
||||
T readTag(IN from) throws IOException;
|
||||
T readTag(NBTLimiter limiter, IN from) throws IOException;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
|
||||
@@ -120,6 +120,7 @@ public class NPC {
|
||||
WrapperPlayServerDestroyEntities destroyEntities = new WrapperPlayServerDestroyEntities(getId());
|
||||
PacketEvents.getAPI().getProtocolManager().sendPacket(channel, destroyEntities);
|
||||
}
|
||||
channels.clear();
|
||||
}
|
||||
|
||||
public void teleport(Location to) {
|
||||
@@ -255,9 +256,16 @@ public class NPC {
|
||||
}
|
||||
PacketEvents.getAPI().getProtocolManager().sendPacket(channel, playerInfoAdd);
|
||||
|
||||
WrapperPlayServerSpawnPlayer spawnPlayer =
|
||||
new WrapperPlayServerSpawnPlayer(getId(), getProfile().getUUID(), getLocation());
|
||||
PacketEvents.getAPI().getProtocolManager().sendPacket(channel, spawnPlayer);
|
||||
PacketWrapper<?> spawnPacket;
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_20_2)) {
|
||||
spawnPacket = new WrapperPlayServerSpawnEntity(getId(), getProfile().getUUID(), EntityTypes.PLAYER, getLocation(), getLocation().getYaw(), 0, null);
|
||||
}
|
||||
else {
|
||||
spawnPacket = new WrapperPlayServerSpawnPlayer(getId(),
|
||||
getProfile().getUUID(),
|
||||
getLocation());
|
||||
}
|
||||
PacketEvents.getAPI().getProtocolManager().sendPacket(channel, spawnPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-4
@@ -38,6 +38,7 @@ import com.github.retrooper.packetevents.protocol.packettype.clientbound.Clientb
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_20_2;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_20_3;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_20_5;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_21;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_7_10;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_8;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_9;
|
||||
@@ -45,6 +46,7 @@ import com.github.retrooper.packetevents.protocol.packettype.clientbound.Clientb
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.clientbound.ClientboundConfigPacketType_1_20_2;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.clientbound.ClientboundConfigPacketType_1_20_3;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.clientbound.ClientboundConfigPacketType_1_20_5;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.clientbound.ClientboundConfigPacketType_1_21;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.serverbound.ServerboundConfigPacketType_1_20_2;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.serverbound.ServerboundConfigPacketType_1_20_5;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.serverbound.ServerboundPacketType_1_12;
|
||||
@@ -100,7 +102,8 @@ public final class PacketType {
|
||||
ClientVersion.V_1_19_4,
|
||||
ClientVersion.V_1_20_2,
|
||||
ClientVersion.V_1_20_3,
|
||||
ClientVersion.V_1_20_5);
|
||||
ClientVersion.V_1_20_5,
|
||||
ClientVersion.V_1_21);
|
||||
|
||||
//TODO UPDATE Update packet type mappings (serverbound pt. 1)
|
||||
private static final VersionMapper SERVERBOUND_PLAY_VERSION_MAPPER = new VersionMapper(
|
||||
@@ -127,7 +130,8 @@ public final class PacketType {
|
||||
private static final VersionMapper CLIENTBOUND_CONFIG_VERSION_MAPPER = new VersionMapper(
|
||||
ClientVersion.V_1_20_2,
|
||||
ClientVersion.V_1_20_3,
|
||||
ClientVersion.V_1_20_5);
|
||||
ClientVersion.V_1_20_5,
|
||||
ClientVersion.V_1_21);
|
||||
// TODO UPDATE Update packet type mappings (config serverbound pt. 1)
|
||||
private static final VersionMapper SERVERBOUND_CONFIG_VERSION_MAPPER = new VersionMapper(
|
||||
ClientVersion.V_1_20_2,
|
||||
@@ -512,7 +516,11 @@ public final class PacketType {
|
||||
RESET_CHAT,
|
||||
STORE_COOKIE,
|
||||
TRANSFER,
|
||||
SELECT_KNOWN_PACKS;
|
||||
SELECT_KNOWN_PACKS,
|
||||
|
||||
// added in 1.21
|
||||
CUSTOM_REPORT_DETAILS,
|
||||
SERVER_LINKS;
|
||||
|
||||
private static int INDEX = 0;
|
||||
private static final Map<Byte, Map<Integer, PacketTypeCommon>> PACKET_TYPE_ID_MAP = new HashMap<>();
|
||||
@@ -528,6 +536,7 @@ public final class PacketType {
|
||||
loadPacketIds(ClientboundConfigPacketType_1_20_2.values());
|
||||
loadPacketIds(ClientboundConfigPacketType_1_20_3.values());
|
||||
loadPacketIds(ClientboundConfigPacketType_1_20_5.values());
|
||||
loadPacketIds(ClientboundConfigPacketType_1_21.values());
|
||||
// TODO UPDATE Update packet type mappings (config clientbound pt. 2)
|
||||
}
|
||||
|
||||
@@ -888,7 +897,11 @@ public final class PacketType {
|
||||
DEBUG_SAMPLE,
|
||||
STORE_COOKIE,
|
||||
TRANSFER,
|
||||
PROJECTILE_POWER;
|
||||
PROJECTILE_POWER,
|
||||
|
||||
// added in 1.21
|
||||
CUSTOM_REPORT_DETAILS,
|
||||
SERVER_LINKS;
|
||||
|
||||
private static int INDEX = 0;
|
||||
private static final Map<Byte, Map<Integer, PacketTypeCommon>> PACKET_TYPE_ID_MAP = new HashMap<>();
|
||||
@@ -958,6 +971,7 @@ public final class PacketType {
|
||||
loadPacketIds(ClientboundPacketType_1_20_2.values());
|
||||
loadPacketIds(ClientboundPacketType_1_20_3.values());
|
||||
loadPacketIds(ClientboundPacketType_1_20_5.values());
|
||||
loadPacketIds(ClientboundPacketType_1_21.values());
|
||||
//TODO UPDATE Update packet type mappings (clientbound pt. 2)
|
||||
}
|
||||
}
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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.packettype.clientbound;
|
||||
|
||||
public enum ClientboundPacketType_1_21 {
|
||||
|
||||
BUNDLE,
|
||||
SPAWN_ENTITY,
|
||||
SPAWN_EXPERIENCE_ORB,
|
||||
ENTITY_ANIMATION,
|
||||
STATISTICS,
|
||||
ACKNOWLEDGE_BLOCK_CHANGES,
|
||||
BLOCK_BREAK_ANIMATION,
|
||||
BLOCK_ENTITY_DATA,
|
||||
BLOCK_ACTION,
|
||||
BLOCK_CHANGE,
|
||||
BOSS_BAR,
|
||||
SERVER_DIFFICULTY,
|
||||
CHUNK_BATCH_END,
|
||||
CHUNK_BATCH_BEGIN,
|
||||
CHUNK_BIOMES,
|
||||
CLEAR_TITLES,
|
||||
TAB_COMPLETE,
|
||||
DECLARE_COMMANDS,
|
||||
CLOSE_WINDOW,
|
||||
WINDOW_ITEMS,
|
||||
WINDOW_PROPERTY,
|
||||
SET_SLOT,
|
||||
COOKIE_REQUEST,
|
||||
SET_COOLDOWN,
|
||||
CUSTOM_CHAT_COMPLETIONS,
|
||||
PLUGIN_MESSAGE,
|
||||
DAMAGE_EVENT,
|
||||
DEBUG_SAMPLE,
|
||||
DELETE_CHAT,
|
||||
DISCONNECT,
|
||||
DISGUISED_CHAT,
|
||||
ENTITY_STATUS,
|
||||
EXPLOSION,
|
||||
UNLOAD_CHUNK,
|
||||
CHANGE_GAME_STATE,
|
||||
OPEN_HORSE_WINDOW,
|
||||
HURT_ANIMATION,
|
||||
INITIALIZE_WORLD_BORDER,
|
||||
KEEP_ALIVE,
|
||||
CHUNK_DATA,
|
||||
EFFECT,
|
||||
PARTICLE,
|
||||
UPDATE_LIGHT,
|
||||
JOIN_GAME,
|
||||
MAP_DATA,
|
||||
MERCHANT_OFFERS,
|
||||
ENTITY_RELATIVE_MOVE,
|
||||
ENTITY_RELATIVE_MOVE_AND_ROTATION,
|
||||
ENTITY_ROTATION,
|
||||
VEHICLE_MOVE,
|
||||
OPEN_BOOK,
|
||||
OPEN_WINDOW,
|
||||
OPEN_SIGN_EDITOR,
|
||||
PING,
|
||||
DEBUG_PONG,
|
||||
CRAFT_RECIPE_RESPONSE,
|
||||
PLAYER_ABILITIES,
|
||||
CHAT_MESSAGE,
|
||||
END_COMBAT_EVENT,
|
||||
ENTER_COMBAT_EVENT,
|
||||
DEATH_COMBAT_EVENT,
|
||||
PLAYER_INFO_REMOVE,
|
||||
PLAYER_INFO_UPDATE,
|
||||
FACE_PLAYER,
|
||||
PLAYER_POSITION_AND_LOOK,
|
||||
UNLOCK_RECIPES,
|
||||
DESTROY_ENTITIES,
|
||||
REMOVE_ENTITY_EFFECT,
|
||||
RESET_SCORE,
|
||||
RESOURCE_PACK_REMOVE,
|
||||
RESOURCE_PACK_SEND,
|
||||
RESPAWN,
|
||||
ENTITY_HEAD_LOOK,
|
||||
MULTI_BLOCK_CHANGE,
|
||||
SELECT_ADVANCEMENTS_TAB,
|
||||
SERVER_DATA,
|
||||
ACTION_BAR,
|
||||
WORLD_BORDER_CENTER,
|
||||
WORLD_BORDER_LERP_SIZE,
|
||||
WORLD_BORDER_SIZE,
|
||||
WORLD_BORDER_WARNING_DELAY,
|
||||
WORLD_BORDER_WARNING_REACH,
|
||||
CAMERA,
|
||||
HELD_ITEM_CHANGE,
|
||||
UPDATE_VIEW_POSITION,
|
||||
UPDATE_VIEW_DISTANCE,
|
||||
SPAWN_POSITION,
|
||||
DISPLAY_SCOREBOARD,
|
||||
ENTITY_METADATA,
|
||||
ATTACH_ENTITY,
|
||||
ENTITY_VELOCITY,
|
||||
ENTITY_EQUIPMENT,
|
||||
SET_EXPERIENCE,
|
||||
UPDATE_HEALTH,
|
||||
SCOREBOARD_OBJECTIVE,
|
||||
SET_PASSENGERS,
|
||||
TEAMS,
|
||||
UPDATE_SCORE,
|
||||
UPDATE_SIMULATION_DISTANCE,
|
||||
SET_TITLE_SUBTITLE,
|
||||
TIME_UPDATE,
|
||||
SET_TITLE_TEXT,
|
||||
SET_TITLE_TIMES,
|
||||
ENTITY_SOUND_EFFECT,
|
||||
SOUND_EFFECT,
|
||||
CONFIGURATION_START,
|
||||
STOP_SOUND,
|
||||
STORE_COOKIE,
|
||||
SYSTEM_CHAT_MESSAGE,
|
||||
PLAYER_LIST_HEADER_AND_FOOTER,
|
||||
NBT_QUERY_RESPONSE,
|
||||
COLLECT_ITEM,
|
||||
ENTITY_TELEPORT,
|
||||
TICKING_STATE,
|
||||
TICKING_STEP,
|
||||
TRANSFER,
|
||||
UPDATE_ADVANCEMENTS,
|
||||
UPDATE_ATTRIBUTES,
|
||||
ENTITY_EFFECT,
|
||||
DECLARE_RECIPES,
|
||||
TAGS,
|
||||
PROJECTILE_POWER,
|
||||
CUSTOM_REPORT_DETAILS, // new packet
|
||||
SERVER_LINKS, // new packet
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.packettype.config.clientbound;
|
||||
|
||||
public enum ClientboundConfigPacketType_1_21 {
|
||||
|
||||
COOKIE_REQUEST,
|
||||
PLUGIN_MESSAGE,
|
||||
DISCONNECT,
|
||||
CONFIGURATION_END,
|
||||
KEEP_ALIVE,
|
||||
PING,
|
||||
RESET_CHAT,
|
||||
REGISTRY_DATA,
|
||||
RESOURCE_PACK_REMOVE,
|
||||
RESOURCE_PACK_SEND,
|
||||
STORE_COOKIE,
|
||||
TRANSFER,
|
||||
UPDATE_ENABLED_FEATURES,
|
||||
UPDATE_TAGS,
|
||||
SELECT_KNOWN_PACKS,
|
||||
CUSTOM_REPORT_DETAILS, // new packet
|
||||
SERVER_LINKS, // new packet
|
||||
}
|
||||
+1
-1
@@ -54,7 +54,7 @@ public class ParticleDustColorTransitionData extends ParticleData {
|
||||
}
|
||||
|
||||
public ParticleDustColorTransitionData(float scale, Color start, Color end) {
|
||||
this(scale, start.red(), start.green(), start.blue(), end.red(), end.green(), end.blue());
|
||||
this(scale, start.red() / 255f, start.green() / 255f, start.blue() / 255f, end.red() / 255f, end.green() / 255f, end.blue() / 255f);
|
||||
}
|
||||
|
||||
public float getScale() {
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public class ParticleDustData extends ParticleData {
|
||||
}
|
||||
|
||||
public ParticleDustData(float scale, Color color) {
|
||||
this(scale, color.red(), color.green(), color.blue());
|
||||
this(scale, color.red() / 255f, color.green() / 255f, color.blue() / 255f);
|
||||
}
|
||||
|
||||
public float getRed() {
|
||||
|
||||
+10
@@ -35,6 +35,8 @@ import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -227,6 +229,14 @@ public class ParticleTypes {
|
||||
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() {
|
||||
return Collections.unmodifiableCollection(PARTICLE_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
+5
-3
@@ -95,13 +95,15 @@ public enum ClientVersion {
|
||||
* 1.20.5 and 1.20.6 have the same protocol version.
|
||||
*/
|
||||
V_1_20_5(766),
|
||||
|
||||
V_1_21(767),
|
||||
//TODO UPDATE Add new protocol version field
|
||||
|
||||
@Deprecated
|
||||
LOWER_THAN_SUPPORTED_VERSIONS(V_1_7_10.protocolVersion - 1, true),
|
||||
//TODO UPDATE Update HIGHER_THAN_SUPPORTED_VERSIONS field
|
||||
@Deprecated
|
||||
HIGHER_THAN_SUPPORTED_VERSIONS(V_1_20_5.protocolVersion + 1, true),
|
||||
HIGHER_THAN_SUPPORTED_VERSIONS(V_1_21.protocolVersion + 1, true),
|
||||
|
||||
UNKNOWN(-1, true);
|
||||
|
||||
@@ -172,9 +174,9 @@ public enum ClientVersion {
|
||||
@NotNull
|
||||
public static ClientVersion getById(int protocolVersion) {
|
||||
if (protocolVersion < LOWEST_SUPPORTED_PROTOCOL_VERSION) {
|
||||
return V_1_7_10;
|
||||
return getOldest();
|
||||
} else if (protocolVersion > HIGHEST_SUPPORTED_PROTOCOL_VERSION) {
|
||||
return V_1_20_3;
|
||||
return getLatest();
|
||||
} else {
|
||||
for (ClientVersion version : VALUES) {
|
||||
if (version.protocolVersion > protocolVersion) {
|
||||
|
||||
+22
-10
@@ -27,33 +27,45 @@ public enum EquipmentSlot {
|
||||
BOOTS(1),
|
||||
LEGGINGS(2),
|
||||
CHEST_PLATE(3),
|
||||
HELMET(4);
|
||||
HELMET(4),
|
||||
BODY(0);
|
||||
|
||||
private static final EquipmentSlot[] VALUES = values();
|
||||
|
||||
private final byte legacyId;
|
||||
|
||||
EquipmentSlot(int legacyId) {
|
||||
this.legacyId =(byte) legacyId;
|
||||
this.legacyId = (byte) legacyId;
|
||||
}
|
||||
|
||||
public int getId(ServerVersion version) {
|
||||
if (version.isOlderThan(ServerVersion.V_1_9)) {
|
||||
return getId(version.toClientVersion());
|
||||
}
|
||||
|
||||
public int getId(ClientVersion version) {
|
||||
if (version.isOlderThan(ClientVersion.V_1_9)) {
|
||||
return legacyId;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return ordinal();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static EquipmentSlot getById(ServerVersion version, int id) {
|
||||
// FIXME: try making this O(1)
|
||||
for (EquipmentSlot slot : VALUES) {
|
||||
if (slot.getId(version) == id) {
|
||||
return slot;
|
||||
public static EquipmentSlot getById(ClientVersion version, int id) {
|
||||
if (version.isOlderThan(ClientVersion.V_1_9)) {
|
||||
for (EquipmentSlot slot : VALUES) {
|
||||
if (slot.getId(version) == id) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return VALUES[id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static EquipmentSlot getById(ServerVersion version, int id) {
|
||||
return getById(version.toClientVersion(), id);
|
||||
}
|
||||
}
|
||||
@@ -209,9 +209,9 @@ public class User {
|
||||
}
|
||||
|
||||
public void sendTitle(Component title, Component subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
|
||||
ServerVersion version = PacketEvents.getAPI().getInjector().isProxy() ? getClientVersion().toServerVersion() :
|
||||
PacketEvents.getAPI().getServerManager().getVersion();
|
||||
boolean modern = version.isNewerThanOrEquals(ServerVersion.V_1_17);
|
||||
ClientVersion version = PacketEvents.getAPI().getInjector().isProxy() ? getClientVersion() :
|
||||
PacketEvents.getAPI().getServerManager().getVersion().toClientVersion();
|
||||
boolean modern = version.isNewerThanOrEquals(ClientVersion.V_1_17);
|
||||
PacketWrapper<?> animation;
|
||||
PacketWrapper<?> setTitle = null;
|
||||
PacketWrapper<?> setSubtitle = null;
|
||||
|
||||
+16
-6
@@ -27,6 +27,8 @@ import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -145,12 +147,20 @@ public class PotionTypes {
|
||||
public static final PotionType DARKNESS = define("darkness");
|
||||
|
||||
// Added in 1.20.5
|
||||
public static final PotionType TRIAL_OMEN = define("darkness");
|
||||
public static final PotionType RAID_OMEN = define("darkness");
|
||||
public static final PotionType WIND_CHARGED = define("darkness");
|
||||
public static final PotionType WEAVING = define("darkness");
|
||||
public static final PotionType OOZING = define("darkness");
|
||||
public static final PotionType INFESTED = define("darkness");
|
||||
public static final PotionType TRIAL_OMEN = define("trial_omen");
|
||||
public static final PotionType RAID_OMEN = define("raid_omen");
|
||||
public static final PotionType WIND_CHARGED = define("wind_charged");
|
||||
public static final PotionType WEAVING = define("weaving");
|
||||
public static final PotionType OOZING = define("oozing");
|
||||
public static final PotionType INFESTED = define("infested");
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the potion types.
|
||||
* @return Potion Types
|
||||
*/
|
||||
public static Collection<PotionType> values() {
|
||||
return Collections.unmodifiableCollection(POTION_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
|
||||
+5
-8
@@ -16,14 +16,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.strategy;
|
||||
package com.github.retrooper.packetevents.protocol.recipe;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface CompressionStrategy {
|
||||
|
||||
byte COMPRESSION_VERSION = 1;
|
||||
|
||||
void compress(final Path from, final Path to);
|
||||
public enum CookingCategory {
|
||||
|
||||
FOOD,
|
||||
BLOCKS,
|
||||
MISC,
|
||||
}
|
||||
+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.recipe;
|
||||
|
||||
public enum CraftingCategory {
|
||||
|
||||
BUILDING,
|
||||
REDSTONE,
|
||||
EQUIPMENT,
|
||||
MISC,
|
||||
}
|
||||
+16
-7
@@ -19,17 +19,26 @@
|
||||
package com.github.retrooper.packetevents.protocol.recipe;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
// From MCProtocolLib
|
||||
public class Ingredient {
|
||||
private final @NotNull ItemStack[] options;
|
||||
|
||||
public Ingredient(@NotNull ItemStack... options) {
|
||||
private final ItemStack[] options;
|
||||
|
||||
public Ingredient(ItemStack... options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public @NotNull ItemStack[] getOptions() {
|
||||
return options;
|
||||
public static Ingredient read(PacketWrapper<?> wrapper) {
|
||||
ItemStack[] options = wrapper.readArray(PacketWrapper::readItemStack, ItemStack.class);
|
||||
return new Ingredient(options);
|
||||
}
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, Ingredient ingredient) {
|
||||
wrapper.writeArray(ingredient.options, PacketWrapper::writeItemStack);
|
||||
}
|
||||
|
||||
public ItemStack[] getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
}
|
||||
@@ -18,39 +18,89 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.recipe;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.data.RecipeData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
// From MCProtocolLib
|
||||
public class Recipe {
|
||||
private final @NotNull RecipeType type;
|
||||
private final @NotNull String identifier;
|
||||
private final RecipeData data;
|
||||
public class Recipe<T extends RecipeData> {
|
||||
|
||||
public Recipe(@NotNull RecipeType type, @NotNull String identifier, RecipeData data) {
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
private final ResourceLocation key;
|
||||
private final RecipeSerializer<T> serializer;
|
||||
private final T data;
|
||||
|
||||
@SuppressWarnings("unchecked") // backwards compat
|
||||
@Deprecated
|
||||
public Recipe(RecipeType serializer, String key, RecipeData data) {
|
||||
this(
|
||||
new ResourceLocation(key),
|
||||
(RecipeSerializer<T>) serializer.getSerializer(),
|
||||
(T) data
|
||||
);
|
||||
}
|
||||
|
||||
public Recipe(ResourceLocation key, RecipeSerializer<T> serializer, T data) {
|
||||
this.key = key;
|
||||
this.serializer = serializer;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public @NotNull RecipeType getType() {
|
||||
return type;
|
||||
public static Recipe<?> read(PacketWrapper<?> wrapper) {
|
||||
ResourceLocation key;
|
||||
RecipeSerializer<?> serializer;
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20_5)) {
|
||||
key = wrapper.readIdentifier();
|
||||
serializer = wrapper.readMappedEntity(RecipeSerializers::getById);
|
||||
} else {
|
||||
serializer = RecipeSerializers.getByName(wrapper.readIdentifier().toString());
|
||||
key = wrapper.readIdentifier();
|
||||
}
|
||||
return read(wrapper, key, serializer);
|
||||
}
|
||||
|
||||
public @NotNull String getIdentifier() {
|
||||
return identifier;
|
||||
private static <T extends RecipeData> Recipe<T> read(
|
||||
PacketWrapper<?> wrapper,
|
||||
ResourceLocation key,
|
||||
RecipeSerializer<T> serializer
|
||||
) {
|
||||
T data = serializer.read(wrapper);
|
||||
return new Recipe<>(key, serializer, data);
|
||||
}
|
||||
|
||||
public @NotNull RecipeData getData() {
|
||||
return data;
|
||||
public static <T extends RecipeData> void write(PacketWrapper<?> wrapper, Recipe<T> recipe) {
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20_5)) {
|
||||
wrapper.writeIdentifier(recipe.key);
|
||||
wrapper.writeMappedEntity(recipe.serializer);
|
||||
} else {
|
||||
wrapper.writeIdentifier(recipe.serializer.getName());
|
||||
wrapper.writeIdentifier(recipe.key);
|
||||
}
|
||||
recipe.serializer.write(wrapper, recipe.data);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public RecipeType getType() {
|
||||
return this.serializer.getLegacyType();
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return this.key.toString();
|
||||
}
|
||||
|
||||
public ResourceLocation getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
public RecipeSerializer<T> getSerializer() {
|
||||
return this.serializer;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Recipe{" +
|
||||
"type=" + type +
|
||||
", identifier='" + identifier + '\'' +
|
||||
", data=" + data +
|
||||
'}';
|
||||
return "Recipe{key=" + this.key + ", serializer=" + this.serializer + ", data=" + this.data + '}';
|
||||
}
|
||||
}
|
||||
}
|
||||
+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.recipe;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.data.RecipeData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public interface RecipeSerializer<T extends RecipeData> extends MappedEntity {
|
||||
|
||||
@Deprecated
|
||||
RecipeType getLegacyType();
|
||||
|
||||
T read(PacketWrapper<?> wrapper);
|
||||
|
||||
void write(PacketWrapper<?> wrapper, T data);
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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.recipe;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.data.CookedRecipeData;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.data.RecipeData;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.data.ShapedRecipeData;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.data.ShapelessRecipeData;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.data.SimpleRecipeData;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.data.SmithingRecipeData;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.data.SmithingTrimRecipeData;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.data.StoneCuttingRecipeData;
|
||||
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.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RecipeSerializers {
|
||||
|
||||
private static final Map<String, RecipeSerializer<?>> PATTERN_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<Byte, Map<Integer, RecipeSerializer<?>>> PATTERN_TYPE_ID_MAP = new HashMap<>();
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/recipe_serializer_mappings");
|
||||
|
||||
public static <T extends RecipeData> RecipeSerializer<T> define(
|
||||
String key,
|
||||
PacketWrapper.Reader<T> reader,
|
||||
PacketWrapper.Writer<T> writer
|
||||
) {
|
||||
return define(key, reader, writer, null);
|
||||
}
|
||||
|
||||
public static <T extends RecipeData> RecipeSerializer<T> define(
|
||||
String key,
|
||||
PacketWrapper.Reader<T> reader,
|
||||
PacketWrapper.Writer<T> writer,
|
||||
@Nullable RecipeType recipeType
|
||||
) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
RecipeSerializer<T> pattern = new RecipeSerializer<T>() {
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
return data.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return MappingHelper.getId(version, TYPES_BUILDER, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeType getLegacyType() {
|
||||
if (recipeType == null) {
|
||||
throw new UnsupportedOperationException("No legacy type found for " + this.getName());
|
||||
}
|
||||
return recipeType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(PacketWrapper<?> wrapper) {
|
||||
return reader.apply(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketWrapper<?> wrapper, T data) {
|
||||
writer.accept(wrapper, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof RecipeSerializer<?>) {
|
||||
return this.getName().equals(((RecipeSerializer<?>) obj).getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, PATTERN_TYPE_MAP, PATTERN_TYPE_ID_MAP, pattern);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
// with key
|
||||
public static RecipeSerializer<?> getByName(String name) {
|
||||
return PATTERN_TYPE_MAP.get(name);
|
||||
}
|
||||
|
||||
public static RecipeSerializer<?> getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, RecipeSerializer<?>> idMap = PATTERN_TYPE_ID_MAP.get((byte) index);
|
||||
return idMap.get(id);
|
||||
}
|
||||
|
||||
public static final RecipeSerializer<ShapedRecipeData> CRAFTING_SHAPED = define("crafting_shaped",
|
||||
ShapedRecipeData::read, ShapedRecipeData::write, RecipeType.CRAFTING_SHAPED);
|
||||
public static final RecipeSerializer<ShapelessRecipeData> CRAFTING_SHAPELESS = define("crafting_shapeless",
|
||||
ShapelessRecipeData::read, ShapelessRecipeData::write, RecipeType.CRAFTING_SHAPELESS);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_ARMORDYE = define("crafting_special_armordye",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_ARMORDYE);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_BOOKCLONING = define("crafting_special_bookcloning",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_BOOKCLONING);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_MAPCLONING = define("crafting_special_mapcloning",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_MAPCLONING);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_MAPEXTENDING = define("crafting_special_mapextending",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_MAPEXTENDING);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_FIREWORK_ROCKET = define("crafting_special_firework_rocket",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_FIREWORK_ROCKET);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_FIREWORK_STAR = define("crafting_special_firework_star",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_FIREWORK_STAR);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_FIREWORK_STAR_FADE = define("crafting_special_firework_star_fade",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_FIREWORK_STAR_FADE);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_TIPPEDARROW = define("crafting_special_tippedarrow",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_TIPPEDARROW);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_BANNERDUPLICATE = define("crafting_special_bannerduplicate",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_BANNERDUPLICATE);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_SHIELDDECORATION = define("crafting_special_shielddecoration",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_SHIELDDECORATION);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_SHULKERBOXCOLORING = define("crafting_special_shulkerboxcoloring",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_SHULKERBOXCOLORING);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_SUSPICIOUSSTEW = define("crafting_special_suspiciousstew",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_SUSPICIOUSSTEW);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_SPECIAL_REPAIRITEM = define("crafting_special_repairitem",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_REPAIRITEM);
|
||||
public static final RecipeSerializer<CookedRecipeData> SMELTING = define("smelting",
|
||||
CookedRecipeData::read, CookedRecipeData::write, RecipeType.SMELTING);
|
||||
public static final RecipeSerializer<CookedRecipeData> BLASTING = define("blasting",
|
||||
CookedRecipeData::read, CookedRecipeData::write, RecipeType.BLASTING);
|
||||
public static final RecipeSerializer<CookedRecipeData> SMOKING = define("smoking",
|
||||
CookedRecipeData::read, CookedRecipeData::write, RecipeType.SMOKING);
|
||||
public static final RecipeSerializer<CookedRecipeData> CAMPFIRE_COOKING = define("campfire_cooking",
|
||||
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",
|
||||
ew -> SmithingRecipeData.read(ew, true),
|
||||
(ew, data) -> SmithingRecipeData.write(ew, data, true),
|
||||
RecipeType.SMITHING);
|
||||
public static final RecipeSerializer<SmithingRecipeData> SMITHING_TRANSFORM = define("smithing_transform",
|
||||
SmithingRecipeData::read, SmithingRecipeData::write, RecipeType.SMITHING);
|
||||
public static final RecipeSerializer<SmithingTrimRecipeData> SMITHING_TRIM = define("smithing_trim",
|
||||
SmithingTrimRecipeData::read, SmithingTrimRecipeData::write);
|
||||
public static final RecipeSerializer<SimpleRecipeData> CRAFTING_DECORATED_POT = define("crafting_decorated_pot",
|
||||
SimpleRecipeData::read, SimpleRecipeData::write);
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the banner patterns.
|
||||
*
|
||||
* @return Banner Patterns
|
||||
*/
|
||||
public static Collection<RecipeSerializer<?>> values() {
|
||||
return Collections.unmodifiableCollection(PATTERN_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
}
|
||||
+39
-22
@@ -18,28 +18,45 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.recipe;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
// From MCProtocolLib
|
||||
@Deprecated
|
||||
public enum RecipeType {
|
||||
CRAFTING_SHAPELESS,
|
||||
CRAFTING_SHAPED,
|
||||
CRAFTING_SPECIAL_ARMORDYE,
|
||||
CRAFTING_SPECIAL_BOOKCLONING,
|
||||
CRAFTING_SPECIAL_MAPCLONING,
|
||||
CRAFTING_SPECIAL_MAPEXTENDING,
|
||||
CRAFTING_SPECIAL_FIREWORK_ROCKET,
|
||||
CRAFTING_SPECIAL_FIREWORK_STAR,
|
||||
CRAFTING_SPECIAL_FIREWORK_STAR_FADE,
|
||||
CRAFTING_SPECIAL_REPAIRITEM,
|
||||
CRAFTING_SPECIAL_TIPPEDARROW,
|
||||
CRAFTING_SPECIAL_BANNERDUPLICATE,
|
||||
CRAFTING_SPECIAL_BANNERADDPATTERN,
|
||||
CRAFTING_SPECIAL_SHIELDDECORATION,
|
||||
CRAFTING_SPECIAL_SHULKERBOXCOLORING,
|
||||
CRAFTING_SPECIAL_SUSPICIOUSSTEW,
|
||||
SMELTING,
|
||||
BLASTING,
|
||||
SMOKING,
|
||||
CAMPFIRE_COOKING,
|
||||
STONECUTTING,
|
||||
SMITHING
|
||||
|
||||
CRAFTING_SHAPELESS(RecipeSerializers.CRAFTING_SHAPELESS),
|
||||
CRAFTING_SHAPED(RecipeSerializers.CRAFTING_SHAPED),
|
||||
CRAFTING_SPECIAL_ARMORDYE(RecipeSerializers.CRAFTING_SPECIAL_ARMORDYE),
|
||||
CRAFTING_SPECIAL_BOOKCLONING(RecipeSerializers.CRAFTING_SPECIAL_BOOKCLONING),
|
||||
CRAFTING_SPECIAL_MAPCLONING(RecipeSerializers.CRAFTING_SPECIAL_MAPCLONING),
|
||||
CRAFTING_SPECIAL_MAPEXTENDING(RecipeSerializers.CRAFTING_SPECIAL_MAPEXTENDING),
|
||||
CRAFTING_SPECIAL_FIREWORK_ROCKET(RecipeSerializers.CRAFTING_SPECIAL_FIREWORK_ROCKET),
|
||||
CRAFTING_SPECIAL_FIREWORK_STAR(RecipeSerializers.CRAFTING_SPECIAL_FIREWORK_STAR),
|
||||
CRAFTING_SPECIAL_FIREWORK_STAR_FADE(RecipeSerializers.CRAFTING_SPECIAL_FIREWORK_STAR_FADE),
|
||||
CRAFTING_SPECIAL_REPAIRITEM(RecipeSerializers.CRAFTING_SPECIAL_REPAIRITEM),
|
||||
CRAFTING_SPECIAL_TIPPEDARROW(RecipeSerializers.CRAFTING_SPECIAL_TIPPEDARROW),
|
||||
CRAFTING_SPECIAL_BANNERDUPLICATE(RecipeSerializers.CRAFTING_SPECIAL_BANNERDUPLICATE),
|
||||
CRAFTING_SPECIAL_BANNERADDPATTERN(null), // I didn't find this anywhere
|
||||
CRAFTING_SPECIAL_SHIELDDECORATION(RecipeSerializers.CRAFTING_SPECIAL_SHIELDDECORATION),
|
||||
CRAFTING_SPECIAL_SHULKERBOXCOLORING(RecipeSerializers.CRAFTING_SPECIAL_SHULKERBOXCOLORING),
|
||||
CRAFTING_SPECIAL_SUSPICIOUSSTEW(RecipeSerializers.CRAFTING_SPECIAL_SUSPICIOUSSTEW),
|
||||
SMELTING(RecipeSerializers.SMELTING),
|
||||
BLASTING(RecipeSerializers.BLASTING),
|
||||
SMOKING(RecipeSerializers.SMOKING),
|
||||
CAMPFIRE_COOKING(RecipeSerializers.CAMPFIRE_COOKING),
|
||||
STONECUTTING(RecipeSerializers.STONECUTTING),
|
||||
SMITHING(RecipeSerializers.SMITHING_TRANSFORM);
|
||||
|
||||
private final @Nullable RecipeSerializer<?> serializer;
|
||||
|
||||
RecipeType(@Nullable RecipeSerializer<?> serializer) {
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
public RecipeSerializer<?> getSerializer() {
|
||||
if (this.serializer == null) {
|
||||
throw new UnsupportedOperationException("No serializer found for legacy recipe type " + this);
|
||||
}
|
||||
return this.serializer;
|
||||
}
|
||||
}
|
||||
+49
-13
@@ -18,45 +18,81 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.recipe.data;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.CookingCategory;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.Ingredient;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class CookedRecipeData implements RecipeData {
|
||||
private final @NotNull String group;
|
||||
private final @NotNull Ingredient ingredient;
|
||||
|
||||
private final String group;
|
||||
private final CookingCategory category;
|
||||
private final Ingredient ingredient;
|
||||
private final ItemStack result;
|
||||
private final float experience;
|
||||
private final int cookingTime;
|
||||
|
||||
public CookedRecipeData(@NotNull String group, @NotNull Ingredient ingredient, @NotNull ItemStack result, float experience, int cookingTime) {
|
||||
@Deprecated
|
||||
public CookedRecipeData(String group, Ingredient ingredient, ItemStack result, float experience, int cookingTime) {
|
||||
this(group, CookingCategory.MISC, ingredient, result, experience, cookingTime);
|
||||
}
|
||||
|
||||
public CookedRecipeData(
|
||||
String group, CookingCategory category, Ingredient ingredient,
|
||||
ItemStack result, float experience, int cookingTime
|
||||
) {
|
||||
this.group = group;
|
||||
this.category = category;
|
||||
this.ingredient = ingredient;
|
||||
this.result = result;
|
||||
this.experience = experience;
|
||||
this.cookingTime = cookingTime;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CookedRecipeData read(PacketWrapper<?> wrapper) {
|
||||
String group = wrapper.readString();
|
||||
CookingCategory category = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3) ?
|
||||
wrapper.readEnum(CookingCategory.values()) : CookingCategory.MISC;
|
||||
Ingredient ingredient = Ingredient.read(wrapper);
|
||||
ItemStack result = wrapper.readItemStack();
|
||||
float experience = wrapper.readFloat();
|
||||
int cookingTime = wrapper.readVarInt();
|
||||
return new CookedRecipeData(group, category, ingredient, result, experience, cookingTime);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, CookedRecipeData data) {
|
||||
wrapper.writeString(data.group);
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)) {
|
||||
wrapper.writeEnum(data.category);
|
||||
}
|
||||
Ingredient.write(wrapper, data.ingredient);
|
||||
wrapper.writeItemStack(data.result);
|
||||
wrapper.writeFloat(data.experience);
|
||||
wrapper.writeVarInt(data.cookingTime);
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
return this.group;
|
||||
}
|
||||
|
||||
public CookingCategory getCategory() {
|
||||
return this.category;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Ingredient getIngredient() {
|
||||
return ingredient;
|
||||
return this.ingredient;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemStack getResult() {
|
||||
return result;
|
||||
return this.result;
|
||||
}
|
||||
|
||||
public float getExperience() {
|
||||
return experience;
|
||||
return this.experience;
|
||||
}
|
||||
|
||||
public int getCookingTime() {
|
||||
return cookingTime;
|
||||
return this.cookingTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
-17
@@ -18,23 +18,108 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.recipe.data;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.CraftingCategory;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.Ingredient;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class ShapedRecipeData implements RecipeData {
|
||||
|
||||
private final String group;
|
||||
private final CraftingCategory category;
|
||||
private final ItemStack result;
|
||||
private final boolean showNotification;
|
||||
|
||||
// pattern
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final @NotNull String group;
|
||||
private final @NotNull Ingredient[] ingredients;
|
||||
private final ItemStack result;
|
||||
private final Ingredient[] ingredients;
|
||||
|
||||
public ShapedRecipeData(final int width, final int height, final @NotNull String group, final @NotNull Ingredient[] ingredients, final ItemStack result) {
|
||||
@Deprecated
|
||||
public ShapedRecipeData(int width, int height, String group, Ingredient[] ingredients, ItemStack result) {
|
||||
this(group, CraftingCategory.MISC, result, true, width, height, ingredients);
|
||||
}
|
||||
|
||||
public ShapedRecipeData(
|
||||
String group, CraftingCategory category, ItemStack result, boolean showNotification,
|
||||
int width, int height, Ingredient[] ingredients
|
||||
) {
|
||||
if (width * height != ingredients.length) {
|
||||
throw new IllegalArgumentException("Illegal ingredients length, found " + ingredients.length
|
||||
+ " but expected " + width + " * " + height);
|
||||
}
|
||||
|
||||
this.group = group;
|
||||
this.category = category;
|
||||
this.result = result;
|
||||
this.showNotification = showNotification;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.group = group;
|
||||
this.ingredients = ingredients;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public static ShapedRecipeData read(PacketWrapper<?> wrapper) {
|
||||
int width = 0, height = 0;
|
||||
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_20_3)) {
|
||||
width = wrapper.readVarInt();
|
||||
height = wrapper.readVarInt();
|
||||
}
|
||||
String group = wrapper.readString();
|
||||
CraftingCategory category = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)
|
||||
? wrapper.readEnum(CraftingCategory.values()) : CraftingCategory.MISC;
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20_3)) {
|
||||
width = wrapper.readVarInt();
|
||||
height = wrapper.readVarInt();
|
||||
}
|
||||
Ingredient[] ingredients = new Ingredient[width * height];
|
||||
for (int i = 0; i < ingredients.length; i++) {
|
||||
ingredients[i] = Ingredient.read(wrapper);
|
||||
}
|
||||
ItemStack result = wrapper.readItemStack();
|
||||
boolean showNotification = true;
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4)) {
|
||||
showNotification = wrapper.readBoolean();
|
||||
}
|
||||
return new ShapedRecipeData(group, category, result, showNotification, width, height, ingredients);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, ShapedRecipeData data) {
|
||||
if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_20_3)) {
|
||||
wrapper.writeVarInt(data.width);
|
||||
wrapper.writeVarInt(data.height);
|
||||
}
|
||||
wrapper.writeString(data.group);
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)) {
|
||||
wrapper.writeEnum(data.category);
|
||||
}
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20_3)) {
|
||||
wrapper.writeVarInt(data.width);
|
||||
wrapper.writeVarInt(data.height);
|
||||
}
|
||||
for (Ingredient ingredient : data.ingredients) {
|
||||
Ingredient.write(wrapper, ingredient);
|
||||
}
|
||||
wrapper.writeItemStack(data.result);
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4)) {
|
||||
wrapper.writeBoolean(data.showNotification);
|
||||
}
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
public CraftingCategory getCategory() {
|
||||
return this.category;
|
||||
}
|
||||
|
||||
public ItemStack getResult() {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
public boolean isShowNotification() {
|
||||
return this.showNotification;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
@@ -45,15 +130,7 @@ public class ShapedRecipeData implements RecipeData {
|
||||
return this.height;
|
||||
}
|
||||
|
||||
public @NotNull String getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
public @NotNull Ingredient[] getIngredients() {
|
||||
public Ingredient[] getIngredients() {
|
||||
return this.ingredients;
|
||||
}
|
||||
|
||||
public ItemStack getResult() {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
-11
@@ -18,30 +18,62 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.recipe.data;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.CraftingCategory;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.Ingredient;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class ShapelessRecipeData implements RecipeData {
|
||||
private final @NotNull String group;
|
||||
private final @NotNull Ingredient[] ingredients;
|
||||
|
||||
private final String group;
|
||||
private final CraftingCategory category;
|
||||
private final Ingredient[] ingredients;
|
||||
private final ItemStack result;
|
||||
|
||||
public ShapelessRecipeData(@NotNull String group, @NotNull Ingredient[] ingredients, @NotNull ItemStack result) {
|
||||
@Deprecated
|
||||
public ShapelessRecipeData(String group, Ingredient[] ingredients, ItemStack result) {
|
||||
this(group, CraftingCategory.MISC, ingredients, result);
|
||||
}
|
||||
|
||||
public ShapelessRecipeData(String group, CraftingCategory category, Ingredient[] ingredients, ItemStack result) {
|
||||
this.group = group;
|
||||
this.category = category;
|
||||
this.ingredients = ingredients;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public @NotNull String getGroup() {
|
||||
return group;
|
||||
public static ShapelessRecipeData read(PacketWrapper<?> wrapper) {
|
||||
String group = wrapper.readString();
|
||||
CraftingCategory category = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)
|
||||
? wrapper.readEnum(CraftingCategory.values()) : CraftingCategory.MISC;
|
||||
Ingredient[] ingredients = wrapper.readArray(Ingredient::read, Ingredient.class);
|
||||
ItemStack result = wrapper.readItemStack();
|
||||
return new ShapelessRecipeData(group, category, ingredients, result);
|
||||
}
|
||||
|
||||
public @NotNull Ingredient[] getIngredients() {
|
||||
return ingredients;
|
||||
public static void write(PacketWrapper<?> wrapper, ShapelessRecipeData data) {
|
||||
wrapper.writeString(data.group);
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)) {
|
||||
wrapper.writeEnum(data.category);
|
||||
}
|
||||
wrapper.writeArray(data.ingredients, Ingredient::write);
|
||||
wrapper.writeItemStack(data.result);
|
||||
}
|
||||
|
||||
public @NotNull ItemStack getResult() {
|
||||
return result;
|
||||
public String getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
}
|
||||
|
||||
public CraftingCategory getCategory() {
|
||||
return this.category;
|
||||
}
|
||||
|
||||
public Ingredient[] getIngredients() {
|
||||
return this.ingredients;
|
||||
}
|
||||
|
||||
public ItemStack getResult() {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.recipe.data;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.CraftingCategory;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class SimpleRecipeData implements RecipeData {
|
||||
|
||||
private final CraftingCategory category;
|
||||
|
||||
public SimpleRecipeData(CraftingCategory category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public static SimpleRecipeData read(PacketWrapper<?> wrapper) {
|
||||
CraftingCategory category = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)
|
||||
? wrapper.readEnum(CraftingCategory.values()) : CraftingCategory.MISC;
|
||||
return new SimpleRecipeData(category);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, SimpleRecipeData data) {
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)) {
|
||||
wrapper.writeEnum(data.getCategory());
|
||||
}
|
||||
}
|
||||
|
||||
public CraftingCategory getCategory() {
|
||||
return this.category;
|
||||
}
|
||||
}
|
||||
+53
-10
@@ -18,32 +18,75 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.recipe.data;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.Ingredient;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
public class SmithingRecipeData implements RecipeData {
|
||||
private final @NotNull Ingredient base;
|
||||
private final @NotNull Ingredient addition;
|
||||
|
||||
private final @UnknownNullability Ingredient template;
|
||||
private final Ingredient base;
|
||||
private final Ingredient addition;
|
||||
private final ItemStack result;
|
||||
|
||||
public SmithingRecipeData(@NotNull Ingredient base, @NotNull Ingredient addition, ItemStack result) {
|
||||
@Deprecated
|
||||
public SmithingRecipeData(Ingredient base, Ingredient addition, ItemStack result) {
|
||||
this(null, base, addition, result);
|
||||
}
|
||||
|
||||
public SmithingRecipeData(
|
||||
@UnknownNullability Ingredient template,
|
||||
Ingredient base, Ingredient addition, ItemStack result
|
||||
) {
|
||||
this.template = template;
|
||||
this.base = base;
|
||||
this.addition = addition;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Ingredient getBase() {
|
||||
return base;
|
||||
public static SmithingRecipeData read(PacketWrapper<?> wrapper) {
|
||||
return read(wrapper, false);
|
||||
}
|
||||
|
||||
public static SmithingRecipeData read(PacketWrapper<?> wrapper, boolean legacy) {
|
||||
Ingredient template = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20)
|
||||
|| (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4) && !legacy)
|
||||
? Ingredient.read(wrapper) : null;
|
||||
Ingredient base = Ingredient.read(wrapper);
|
||||
Ingredient addition = Ingredient.read(wrapper);
|
||||
ItemStack result = wrapper.readItemStack();
|
||||
return new SmithingRecipeData(template, base, addition, result);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, SmithingRecipeData data) {
|
||||
write(wrapper, data, false);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, SmithingRecipeData data, boolean legacy) {
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20)
|
||||
|| (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4) && !legacy)) {
|
||||
Ingredient.write(wrapper, data.template);
|
||||
}
|
||||
Ingredient.write(wrapper, data.base);
|
||||
Ingredient.write(wrapper, data.addition);
|
||||
wrapper.writeItemStack(data.result);
|
||||
}
|
||||
|
||||
public @UnknownNullability Ingredient getTemplate() {
|
||||
return this.template;
|
||||
}
|
||||
|
||||
public Ingredient getBase() {
|
||||
return this.base;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Ingredient getAddition() {
|
||||
return addition;
|
||||
return this.addition;
|
||||
}
|
||||
|
||||
public ItemStack getResult() {
|
||||
return result;
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.recipe.data;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.recipe.Ingredient;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class SmithingTrimRecipeData implements RecipeData {
|
||||
|
||||
private final Ingredient template;
|
||||
private final Ingredient base;
|
||||
private final Ingredient addition;
|
||||
|
||||
public SmithingTrimRecipeData(Ingredient template, Ingredient base, Ingredient addition) {
|
||||
this.template = template;
|
||||
this.base = base;
|
||||
this.addition = addition;
|
||||
}
|
||||
|
||||
public static SmithingTrimRecipeData read(PacketWrapper<?> wrapper) {
|
||||
Ingredient template = Ingredient.read(wrapper);
|
||||
Ingredient base = Ingredient.read(wrapper);
|
||||
Ingredient addition = Ingredient.read(wrapper);
|
||||
return new SmithingTrimRecipeData(template, base, addition);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, SmithingTrimRecipeData data) {
|
||||
Ingredient.write(wrapper, data.template);
|
||||
Ingredient.write(wrapper, data.base);
|
||||
Ingredient.write(wrapper, data.addition);
|
||||
}
|
||||
|
||||
public Ingredient getTemplate() {
|
||||
return this.template;
|
||||
}
|
||||
|
||||
public Ingredient getBase() {
|
||||
return this.base;
|
||||
}
|
||||
|
||||
public Ingredient getAddition() {
|
||||
return this.addition;
|
||||
}
|
||||
}
|
||||
+21
-10
@@ -20,31 +20,42 @@ package com.github.retrooper.packetevents.protocol.recipe.data;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.recipe.Ingredient;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class StoneCuttingRecipeData implements RecipeData {
|
||||
private final @NotNull String group;
|
||||
private final @NotNull Ingredient ingredient;
|
||||
|
||||
private final String group;
|
||||
private final Ingredient ingredient;
|
||||
private final ItemStack result;
|
||||
|
||||
public StoneCuttingRecipeData(@NotNull String group, @NotNull Ingredient ingredient, ItemStack result) {
|
||||
public StoneCuttingRecipeData(String group, Ingredient ingredient, ItemStack result) {
|
||||
this.group = group;
|
||||
this.ingredient = ingredient;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static StoneCuttingRecipeData read(PacketWrapper<?> wrapper) {
|
||||
String group = wrapper.readString();
|
||||
Ingredient ingredient = Ingredient.read(wrapper);
|
||||
ItemStack result = wrapper.readItemStack();
|
||||
return new StoneCuttingRecipeData(group, ingredient, result);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, StoneCuttingRecipeData data) {
|
||||
wrapper.writeString(data.group);
|
||||
Ingredient.write(wrapper, data.ingredient);
|
||||
wrapper.writeItemStack(data.result);
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
return this.group;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Ingredient getIngredient() {
|
||||
return ingredient;
|
||||
return this.ingredient;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemStack getResult() {
|
||||
return result;
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
+10
@@ -23,6 +23,8 @@ import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
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;
|
||||
@@ -43,6 +45,14 @@ public final class ScoreFormatTypes {
|
||||
wrapper -> ScoreFormat.fixedScore(wrapper.readComponent()),
|
||||
(wrapper, format) -> wrapper.writeComponent(format.getValue()));
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the score format types.
|
||||
* @return Score Format Types
|
||||
*/
|
||||
public static Collection<ScoreFormatType> values() {
|
||||
return Collections.unmodifiableCollection(SCORE_FORMAT_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
private ScoreFormatTypes() {
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -41,7 +43,7 @@ public class Sounds {
|
||||
|
||||
public static Sound define(String key, ResourceLocation soundId, @Nullable Float range) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
Sound potionType = new Sound() {
|
||||
Sound soundType = new Sound() {
|
||||
@Override
|
||||
public ResourceLocation getSoundId() {
|
||||
return soundId;
|
||||
@@ -70,8 +72,8 @@ public class Sounds {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, SOUND_TYPE_MAP, SOUND_TYPE_ID_MAP, potionType);
|
||||
return potionType;
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, SOUND_TYPE_MAP, SOUND_TYPE_ID_MAP, soundType);
|
||||
return soundType;
|
||||
}
|
||||
|
||||
public static @Nullable Sound getByName(String name) {
|
||||
@@ -767,9 +769,19 @@ public class Sounds {
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_SPAWN_ITEM = define("block.trial_spawner.spawn_item");
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_SPAWN_ITEM_BEGIN = define("block.trial_spawner.spawn_item_begin");
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_DETECT_PLAYER = define("block.trial_spawner.detect_player");
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_CHARGE_ACTIVATE = define("block.trial_spawner.charge_activate");
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_OMINOUS_ACTIVATE = define("block.trial_spawner.ominous_activate");
|
||||
/**
|
||||
* Removed in 1.21
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_CHARGE_ACTIVATE = BLOCK_TRIAL_SPAWNER_OMINOUS_ACTIVATE;
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_AMBIENT = define("block.trial_spawner.ambient");
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_AMBIENT_CHARGED = define("block.trial_spawner.ambient_charged");
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_AMBIENT_OMINOUS = define("block.trial_spawner.ambient_ominous");
|
||||
/**
|
||||
* Removed in 1.21
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_AMBIENT_CHARGED = BLOCK_TRIAL_SPAWNER_AMBIENT_OMINOUS;
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_OPEN_SHUTTER = define("block.trial_spawner.open_shutter");
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_CLOSE_SHUTTER = define("block.trial_spawner.close_shutter");
|
||||
public static final Sound BLOCK_TRIAL_SPAWNER_EJECT_ITEM = define("block.trial_spawner.eject_item");
|
||||
@@ -1692,6 +1704,20 @@ public class Sounds {
|
||||
public static final Sound EVENT_MOB_EFFECT_TRIAL_OMEN = define("event.mob_effect.trial_omen");
|
||||
public static final Sound EVENT_MOB_EFFECT_RAID_OMEN = define("event.mob_effect.raid_omen");
|
||||
|
||||
// Added with 1.21
|
||||
public static final Sound MUSIC_DISC_CREATOR = define("music_disc.creator");
|
||||
public static final Sound MUSIC_DISC_CREATOR_MUSIC_BOX = define("music_disc.creator_music_box");
|
||||
public static final Sound MUSIC_DISC_PRECIPICE = define("music_disc.precipice");
|
||||
public static final Sound BLOCK_VAULT_REJECT_REWARDED_PLAYER = define("block.vault.reject_rewarded_player");
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the sounds.
|
||||
* @return Sounds
|
||||
*/
|
||||
public static Collection<Sound> values() {
|
||||
return Collections.unmodifiableCollection(SOUND_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
+4
-2
@@ -18,11 +18,13 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.world;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// From MCProtocolLib
|
||||
//TODO Recode and make registry
|
||||
@ApiStatus.Obsolete
|
||||
public enum PaintingType {
|
||||
KEBAB("Kebab", 0, 1, 1),
|
||||
AZTEC("Aztec", 1, 1, 1),
|
||||
@@ -105,4 +107,4 @@ public enum PaintingType {
|
||||
}
|
||||
|
||||
private static final PaintingType[] VALUES = values();
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.world;
|
||||
|
||||
@Deprecated
|
||||
public enum TileEntityType {
|
||||
MOB_SPAWNER,
|
||||
COMMAND_BLOCK,
|
||||
|
||||
+10
@@ -23,6 +23,8 @@ import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -123,6 +125,14 @@ public class BlockEntityTypes {
|
||||
public static final BlockEntityType TRIAL_SPAWNER = define("trial_spawner");
|
||||
public static final BlockEntityType VAULT = define("vault");
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the block entity types.
|
||||
* @return Block Entity Types
|
||||
*/
|
||||
public static Collection<BlockEntityType> values() {
|
||||
return Collections.unmodifiableCollection(BLOCK_ENTITY_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.chunk;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class ChunkBitMask {
|
||||
|
||||
private ChunkBitMask() {
|
||||
}
|
||||
|
||||
public static long[] readBitSetLongs(PacketWrapper<?> packet) {
|
||||
if (packet.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_17)) {
|
||||
//Read primary bit mask
|
||||
return packet.readLongArray();
|
||||
} else if (packet.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
|
||||
//Read primary bit mask
|
||||
return new long[]{packet.readVarInt()};
|
||||
} else {
|
||||
//Read primary bit mask
|
||||
return new long[]{packet.readUnsignedShort()};
|
||||
}
|
||||
}
|
||||
|
||||
public static BitSet readChunkMask(PacketWrapper<?> packet) {
|
||||
return BitSet.valueOf(readBitSetLongs(packet));
|
||||
}
|
||||
|
||||
public static void writeChunkMask(PacketWrapper<?> packet, BitSet chunkMask) {
|
||||
long[] longArray = chunkMask.toLongArray();
|
||||
|
||||
if (packet.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_17)) {
|
||||
//Write primary bit mask
|
||||
packet.writeLongArray(longArray);
|
||||
} else if (packet.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
|
||||
if (longArray.length > 0) {
|
||||
packet.writeVarInt((int) longArray[0]);
|
||||
} else {
|
||||
packet.writeVarInt(0);
|
||||
}
|
||||
} else {
|
||||
if (longArray.length > 0) {
|
||||
packet.writeShort((int) longArray[0]);
|
||||
} else {
|
||||
packet.writeShort(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.chunk;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public class LightData implements Cloneable {
|
||||
private boolean trustEdges;
|
||||
private BitSet blockLightMask;
|
||||
private BitSet skyLightMask;
|
||||
private BitSet emptyBlockLightMask;
|
||||
private BitSet emptySkyLightMask;
|
||||
private int skyLightCount;
|
||||
private int blockLightCount;
|
||||
private byte[][] skyLightArray;
|
||||
private byte[][] blockLightArray;
|
||||
|
||||
public LightData() {
|
||||
}
|
||||
|
||||
public LightData(boolean trustEdges, BitSet blockLightMask, BitSet skyLightMask, BitSet emptyBlockLightMask, BitSet emptySkyLightMask, int skyLightCount, int blockLightCount, byte[][] skyLightArray, byte[][] blockLightArray) {
|
||||
this.trustEdges = trustEdges;
|
||||
this.blockLightMask = blockLightMask;
|
||||
this.skyLightMask = skyLightMask;
|
||||
this.emptyBlockLightMask = emptyBlockLightMask;
|
||||
this.emptySkyLightMask = emptySkyLightMask;
|
||||
this.skyLightCount = skyLightCount;
|
||||
this.blockLightCount = blockLightCount;
|
||||
this.skyLightArray = skyLightArray;
|
||||
this.blockLightArray = blockLightArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LightData clone() {
|
||||
try {
|
||||
LightData clone = (LightData) super.clone();
|
||||
clone.blockLightMask = (BitSet) blockLightMask.clone();
|
||||
clone.skyLightMask = (BitSet) skyLightMask.clone();
|
||||
clone.emptyBlockLightMask = (BitSet) emptyBlockLightMask.clone();
|
||||
clone.emptySkyLightMask = (BitSet) emptySkyLightMask.clone();
|
||||
clone.skyLightArray = skyLightArray.clone();
|
||||
clone.blockLightArray = blockLightArray.clone();
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTrustEdges() {
|
||||
return trustEdges;
|
||||
}
|
||||
|
||||
public void setTrustEdges(boolean trustEdges) {
|
||||
this.trustEdges = trustEdges;
|
||||
}
|
||||
|
||||
public BitSet getBlockLightMask() {
|
||||
return blockLightMask;
|
||||
}
|
||||
|
||||
public void setBlockLightMask(BitSet blockLightMask) {
|
||||
this.blockLightMask = blockLightMask;
|
||||
}
|
||||
|
||||
public BitSet getSkyLightMask() {
|
||||
return skyLightMask;
|
||||
}
|
||||
|
||||
public void setSkyLightMask(BitSet skyLightMask) {
|
||||
this.skyLightMask = skyLightMask;
|
||||
}
|
||||
|
||||
public BitSet getEmptyBlockLightMask() {
|
||||
return emptyBlockLightMask;
|
||||
}
|
||||
|
||||
public void setEmptyBlockLightMask(BitSet emptyBlockLightMask) {
|
||||
this.emptyBlockLightMask = emptyBlockLightMask;
|
||||
}
|
||||
|
||||
public BitSet getEmptySkyLightMask() {
|
||||
return emptySkyLightMask;
|
||||
}
|
||||
|
||||
public void setEmptySkyLightMask(BitSet emptySkyLightMask) {
|
||||
this.emptySkyLightMask = emptySkyLightMask;
|
||||
}
|
||||
|
||||
public int getSkyLightCount() {
|
||||
return skyLightCount;
|
||||
}
|
||||
|
||||
public void setSkyLightCount(int skyLightCount) {
|
||||
this.skyLightCount = skyLightCount;
|
||||
}
|
||||
|
||||
public int getBlockLightCount() {
|
||||
return blockLightCount;
|
||||
}
|
||||
|
||||
public void setBlockLightCount(int blockLightCount) {
|
||||
this.blockLightCount = blockLightCount;
|
||||
}
|
||||
|
||||
public byte[][] getSkyLightArray() {
|
||||
return skyLightArray;
|
||||
}
|
||||
|
||||
public void setSkyLightArray(byte[][] skyLightArray) {
|
||||
this.skyLightArray = skyLightArray;
|
||||
}
|
||||
|
||||
public byte[][] getBlockLightArray() {
|
||||
return blockLightArray;
|
||||
}
|
||||
|
||||
public void setBlockLightArray(byte[][] blockLightArray) {
|
||||
this.blockLightArray = blockLightArray;
|
||||
}
|
||||
|
||||
public static LightData read(PacketWrapper<?> packet) {
|
||||
LightData lightData = new LightData();
|
||||
ServerVersion serverVersion = packet.getServerVersion();
|
||||
if (serverVersion.isOlderThanOrEquals(ServerVersion.V_1_19_4)) {
|
||||
lightData.trustEdges = packet.readBoolean();
|
||||
}
|
||||
|
||||
lightData.skyLightMask = ChunkBitMask.readChunkMask(packet);
|
||||
lightData.blockLightMask = ChunkBitMask.readChunkMask(packet);
|
||||
lightData.emptySkyLightMask = ChunkBitMask.readChunkMask(packet);
|
||||
lightData.emptyBlockLightMask = ChunkBitMask.readChunkMask(packet);
|
||||
|
||||
boolean v17 = serverVersion.isNewerThanOrEquals(ServerVersion.V_1_17);
|
||||
lightData.skyLightCount = v17 ? packet.readVarInt() : 18;
|
||||
lightData.skyLightArray = new byte[lightData.skyLightCount][];
|
||||
for (int i = 0; i < lightData.skyLightCount; i++) {
|
||||
if (v17 || lightData.skyLightMask.get(i)) {
|
||||
lightData.skyLightArray[i] = packet.readByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
lightData.blockLightCount = v17 ? packet.readVarInt() : 18;
|
||||
lightData.blockLightArray = new byte[lightData.blockLightCount][];
|
||||
for (int i = 0; i < lightData.blockLightCount; i++) {
|
||||
if (v17 || lightData.blockLightMask.get(i)) {
|
||||
lightData.blockLightArray[i] = packet.readByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
return lightData;
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> packet, LightData lightData) {
|
||||
ServerVersion serverVersion = packet.getServerVersion();
|
||||
if (serverVersion.isOlderThanOrEquals(ServerVersion.V_1_19_4)) {
|
||||
packet.writeBoolean(lightData.trustEdges);
|
||||
}
|
||||
ChunkBitMask.writeChunkMask(packet, lightData.skyLightMask);
|
||||
ChunkBitMask.writeChunkMask(packet, lightData.blockLightMask);
|
||||
ChunkBitMask.writeChunkMask(packet, lightData.emptySkyLightMask);
|
||||
ChunkBitMask.writeChunkMask(packet, lightData.emptyBlockLightMask);
|
||||
|
||||
boolean v17 = serverVersion.isNewerThanOrEquals(ServerVersion.V_1_17);
|
||||
if (v17) {
|
||||
packet.writeVarInt(lightData.skyLightCount);
|
||||
}
|
||||
for (int i = 0; i < lightData.skyLightCount; i++) {
|
||||
if (v17 || lightData.skyLightMask.get(i)) {
|
||||
packet.writeByteArray(lightData.skyLightArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (v17) {
|
||||
packet.writeVarInt(lightData.blockLightCount);
|
||||
}
|
||||
for (int i = 0; i < lightData.blockLightCount; i++) {
|
||||
if (v17 || lightData.blockLightMask.get(i)) {
|
||||
packet.writeByteArray(lightData.blockLightArray[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.world.painting;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public interface PaintingVariant extends MappedEntity {
|
||||
|
||||
int getWidth();
|
||||
|
||||
int getHeight();
|
||||
|
||||
ResourceLocation getAssetId();
|
||||
|
||||
static PaintingVariant readDirect(PacketWrapper<?> wrapper) {
|
||||
int width = wrapper.readVarInt();
|
||||
int height = wrapper.readVarInt();
|
||||
ResourceLocation assetId = wrapper.readIdentifier();
|
||||
return new StaticPaintingVariant(width, height, assetId);
|
||||
}
|
||||
|
||||
static void writeDirect(PacketWrapper<?> wrapper, PaintingVariant variant) {
|
||||
wrapper.writeVarInt(variant.getWidth());
|
||||
wrapper.writeVarInt(variant.getHeight());
|
||||
wrapper.writeIdentifier(variant.getAssetId());
|
||||
}
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.world.painting;
|
||||
|
||||
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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PaintingVariants {
|
||||
|
||||
private static final Map<String, PaintingVariant> PAINTING_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<Byte, Map<Integer, PaintingVariant>> PAINTING_TYPE_ID_MAP = new HashMap<>();
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_banner_pattern_mappings");
|
||||
|
||||
public static PaintingVariant define(String key, int width, int height) {
|
||||
ResourceLocation assetId = ResourceLocation.minecraft(key);
|
||||
return define(key, width, height, assetId);
|
||||
}
|
||||
|
||||
public static PaintingVariant define(String key, int width, int height, ResourceLocation assetId) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
PaintingVariant variant = new PaintingVariant() {
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getAssetId() {
|
||||
return assetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
return data.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return TYPES_BUILDER.getDataIndex(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof PaintingVariant) {
|
||||
return this.getName().equals(((PaintingVariant) obj).getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, PAINTING_TYPE_MAP, PAINTING_TYPE_ID_MAP, variant);
|
||||
return variant;
|
||||
}
|
||||
|
||||
// with key
|
||||
public static PaintingVariant getByName(String name) {
|
||||
return PAINTING_TYPE_MAP.get(name);
|
||||
}
|
||||
|
||||
public static PaintingVariant getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, PaintingVariant> idMap = PAINTING_TYPE_ID_MAP.get((byte) index);
|
||||
return idMap.get(id);
|
||||
}
|
||||
|
||||
public static final PaintingVariant POINTER = define("pointer", 4, 4);
|
||||
public static final PaintingVariant CREEBET = define("creebet", 2, 1);
|
||||
public static final PaintingVariant PRAIRIE_RIDE = define("prairie_ride", 1, 2);
|
||||
public static final PaintingVariant POOL = define("pool", 2, 1);
|
||||
public static final PaintingVariant EARTH = define("earth", 2, 2);
|
||||
public static final PaintingVariant SKELETON = define("skeleton", 4, 3);
|
||||
public static final PaintingVariant MATCH = define("match", 2, 2);
|
||||
public static final PaintingVariant POND = define("pond", 3, 4);
|
||||
public static final PaintingVariant HUMBLE = define("humble", 2, 2);
|
||||
public static final PaintingVariant PIGSCENE = define("pigscene", 4, 4);
|
||||
public static final PaintingVariant WATER = define("water", 2, 2);
|
||||
public static final PaintingVariant ALBAN = define("alban", 1, 1);
|
||||
public static final PaintingVariant FINDING = define("finding", 4, 2);
|
||||
public static final PaintingVariant AZTEC2 = define("aztec2", 1, 1);
|
||||
public static final PaintingVariant TIDES = define("tides", 3, 3);
|
||||
public static final PaintingVariant FIGHTERS = define("fighters", 4, 2);
|
||||
public static final PaintingVariant FIRE = define("fire", 2, 2);
|
||||
public static final PaintingVariant CHANGING = define("changing", 4, 2);
|
||||
public static final PaintingVariant BURNING_SKULL = define("burning_skull", 4, 4);
|
||||
public static final PaintingVariant COTAN = define("cotan", 3, 3);
|
||||
public static final PaintingVariant WANDERER = define("wanderer", 1, 2);
|
||||
public static final PaintingVariant UNPACKED = define("unpacked", 4, 4);
|
||||
public static final PaintingVariant SUNSET = define("sunset", 2, 1);
|
||||
public static final PaintingVariant FERN = define("fern", 3, 3);
|
||||
public static final PaintingVariant BUST = define("bust", 2, 2);
|
||||
public static final PaintingVariant WIND = define("wind", 2, 2);
|
||||
public static final PaintingVariant LOWMIST = define("lowmist", 4, 2);
|
||||
public static final PaintingVariant PASSAGE = define("passage", 4, 2);
|
||||
public static final PaintingVariant SUNFLOWERS = define("sunflowers", 3, 3);
|
||||
public static final PaintingVariant GRAHAM = define("graham", 1, 2);
|
||||
public static final PaintingVariant WASTELAND = define("wasteland", 1, 1);
|
||||
public static final PaintingVariant SKULL_AND_ROSES = define("skull_and_roses", 2, 2);
|
||||
public static final PaintingVariant BOUQUET = define("bouquet", 3, 3);
|
||||
public static final PaintingVariant ORB = define("orb", 4, 4);
|
||||
public static final PaintingVariant BOMB = define("bomb", 1, 1);
|
||||
public static final PaintingVariant WITHER = define("wither", 2, 2);
|
||||
public static final PaintingVariant BACKYARD = define("backyard", 3, 4);
|
||||
public static final PaintingVariant ENDBOSS = define("endboss", 3, 3);
|
||||
public static final PaintingVariant MEDITATIVE = define("meditative", 1, 1);
|
||||
public static final PaintingVariant VOID = define("void", 2, 2);
|
||||
public static final PaintingVariant KEBAB = define("kebab", 1, 1);
|
||||
public static final PaintingVariant SEA = define("sea", 2, 1);
|
||||
public static final PaintingVariant DONKEY_KONG = define("donkey_kong", 4, 3);
|
||||
public static final PaintingVariant BAROQUE = define("baroque", 2, 2);
|
||||
public static final PaintingVariant STAGE = define("stage", 2, 2);
|
||||
public static final PaintingVariant AZTEC = define("aztec", 1, 1);
|
||||
public static final PaintingVariant PLANT = define("plant", 1, 1);
|
||||
public static final PaintingVariant CAVEBIRD = define("cavebird", 3, 3);
|
||||
public static final PaintingVariant COURBET = define("courbet", 2, 1);
|
||||
public static final PaintingVariant OWLEMONS = define("owlemons", 3, 3);
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.painting;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
|
||||
public class StaticPaintingVariant implements PaintingVariant {
|
||||
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final ResourceLocation assetId;
|
||||
|
||||
public StaticPaintingVariant(int width, int height, ResourceLocation assetId) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.assetId = assetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return this.width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return this.height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getAssetId() {
|
||||
return this.assetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+95
-75
@@ -37,8 +37,23 @@ public class WrappedBlockState {
|
||||
static {
|
||||
STRING_UPDATER.put("grass_path", "dirt_path"); // 1.16 -> 1.17
|
||||
|
||||
loadLegacy();
|
||||
loadModern();
|
||||
// Try to reduce memory footprint by re-using hashmaps when they are equal
|
||||
// We do this by setting the key to the NBTCompound of the data and the value to the data
|
||||
// this.data = cache.computeIfAbsent(dataContent, (key) -> { // NBTCompound to data });
|
||||
// This will get an equal value if present, otherwise it will compute the value
|
||||
// Once this is done, we remove this cache to save memory
|
||||
// A HashMap is used instead of another data type because a hashmap is o(1)
|
||||
//
|
||||
// 6160 total combinations, last updated with 1.20.5
|
||||
// This brings total memory usage from 62 MB to 34 MB, a 28 MB reduction
|
||||
// Using a HashMap reduces memory usage to less than a megabyte, I can't get precise numbers because it is hard to see on a heapdump
|
||||
Map<NBTCompound, Map.Entry<Map<StateValue, Object>, String>> cache = new HashMap<>(6160, 70);
|
||||
|
||||
loadLegacy(cache);
|
||||
loadModern(cache);
|
||||
|
||||
cache.clear();
|
||||
cache = null;
|
||||
}
|
||||
|
||||
int globalID;
|
||||
@@ -164,14 +179,12 @@ public class WrappedBlockState {
|
||||
return 11;
|
||||
} else if (version.isOlderThanOrEquals(ClientVersion.V_1_20_2)) {
|
||||
return 12;
|
||||
} else if (version.isOlderThanOrEquals(ClientVersion.V_1_20_5)) {
|
||||
return 13;
|
||||
}
|
||||
// TODO UPDATE increment index (and add previous above)
|
||||
return 14;
|
||||
return 13;
|
||||
}
|
||||
|
||||
private static void loadLegacy() {
|
||||
private static void loadLegacy(Map<NBTCompound, Map.Entry<Map<StateValue, Object>, String>> cache) {
|
||||
Map<Integer, WrappedBlockState> stateByIdMap = new HashMap<>();
|
||||
Map<WrappedBlockState, Integer> stateToIdMap = new HashMap<>();
|
||||
Map<String, WrappedBlockState> stateByStringMap = new HashMap<>();
|
||||
@@ -196,45 +209,49 @@ public class WrappedBlockState {
|
||||
int data = Integer.parseInt(ids[1]);
|
||||
int combinedID = (id << 4) | data;
|
||||
|
||||
StringBuilder dataStringBuilder = new StringBuilder();
|
||||
NBTCompound dataContent = (NBTCompound) element.getValue();
|
||||
Map<StateValue, Object> dataMap = new HashMap<>(dataContent.size());
|
||||
Map.Entry<Map<StateValue, Object>, String> dataEntry = cache.computeIfAbsent(dataContent, (key) -> {
|
||||
StringBuilder dataStringBuilder = new StringBuilder();
|
||||
Map<StateValue, Object> dataMap = new HashMap<>(key.size());
|
||||
|
||||
for (Map.Entry<String, NBT> props : dataContent.getTags().entrySet()) {
|
||||
StateValue state = StateValue.byName(props.getKey());
|
||||
if (state == null) {
|
||||
PacketEvents.getAPI().getLogger().warning("Could not find value for " + props.getKey());
|
||||
continue;
|
||||
for (Map.Entry<String, NBT> props : key.getTags().entrySet()) {
|
||||
StateValue state = StateValue.byName(props.getKey());
|
||||
if (state == null) {
|
||||
PacketEvents.getAPI().getLogger().warning("Could not find value for " + props.getKey());
|
||||
continue;
|
||||
}
|
||||
|
||||
dataStringBuilder.append(props.getKey()).append("=");
|
||||
NBT value = props.getValue();
|
||||
Object v;
|
||||
if (value instanceof NBTByte) {
|
||||
v = ((NBTByte) value).getAsInt() == 1;
|
||||
} else if (value instanceof NBTNumber) {
|
||||
v = ((NBTNumber) value).getAsInt();
|
||||
} else if (value instanceof NBTString) {
|
||||
v = ((NBTString) value).getValue();
|
||||
} else {
|
||||
PacketEvents.getAPI().getLogger().warning("Unknown NBT type in legacy mapping: " + value.getClass().getSimpleName());
|
||||
dataStringBuilder = new StringBuilder(dataStringBuilder.substring(0, dataStringBuilder.length() - props.getKey().length() - 1));
|
||||
continue;
|
||||
}
|
||||
|
||||
dataStringBuilder.append(v).append(",");
|
||||
dataMap.put(state, state.getParser().apply(v.toString().toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
|
||||
dataStringBuilder.append(props.getKey()).append("=");
|
||||
NBT value = props.getValue();
|
||||
Object v;
|
||||
if (value instanceof NBTByte) {
|
||||
v = ((NBTByte) value).getAsInt() == 1;
|
||||
} else if (value instanceof NBTNumber) {
|
||||
v = ((NBTNumber) value).getAsInt();
|
||||
} else if (value instanceof NBTString) {
|
||||
v = ((NBTString) value).getValue();
|
||||
String dataString;
|
||||
if (dataStringBuilder.length() == 0) {
|
||||
dataString = "";
|
||||
} else {
|
||||
PacketEvents.getAPI().getLogger().warning("Unknown NBT type in legacy mapping: " + value.getClass().getSimpleName());
|
||||
dataStringBuilder = new StringBuilder(dataStringBuilder.substring(0, dataStringBuilder.length() - props.getKey().length() - 1));
|
||||
continue;
|
||||
dataString = "[" + dataStringBuilder.substring(0, dataStringBuilder.length() - 1) + "]";
|
||||
}
|
||||
|
||||
dataStringBuilder.append(v).append(",");
|
||||
dataMap.put(state, state.getParser().apply(v.toString().toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
return new AbstractMap.SimpleEntry<>(dataMap, dataString);
|
||||
});
|
||||
|
||||
String dataString;
|
||||
if (dataStringBuilder.length() == 0) {
|
||||
dataString = "";
|
||||
} else {
|
||||
dataString = "[" + dataStringBuilder.substring(0, dataStringBuilder.length() - 1) + "]";
|
||||
}
|
||||
String fullString = entry.getKey() + dataString;
|
||||
|
||||
WrappedBlockState state = new WrappedBlockState(type, dataMap, combinedID, (byte) 0);
|
||||
String fullString = entry.getKey() + dataEntry.getValue();
|
||||
WrappedBlockState state = new WrappedBlockState(type, dataEntry.getKey(), combinedID, (byte) 0);
|
||||
|
||||
stateByIdMap.put(combinedID, state);
|
||||
stateToStringMap.put(state, fullString);
|
||||
@@ -257,21 +274,21 @@ public class WrappedBlockState {
|
||||
DEFAULT_STATES.put((byte) 0, stateTypeToBlockStateMap);
|
||||
}
|
||||
|
||||
private static void loadModern() {
|
||||
private static void loadModern(Map<NBTCompound, Map.Entry<Map<StateValue, Object>, String>> cache) {
|
||||
final NBTCompound compound = MappingHelper.decompress("mappings/block/modern_block_mappings");
|
||||
|
||||
for (Map.Entry<String, NBT> versionEntry : compound.getTags().entrySet()) {
|
||||
if (versionEntry.getKey().equals("version")) continue;
|
||||
ClientVersion version = ClientVersion.valueOf(versionEntry.getKey());
|
||||
byte mappingIndex = getMappingsIndex(version);
|
||||
NBTList<NBTCompound> list = (NBTList<NBTCompound>) versionEntry.getValue();
|
||||
|
||||
Map<Integer, WrappedBlockState> stateByIdMap = new HashMap<>();
|
||||
Map<WrappedBlockState, Integer> stateToIdMap = new HashMap<>();
|
||||
Map<String, WrappedBlockState> stateByStringMap = new HashMap<>();
|
||||
Map<WrappedBlockState, String> stateToStringMap = new HashMap<>();
|
||||
Map<StateType, WrappedBlockState> stateTypeToBlockStateMap = new HashMap<>();
|
||||
|
||||
if (versionEntry.getKey().equals("version")) continue;
|
||||
ClientVersion version = ClientVersion.valueOf(versionEntry.getKey());
|
||||
byte mappingIndex = getMappingsIndex(version);
|
||||
NBTList<NBTCompound> list = (NBTList<NBTCompound>) versionEntry.getValue();
|
||||
|
||||
int id = 0;
|
||||
for (NBTCompound element : list.getTags()) {
|
||||
String typeString = element.getStringTagValueOrThrow("type");
|
||||
@@ -299,45 +316,48 @@ public class WrappedBlockState {
|
||||
|
||||
int index = 0;
|
||||
for (NBTCompound dataContent : element.getCompoundListTagOrThrow("entries").getTags()) {
|
||||
StringBuilder dataStringBuilder = new StringBuilder();
|
||||
Map.Entry<Map<StateValue, Object>, String> dataEntry = cache.computeIfAbsent(dataContent, (key) -> {
|
||||
StringBuilder dataStringBuilder = new StringBuilder();
|
||||
Map<StateValue, Object> dataMap = new HashMap<>(key.size());
|
||||
|
||||
Map<StateValue, Object> dataMap = new HashMap<>(dataContent.size());
|
||||
for (Map.Entry<String, NBT> props : key.getTags().entrySet()) {
|
||||
StateValue state = StateValue.byName(props.getKey());
|
||||
if (state == null) {
|
||||
PacketEvents.getAPI().getLogger().warning("Could not find value for " + props.getKey());
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, NBT> props : dataContent.getTags().entrySet()) {
|
||||
StateValue state = StateValue.byName(props.getKey());
|
||||
if (state == null) {
|
||||
PacketEvents.getAPI().getLogger().warning("Could not find value for " + props.getKey());
|
||||
continue;
|
||||
dataStringBuilder.append(props.getKey()).append("=");
|
||||
NBT value = props.getValue();
|
||||
Object v;
|
||||
if (value instanceof NBTByte) {
|
||||
v = ((NBTByte) value).getAsInt() == 1;
|
||||
} else if (value instanceof NBTNumber) {
|
||||
v = ((NBTNumber) value).getAsInt();
|
||||
} else if (value instanceof NBTString) {
|
||||
v = ((NBTString) value).getValue();
|
||||
} else {
|
||||
PacketEvents.getAPI().getLogger().warning("Unknown NBT typeString in modern mapping: " + value.getClass().getSimpleName());
|
||||
dataStringBuilder = new StringBuilder(dataStringBuilder.substring(0, dataStringBuilder.length() - props.getKey().length() - 1));
|
||||
continue;
|
||||
}
|
||||
|
||||
dataStringBuilder.append(v).append(",");
|
||||
dataMap.put(state, state.getParser().apply(v.toString().toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
|
||||
dataStringBuilder.append(props.getKey()).append("=");
|
||||
NBT value = props.getValue();
|
||||
Object v;
|
||||
if (value instanceof NBTByte) {
|
||||
v = ((NBTByte) value).getAsInt() == 1;
|
||||
} else if (value instanceof NBTNumber) {
|
||||
v = ((NBTNumber) value).getAsInt();
|
||||
} else if (value instanceof NBTString) {
|
||||
v = ((NBTString) value).getValue();
|
||||
String dataString;
|
||||
if (dataStringBuilder.length() == 0) {
|
||||
dataString = "";
|
||||
} else {
|
||||
PacketEvents.getAPI().getLogger().warning("Unknown NBT typeString in modern mapping: " + value.getClass().getSimpleName());
|
||||
dataStringBuilder = new StringBuilder(dataStringBuilder.substring(0, dataStringBuilder.length() - props.getKey().length() - 1));
|
||||
continue;
|
||||
dataString = "[" + dataStringBuilder.substring(0, dataStringBuilder.length() - 1) + "]";
|
||||
}
|
||||
|
||||
dataStringBuilder.append(v).append(",");
|
||||
dataMap.put(state, state.getParser().apply(v.toString().toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
return new AbstractMap.SimpleEntry<>(dataMap, dataString);
|
||||
});
|
||||
|
||||
String dataString;
|
||||
if (dataStringBuilder.length() == 0) {
|
||||
dataString = "";
|
||||
} else {
|
||||
dataString = "[" + dataStringBuilder.substring(0, dataStringBuilder.length() - 1) + "]";
|
||||
}
|
||||
String fullString = typeString + dataString;
|
||||
|
||||
WrappedBlockState state = new WrappedBlockState(type, dataMap, id, mappingIndex);
|
||||
String fullString = typeString + dataEntry.getValue();
|
||||
WrappedBlockState state = new WrappedBlockState(type, dataEntry.getKey(), id, mappingIndex);
|
||||
|
||||
if (defaultIdx == index) {
|
||||
stateTypeToBlockStateMap.put(type, state);
|
||||
@@ -363,7 +383,7 @@ public class WrappedBlockState {
|
||||
|
||||
@Override
|
||||
public WrappedBlockState clone() {
|
||||
return new WrappedBlockState(type, new HashMap<>(data), globalID, mappingsIndex);
|
||||
return new WrappedBlockState(type, data, globalID, mappingsIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -426,7 +426,7 @@ public class BlockTags {
|
||||
BlockTags.SCULK_REPLACEABLE_WORLD_GEN.addTag(BlockTags.SCULK_REPLACEABLE).add(StateTypes.DEEPSLATE_BRICKS, StateTypes.DEEPSLATE_TILES, StateTypes.COBBLED_DEEPSLATE, StateTypes.CRACKED_DEEPSLATE_BRICKS, StateTypes.CRACKED_DEEPSLATE_TILES, StateTypes.POLISHED_DEEPSLATE);
|
||||
BlockTags.COMPLETES_FIND_TREE_TUTORIAL.addTag(BlockTags.LOGS).addTag(BlockTags.LEAVES).addTag(BlockTags.WART_BLOCKS);
|
||||
BlockTags.MINEABLE_AXE.addTag(BlockTags.BANNERS).addTag(BlockTags.FENCE_GATES).addTag(BlockTags.LOGS).addTag(BlockTags.PLANKS).addTag(BlockTags.SAPLINGS).addTag(BlockTags.SIGNS).addTag(BlockTags.WOODEN_BUTTONS).addTag(BlockTags.WOODEN_DOORS).addTag(BlockTags.WOODEN_FENCES).addTag(BlockTags.WOODEN_PRESSURE_PLATES).addTag(BlockTags.WOODEN_SLABS).addTag(BlockTags.WOODEN_STAIRS).addTag(BlockTags.WOODEN_TRAPDOORS).addTag(BlockTags.ALL_HANGING_SIGNS).addTag(BlockTags.BAMBOO_BLOCKS).add(StateTypes.NOTE_BLOCK, StateTypes.ATTACHED_MELON_STEM, StateTypes.ATTACHED_PUMPKIN_STEM, StateTypes.AZALEA, StateTypes.BAMBOO, StateTypes.BARREL, StateTypes.BEE_NEST, StateTypes.BEEHIVE, StateTypes.BEETROOTS, StateTypes.BIG_DRIPLEAF_STEM, StateTypes.BIG_DRIPLEAF, StateTypes.BOOKSHELF, StateTypes.BROWN_MUSHROOM_BLOCK, StateTypes.BROWN_MUSHROOM, StateTypes.CAMPFIRE, StateTypes.CARROTS, StateTypes.CARTOGRAPHY_TABLE, StateTypes.CARVED_PUMPKIN, StateTypes.CAVE_VINES_PLANT, StateTypes.CAVE_VINES, StateTypes.CHEST, StateTypes.CHORUS_FLOWER, StateTypes.CHORUS_PLANT, StateTypes.COCOA, StateTypes.COMPOSTER, StateTypes.CRAFTING_TABLE, StateTypes.CRIMSON_FUNGUS, StateTypes.DAYLIGHT_DETECTOR, StateTypes.DEAD_BUSH, StateTypes.FERN, StateTypes.FLETCHING_TABLE, StateTypes.GLOW_LICHEN, StateTypes.SHORT_GRASS, StateTypes.HANGING_ROOTS, StateTypes.JACK_O_LANTERN, StateTypes.JUKEBOX, StateTypes.LADDER, StateTypes.LARGE_FERN, StateTypes.LECTERN, StateTypes.LILY_PAD, StateTypes.LOOM, StateTypes.MELON_STEM, StateTypes.MELON, StateTypes.MUSHROOM_STEM, StateTypes.NETHER_WART, StateTypes.POTATOES, StateTypes.PUMPKIN_STEM, StateTypes.PUMPKIN, StateTypes.RED_MUSHROOM_BLOCK, StateTypes.RED_MUSHROOM, StateTypes.SCAFFOLDING, StateTypes.SMALL_DRIPLEAF, StateTypes.SMITHING_TABLE, StateTypes.SOUL_CAMPFIRE, StateTypes.SPORE_BLOSSOM, StateTypes.SUGAR_CANE, StateTypes.SWEET_BERRY_BUSH, StateTypes.TALL_GRASS, StateTypes.TRAPPED_CHEST, StateTypes.TWISTING_VINES_PLANT, StateTypes.TWISTING_VINES, StateTypes.VINE, StateTypes.WARPED_FUNGUS, StateTypes.WEEPING_VINES_PLANT, StateTypes.WEEPING_VINES, StateTypes.WHEAT, StateTypes.MANGROVE_ROOTS, StateTypes.BAMBOO_MOSAIC, StateTypes.BAMBOO_MOSAIC_SLAB, StateTypes.BAMBOO_MOSAIC_STAIRS, StateTypes.CHISELED_BOOKSHELF);
|
||||
BlockTags.LAVA_POOL_STONE_CANNOT_REPLACE.addTag(BlockTags.FEATURES_CANNOT_REPLACE).addTag(BlockTags.LEAVES).addTag(BlockTags.LOGS).addTag(BlockTags.FEATURES_CANNOT_REPLACE);
|
||||
BlockTags.LAVA_POOL_STONE_CANNOT_REPLACE.addTag(BlockTags.FEATURES_CANNOT_REPLACE).addTag(BlockTags.LEAVES).addTag(BlockTags.LOGS);
|
||||
BlockTags.PARROTS_SPAWNABLE_ON.addTag(BlockTags.LEAVES).addTag(BlockTags.LOGS).add(StateTypes.GRASS_BLOCK, StateTypes.AIR);
|
||||
// Legacy/Unofficial, I don't know
|
||||
BlockTags.AZALEA_GROWS_ON.addTag(BlockTags.DIRT).addTag(BlockTags.SAND).addTag(BlockTags.TERRACOTTA).add(StateTypes.SNOW_BLOCK, StateTypes.POWDER_SNOW);
|
||||
|
||||
+4
-4
@@ -193,7 +193,7 @@ public class ItemTags {
|
||||
copy(BlockTags.WOODEN_BUTTONS, ItemTags.WOODEN_BUTTONS);
|
||||
copy(BlockTags.STONE_BUTTONS, ItemTags.STONE_BUTTONS);
|
||||
copy(BlockTags.WOOL_CARPETS, ItemTags.WOOL_CARPETS);
|
||||
ItemTags.WOODEN_DOORS.add(ItemTypes.OAK_DOOR, ItemTypes.SPRUCE_DOOR, ItemTypes.BIRCH_DOOR, ItemTypes.JUNGLE_DOOR, ItemTypes.ACACIA_DOOR, ItemTypes.DARK_OAK_DOOR, ItemTypes.CRIMSON_DOOR, ItemTypes.WARPED_DOOR, ItemTypes.MANGROVE_DOOR, ItemTypes.BAMBOO_DOOR, ItemTypes.CHERRY_DOOR);
|
||||
copy(BlockTags.WOODEN_DOORS, ItemTags.WOODEN_DOORS);
|
||||
copy(BlockTags.WOODEN_STAIRS, ItemTags.WOODEN_STAIRS);
|
||||
copy(BlockTags.WOODEN_SLABS, ItemTags.WOODEN_SLABS);
|
||||
copy(BlockTags.WOODEN_FENCES, ItemTags.WOODEN_FENCES);
|
||||
@@ -313,10 +313,10 @@ public class ItemTags {
|
||||
ItemTags.WOLF_FOOD.addTag(ItemTags.MEAT);
|
||||
ItemTags.STRIDER_TEMPT_ITEMS.addTag(ItemTags.STRIDER_FOOD).add(ItemTypes.WARPED_FUNGUS_ON_A_STICK);
|
||||
ItemTags.BOATS.addTag(ItemTags.CHEST_BOATS).add(ItemTypes.OAK_BOAT, ItemTypes.SPRUCE_BOAT, ItemTypes.BIRCH_BOAT, ItemTypes.JUNGLE_BOAT, ItemTypes.ACACIA_BOAT, ItemTypes.DARK_OAK_BOAT, ItemTypes.MANGROVE_BOAT, ItemTypes.BAMBOO_RAFT, ItemTypes.CHERRY_BOAT);
|
||||
ItemTags.MUSIC_DISCS.addTag(ItemTags.CREEPER_DROP_MUSIC_DISCS).add(ItemTypes.MUSIC_DISC_PIGSTEP, ItemTypes.MUSIC_DISC_OTHERSIDE, ItemTypes.MUSIC_DISC_5, ItemTypes.MUSIC_DISC_RELIC);
|
||||
ItemTags.MUSIC_DISCS.addTag(ItemTags.CREEPER_DROP_MUSIC_DISCS).add(ItemTypes.MUSIC_DISC_PIGSTEP, ItemTypes.MUSIC_DISC_OTHERSIDE, ItemTypes.MUSIC_DISC_5, ItemTypes.MUSIC_DISC_RELIC, ItemTypes.MUSIC_DISC_CREATOR, ItemTypes.MUSIC_DISC_CREATOR_MUSIC_BOX, ItemTypes.MUSIC_DISC_PRECIPICE);
|
||||
copy(BlockTags.DAMPENS_VIBRATIONS, ItemTags.DAMPENS_VIBRATIONS);
|
||||
ItemTags.TRIMMABLE_ARMOR.addTag(ItemTags.FOOT_ARMOR).addTag(ItemTags.LEG_ARMOR).addTag(ItemTags.CHEST_ARMOR).addTag(ItemTags.HEAD_ARMOR);
|
||||
ItemTags.DECORATED_POT_INGREDIENTS.addTag(ItemTags.DECORATED_POT_SHERDS).add(ItemTypes.BRICK, ItemTypes.FLOW_POTTERY_SHERD, ItemTypes.GUSTER_POTTERY_SHERD, ItemTypes.SCRAPE_POTTERY_SHERD);
|
||||
ItemTags.DECORATED_POT_INGREDIENTS.addTag(ItemTags.DECORATED_POT_SHERDS).add(ItemTypes.BRICK);
|
||||
ItemTags.BREAKS_DECORATED_POTS.addTag(ItemTags.SWORDS).addTag(ItemTags.AXES).addTag(ItemTags.PICKAXES).addTag(ItemTags.SHOVELS).addTag(ItemTags.HOES).add(ItemTypes.TRIDENT, ItemTypes.MACE);
|
||||
ItemTags.ENCHANTABLE_FOOT_ARMOR.addTag(ItemTags.FOOT_ARMOR);
|
||||
ItemTags.ENCHANTABLE_LEG_ARMOR.addTag(ItemTags.LEG_ARMOR);
|
||||
@@ -333,7 +333,7 @@ public class ItemTags {
|
||||
ItemTags.ENCHANTABLE_ARMOR.addTag(ItemTags.ENCHANTABLE_FOOT_ARMOR).addTag(ItemTags.ENCHANTABLE_LEG_ARMOR).addTag(ItemTags.ENCHANTABLE_CHEST_ARMOR).addTag(ItemTags.ENCHANTABLE_HEAD_ARMOR);
|
||||
ItemTags.ENCHANTABLE_FIRE_ASPECT.addTag(ItemTags.ENCHANTABLE_SWORD).add(ItemTypes.MACE);
|
||||
ItemTags.ENCHANTABLE_WEAPON.addTag(ItemTags.ENCHANTABLE_SHARP_WEAPON).add(ItemTypes.MACE);
|
||||
ItemTags.ENCHANTABLE_VANISHING.addTag(ItemTags.ENCHANTABLE_DURABILITY).addTag(ItemTags.SKULLS).add(ItemTypes.COMPASS, ItemTypes.CARVED_PUMPKIN, ItemTypes.MACE);
|
||||
ItemTags.ENCHANTABLE_VANISHING.addTag(ItemTags.ENCHANTABLE_DURABILITY).addTag(ItemTags.SKULLS).add(ItemTypes.COMPASS, ItemTypes.CARVED_PUMPKIN);
|
||||
copy(BlockTags.COMPLETES_FIND_TREE_TUTORIAL, ItemTags.COMPLETES_FIND_TREE_TUTORIAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
package com.github.retrooper.packetevents.resources;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ResourceLocation {
|
||||
protected final String namespace;
|
||||
protected final String key;
|
||||
@@ -48,6 +50,11 @@ public class ResourceLocation {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.namespace, this.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof ResourceLocation) {
|
||||
|
||||
+7
-4
@@ -35,7 +35,6 @@ public class PacketEventsSettings {
|
||||
private boolean defaultReencode = true; // true for backwards compat and more idiot-proof
|
||||
private boolean checkForUpdates = true;
|
||||
private boolean downsampleColors = false;
|
||||
private boolean bStatsEnabled = true;
|
||||
private boolean debugEnabled = false;
|
||||
private boolean fullStackTraceEnabled = false;
|
||||
private boolean kickOnPacketExceptionEnabled = true;
|
||||
@@ -98,9 +97,10 @@ public class PacketEventsSettings {
|
||||
*
|
||||
* @param bStatsEnabled Value
|
||||
* @return Settings instance.
|
||||
* @deprecated This method has been deprecated. To disable bStats use the config file found in the bStats folder.
|
||||
*/
|
||||
@Deprecated()
|
||||
public PacketEventsSettings bStats(boolean bStatsEnabled) {
|
||||
this.bStatsEnabled = bStatsEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -179,10 +179,13 @@ public class PacketEventsSettings {
|
||||
/**
|
||||
* Should we collect server data anonymously and report to bStats?
|
||||
*
|
||||
* @return Getter for {@link #bStatsEnabled}
|
||||
* @return Getter for bStatsEnabled
|
||||
* @deprecated This method has been deprecated, because the setter has been removed.
|
||||
* Disabling bStats is now done through the bStats config file.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isbStatsEnabled() {
|
||||
return bStatsEnabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
@@ -18,142 +18,223 @@
|
||||
|
||||
package com.github.retrooper.packetevents.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* PacketEvents version.
|
||||
* This class represents a PacketEvents version.
|
||||
*
|
||||
* @author retrooper
|
||||
* @since 1.8
|
||||
* Represents a PacketEvents version using Semantic Versioning.
|
||||
* Supports version comparison, cloning, and provides a string representation.
|
||||
* Snapshots will always resolve to a newer version than the non-snapshot version if major, minor, and patch are the same.
|
||||
*/
|
||||
public class PEVersion {
|
||||
/**
|
||||
* Array containing the digits in the version.
|
||||
* For example, "1.8.9" will be stored as {1, 8, 9} in an array.
|
||||
*/
|
||||
private final int[] versionIntArray;
|
||||
public class PEVersion implements Comparable<PEVersion> {
|
||||
|
||||
private final int major;
|
||||
private final int minor;
|
||||
private final int patch;
|
||||
private final boolean snapshot;
|
||||
|
||||
/**
|
||||
* Specify your version using an array.
|
||||
* Constructs a {@link PEVersion} instance.
|
||||
*
|
||||
* @param version Array version.
|
||||
* @param major the major version number.
|
||||
* @param minor the minor version number.
|
||||
* @param patch the patch version number.
|
||||
* @param snapshot whether the version is a snapshot.
|
||||
*/
|
||||
public PEVersion(final int major, final int minor, final int patch, final boolean snapshot) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.patch = patch;
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link PEVersion} instance with snapshot defaulted to false.
|
||||
*
|
||||
* @param major the major version number.
|
||||
* @param minor the minor version number.
|
||||
* @param patch the patch version number.
|
||||
*/
|
||||
public PEVersion(final int major, final int minor, final int patch) {
|
||||
this(major, minor, patch, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link PEVersion} instance from an array of version numbers.
|
||||
*
|
||||
* @param version the version numbers (e.g., {1, 8, 9}).
|
||||
* @deprecated use {@link #PEVersion(int, int, int)} or {@link #PEVersion(int, int, int, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public PEVersion(final int... version) {
|
||||
this.versionIntArray = version;
|
||||
this(version[0], version[1], version[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify your version using a string, for example: "1.8.9".
|
||||
* Constructs a {@link PEVersion} instance from a version string.
|
||||
*
|
||||
* @param version String version.
|
||||
* @param version the version string (e.g., "1.8.9-SNAPSHOT").
|
||||
* @throws IllegalArgumentException if the version string format is incorrect.
|
||||
* @deprecated use {@link #fromString(String)} instead.
|
||||
*/
|
||||
public PEVersion(final String version) {
|
||||
String[] versionIntegers = version.split("\\.");
|
||||
int length = versionIntegers.length;
|
||||
this.versionIntArray = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
versionIntArray[i] = Integer.parseInt(versionIntegers[i]);
|
||||
@Deprecated
|
||||
public PEVersion(@NotNull final String version) {
|
||||
String versionWithoutSnapshot = version.replace("-SNAPSHOT", "");
|
||||
String[] parts = versionWithoutSnapshot.split("\\.");
|
||||
|
||||
if (parts.length < 2 || parts.length > 3) {
|
||||
throw new IllegalArgumentException("Version string must be in the format 'major.minor[.patch][-SNAPSHOT]' found '" + version + "' instead.");
|
||||
}
|
||||
|
||||
this.major = Integer.parseInt(parts[0]);
|
||||
this.minor = Integer.parseInt(parts[1]);
|
||||
this.patch = parts.length > 2 ? Integer.parseInt(parts[2]) : 0;
|
||||
this.snapshot = version.contains("-SNAPSHOT");
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare to another PEVersion.
|
||||
* If we are newer than the compared version,
|
||||
* this method will return 1.
|
||||
* If we are older than the compared version,
|
||||
* this method will return -1.
|
||||
* If we are equal to the compared version,
|
||||
* this method will return 0.
|
||||
* Similar to {@link Integer#compareTo(Integer)}.
|
||||
* Constructs a {@link PEVersion} instance from a version string.
|
||||
*
|
||||
* @param version Compared version
|
||||
* @return Comparing to another Version.
|
||||
* @param version the version string (e.g., "1.8.9-SNAPSHOT").
|
||||
* @throws IllegalArgumentException if the version string format is incorrect.
|
||||
*/
|
||||
public int compareTo(PEVersion version) {
|
||||
int localLength = versionIntArray.length;
|
||||
int oppositeLength = version.versionIntArray.length;
|
||||
int length = Math.max(localLength, oppositeLength);
|
||||
for (int i = 0; i < length; i++) {
|
||||
int localInteger = i < localLength ? versionIntArray[i] : 0;
|
||||
int oppositeInteger = i < oppositeLength ? version.versionIntArray[i] : 0;
|
||||
if (localInteger > oppositeInteger) {
|
||||
return 1;
|
||||
} else if (localInteger < oppositeInteger) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
public static PEVersion fromString(@NotNull final String version) {
|
||||
return new PEVersion(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the {@link #compareTo(PEVersion)} return 1?
|
||||
* Gets the major version number.
|
||||
*
|
||||
* @param version Compared version.
|
||||
* @return Is this newer than the compared version.
|
||||
* @return the major version number.
|
||||
*/
|
||||
public boolean isNewerThan(PEVersion version) {
|
||||
return compareTo(version) == 1;
|
||||
public int major() {
|
||||
return major;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the {@link #compareTo(PEVersion)} return -1?
|
||||
* Gets the minor version number.
|
||||
*
|
||||
* @param version Compared version.
|
||||
* @return Is this older than the compared version.
|
||||
* @return the minor version number.
|
||||
*/
|
||||
public boolean isOlderThan(PEVersion version) {
|
||||
return compareTo(version) == -1;
|
||||
public int minor() {
|
||||
return minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represented as an array.
|
||||
* Gets the patch version number.
|
||||
*
|
||||
* @return Array version.
|
||||
* @return the patch version number.
|
||||
*/
|
||||
public int[] asArray() {
|
||||
return versionIntArray;
|
||||
public int patch() {
|
||||
return patch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this version equal to the compared object.
|
||||
* The object must be a PEVersion and the array values must be equal.
|
||||
* Checks if the version is a snapshot.
|
||||
*
|
||||
* @param obj Compared object.
|
||||
* @return Are they equal?
|
||||
* @return true if snapshot, false otherwise.
|
||||
*/
|
||||
public boolean snapshot() {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@link PEVersion} with another {@link PEVersion}.
|
||||
*
|
||||
* @param other the other {@link PEVersion}.
|
||||
* @return a negative integer, zero, or a positive integer as this version is less than,
|
||||
* equal to, or greater than the specified version.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj instanceof PEVersion) {
|
||||
return Arrays.equals(versionIntArray, ((PEVersion) obj).versionIntArray);
|
||||
}
|
||||
return false;
|
||||
public int compareTo(@NotNull final PEVersion other) {
|
||||
int majorCompare = Integer.compare(this.major, other.major);
|
||||
if (majorCompare != 0) return majorCompare;
|
||||
|
||||
int minorCompare = Integer.compare(this.minor, other.minor);
|
||||
if (minorCompare != 0) return minorCompare;
|
||||
|
||||
int patchCompare = Integer.compare(this.patch, other.patch);
|
||||
if (patchCompare != 0) return patchCompare;
|
||||
|
||||
return Boolean.compare(other.snapshot, this.snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the PEVersion.
|
||||
* Checks if the provided object is equal to this {@link PEVersion}.
|
||||
*
|
||||
* @return A clone.
|
||||
* @param obj the object to compare.
|
||||
* @return true if the provided object is equal to this {@link PEVersion}, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@NotNull final Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof PEVersion)) return false;
|
||||
PEVersion other = (PEVersion) obj;
|
||||
|
||||
return this.major == other.major &&
|
||||
this.minor == other.minor &&
|
||||
this.patch == other.patch &&
|
||||
this.snapshot == other.snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this version is newer than the provided version.
|
||||
*
|
||||
* @param otherVersion the other {@link PEVersion}.
|
||||
* @return true if this version is newer, false otherwise.
|
||||
*/
|
||||
public boolean isNewerThan(@NotNull final PEVersion otherVersion) {
|
||||
return this.compareTo(otherVersion) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this version is older than the provided version.
|
||||
*
|
||||
* @param otherVersion the other {@link PEVersion}.
|
||||
* @return true if this version is older, false otherwise.
|
||||
*/
|
||||
public boolean isOlderThan(@NotNull final PEVersion otherVersion) {
|
||||
return this.compareTo(otherVersion) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code value for this {@link PEVersion}.
|
||||
*
|
||||
* @return a hash code value.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(major, minor, patch, snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a copy of this {@link PEVersion}.
|
||||
*
|
||||
* @return a clone of this instance.
|
||||
*/
|
||||
@Override
|
||||
public PEVersion clone() {
|
||||
return new PEVersion(versionIntArray);
|
||||
return new PEVersion(major, minor, patch, snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent the version as a string.
|
||||
* Converts the {@link PEVersion} to a string representation.
|
||||
*
|
||||
* @return String representation.
|
||||
* @return a string representation of the version.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(versionIntArray.length * 2 - 1).append(versionIntArray[0]);
|
||||
for (int i = 1; i < versionIntArray.length; i++) {
|
||||
sb.append(".").append(versionIntArray[i]);
|
||||
}
|
||||
return sb.toString();
|
||||
return major + "." + minor + "." + patch + (snapshot ? "-SNAPSHOT" : "");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the {@link PEVersion} to an array of version numbers.
|
||||
*
|
||||
* @return an array of version numbers.
|
||||
*/
|
||||
@Deprecated
|
||||
public int[] asArray() {
|
||||
return new int[]{major, minor, patch};
|
||||
}
|
||||
}
|
||||
+7
-3
@@ -24,6 +24,7 @@ import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.event.UserDisconnectEvent;
|
||||
import com.github.retrooper.packetevents.manager.protocol.ProtocolManager;
|
||||
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
|
||||
import com.github.retrooper.packetevents.netty.buffer.UnpooledByteBufAllocationHelper;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -70,7 +71,7 @@ public class PacketEventsImplHelper {
|
||||
return packetSendEvent;
|
||||
}
|
||||
|
||||
public static PacketReceiveEvent handleServerBoundPacket(Object channel, User user,
|
||||
public static Object handleServerBoundPacket(Object channel, User user,
|
||||
Object player,
|
||||
Object buffer,
|
||||
boolean autoProtocolTranslation) throws Exception {
|
||||
@@ -79,14 +80,17 @@ public class PacketEventsImplHelper {
|
||||
int preProcessIndex = ByteBufHelper.readerIndex(buffer);
|
||||
PacketReceiveEvent packetReceiveEvent = EventCreationUtil.createReceiveEvent(channel, user, player, buffer, autoProtocolTranslation);
|
||||
int processIndex = ByteBufHelper.readerIndex(buffer);
|
||||
Object finalBuffer = buffer;
|
||||
PacketEvents.getAPI().getEventManager().callEvent(packetReceiveEvent, () -> {
|
||||
ByteBufHelper.readerIndex(buffer, processIndex);
|
||||
ByteBufHelper.readerIndex(finalBuffer, processIndex);
|
||||
});
|
||||
if (!packetReceiveEvent.isCancelled()) {
|
||||
//Did they ever use a wrapper?
|
||||
if (packetReceiveEvent.getLastUsedWrapper() != null) {
|
||||
//Rewrite the buffer
|
||||
ByteBufHelper.clear(buffer);
|
||||
buffer = UnpooledByteBufAllocationHelper.buffer();
|
||||
packetReceiveEvent.getLastUsedWrapper().setBuffer(buffer);
|
||||
packetReceiveEvent.getLastUsedWrapper().writeVarInt(packetReceiveEvent.getPacketId());
|
||||
packetReceiveEvent.getLastUsedWrapper().write();
|
||||
} else {
|
||||
@@ -103,7 +107,7 @@ public class PacketEventsImplHelper {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
return packetReceiveEvent;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static void handleDisconnection(Object channel, @Nullable UUID uuid) {
|
||||
|
||||
+20
@@ -21,9 +21,12 @@ package com.github.retrooper.packetevents.util;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
|
||||
import com.github.retrooper.packetevents.protocol.player.Equipment;
|
||||
import com.github.retrooper.packetevents.protocol.world.chunk.LightData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChunkData;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateLight;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -51,6 +54,23 @@ public class PacketTransformationUtil {
|
||||
Equipment equipment = entityEquipment.getEquipment().get(i);
|
||||
output[i] = new WrapperPlayServerEntityEquipment(entityEquipment.getEntityId(), Collections.singletonList(equipment));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
} else if (wrapper instanceof WrapperPlayServerChunkData) {
|
||||
WrapperPlayServerChunkData chunkData = (WrapperPlayServerChunkData) wrapper;
|
||||
LightData lightData = chunkData.getLightData();
|
||||
|
||||
if (chunkData.getServerVersion().isOlderThan(ServerVersion.V_1_18) && lightData != null) {
|
||||
//Transform into chunk data & light data packets
|
||||
PacketWrapper<?>[] output = new PacketWrapper[2];
|
||||
output[0] = new WrapperPlayServerUpdateLight(
|
||||
chunkData.getColumn().getX(),
|
||||
chunkData.getColumn().getZ(),
|
||||
lightData
|
||||
);
|
||||
// Light packet must be sent first
|
||||
output[1] = chunkData;
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
+162
-13
@@ -18,21 +18,55 @@
|
||||
|
||||
package com.github.retrooper.packetevents.util.adventure;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.*;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTByte;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTByteArray;
|
||||
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.NBTIntArray;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTLong;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTLongArray;
|
||||
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 net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.kyori.adventure.text.*;
|
||||
import net.kyori.adventure.text.BlockNBTComponent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentBuilder;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
import net.kyori.adventure.text.EntityNBTComponent;
|
||||
import net.kyori.adventure.text.KeybindComponent;
|
||||
import net.kyori.adventure.text.NBTComponent;
|
||||
import net.kyori.adventure.text.ScoreComponent;
|
||||
import net.kyori.adventure.text.SelectorComponent;
|
||||
import net.kyori.adventure.text.StorageNBTComponent;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.TranslationArgument;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.DataComponentValue;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.ComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.gson.BackwardCompatUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -79,7 +113,39 @@ public class AdventureNBTSerializer implements ComponentSerializer<Component, Co
|
||||
|
||||
String translate = reader.readUTF("translate", Function.identity());
|
||||
String translateFallback = reader.readUTF("fallback", Function.identity());
|
||||
List<Component> translateWith = reader.readList("with", this::deserializeComponentList);
|
||||
List<? extends ComponentLike> translateWith;
|
||||
if (BackwardCompatUtil.IS_4_15_0_OR_NEWER) {
|
||||
NBTType<?> type = reader.type("with");
|
||||
if (type == NBTType.INT_ARRAY) {
|
||||
translateWith = reader.readIntArray("with", params -> {
|
||||
List<TranslationArgument> args = new ArrayList<>(params.length);
|
||||
for (int param : params) {
|
||||
args.add(TranslationArgument.numeric(param));
|
||||
}
|
||||
return args;
|
||||
});
|
||||
} else if (type == NBTType.BYTE_ARRAY) {
|
||||
translateWith = reader.readByteArray("with", params -> {
|
||||
List<TranslationArgument> args = new ArrayList<>(params.length);
|
||||
for (byte param : params) {
|
||||
args.add(TranslationArgument.bool(param != (byte) 0));
|
||||
}
|
||||
return args;
|
||||
});
|
||||
} else if (type == NBTType.LONG_ARRAY) {
|
||||
translateWith = reader.readLongArray("with", params -> {
|
||||
List<TranslationArgument> args = new ArrayList<>(params.length);
|
||||
for (long param : params) {
|
||||
args.add(TranslationArgument.numeric(param));
|
||||
}
|
||||
return args;
|
||||
});
|
||||
} else {
|
||||
translateWith = reader.readList("with", this::deserializeTranslationArgumentList);
|
||||
}
|
||||
} else {
|
||||
translateWith = reader.readList("with", this::deserializeComponentList);
|
||||
}
|
||||
NBTReader score = reader.child("score");
|
||||
String selector = reader.readUTF("selector", Function.identity());
|
||||
String keybind = reader.readUTF("keybind", Function.identity());
|
||||
@@ -98,7 +164,11 @@ public class AdventureNBTSerializer implements ComponentSerializer<Component, Co
|
||||
builder = Component.text().content(text);
|
||||
} else if (translate != null) {
|
||||
if (translateWith != null) {
|
||||
builder = Component.translatable().key(translate).fallback(translateFallback).arguments(translateWith);
|
||||
if (BackwardCompatUtil.IS_4_15_0_OR_NEWER) {
|
||||
builder = Component.translatable().key(translate).fallback(translateFallback).arguments(translateWith);
|
||||
} else {
|
||||
builder = Component.translatable().key(translate).fallback(translateFallback).args(translateWith);
|
||||
}
|
||||
} else {
|
||||
builder = Component.translatable().key(translate).fallback(translateFallback);
|
||||
}
|
||||
@@ -168,7 +238,11 @@ public class AdventureNBTSerializer implements ComponentSerializer<Component, Co
|
||||
// translation arguments
|
||||
List<Component> args = ((TranslatableComponent) component).args();
|
||||
if (!args.isEmpty()) {
|
||||
writer.writeList("with", NBTType.COMPOUND, serializeComponentList(args));
|
||||
if (BackwardCompatUtil.IS_4_15_0_OR_NEWER) {
|
||||
writer.writeList("with", NBTType.COMPOUND, serializeTranslationArgumentList(((TranslatableComponent) component).arguments()));
|
||||
} else {
|
||||
writer.writeList("with", NBTType.COMPOUND, serializeComponentList(args));
|
||||
}
|
||||
}
|
||||
} else if (component instanceof ScoreComponent) {
|
||||
// nested compound
|
||||
@@ -271,11 +345,30 @@ public class AdventureNBTSerializer implements ComponentSerializer<Component, Co
|
||||
style.hoverEvent(HoverEvent.showItem(hoverEvent.readUTF("contents", Key::key), 1));
|
||||
} else {
|
||||
NBTReader child = hoverEvent.child("contents");
|
||||
style.hoverEvent(HoverEvent.showItem(
|
||||
child.readUTF("id", Key::key),
|
||||
child.readInt("count", Function.identity()),
|
||||
child.readUTF("tag", BinaryTagHolder::binaryTagHolder)
|
||||
));
|
||||
Key itemId = child.readUTF("id", Key::key);
|
||||
Integer count = child.readInt("count", Function.identity());
|
||||
int nonNullCount = count == null ? 1 : count;
|
||||
|
||||
BinaryTagHolder tag = child.readUTF("tag", BinaryTagHolder::binaryTagHolder);
|
||||
if (tag != null || !BackwardCompatUtil.IS_4_17_0_OR_NEWER) {
|
||||
style.hoverEvent(HoverEvent.showItem(itemId, nonNullCount, tag));
|
||||
} else {
|
||||
Map<Key, DataComponentValue> components = child.readCompound("components", nbt -> {
|
||||
Map<Key, DataComponentValue> map = new HashMap<>(nbt.size());
|
||||
for (Map.Entry<String, NBT> entry : nbt.getTags().entrySet()) {
|
||||
if (entry.getKey().startsWith("!")) { // removed component
|
||||
Key key = Key.key(entry.getKey().substring(1));
|
||||
map.put(key, DataComponentValue.removed());
|
||||
continue;
|
||||
}
|
||||
Key key = Key.key(entry.getKey());
|
||||
map.put(key, new NbtComponentValue(entry.getValue()));
|
||||
}
|
||||
return map;
|
||||
});
|
||||
style.hoverEvent(HoverEvent.showItem(itemId, nonNullCount,
|
||||
components == null ? Collections.emptyMap() : components));
|
||||
}
|
||||
}
|
||||
} else if (action.equals(HoverEvent.Action.SHOW_ENTITY)) {
|
||||
NBTReader child = hoverEvent.child("contents");
|
||||
@@ -332,14 +425,32 @@ public class AdventureNBTSerializer implements ComponentSerializer<Component, Co
|
||||
Key itemId = item.item();
|
||||
int count = item.count();
|
||||
BinaryTagHolder nbt = item.nbt();
|
||||
boolean emptyComps = !BackwardCompatUtil.IS_4_17_0_OR_NEWER || item.dataComponents().isEmpty();
|
||||
|
||||
if (count == 1 && nbt == null) {
|
||||
if (count == 1 && nbt == null && emptyComps) {
|
||||
child.writeUTF("contents", itemId.asString());
|
||||
} else {
|
||||
NBTWriter itemNBT = child.child("contents");
|
||||
itemNBT.writeUTF("id", itemId.asString());
|
||||
itemNBT.writeInt("count", count);
|
||||
if (nbt != null) itemNBT.writeUTF("tag", nbt.string());
|
||||
if (nbt != null) {
|
||||
itemNBT.writeUTF("tag", nbt.string());
|
||||
}
|
||||
if (!emptyComps) {
|
||||
NBTWriter compsNbt = itemNBT.child("components");
|
||||
for (Map.Entry<Key, DataComponentValue> entry : item.dataComponents().entrySet()) {
|
||||
if (entry.getValue() == DataComponentValue.removed()) {
|
||||
// I don't think value matters here
|
||||
compsNbt.writeCompound("!" + entry.getKey(), new NBTCompound());
|
||||
continue;
|
||||
}
|
||||
if (entry.getValue() instanceof NbtComponentValue) {
|
||||
NBT compNbt = ((NbtComponentValue) entry.getValue()).nbt;
|
||||
compsNbt.write(entry.getKey().toString(), compNbt);
|
||||
}
|
||||
// unsupported entry component value, skip for now
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -427,6 +538,35 @@ public class AdventureNBTSerializer implements ComponentSerializer<Component, Co
|
||||
}
|
||||
// -------------------------------------------------
|
||||
|
||||
// ------------ TranslationArgument List ------------
|
||||
private @NotNull List<TranslationArgument> deserializeTranslationArgumentList(List<?> value) {
|
||||
if (value.isEmpty()) return Collections.emptyList();
|
||||
|
||||
List<TranslationArgument> arguments = new ArrayList<>(value.size());
|
||||
for (Object nbt : value) {
|
||||
if (nbt instanceof NBTByte) {
|
||||
arguments.add(TranslationArgument.bool(((NBTByte) nbt).getAsByte() != (byte) 0));
|
||||
} else if (nbt instanceof NBTNumber) {
|
||||
arguments.add(TranslationArgument.numeric(((NBTNumber) nbt).getAsInt()));
|
||||
} else if (nbt instanceof NBTString) {
|
||||
arguments.add(TranslationArgument.component(Component.text(((NBTString) nbt).getValue())));
|
||||
} else {
|
||||
arguments.add(TranslationArgument.component(deserialize(requireType((NBT) nbt, NBTType.COMPOUND))));
|
||||
}
|
||||
}
|
||||
|
||||
return arguments;
|
||||
}
|
||||
|
||||
private List<NBTCompound> serializeTranslationArgumentList(List<TranslationArgument> value) {
|
||||
List<NBTCompound> arguments = new ArrayList<>(value.size());
|
||||
for (TranslationArgument argument : value) {
|
||||
arguments.add(serializeComponent(argument.asComponent()));
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
// -------------------------------------------------
|
||||
|
||||
static class NBTReader {
|
||||
private final NBTCompound compound;
|
||||
|
||||
@@ -644,4 +784,13 @@ public class AdventureNBTSerializer implements ComponentSerializer<Component, Co
|
||||
}
|
||||
return (T) nbt;
|
||||
}
|
||||
|
||||
private static final class NbtComponentValue implements DataComponentValue {
|
||||
|
||||
private final NBT nbt;
|
||||
|
||||
public NbtComponentValue(NBT nbt) {
|
||||
this.nbt = nbt;
|
||||
}
|
||||
}
|
||||
}
|
||||
-168
@@ -1,168 +0,0 @@
|
||||
package com.github.retrooper.packetevents.util.adventure;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.util.reflection.Reflection;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.BlockNBTComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.json.JSONOptions;
|
||||
import net.kyori.adventure.util.Index;
|
||||
import net.kyori.option.OptionState;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class AdventureReflectionUtil {
|
||||
|
||||
static boolean IS_LEGACY_ADVENTURE;
|
||||
static boolean IS_4_15_0_OR_NEWER = false;
|
||||
static TypeAdapter<Key> KEY_SERIALIZER_INSTANCE;
|
||||
static Function<Gson, Object> COMPONENT_SERIALIZER_CREATE;
|
||||
static TypeAdapter<ClickEvent.Action> CLICK_EVENT_ACTION_SERIALIZER_INSTANCE;
|
||||
static TypeAdapter<HoverEvent.Action<?>> HOVER_EVENT_ACTION_SERIALIZER_INSTANCE;
|
||||
static Function<Gson, Object> SHOW_ITEM_SERIALIZER_CREATE;
|
||||
static Function<Gson, Object> SHOW_ENTITY_SERIALIZER_CREATE;
|
||||
static TypeAdapter<TextColor> TEXT_COLOR_SERIALIZER_INSTANCE;
|
||||
static TypeAdapter<TextColor> TEXT_COLOR_SERIALIZER_DOWNSAMPLE_COLOR_INSTANCE;
|
||||
static TypeAdapter<TextDecoration> TEXT_DECORATION_SERIALIZER_INSTANCE;
|
||||
static TypeAdapter<BlockNBTComponent.Pos> BLOCK_NBT_POS_SERIALIZER_INSTANCE;
|
||||
static TypeAdapter<UUID> UUID_SERIALIZER_INSTANCE;
|
||||
static Function<Gson, Object> TRANSLATION_ARGUMENT_SERIALIZER_CREATE;
|
||||
|
||||
static {
|
||||
IS_LEGACY_ADVENTURE = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.SerializerFactory") == null;
|
||||
Class<?> KEY_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.KeySerializer");
|
||||
Field KEY_SERIALIZER_INSTANCE_FIELD = Reflection.getField(KEY_SERIALIZER, "INSTANCE");
|
||||
KEY_SERIALIZER_INSTANCE = (TypeAdapter<Key>) getSafe(KEY_SERIALIZER_INSTANCE_FIELD);
|
||||
|
||||
Class<?> COMPONENT_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.ComponentSerializerImpl");
|
||||
Class<?> SHOW_ITEM_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.ShowItemSerializer");
|
||||
Class<?> SHOW_ENTITY_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.ShowEntitySerializer");
|
||||
|
||||
if (IS_LEGACY_ADVENTURE) {
|
||||
Constructor<?> COMPONENT_SERIALIZER_CONSTRUCTOR = Reflection.getConstructor(COMPONENT_SERIALIZER, 0);
|
||||
COMPONENT_SERIALIZER_CREATE = gson -> invokeSafe(COMPONENT_SERIALIZER_CONSTRUCTOR);
|
||||
|
||||
Class<?> INDEXED_SERIALIZER_CLASS = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.IndexedSerializer");
|
||||
Method INDEXED_SERIALIZER_CREATE_METHOD = Reflection.getMethod(INDEXED_SERIALIZER_CLASS, "of", String.class, Index.class);
|
||||
|
||||
CLICK_EVENT_ACTION_SERIALIZER_INSTANCE = (TypeAdapter<ClickEvent.Action>) invokeSafe(INDEXED_SERIALIZER_CREATE_METHOD, "click action", ClickEvent.Action.NAMES);
|
||||
HOVER_EVENT_ACTION_SERIALIZER_INSTANCE = (TypeAdapter<HoverEvent.Action<?>>) invokeSafe(INDEXED_SERIALIZER_CREATE_METHOD, "hover action", HoverEvent.Action.NAMES);
|
||||
TEXT_DECORATION_SERIALIZER_INSTANCE = (TypeAdapter<TextDecoration>) invokeSafe(INDEXED_SERIALIZER_CREATE_METHOD, "text decoration", TextDecoration.NAMES);
|
||||
|
||||
Constructor<?> SHOW_ITEM_SERIALIZER_CONSTRUCTOR = Reflection.getConstructor(SHOW_ITEM_SERIALIZER, 0);
|
||||
SHOW_ITEM_SERIALIZER_CREATE = gson -> invokeSafe(SHOW_ITEM_SERIALIZER_CONSTRUCTOR);
|
||||
|
||||
Constructor<?> SHOW_ENTITY_SERIALIZER_CONSTRUCTOR = Reflection.getConstructor(SHOW_ENTITY_SERIALIZER, 0);
|
||||
SHOW_ENTITY_SERIALIZER_CREATE = gson -> invokeSafe(SHOW_ENTITY_SERIALIZER_CONSTRUCTOR);
|
||||
} else {
|
||||
IS_4_15_0_OR_NEWER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.TranslationArgumentSerializer") != null;
|
||||
|
||||
final Object optionState;
|
||||
if (IS_4_15_0_OR_NEWER) {
|
||||
// adventure >= v4.15; add option state for serializer construction
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_16)) {
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_20_3)) {
|
||||
optionState = JSONOptions.byDataVersion();
|
||||
} else {
|
||||
optionState = JSONOptions.byDataVersion().at(2526);
|
||||
}
|
||||
} else {
|
||||
optionState = JSONOptions.byDataVersion().at(2525);
|
||||
}
|
||||
Method COMPONENT_SERIALIZER_CREATE_METHOD = Reflection.getMethod(COMPONENT_SERIALIZER, "create", OptionState.class, Gson.class);
|
||||
COMPONENT_SERIALIZER_CREATE = gson -> invokeSafe(COMPONENT_SERIALIZER_CREATE_METHOD, optionState, gson);
|
||||
} else {
|
||||
// adventure < 4.15; no option states available
|
||||
optionState = null;
|
||||
Method COMPONENT_SERIALIZER_CREATE_METHOD = Reflection.getMethod(COMPONENT_SERIALIZER, "create", Gson.class);
|
||||
COMPONENT_SERIALIZER_CREATE = gson -> invokeSafe(COMPONENT_SERIALIZER_CREATE_METHOD, gson);
|
||||
}
|
||||
|
||||
Class<?> CLICK_EVENT_ACTION_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.ClickEventActionSerializer");
|
||||
Field CLICK_EVENT_ACTION_SERIALIZER_INSTANCE_FIELD = Reflection.getField(CLICK_EVENT_ACTION_SERIALIZER, "INSTANCE");
|
||||
CLICK_EVENT_ACTION_SERIALIZER_INSTANCE = (TypeAdapter<ClickEvent.Action>) getSafe(CLICK_EVENT_ACTION_SERIALIZER_INSTANCE_FIELD);
|
||||
|
||||
Class<?> HOVER_EVENT_ACTION_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.HoverEventActionSerializer");
|
||||
Field HOVER_EVENT_ACTION_SERIALIZER_INSTANCE_FIELD = Reflection.getField(HOVER_EVENT_ACTION_SERIALIZER, "INSTANCE");
|
||||
HOVER_EVENT_ACTION_SERIALIZER_INSTANCE = (TypeAdapter<HoverEvent.Action<?>>) getSafe(HOVER_EVENT_ACTION_SERIALIZER_INSTANCE_FIELD);
|
||||
|
||||
Class<?> TEXT_DECORATION_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.TextDecorationSerializer");
|
||||
Field TEXT_DECORATION_SERIALIZER_INSTANCE_FIELD = Reflection.getField(TEXT_DECORATION_SERIALIZER, "INSTANCE");
|
||||
TEXT_DECORATION_SERIALIZER_INSTANCE = (TypeAdapter<TextDecoration>) getSafe(TEXT_DECORATION_SERIALIZER_INSTANCE_FIELD);
|
||||
|
||||
Method SHOW_ITEM_SERIALIZER_CREATE_METHOD = Reflection.getMethod(SHOW_ITEM_SERIALIZER, "create", Gson.class);
|
||||
SHOW_ITEM_SERIALIZER_CREATE = gson -> invokeSafe(SHOW_ITEM_SERIALIZER_CREATE_METHOD, gson);
|
||||
|
||||
Method SHOW_ENTITY_SERIALIZER_CREATE_METHOD = Reflection.getMethod(SHOW_ENTITY_SERIALIZER, "create", Gson.class);
|
||||
SHOW_ENTITY_SERIALIZER_CREATE = gson -> invokeSafe(SHOW_ENTITY_SERIALIZER_CREATE_METHOD, gson);
|
||||
|
||||
if (IS_4_15_0_OR_NEWER) {
|
||||
Class<?> UUID_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.UUIDSerializer");
|
||||
Method UUID_SERIALIZER_CREATE = Reflection.getMethod(UUID_SERIALIZER, "uuidSerializer", OptionState.class);
|
||||
UUID_SERIALIZER_INSTANCE = (TypeAdapter<UUID>) invokeSafe(UUID_SERIALIZER_CREATE, optionState);
|
||||
|
||||
Class<?> TRANSLATION_ARGUMENT_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.TranslationArgumentSerializer");
|
||||
Method TRANSLATION_ARGUMENT_SERIALIZER_CREATE_METHOD = Reflection.getMethod(TRANSLATION_ARGUMENT_SERIALIZER, "create", Gson.class);
|
||||
TRANSLATION_ARGUMENT_SERIALIZER_CREATE = gson -> invokeSafe(TRANSLATION_ARGUMENT_SERIALIZER_CREATE_METHOD, gson);
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> TEXT_COLOR_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.TextColorSerializer");
|
||||
Field TEXT_COLOR_SERIALIZER_INSTANCE_FIELD = Reflection.getField(TEXT_COLOR_SERIALIZER, "INSTANCE");
|
||||
TEXT_COLOR_SERIALIZER_INSTANCE = (TypeAdapter<TextColor>) getSafe(TEXT_COLOR_SERIALIZER_INSTANCE_FIELD);
|
||||
|
||||
Field TEXT_COLOR_SERIALIZER_DOWNSAMPLE_COLOR_INSTANCE_FIELD = Reflection.getField(TEXT_COLOR_SERIALIZER, "DOWNSAMPLE_COLOR");
|
||||
TEXT_COLOR_SERIALIZER_DOWNSAMPLE_COLOR_INSTANCE = (TypeAdapter<TextColor>) getSafe(TEXT_COLOR_SERIALIZER_DOWNSAMPLE_COLOR_INSTANCE_FIELD);
|
||||
|
||||
Class<?> BLOCK_NBT_COMPONENT_POS_SERIALIZER = Reflection.getClassByNameWithoutException("net.kyori.adventure.text.serializer.gson.BlockNBTComponentPosSerializer");
|
||||
Field BLOCK_NBT_COMPONENT_POS_SERIALIZER_INSTANCE_FIELD = Reflection.getField(BLOCK_NBT_COMPONENT_POS_SERIALIZER, "INSTANCE");
|
||||
BLOCK_NBT_POS_SERIALIZER_INSTANCE = (TypeAdapter<BlockNBTComponent.Pos>) getSafe(BLOCK_NBT_COMPONENT_POS_SERIALIZER_INSTANCE_FIELD);
|
||||
}
|
||||
|
||||
static Object getSafe(Field field) {
|
||||
return getSafe(field, null);
|
||||
}
|
||||
|
||||
static Object getSafe(Field field, Object instance) {
|
||||
if (field == null) return null;
|
||||
|
||||
try {
|
||||
return field.get(instance);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Object invokeSafe(Method method, Object... params) {
|
||||
return invokeSafe(null, method, params);
|
||||
}
|
||||
|
||||
static Object invokeSafe(Object instance, Method method, Object... params) {
|
||||
if (method == null) return null;
|
||||
try {
|
||||
return method.invoke(instance, params);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Object invokeSafe(Constructor<?> constructor, Object... params) {
|
||||
if (constructor == null) return null;
|
||||
try {
|
||||
return constructor.newInstance(params);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+14
-4
@@ -21,9 +21,12 @@ package com.github.retrooper.packetevents.util.adventure;
|
||||
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.stats.Statistics;
|
||||
import com.google.gson.JsonElement;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.json.JSONOptions;
|
||||
import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
public class AdventureSerializer {
|
||||
@@ -35,10 +38,17 @@ public class AdventureSerializer {
|
||||
public static GsonComponentSerializer getGsonSerializer() {
|
||||
if (GSON == null) {
|
||||
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
|
||||
GSON = new GsonComponentSerializerExtended(
|
||||
version.isOlderThan(ServerVersion.V_1_16) || PacketEvents.getAPI().getSettings().shouldDownsampleColors(),
|
||||
version.isOlderThanOrEquals(ServerVersion.V_1_12_2)
|
||||
);
|
||||
GSON = GsonComponentSerializer.builder().editOptions(builder -> {
|
||||
boolean is_1_20_3_or_new = version.isNewerThanOrEquals(ServerVersion.V_1_20_3);
|
||||
builder.value(JSONOptions.EMIT_RGB, version.isNewerThanOrEquals(ServerVersion.V_1_16) && !PacketEvents.getAPI().getSettings().shouldDownsampleColors());
|
||||
builder.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.BOTH);
|
||||
builder.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, is_1_20_3_or_new);
|
||||
builder.value(JSONOptions.VALIDATE_STRICT_EVENTS, is_1_20_3_or_new);
|
||||
builder.value(JSONOptions.SHOW_ITEM_HOVER_DATA_MODE, JSONOptions.ShowItemHoverDataMode.EMIT_EITHER);
|
||||
})
|
||||
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
||||
.showAchievementToComponent(input -> Statistics.getById(input).display())
|
||||
.build();
|
||||
}
|
||||
return GSON;
|
||||
}
|
||||
|
||||
-119
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2022 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.util.adventure;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.BlockNBTComponent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
/**
|
||||
* Implementing adventures {@link GsonComponentSerializer} to fix jsons for legacy versions.
|
||||
*/
|
||||
public class GsonComponentSerializerExtended implements GsonComponentSerializer {
|
||||
|
||||
private final Gson serializer;
|
||||
private final UnaryOperator<GsonBuilder> populator;
|
||||
|
||||
public GsonComponentSerializerExtended(final boolean downsampleColor, final boolean emitLegacyHover) {
|
||||
if (AdventureReflectionUtil.IS_LEGACY_ADVENTURE) {
|
||||
this.populator = builder -> {
|
||||
builder.registerTypeHierarchyAdapter(Key.class, AdventureReflectionUtil.KEY_SERIALIZER_INSTANCE);
|
||||
builder.registerTypeHierarchyAdapter(Component.class, AdventureReflectionUtil.COMPONENT_SERIALIZER_CREATE.apply(null));
|
||||
builder.registerTypeHierarchyAdapter(Style.class, new Legacy_StyleSerializerExtended(emitLegacyHover));
|
||||
builder.registerTypeAdapter(ClickEvent.Action.class, AdventureReflectionUtil.CLICK_EVENT_ACTION_SERIALIZER_INSTANCE);
|
||||
builder.registerTypeAdapter(HoverEvent.Action.class, AdventureReflectionUtil.HOVER_EVENT_ACTION_SERIALIZER_INSTANCE);
|
||||
builder.registerTypeAdapter(HoverEvent.ShowItem.class, AdventureReflectionUtil.SHOW_ITEM_SERIALIZER_CREATE.apply(null));
|
||||
builder.registerTypeAdapter(HoverEvent.ShowEntity.class, AdventureReflectionUtil.SHOW_ENTITY_SERIALIZER_CREATE.apply(null));
|
||||
builder.registerTypeAdapter(TextColorWrapper.class, TextColorWrapper.Serializer.INSTANCE);
|
||||
builder.registerTypeHierarchyAdapter(TextColor.class, downsampleColor ? AdventureReflectionUtil.TEXT_COLOR_SERIALIZER_DOWNSAMPLE_COLOR_INSTANCE : AdventureReflectionUtil.TEXT_COLOR_SERIALIZER_INSTANCE);
|
||||
builder.registerTypeAdapter(TextDecoration.class, AdventureReflectionUtil.TEXT_DECORATION_SERIALIZER_INSTANCE);
|
||||
builder.registerTypeHierarchyAdapter(BlockNBTComponent.Pos.class, AdventureReflectionUtil.BLOCK_NBT_POS_SERIALIZER_INSTANCE);
|
||||
return builder;
|
||||
};
|
||||
} else {
|
||||
this.populator = builder -> {
|
||||
builder.registerTypeAdapterFactory(new SerializerFactory(downsampleColor, emitLegacyHover));
|
||||
return builder;
|
||||
};
|
||||
}
|
||||
this.serializer = this.populator.apply(new GsonBuilder().disableHtmlEscaping()).create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Gson serializer() {
|
||||
return this.serializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull UnaryOperator<GsonBuilder> populator() {
|
||||
return this.populator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component deserialize(final @NotNull String string) {
|
||||
final Component component = this.serializer().fromJson(string, Component.class);
|
||||
if (component == null) throw new JsonParseException("Don't know how to turn " + string + " into a Component");
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Component deserializeOr(final @Nullable String input, final @Nullable Component fallback) {
|
||||
if (input == null) return fallback;
|
||||
final Component component = this.serializer().fromJson(input, Component.class);
|
||||
if (component == null) return fallback;
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String serialize(final @NotNull Component component) {
|
||||
return this.serializer().toJson(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component deserializeFromTree(final @NotNull JsonElement input) {
|
||||
final Component component = this.serializer().fromJson(input, Component.class);
|
||||
if (component == null) throw new JsonParseException("Don't know how to turn " + input + " into a Component");
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull JsonElement serializeToTree(final @NotNull Component component) {
|
||||
return this.serializer().toJsonTree(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Builder toBuilder() {
|
||||
throw new UnsupportedOperationException("Builder pattern is not supported."); // We don't need to support this
|
||||
}
|
||||
|
||||
}
|
||||
-173
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2022 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.util.adventure;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.stats.Statistics;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.util.Codec;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class HoverSerializer {
|
||||
|
||||
private static final TagStringIO SNBT_IO = TagStringIO.get();
|
||||
private static final Codec<CompoundBinaryTag, String, IOException, IOException> SNBT_CODEC = createCodec(SNBT_IO::asCompound, SNBT_IO::asString);
|
||||
|
||||
static final String ITEM_TYPE = "id";
|
||||
static final String ITEM_COUNT = "Count";
|
||||
static final String ITEM_TAG = "tag";
|
||||
|
||||
static final String ENTITY_NAME = "name";
|
||||
static final String ENTITY_TYPE = "type";
|
||||
static final String ENTITY_ID = "id";
|
||||
static final Pattern LEGACY_NAME_PATTERN = Pattern.compile("([A-Z][a-z]+)([A-Z][a-z]+)?");
|
||||
|
||||
public HoverEvent.ShowItem deserializeShowItem(final GsonLike gson, final JsonElement input, boolean legacy) throws IOException {
|
||||
if (legacy) {
|
||||
final Component component = gson.fromJson(input, Component.class);
|
||||
assertTextComponent(component);
|
||||
final CompoundBinaryTag contents = SNBT_CODEC.decode(((TextComponent) component).content());
|
||||
final CompoundBinaryTag tag = contents.getCompound(ITEM_TAG);
|
||||
return createShowItem(
|
||||
Key.key(contents.getString(ITEM_TYPE)),
|
||||
contents.getByte(ITEM_COUNT, (byte) 1),
|
||||
tag == CompoundBinaryTag.empty() ? null : BinaryTagHolder.encode(tag, SNBT_CODEC)
|
||||
);
|
||||
} else {
|
||||
return gson.fromJson(input, HoverEvent.ShowItem.class);
|
||||
}
|
||||
}
|
||||
|
||||
public HoverEvent.ShowEntity deserializeShowEntity(final GsonLike gson, final JsonElement input, final Codec.Decoder<Component, String, ? extends RuntimeException> componentCodec, boolean legacy) throws IOException {
|
||||
if (legacy) {
|
||||
final Component component = gson.fromJson(input, Component.class);
|
||||
assertTextComponent(component);
|
||||
final CompoundBinaryTag contents = SNBT_CODEC.decode(((TextComponent) component).content());
|
||||
String type = contents.getString(ENTITY_TYPE);
|
||||
final Matcher matcher = LEGACY_NAME_PATTERN.matcher(type);
|
||||
if (matcher.matches()) {
|
||||
final StringJoiner joiner = new StringJoiner("_");
|
||||
joiner.add(matcher.group(1));
|
||||
if (matcher.group(2) != null) {
|
||||
joiner.add(matcher.group(2));
|
||||
}
|
||||
type = joiner.toString().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
return createShowEntity(
|
||||
Key.key(type),
|
||||
UUID.fromString(contents.getString(ENTITY_ID)),
|
||||
componentCodec.decode(contents.getString(ENTITY_NAME))
|
||||
);
|
||||
} else {
|
||||
return gson.fromJson(input, HoverEvent.ShowEntity.class);
|
||||
}
|
||||
}
|
||||
|
||||
public Component deserializeShowAchievement(final JsonElement input) {
|
||||
assertStringValue(input);
|
||||
return Statistics.getById(input.getAsString()).display();
|
||||
}
|
||||
|
||||
private static void assertStringValue(final JsonElement element) {
|
||||
if (!(element.isJsonPrimitive() && ((JsonPrimitive) element).isString())) {
|
||||
throw new IllegalArgumentException("Legacy events must be single Component instances");
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertTextComponent(final Component component) {
|
||||
if (!(component instanceof TextComponent) || !component.children().isEmpty()) {
|
||||
throw new IllegalArgumentException("Legacy events must be single Component instances");
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull Component serializeShowItem(final HoverEvent.@NotNull ShowItem input) throws IOException {
|
||||
final CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
|
||||
.putString(ITEM_TYPE, input.item().asString())
|
||||
.putByte(ITEM_COUNT, (byte) input.count());
|
||||
final BinaryTagHolder nbt = input.nbt();
|
||||
if (nbt != null) {
|
||||
builder.put(ITEM_TAG, nbt.get(SNBT_CODEC));
|
||||
}
|
||||
return Component.text(SNBT_CODEC.encode(builder.build()));
|
||||
}
|
||||
|
||||
public @NotNull Component serializeShowEntity(final HoverEvent.@NotNull ShowEntity input, final Codec.Encoder<Component, String, ? extends RuntimeException> componentCodec) throws IOException {
|
||||
final CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
|
||||
.putString(ENTITY_ID, input.id().toString())
|
||||
.putString(ENTITY_TYPE, input.type().asString());
|
||||
final Component name = input.name();
|
||||
if (name != null) {
|
||||
builder.putString(ENTITY_NAME, componentCodec.encode(name));
|
||||
}
|
||||
return Component.text(SNBT_CODEC.encode(builder.build()));
|
||||
}
|
||||
|
||||
public interface GsonLike {
|
||||
|
||||
static GsonLike fromGson(final Gson gson) {
|
||||
return gson::fromJson;
|
||||
}
|
||||
|
||||
<T> T fromJson(final @Nullable JsonElement json, final Class<T> classOfT);
|
||||
|
||||
}
|
||||
|
||||
// Backward Compatibility
|
||||
private static HoverEvent.ShowItem createShowItem(final @NotNull Key item, final @Range(from = 0, to = Integer.MAX_VALUE) int count, final @Nullable BinaryTagHolder nbt) {
|
||||
try {
|
||||
return HoverEvent.ShowItem.showItem(item, count, nbt);
|
||||
} catch (final NoSuchMethodError ignored) {
|
||||
return HoverEvent.ShowItem.of(item, count, nbt);
|
||||
}
|
||||
}
|
||||
|
||||
private static HoverEvent.ShowEntity createShowEntity(final @NotNull Key type, final @NotNull UUID id, final @Nullable Component name) {
|
||||
try {
|
||||
return HoverEvent.ShowEntity.showEntity(type, id, name);
|
||||
} catch (final NoSuchMethodError ignored) {
|
||||
return HoverEvent.ShowEntity.of(type, id, name);
|
||||
}
|
||||
}
|
||||
|
||||
private static <D, E, DX extends Throwable, EX extends Throwable> @NotNull Codec<D, E, DX, EX> createCodec(final @NotNull Codec.Decoder<D, E, DX> decoder, final @NotNull Codec.Encoder<D, E, EX> encoder) {
|
||||
try {
|
||||
return Codec.codec(decoder, encoder);
|
||||
} catch (final NoSuchMethodError ignored) {
|
||||
return Codec.of(decoder, encoder);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-260
@@ -1,260 +0,0 @@
|
||||
package com.github.retrooper.packetevents.util.adventure;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.internal.Streams;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.util.Codec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Legacy_StyleSerializerExtended implements JsonDeserializer<Style>, JsonSerializer<Style> {
|
||||
|
||||
private static final TextDecoration[] DECORATIONS = {
|
||||
TextDecoration.BOLD,
|
||||
TextDecoration.ITALIC,
|
||||
TextDecoration.UNDERLINED,
|
||||
TextDecoration.STRIKETHROUGH,
|
||||
TextDecoration.OBFUSCATED
|
||||
};
|
||||
|
||||
static {
|
||||
// Ensure coverage of decorations
|
||||
final Set<TextDecoration> knownDecorations = EnumSet.allOf(TextDecoration.class);
|
||||
for (final TextDecoration decoration : DECORATIONS) {
|
||||
knownDecorations.remove(decoration);
|
||||
}
|
||||
if (!knownDecorations.isEmpty()) {
|
||||
throw new IllegalStateException("Gson serializer is missing some text decorations: " + knownDecorations);
|
||||
}
|
||||
}
|
||||
|
||||
static final String FONT = "font";
|
||||
static final String COLOR = "color";
|
||||
static final String INSERTION = "insertion";
|
||||
static final String CLICK_EVENT = "clickEvent";
|
||||
static final String CLICK_EVENT_ACTION = "action";
|
||||
static final String CLICK_EVENT_VALUE = "value";
|
||||
static final String HOVER_EVENT = "hoverEvent";
|
||||
static final String HOVER_EVENT_ACTION = "action";
|
||||
static final String HOVER_EVENT_CONTENTS = "contents";
|
||||
static final @Deprecated String HOVER_EVENT_VALUE = "value";
|
||||
private final boolean emitLegacyHover;
|
||||
private final HoverSerializer hoverSerializer;
|
||||
|
||||
Legacy_StyleSerializerExtended(final boolean emitLegacyHover) {
|
||||
this.emitLegacyHover = emitLegacyHover;
|
||||
this.hoverSerializer = new HoverSerializer();
|
||||
}
|
||||
|
||||
public Style deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
return this.deserialize(object, context);
|
||||
}
|
||||
|
||||
private Style deserialize(final JsonObject json, final JsonDeserializationContext context) throws JsonParseException {
|
||||
final Style.Builder style = Style.style();
|
||||
if (json.has(FONT)) {
|
||||
style.font(context.deserialize(json.get(FONT), Key.class));
|
||||
}
|
||||
|
||||
if (json.has(COLOR)) {
|
||||
final TextColorWrapper color = context.deserialize(json.get(COLOR), TextColorWrapper.class);
|
||||
if (color.color != null) {
|
||||
style.color(color.color);
|
||||
} else if (color.decoration != null) {
|
||||
style.decoration(color.decoration, true);
|
||||
}
|
||||
}
|
||||
|
||||
for (final TextDecoration decoration : DECORATIONS) {
|
||||
final String value = TextDecoration.NAMES.key(decoration);
|
||||
if (json.has(value)) {
|
||||
style.decoration(decoration, json.get(value).getAsBoolean());
|
||||
}
|
||||
}
|
||||
|
||||
if (json.has(INSERTION)) {
|
||||
style.insertion(json.get(INSERTION).getAsString());
|
||||
}
|
||||
|
||||
if (json.has(CLICK_EVENT)) {
|
||||
final JsonObject clickEvent = json.getAsJsonObject(CLICK_EVENT);
|
||||
if (clickEvent != null) {
|
||||
final ClickEvent.Action action = optionallyDeserialize(clickEvent.getAsJsonPrimitive(CLICK_EVENT_ACTION), context, ClickEvent.Action.class);
|
||||
if (action != null && action.readable()) {
|
||||
final JsonPrimitive rawValue = clickEvent.getAsJsonPrimitive(CLICK_EVENT_VALUE);
|
||||
final String value = rawValue == null ? null : rawValue.getAsString();
|
||||
if (value != null) {
|
||||
style.clickEvent(ClickEvent.clickEvent(action, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (json.has(HOVER_EVENT)) {
|
||||
final JsonObject hoverEventObject = json.getAsJsonObject(HOVER_EVENT);
|
||||
if (hoverEventObject != null) {
|
||||
// Patch for hover event deserialization
|
||||
final JsonPrimitive serializedAction = hoverEventObject.getAsJsonPrimitive(HOVER_EVENT_ACTION);
|
||||
if (serializedAction != null) {
|
||||
final JsonElement rawValue;
|
||||
final boolean legacy;
|
||||
if (hoverEventObject.has(HOVER_EVENT_CONTENTS)) {
|
||||
legacy = false;
|
||||
rawValue = hoverEventObject.get(HOVER_EVENT_CONTENTS);
|
||||
} else if (hoverEventObject.has(HOVER_EVENT_VALUE)) {
|
||||
rawValue = hoverEventObject.get(HOVER_EVENT_VALUE);
|
||||
legacy = true;
|
||||
} else {
|
||||
legacy = false;
|
||||
rawValue = null;
|
||||
}
|
||||
|
||||
if (rawValue != null) {
|
||||
HoverEvent.Action action = null;
|
||||
Object value = null;
|
||||
switch (serializedAction.getAsString()) {
|
||||
case "show_text":
|
||||
action = HoverEvent.Action.SHOW_TEXT;
|
||||
value = context.deserialize(rawValue, Component.class);;
|
||||
break;
|
||||
case "show_item":
|
||||
action = HoverEvent.Action.SHOW_ITEM;
|
||||
value = tryIgnoring(() -> this.hoverSerializer.deserializeShowItem(context::deserialize, rawValue, legacy));
|
||||
break;
|
||||
case "show_entity":
|
||||
action = HoverEvent.Action.SHOW_ENTITY;
|
||||
value = tryIgnoring(() -> this.hoverSerializer.deserializeShowEntity(context::deserialize, rawValue, this.decoder(context), legacy));
|
||||
break;
|
||||
case "show_achievement":
|
||||
action = HoverEvent.Action.SHOW_TEXT;
|
||||
value = tryIgnoring(() -> this.hoverSerializer.deserializeShowAchievement(rawValue));
|
||||
break;
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
style.hoverEvent(HoverEvent.hoverEvent(action, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (json.has(FONT)) {
|
||||
style.font(context.deserialize(json.get(FONT), Key.class));
|
||||
}
|
||||
|
||||
return style.build();
|
||||
}
|
||||
|
||||
private <T> T tryIgnoring(final ExceptionalFunction<T> function) {
|
||||
try {
|
||||
return function.invoke();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface ExceptionalFunction<T> {
|
||||
T invoke() throws IOException;
|
||||
}
|
||||
|
||||
private static <T> T optionallyDeserialize(final JsonElement json, final JsonDeserializationContext context, final Class<T> type) {
|
||||
return json == null ? null : context.deserialize(json, type);
|
||||
}
|
||||
|
||||
private Codec.Decoder<Component, String, JsonParseException> decoder(final JsonDeserializationContext ctx) {
|
||||
return string -> {
|
||||
final JsonReader reader = new JsonReader(new StringReader(string));
|
||||
return (Component) ctx.deserialize(Streams.parse(reader), Component.class);
|
||||
};
|
||||
}
|
||||
|
||||
public JsonElement serialize(final Style src, final Type typeOfSrc, final JsonSerializationContext context) {
|
||||
final JsonObject json = new JsonObject();
|
||||
|
||||
for (final TextDecoration decoration : DECORATIONS) {
|
||||
final TextDecoration.State state = src.decoration(decoration);
|
||||
if (state != TextDecoration.State.NOT_SET) {
|
||||
final String name = TextDecoration.NAMES.key(decoration);
|
||||
assert name != null; // should never be null
|
||||
json.addProperty(name, state == TextDecoration.State.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
final TextColor color = src.color();
|
||||
if (color != null) {
|
||||
json.add(COLOR, context.serialize(color));
|
||||
}
|
||||
|
||||
final String insertion = src.insertion();
|
||||
if (insertion != null) {
|
||||
json.addProperty(INSERTION, insertion);
|
||||
}
|
||||
|
||||
final ClickEvent clickEvent = src.clickEvent();
|
||||
if (clickEvent != null) {
|
||||
JsonObject eventJson = new JsonObject();
|
||||
eventJson.add(CLICK_EVENT_ACTION, context.serialize(clickEvent.action()));
|
||||
eventJson.addProperty(CLICK_EVENT_VALUE, clickEvent.value());
|
||||
json.add(CLICK_EVENT, eventJson);
|
||||
}
|
||||
|
||||
final HoverEvent<?> hoverEvent = src.hoverEvent();
|
||||
if (hoverEvent != null) {
|
||||
final JsonObject eventJson = new JsonObject();
|
||||
eventJson.add(HOVER_EVENT_ACTION, context.serialize(hoverEvent.action()));
|
||||
final JsonElement modernContents = context.serialize(hoverEvent.value());
|
||||
eventJson.add(HOVER_EVENT_CONTENTS, modernContents);
|
||||
if (this.emitLegacyHover) {
|
||||
eventJson.add(HOVER_EVENT_VALUE, this.serializeLegacyHoverEvent(hoverEvent, modernContents, context));
|
||||
}
|
||||
|
||||
json.add(HOVER_EVENT, eventJson);
|
||||
}
|
||||
|
||||
final Key font = src.font();
|
||||
if (font != null) {
|
||||
json.add(FONT, context.serialize(font));
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
private JsonElement serializeLegacyHoverEvent(final HoverEvent<?> hoverEvent, final JsonElement modernContents, final JsonSerializationContext context) {
|
||||
if (hoverEvent.action() == HoverEvent.Action.SHOW_TEXT) { // serialization is the same
|
||||
return modernContents;
|
||||
}
|
||||
|
||||
// Patch for hover event serialization
|
||||
Component serialized = null;
|
||||
try {
|
||||
if (hoverEvent.action() == HoverEvent.Action.SHOW_ENTITY) {
|
||||
serialized = this.hoverSerializer.serializeShowEntity((HoverEvent.ShowEntity) hoverEvent.value(), this.encoder(context));
|
||||
} else if (hoverEvent.action() == HoverEvent.Action.SHOW_ITEM) {
|
||||
serialized = this.hoverSerializer.serializeShowItem((HoverEvent.ShowItem) hoverEvent.value());
|
||||
}
|
||||
} catch (IOException var6) {
|
||||
throw new JsonSyntaxException(var6);
|
||||
}
|
||||
|
||||
return serialized == null ? JsonNull.INSTANCE : context.serialize(serialized);
|
||||
}
|
||||
|
||||
private Codec.Encoder<Component, String, RuntimeException> encoder(final JsonSerializationContext ctx) {
|
||||
return component -> ctx.serialize(component).toString();
|
||||
}
|
||||
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2022 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.util.adventure;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.TypeAdapterFactory;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.BlockNBTComponent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslationArgument;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SerializerFactory implements TypeAdapterFactory {
|
||||
|
||||
private final boolean downsampleColors;
|
||||
private final boolean emitLegacyHover;
|
||||
|
||||
SerializerFactory(final boolean downsampleColors, final boolean emitLegacyHover) {
|
||||
this.downsampleColors = downsampleColors;
|
||||
this.emitLegacyHover = emitLegacyHover;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
final Class<? super T> rawType = type.getRawType();
|
||||
if (Component.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) AdventureReflectionUtil.COMPONENT_SERIALIZER_CREATE.apply(gson);
|
||||
} else if (Key.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) AdventureReflectionUtil.KEY_SERIALIZER_INSTANCE;
|
||||
} else if (Style.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) StyleSerializerExtended.create(this.emitLegacyHover, gson);
|
||||
} else if (ClickEvent.Action.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) AdventureReflectionUtil.CLICK_EVENT_ACTION_SERIALIZER_INSTANCE;
|
||||
} else if (HoverEvent.Action.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) AdventureReflectionUtil.HOVER_EVENT_ACTION_SERIALIZER_INSTANCE;
|
||||
} else if (HoverEvent.ShowItem.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) AdventureReflectionUtil.SHOW_ITEM_SERIALIZER_CREATE.apply(gson);
|
||||
} else if (HoverEvent.ShowEntity.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) AdventureReflectionUtil.SHOW_ENTITY_SERIALIZER_CREATE.apply(gson);
|
||||
} else if (TextColorWrapper.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) TextColorWrapper.Serializer.INSTANCE;
|
||||
} else if (TextColor.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) (this.downsampleColors ? AdventureReflectionUtil.TEXT_COLOR_SERIALIZER_DOWNSAMPLE_COLOR_INSTANCE : AdventureReflectionUtil.TEXT_COLOR_SERIALIZER_INSTANCE);
|
||||
} else if (TextDecoration.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) AdventureReflectionUtil.TEXT_DECORATION_SERIALIZER_INSTANCE;
|
||||
} else if (BlockNBTComponent.Pos.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) AdventureReflectionUtil.BLOCK_NBT_POS_SERIALIZER_INSTANCE;
|
||||
} else if (AdventureReflectionUtil.IS_4_15_0_OR_NEWER) {
|
||||
if (UUID.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) AdventureReflectionUtil.UUID_SERIALIZER_INSTANCE;
|
||||
} else if (TranslationArgument.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) AdventureReflectionUtil.TRANSLATION_ARGUMENT_SERIALIZER_CREATE.apply(gson);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
-297
@@ -1,297 +0,0 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2022 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.util.adventure;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.util.Codec;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class StyleSerializerExtended extends TypeAdapter<Style> {
|
||||
|
||||
private static final TextDecoration[] DECORATIONS = {
|
||||
TextDecoration.BOLD,
|
||||
TextDecoration.ITALIC,
|
||||
TextDecoration.UNDERLINED,
|
||||
TextDecoration.STRIKETHROUGH,
|
||||
TextDecoration.OBFUSCATED
|
||||
};
|
||||
|
||||
static {
|
||||
// Ensure coverage of decorations
|
||||
final Set<TextDecoration> knownDecorations = EnumSet.allOf(TextDecoration.class);
|
||||
for (final TextDecoration decoration : DECORATIONS) {
|
||||
knownDecorations.remove(decoration);
|
||||
}
|
||||
if (!knownDecorations.isEmpty()) {
|
||||
throw new IllegalStateException("Gson serializer is missing some text decorations: " + knownDecorations);
|
||||
}
|
||||
}
|
||||
|
||||
static final String FONT = "font";
|
||||
static final String COLOR = "color";
|
||||
static final String INSERTION = "insertion";
|
||||
static final String CLICK_EVENT = "clickEvent";
|
||||
static final String CLICK_EVENT_ACTION = "action";
|
||||
static final String CLICK_EVENT_VALUE = "value";
|
||||
static final String HOVER_EVENT = "hoverEvent";
|
||||
static final String HOVER_EVENT_ACTION = "action";
|
||||
static final String HOVER_EVENT_CONTENTS = "contents";
|
||||
static final @Deprecated String HOVER_EVENT_VALUE = "value";
|
||||
|
||||
static TypeAdapter<Style> create(final boolean emitLegacyHover, final Gson gson) {
|
||||
return new StyleSerializerExtended(emitLegacyHover, gson).nullSafe();
|
||||
}
|
||||
|
||||
private final boolean emitLegacyHover;
|
||||
private final Gson gson;
|
||||
private final HoverSerializer hoverSerializer;
|
||||
|
||||
private StyleSerializerExtended(final boolean emitLegacyHover, final Gson gson) {
|
||||
this.emitLegacyHover = emitLegacyHover;
|
||||
this.gson = gson;
|
||||
this.hoverSerializer = new HoverSerializer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Style read(final JsonReader in) throws IOException {
|
||||
in.beginObject();
|
||||
final Style.Builder style = Style.style();
|
||||
|
||||
while (in.hasNext()) {
|
||||
final String fieldName = in.nextName();
|
||||
if (fieldName.equals(FONT)) {
|
||||
style.font(this.gson.fromJson(in, Key.class));
|
||||
} else if (fieldName.equals(COLOR)) {
|
||||
final TextColorWrapper color = this.gson.fromJson(in, TextColorWrapper.class);
|
||||
if (color.color != null) {
|
||||
style.color(color.color);
|
||||
} else if (color.decoration != null) {
|
||||
style.decoration(color.decoration, TextDecoration.State.TRUE);
|
||||
}
|
||||
} else if (TextDecoration.NAMES.keys().contains(fieldName)) {
|
||||
style.decoration(TextDecoration.NAMES.value(fieldName), this.readBoolean(in));
|
||||
} else if (fieldName.equals(INSERTION)) {
|
||||
style.insertion(in.nextString());
|
||||
} else if (fieldName.equals(CLICK_EVENT)) {
|
||||
in.beginObject();
|
||||
ClickEvent.Action action = null;
|
||||
String value = null;
|
||||
while (in.hasNext()) {
|
||||
final String clickEventField = in.nextName();
|
||||
if (clickEventField.equals(CLICK_EVENT_ACTION)) {
|
||||
action = this.gson.fromJson(in, ClickEvent.Action.class);
|
||||
} else if (clickEventField.equals(CLICK_EVENT_VALUE)) {
|
||||
value = in.peek() == JsonToken.NULL ? null : in.nextString();
|
||||
} else {
|
||||
in.skipValue();
|
||||
}
|
||||
}
|
||||
if (action != null && action.readable() && value != null) {
|
||||
style.clickEvent(ClickEvent.clickEvent(action, value));
|
||||
}
|
||||
in.endObject();
|
||||
} else if (fieldName.equals(HOVER_EVENT)) {
|
||||
final JsonObject hoverEventObject = this.gson.fromJson(in, JsonObject.class);
|
||||
if (hoverEventObject != null) {
|
||||
final JsonPrimitive serializedAction = hoverEventObject.getAsJsonPrimitive(HOVER_EVENT_ACTION);
|
||||
if (serializedAction == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Patch for hover event deserialization
|
||||
final JsonElement rawValue;
|
||||
boolean legacy = false;
|
||||
if (hoverEventObject.has(HOVER_EVENT_CONTENTS)) {
|
||||
rawValue = hoverEventObject.get(HOVER_EVENT_CONTENTS);
|
||||
} else if (hoverEventObject.has(HOVER_EVENT_VALUE)) {
|
||||
rawValue = hoverEventObject.get(HOVER_EVENT_VALUE);
|
||||
legacy = true;
|
||||
} else {
|
||||
rawValue = null;
|
||||
}
|
||||
|
||||
if (rawValue != null) {
|
||||
HoverEvent.Action action = null;
|
||||
Object value = null;
|
||||
switch (serializedAction.getAsString()) {
|
||||
case "show_text":
|
||||
action = HoverEvent.Action.SHOW_TEXT;
|
||||
value = this.gson.fromJson(rawValue, Component.class);;
|
||||
break;
|
||||
case "show_item":
|
||||
action = HoverEvent.Action.SHOW_ITEM;
|
||||
value = this.hoverSerializer.deserializeShowItem(HoverSerializer.GsonLike.fromGson(gson), rawValue, legacy);
|
||||
break;
|
||||
case "show_entity":
|
||||
action = HoverEvent.Action.SHOW_ENTITY;
|
||||
value = this.hoverSerializer.deserializeShowEntity(HoverSerializer.GsonLike.fromGson(gson), rawValue, this.decoder(), legacy);
|
||||
break;
|
||||
case "show_achievement":
|
||||
action = HoverEvent.Action.SHOW_TEXT;
|
||||
value = this.hoverSerializer.deserializeShowAchievement(rawValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
style.hoverEvent(HoverEvent.hoverEvent(action, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
in.skipValue();
|
||||
}
|
||||
}
|
||||
|
||||
in.endObject();
|
||||
return style.build();
|
||||
}
|
||||
|
||||
private boolean readBoolean(final JsonReader in) throws IOException {
|
||||
final JsonToken peek = in.peek();
|
||||
if (peek == JsonToken.BOOLEAN) {
|
||||
return in.nextBoolean();
|
||||
} else if (peek == JsonToken.STRING || peek == JsonToken.NUMBER) {
|
||||
return Boolean.parseBoolean(in.nextString());
|
||||
} else {
|
||||
throw new JsonParseException("Token of type " + peek + " cannot be interpreted as a boolean");
|
||||
}
|
||||
}
|
||||
|
||||
private Codec.Decoder<Component, String, JsonParseException> decoder() {
|
||||
return string -> this.gson.fromJson(string, Component.class);
|
||||
}
|
||||
|
||||
private Codec.Encoder<Component, String, JsonParseException> encoder() {
|
||||
return component -> this.gson.toJson(component, Component.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final JsonWriter out, final Style value) throws IOException {
|
||||
out.beginObject();
|
||||
|
||||
for (final TextDecoration decoration : DECORATIONS) {
|
||||
final TextDecoration.State state = value.decoration(decoration);
|
||||
if (state != TextDecoration.State.NOT_SET) {
|
||||
final String name = TextDecoration.NAMES.key(decoration);
|
||||
assert name != null; // should never be null
|
||||
out.name(name);
|
||||
out.value(state == TextDecoration.State.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
final @Nullable TextColor color = value.color();
|
||||
if (color != null) {
|
||||
out.name(COLOR);
|
||||
this.gson.toJson(color, TextColor.class, out);
|
||||
}
|
||||
|
||||
final @Nullable String insertion = value.insertion();
|
||||
if (insertion != null) {
|
||||
out.name(INSERTION);
|
||||
out.value(insertion);
|
||||
}
|
||||
|
||||
final @Nullable ClickEvent clickEvent = value.clickEvent();
|
||||
if (clickEvent != null) {
|
||||
out.name(CLICK_EVENT);
|
||||
out.beginObject();
|
||||
out.name(CLICK_EVENT_ACTION);
|
||||
this.gson.toJson(clickEvent.action(), ClickEvent.Action.class, out);
|
||||
out.name(CLICK_EVENT_VALUE);
|
||||
out.value(clickEvent.value());
|
||||
out.endObject();
|
||||
}
|
||||
|
||||
final @Nullable HoverEvent<?> hoverEvent = value.hoverEvent();
|
||||
if (hoverEvent != null) {
|
||||
out.name(HOVER_EVENT);
|
||||
out.beginObject();
|
||||
out.name(HOVER_EVENT_ACTION);
|
||||
final HoverEvent.Action<?> action = hoverEvent.action();
|
||||
this.gson.toJson(action, HoverEvent.Action.class, out);
|
||||
if (this.emitLegacyHover) {
|
||||
out.name(HOVER_EVENT_VALUE);
|
||||
this.serializeLegacyHoverEvent(hoverEvent, out);
|
||||
} else if (!action.toString().equals("show_achievement")) { // Using string because the variable for SHOW_ACHIEVEMENT is not available in version before 4.14.0
|
||||
out.name(HOVER_EVENT_CONTENTS);
|
||||
if (action == HoverEvent.Action.SHOW_ITEM) {
|
||||
this.gson.toJson(hoverEvent.value(), HoverEvent.ShowItem.class, out);
|
||||
} else if (action == HoverEvent.Action.SHOW_ENTITY) {
|
||||
this.gson.toJson(hoverEvent.value(), HoverEvent.ShowEntity.class, out);
|
||||
} else if (action == HoverEvent.Action.SHOW_TEXT) {
|
||||
this.gson.toJson(hoverEvent.value(), Component.class, out);
|
||||
} else {
|
||||
throw new JsonParseException("Don't know how to serialize " + hoverEvent.value());
|
||||
}
|
||||
}
|
||||
|
||||
out.endObject();
|
||||
}
|
||||
|
||||
final @Nullable Key font = value.font();
|
||||
if (font != null) {
|
||||
out.name(FONT);
|
||||
this.gson.toJson(font, Key.class, out);
|
||||
}
|
||||
|
||||
out.endObject();
|
||||
}
|
||||
|
||||
private void serializeLegacyHoverEvent(final HoverEvent<?> hoverEvent, final JsonWriter out) throws IOException {
|
||||
if (hoverEvent.action() == HoverEvent.Action.SHOW_TEXT) { // serialization is the same
|
||||
this.gson.toJson(hoverEvent.value(), Component.class, out);
|
||||
return;
|
||||
} else if (hoverEvent.action().toString().equals("show_achievement")) {
|
||||
this.gson.toJson(hoverEvent.value(), String.class, out);
|
||||
return;
|
||||
}
|
||||
|
||||
// Patch for hover event serialization
|
||||
Component serialized = null;
|
||||
try {
|
||||
if (hoverEvent.action() == HoverEvent.Action.SHOW_ENTITY) {
|
||||
serialized = this.hoverSerializer.serializeShowEntity((HoverEvent.ShowEntity) hoverEvent.value(), this.encoder());
|
||||
} else if (hoverEvent.action() == HoverEvent.Action.SHOW_ITEM) {
|
||||
serialized = this.hoverSerializer.serializeShowItem((HoverEvent.ShowItem) hoverEvent.value());
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
throw new JsonSyntaxException(ex);
|
||||
}
|
||||
if (serialized != null) {
|
||||
this.gson.toJson(serialized, Component.class, out);
|
||||
} else {
|
||||
out.nullValue();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2022 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.util.adventure;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TextColorWrapper {
|
||||
|
||||
final @Nullable TextColor color;
|
||||
final @Nullable TextDecoration decoration;
|
||||
final boolean reset;
|
||||
|
||||
TextColorWrapper(final @Nullable TextColor color, final @Nullable TextDecoration decoration, final boolean reset) {
|
||||
this.color = color;
|
||||
this.decoration = decoration;
|
||||
this.reset = reset;
|
||||
}
|
||||
|
||||
static final class Serializer extends TypeAdapter<TextColorWrapper> {
|
||||
static final TextColorWrapper.Serializer INSTANCE = new TextColorWrapper.Serializer();
|
||||
|
||||
private Serializer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final JsonWriter out, final TextColorWrapper value) {
|
||||
throw new JsonSyntaxException("Cannot write TextColorWrapper instances");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextColorWrapper read(final JsonReader in) throws IOException {
|
||||
final String input = in.nextString();
|
||||
final TextColor color = this.colorFromString(input);
|
||||
final TextDecoration decoration = TextDecoration.NAMES.value(input);
|
||||
final boolean reset = decoration == null && input.equals("reset");
|
||||
if (color == null && decoration == null && !reset) {
|
||||
throw new JsonParseException("Don't know how to parse " + input + " at " + in.getPath());
|
||||
}
|
||||
return new TextColorWrapper(color, decoration, reset);
|
||||
}
|
||||
|
||||
TextColor colorFromString(final String value) {
|
||||
if (value.startsWith("#")) {
|
||||
return TextColor.fromHexString(value);
|
||||
} else {
|
||||
return NamedTextColor.NAMES.value(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loaded 100 of 233 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user