From d5907903ebb1c09776f82a9255051f931fedb58a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 3 Apr 2025 04:14:55 +0800 Subject: [PATCH 01/37] Update ItemBrowserManagerImpl.java --- .../core/plugin/gui/category/ItemBrowserManagerImpl.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index 2b203b19d..cc496f346 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -76,9 +76,6 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { String name = section.getOrDefault("name", id).toString(); List members = MiscUtils.getAsStringList(section.getOrDefault("list", List.of())); Key icon = Key.of(section.getOrDefault("icon", ItemKeys.STONE).toString()); - if (this.plugin.itemManager().getCustomItem(icon).isEmpty()) { - icon = ItemKeys.STONE; - } int priority = MiscUtils.getAsInt(section.getOrDefault("priority", 0)); Category category = new Category(id, name, MiscUtils.getAsStringList(section.getOrDefault("lore", List.of())), icon, members.stream().distinct().toList(), priority, (boolean) section.getOrDefault("hidden", false)); if (this.byId.containsKey(id)) { From 208488d401a412c3072e51cf3fce09793cbab669 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 3 Apr 2025 05:09:23 +0800 Subject: [PATCH 02/37] add ahocorasick --- bukkit/build.gradle.kts | 1 + bukkit/loader/build.gradle.kts | 1 + bukkit/loader/src/main/resources/craft-engine.properties | 3 ++- client-mod/build.gradle.kts | 2 +- core/build.gradle.kts | 3 +++ .../momirealms/craftengine/core/item/ItemBuildContext.java | 2 +- .../momirealms/craftengine/core/plugin/CraftEngine.java | 3 ++- .../craftengine/core/plugin/dependency/Dependencies.java | 7 +++++++ .../plugin/locale/MiniMessageTranslationRegistryImpl.java | 6 +++--- .../core/plugin/{ => text}/minimessage/I18NTag.java | 2 +- .../core/plugin/{ => text}/minimessage/ImageTag.java | 2 +- .../plugin/{ => text}/minimessage/IndexedArgumentTag.java | 2 +- .../{ => text}/minimessage/MiniMessageTextContext.java | 2 +- .../plugin/{ => text}/minimessage/NamedArgumentTag.java | 2 +- .../core/plugin/{ => text}/minimessage/PlaceholderTag.java | 2 +- .../core/plugin/{ => text}/minimessage/ShiftTag.java | 2 +- gradle.properties | 1 + server-mod/build.gradle.kts | 4 ++-- 18 files changed, 31 insertions(+), 16 deletions(-) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => text}/minimessage/I18NTag.java (95%) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => text}/minimessage/ImageTag.java (97%) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => text}/minimessage/IndexedArgumentTag.java (96%) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => text}/minimessage/MiniMessageTextContext.java (79%) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => text}/minimessage/NamedArgumentTag.java (96%) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => text}/minimessage/PlaceholderTag.java (95%) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => text}/minimessage/ShiftTag.java (95%) diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 7b21b01a6..d2e52a736 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -93,6 +93,7 @@ tasks { relocate("net.objecthunter.exp4j", "net.momirealms.craftengine.libraries.exp4j") relocate("net.bytebuddy", "net.momirealms.craftengine.libraries.bytebuddy") relocate("org.yaml.snakeyaml", "net.momirealms.craftengine.libraries.snakeyaml") + relocate("org.ahocorasick", "net.momirealms.craftengine.libraries.ahocorasick") } } diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index 9c093d371..20a743b2a 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -72,5 +72,6 @@ tasks { relocate("net.objecthunter.exp4j", "net.momirealms.craftengine.libraries.exp4j") relocate("net.bytebuddy", "net.momirealms.craftengine.libraries.bytebuddy") relocate("org.yaml.snakeyaml", "net.momirealms.craftengine.libraries.snakeyaml") + relocate("org.ahocorasick", "net.momirealms.craftengine.libraries.ahocorasick") } } diff --git a/bukkit/loader/src/main/resources/craft-engine.properties b/bukkit/loader/src/main/resources/craft-engine.properties index 496fba7c7..1972baa7d 100644 --- a/bukkit/loader/src/main/resources/craft-engine.properties +++ b/bukkit/loader/src/main/resources/craft-engine.properties @@ -25,4 +25,5 @@ snake-yaml=${snake_yaml_version} adventure-text-minimessage=${adventure_bundle_version} adventure-text-serializer-gson=${adventure_bundle_version} adventure-text-serializer-json=${adventure_bundle_version} -netty-codec-http=${netty_version} \ No newline at end of file +netty-codec-http=${netty_version} +ahocorasick=${ahocorasick_version} \ No newline at end of file diff --git a/client-mod/build.gradle.kts b/client-mod/build.gradle.kts index e662f9c3e..0b2b01c08 100644 --- a/client-mod/build.gradle.kts +++ b/client-mod/build.gradle.kts @@ -40,7 +40,7 @@ tasks.remapJar { inputFile.set(tasks.shadowJar.get().archiveFile) destinationDirectory.set(file("$rootDir/target")) - archiveFileName.set("${base.archivesName.get()}-${project.version}.jar") + archiveFileName.set("${base.archivesName.get()}-${project.version}+${rootProject.properties["latest_minecraft_version"]}.jar") } loom { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 5099cf31c..0770ba058 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -49,6 +49,8 @@ dependencies { compileOnly("commons-io:commons-io:${rootProject.properties["commons_io_version"]}") // Data Fixer Upper compileOnly("com.mojang:datafixerupper:${rootProject.properties["datafixerupper_version"]}") + // Aho-Corasick java implementation + compileOnly("org.ahocorasick:ahocorasick:${rootProject.properties["ahocorasick_version"]}") } java { @@ -75,6 +77,7 @@ tasks { relocate("com.saicone.rtag", "net.momirealms.craftengine.libraries.rtag") relocate("org.yaml.snakeyaml", "net.momirealms.craftengine.libraries.snakeyaml") relocate("net.kyori", "net.momirealms.craftengine.libraries") + relocate("org.ahocorasick", "net.momirealms.craftengine.libraries.ahocorasick") relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt") } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java index aeb808506..2c77dcbd9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemBuildContext.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.item; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.minimessage.*; +import net.momirealms.craftengine.core.plugin.text.minimessage.*; import net.momirealms.craftengine.core.util.context.ContextHolder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 36e73985e..684fee835 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -203,7 +203,8 @@ public abstract class CraftEngine implements Plugin { Dependencies.BOOSTED_YAML, Dependencies.MINIMESSAGE, Dependencies.TEXT_SERIALIZER_GSON, - Dependencies.TEXT_SERIALIZER_JSON + Dependencies.TEXT_SERIALIZER_JSON, + Dependencies.AHO_CORASICK ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java index d686ecf8d..710afff74 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependencies.java @@ -207,4 +207,11 @@ public class Dependencies { "adventure-text-serializer-json", List.of(Relocation.of("adventure", "net{}kyori{}adventure")) ); + public static final Dependency AHO_CORASICK = new Dependency( + "ahocorasick", + "org{}ahocorasick", + "ahocorasick", + "aho-corasick", + List.of(Relocation.of("ahocorasick", "org{}ahocorasick")) + ); } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslationRegistryImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslationRegistryImpl.java index 689f4b715..83e6b85a9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslationRegistryImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslationRegistryImpl.java @@ -8,9 +8,9 @@ import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.util.TriState; import net.kyori.examination.Examinable; import net.kyori.examination.ExaminableProperty; -import net.momirealms.craftengine.core.plugin.minimessage.ImageTag; -import net.momirealms.craftengine.core.plugin.minimessage.IndexedArgumentTag; -import net.momirealms.craftengine.core.plugin.minimessage.ShiftTag; +import net.momirealms.craftengine.core.plugin.text.minimessage.ImageTag; +import net.momirealms.craftengine.core.plugin.text.minimessage.IndexedArgumentTag; +import net.momirealms.craftengine.core.plugin.text.minimessage.ShiftTag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/I18NTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/I18NTag.java similarity index 95% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/I18NTag.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/I18NTag.java index 2af7a01e9..c805a98d6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/I18NTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/I18NTag.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.plugin.minimessage; +package net.momirealms.craftengine.core.plugin.text.minimessage; import net.kyori.adventure.text.minimessage.Context; import net.kyori.adventure.text.minimessage.ParsingException; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/ImageTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ImageTag.java similarity index 97% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/ImageTag.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ImageTag.java index 6e129bfcd..4e726e415 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/ImageTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ImageTag.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.plugin.minimessage; +package net.momirealms.craftengine.core.plugin.text.minimessage; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.Context; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/IndexedArgumentTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/IndexedArgumentTag.java similarity index 96% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/IndexedArgumentTag.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/IndexedArgumentTag.java index 10d887af8..5b8c768dc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/IndexedArgumentTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/IndexedArgumentTag.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.plugin.minimessage; +package net.momirealms.craftengine.core.plugin.text.minimessage; import net.kyori.adventure.text.ComponentLike; import net.kyori.adventure.text.minimessage.Context; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/MiniMessageTextContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/MiniMessageTextContext.java similarity index 79% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/MiniMessageTextContext.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/MiniMessageTextContext.java index 63129ca8d..e9ea34494 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/MiniMessageTextContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/MiniMessageTextContext.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.plugin.minimessage; +package net.momirealms.craftengine.core.plugin.text.minimessage; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.momirealms.craftengine.core.util.context.ContextHolder; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/NamedArgumentTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java similarity index 96% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/NamedArgumentTag.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java index 06fcd663c..e63f82acd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/NamedArgumentTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/NamedArgumentTag.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.plugin.minimessage; +package net.momirealms.craftengine.core.plugin.text.minimessage; import net.kyori.adventure.text.minimessage.Context; import net.kyori.adventure.text.minimessage.ParsingException; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/PlaceholderTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java similarity index 95% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/PlaceholderTag.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java index 3c78280a5..d8c478d66 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/PlaceholderTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.plugin.minimessage; +package net.momirealms.craftengine.core.plugin.text.minimessage; import net.kyori.adventure.text.minimessage.Context; import net.kyori.adventure.text.minimessage.ParsingException; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/ShiftTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ShiftTag.java similarity index 95% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/ShiftTag.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ShiftTag.java index 633c22b8f..0240c25fe 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/minimessage/ShiftTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ShiftTag.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.plugin.minimessage; +package net.momirealms.craftengine.core.plugin.text.minimessage; import net.kyori.adventure.text.minimessage.Context; import net.kyori.adventure.text.minimessage.ParsingException; diff --git a/gradle.properties b/gradle.properties index 005ca4cf7..660e66ce0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -47,6 +47,7 @@ joml_version=1.10.8 datafixerupper_version=1.0.20 mojang_brigadier_version=1.0.18 byte_buddy_version=1.15.11 +ahocorasick_version=0.6.3 snake_yaml_version=2.3 anti_grief_version=0.13 nms_helper_version=0.34 diff --git a/server-mod/build.gradle.kts b/server-mod/build.gradle.kts index f407dd6fe..dc788e3d7 100644 --- a/server-mod/build.gradle.kts +++ b/server-mod/build.gradle.kts @@ -15,7 +15,7 @@ repositories { dependencies { implementation(project(":shared")) remapper("net.fabricmc:tiny-remapper:${rootProject.properties["tiny_remapper_version"]}:fat") - paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:${property("latest_minecraft_version")}-R0.1-SNAPSHOT") + paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:${rootProject.properties["latest_minecraft_version"]}-R0.1-SNAPSHOT") compileOnly("space.vectrix.ignite:ignite-api:${rootProject.properties["ignite_version"]}") compileOnly("net.fabricmc:sponge-mixin:${rootProject.properties["mixin_version"]}") compileOnly("io.github.llamalad7:mixinextras-common:${rootProject.properties["mixinextras_version"]}") @@ -44,7 +44,7 @@ artifacts { tasks { shadowJar { archiveClassifier = "" - archiveFileName = "${rootProject.name}-ignite-mod-${rootProject.properties["project_version"]}.jar" + archiveFileName = "${rootProject.name}-ignite-mod-${rootProject.properties["project_version"]}+${rootProject.properties["latest_minecraft_version"]}.jar" destinationDirectory.set(file("$rootDir/target")) } } From 9993889e5903a6e1570cdadefb353b3514256542 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 3 Apr 2025 05:18:30 +0800 Subject: [PATCH 03/37] bump versions --- gradle.properties | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/gradle.properties b/gradle.properties index 660e66ce0..9045e8e41 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,12 +13,12 @@ supported_languages=en,zh_cn,zh_tw,es # Dependency settings paper_version=1.21.4 -jetbrains_annotations_version=24.0.0 -slf4j_version=2.0.16 -log4j_version=2.24.1 +jetbrains_annotations_version=26.0.2 +slf4j_version=2.0.17 +log4j_version=2.24.3 gson_version=2.11.0 -asm_version=9.7.1 -asm_commons_version=9.7.1 +asm_version=9.8 +asm_commons_version=9.8 jar_relocator_version=1.7 adventure_bundle_version=4.19.0 adventure_platform_version=4.3.4 @@ -29,16 +29,16 @@ cloud_bukkit_version=2.0.0-beta.10 cloud_paper_version=2.0.0-beta.10 cloud_minecraft_extras_version=2.0.0-beta.10 boosted_yaml_version=1.3.7 -bstats_version=3.0.2 -caffeine_version=3.1.8 +bstats_version=3.1.0 +caffeine_version=3.2.0 rtag_version=1.5.10 placeholder_api_version=2.11.6 vault_version=1.7 -guava_version=33.3.1-jre +guava_version=33.4.6-jre lz4_version=1.8.0 geantyref_version=1.3.16 -zstd_version=1.5.6-9 -commons_io_version=2.17.0 +zstd_version=1.5.7-2 +commons_io_version=2.18.0 sparrow_nbt_version=0.3 sparrow_util_version=0.35 fastutil_version=8.5.15 @@ -46,9 +46,9 @@ netty_version=4.1.119.Final joml_version=1.10.8 datafixerupper_version=1.0.20 mojang_brigadier_version=1.0.18 -byte_buddy_version=1.15.11 +byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 -snake_yaml_version=2.3 +snake_yaml_version=2.4 anti_grief_version=0.13 nms_helper_version=0.34 # Ignite Dependencies From 27c83150345907903c22e2397221a7faec80c083 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Thu, 3 Apr 2025 06:52:00 +0800 Subject: [PATCH 04/37] =?UTF-8?q?perf(bukkit):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=96=B9=E5=9D=97=E7=8A=B6=E6=80=81=E6=98=A0=E5=B0=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/network/PacketConsumers.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 424b361e6..0b2d8cdb9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -61,6 +61,11 @@ public class PacketConsumers { mappingsMOD[entry.getKey()] = entry.getValue(); } } + for (int i = 0; i < mappingsMOD.length; i++) { + if (BlockStateUtils.isVanillaBlock(i)) { + mappingsMOD[i] = remap(i); + } + } BLOCK_LIST = new IntIdentityList(registrySize); BIOME_LIST = new IntIdentityList(RegistryUtils.currentBiomeRegistrySize()); } @@ -70,8 +75,7 @@ public class PacketConsumers { } public static int remapMOD(int stateId) { - int modStateId = mappingsMOD[stateId]; - return BlockStateUtils.isVanillaBlock(modStateId) ? remap(modStateId) : modStateId; + return mappingsMOD[stateId]; } public static final TriConsumer LEVEL_CHUNK_WITH_LIGHT = (user, event, packet) -> { From db9d7516b67357bcfaefb3aa95cfe43591e420ab Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Thu, 3 Apr 2025 07:25:39 +0800 Subject: [PATCH 05/37] =?UTF-8?q?fix(entity):=20=E4=BF=AE=E5=A4=8D=20shulk?= =?UTF-8?q?er=20=E4=B8=8D=E5=BC=80=E5=A3=B3=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/furniture/hitbox/ShulkerHitBox.java | 17 ++++++++++++++--- .../craftengine/bukkit/util/Reflections.java | 6 ++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java index f4d61ad0d..583bdef6b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java @@ -36,7 +36,7 @@ public class ShulkerHitBox extends AbstractHitBox { ShulkerData.Peek.addEntityDataIfNotDefaultValue(peek, this.cachedShulkerValues); ShulkerData.Color.addEntityDataIfNotDefaultValue((byte) 0, this.cachedShulkerValues); -// ShulkerData.AttachFace.addEntityDataIfNotDefaultValue(DirectionUtils.toNMSDirection(direction), this.cachedShulkerValues); + // ShulkerData.AttachFace.addEntityDataIfNotDefaultValue(DirectionUtils.toNMSDirection(direction), this.cachedShulkerValues); ShulkerData.NoGravity.addEntityDataIfNotDefaultValue(true, this.cachedShulkerValues); ShulkerData.Silent.addEntityDataIfNotDefaultValue(true, this.cachedShulkerValues); ShulkerData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, this.cachedShulkerValues); // 无ai @@ -119,16 +119,27 @@ public class ShulkerHitBox extends AbstractHitBox { public void addSpawnPackets(int[] entityIds, double x, double y, double z, float yaw, Quaternionf conjugated, BiConsumer packets) { Vector3f offset = conjugated.transform(new Vector3f(position())); try { + double originalY = y + offset.y; + double integerPart = Math.floor(originalY); + double fractionalPart = originalY - integerPart; + double processedY = (fractionalPart >= 0.5) ? integerPart + 1 : originalY; packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance( - entityIds[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + entityIds[0], UUID.randomUUID(), x + offset.x, originalY, z - offset.z, 0, yaw, Reflections.instance$EntityType$ITEM_DISPLAY, 0, Reflections.instance$Vec3$Zero, 0 ), false); packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance( - entityIds[1], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, + entityIds[1], UUID.randomUUID(), x + offset.x, processedY, z - offset.z, 0, yaw, Reflections.instance$EntityType$SHULKER, 0, Reflections.instance$Vec3$Zero, 0 ), false); packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityIds[1], List.copyOf(this.cachedShulkerValues)), false); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetPassengersPacket(entityIds[0], entityIds[1]), false); + if (originalY != processedY) { + double deltaY = originalY - processedY; + short ya = (short) (deltaY * 8192); + packets.accept(Reflections.constructor$ClientboundMoveEntityPacket$Pos.newInstance( + entityIds[1], (short) 0, ya, (short) 0, true + ), false); + } if (VersionHelper.isVersionNewerThan1_20_5()) { Object attributeInstance = Reflections.constructor$AttributeInstance.newInstance(Reflections.instance$Holder$Attribute$scale, (Consumer) (o) -> {}); Reflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, scale); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 6932a75b8..3da93b0fd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6050,4 +6050,10 @@ public class Reflections { clazz$BlockStateBase, clazz$BlockState, clazz$Mirror ) ); + + public static final Constructor constructor$ClientboundMoveEntityPacket$Pos = requireNonNull( + ReflectionUtils.getDeclaredConstructor( + clazz$ClientboundMoveEntityPacket$Pos, int.class, short.class, short.class, short.class, boolean.class + ) + ); } From c16db7b29a9fc6f7cae6400bcc8605ff69a90ae1 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 3 Apr 2025 16:38:30 +0800 Subject: [PATCH 06/37] add alias for section name --- .../craftengine/core/block/BlockManager.java | 4 ++-- .../core/entity/furniture/FurnitureManager.java | 4 ++-- .../craftengine/core/font/ImageManager.java | 16 ++++++++-------- .../core/font/emoji/AbstractEmojiManager.java | 13 +++++++++++++ .../core/font/emoji/EmojiManager.java | 17 +++++++++++++++++ .../craftengine/core/item/ItemManager.java | 4 ++-- .../core/item/recipe/RecipeManager.java | 4 ++-- .../core/loot/VanillaLootManager.java | 4 ++-- .../core/pack/AbstractPackManager.java | 16 ++++++++++------ .../craftengine/core/pack/LoadingSequence.java | 1 + .../craftengine/core/pack/PackManager.java | 6 ++++-- .../plugin/command/AbstractCommandManager.java | 2 +- .../plugin/command/parser/BlockStateParser.java | 5 ++--- .../core/plugin/config/ConfigSectionParser.java | 2 +- .../plugin/config/template/TemplateManager.java | 4 ++-- .../plugin/gui/category/ItemBrowserManager.java | 4 ++-- .../core/plugin/locale/ClientLangManager.java | 4 ++-- .../core/plugin/locale/TranslationManager.java | 4 ++-- .../craftengine/core/sound/SoundManager.java | 4 ++-- .../core/sound/song/JukeboxSongManager.java | 4 ++-- 20 files changed, 79 insertions(+), 43 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/font/emoji/AbstractEmojiManager.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/font/emoji/EmojiManager.java diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java index d70452e54..3ff93fd51 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java @@ -14,9 +14,9 @@ import java.util.Map; import java.util.Optional; public interface BlockManager extends Reloadable, ModelGenerator, ConfigSectionParser { - String CONFIG_SECTION_NAME = "blocks"; + String[] CONFIG_SECTION_NAME = new String[] {"blocks", "block"}; - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java index 965337964..e14dd5836 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java @@ -10,7 +10,7 @@ import java.util.Collection; import java.util.Optional; public interface FurnitureManager extends Reloadable, ConfigSectionParser { - String CONFIG_SECTION_NAME = "furniture"; + String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; String FURNITURE_ADMIN_NODE = "craftengine.furniture.admin"; void delayedLoad(); @@ -22,7 +22,7 @@ public interface FurnitureManager extends Reloadable, ConfigSectionParser { void delayedInit(); @Override - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java index eb2b5ab6d..357d80795 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java @@ -12,7 +12,7 @@ import java.util.Optional; import java.util.function.BiFunction; public interface ImageManager extends Reloadable, ConfigSectionParser { - String CONFIG_SECTION_NAME = "images"; + String[] CONFIG_SECTION_NAME = new String[] {"images", "image"}; Key DEFAULT_FONT = Key.of("minecraft:default"); String BYPASS_BOOK = "craftengine.filter.bypass.book"; String BYPASS_SIGN = "craftengine.filter.bypass.sign"; @@ -20,12 +20,18 @@ public interface ImageManager extends Reloadable, ConfigSectionParser { String BYPASS_COMMAND = "craftengine.filter.bypass.command"; String BYPASS_ANVIL = "craftengine.filter.bypass.anvil"; - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } void delayedLoad(); + void delayedInit(); + + default int loadingSequence() { + return LoadingSequence.FONT; + } + boolean isDefaultFontInUse(); boolean isIllegalCharacter(int codepoint); @@ -69,10 +75,4 @@ public interface ImageManager extends Reloadable, ConfigSectionParser { default String createRawOffsets(int offset) { return createOffsets(offset, (raw, font) -> raw); } - - default int loadingSequence() { - return LoadingSequence.FONT; - } - - void delayedInit(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/emoji/AbstractEmojiManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/emoji/AbstractEmojiManager.java new file mode 100644 index 000000000..1b670a458 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/font/emoji/AbstractEmojiManager.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.font.emoji; + +import net.momirealms.craftengine.core.plugin.CraftEngine; + +public abstract class AbstractEmojiManager implements EmojiManager { + protected CraftEngine plugin; + + public AbstractEmojiManager(CraftEngine plugin) { + this.plugin = plugin; + } + + +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/emoji/EmojiManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/emoji/EmojiManager.java new file mode 100644 index 000000000..04c105dce --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/font/emoji/EmojiManager.java @@ -0,0 +1,17 @@ +package net.momirealms.craftengine.core.font.emoji; + +import net.momirealms.craftengine.core.pack.LoadingSequence; +import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; + +public interface EmojiManager extends Reloadable, ConfigSectionParser { + String[] CONFIG_SECTION_NAME = new String[] {"emoji", "emojis"}; + + default String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + default int loadingSequence() { + return LoadingSequence.EMOJI; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index 3b2b406fb..0e9829e5e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -17,9 +17,9 @@ import javax.annotation.Nullable; import java.util.*; public interface ItemManager extends Reloadable, ModelGenerator, ConfigSectionParser { - String CONFIG_SECTION_NAME = "items"; + String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java index ccdbcb228..6e5ef3d37 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java @@ -12,9 +12,9 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; public interface RecipeManager extends Reloadable, ConfigSectionParser { - String CONFIG_SECTION_NAME = "recipes"; + String[] CONFIG_SECTION_NAME = new String[] {"recipes", "recipe"}; - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java index 4fc6d33ee..97c2b0d59 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import java.util.Optional; public interface VanillaLootManager extends ConfigSectionParser, Reloadable { - String CONFIG_SECTION_NAME = "vanilla-loots"; + String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot", "loots", "loot"}; @Override default int loadingSequence() { @@ -15,7 +15,7 @@ public interface VanillaLootManager extends ConfigSectionParser, Reloadable { } @Override - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 131012a03..c0fe2ed1c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -192,8 +192,12 @@ public abstract class AbstractPackManager implements PackManager { @Override public boolean registerConfigSectionParser(ConfigSectionParser parser) { - if (this.sectionParsers.containsKey(parser.sectionId())) return false; - this.sectionParsers.put(parser.sectionId(), parser); + for (String id : parser.sectionId()) { + if (this.sectionParsers.containsKey(id)) return false; + } + for (String id : parser.sectionId()) { + this.sectionParsers.put(id, parser); + } return true; } @@ -404,7 +408,7 @@ public abstract class AbstractPackManager implements PackManager { this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); for (Map.Entry> entry : this.cachedConfigs.entrySet()) { ConfigSectionParser parser = entry.getKey(); - boolean isTemplate = parser.sectionId().equals(TemplateManager.CONFIG_SECTION_NAME); + boolean isTemplate = parser.sectionId()[0].equals(TemplateManager.CONFIG_SECTION_NAME[0]); long t1 = System.nanoTime(); for (CachedConfig cached : entry.getValue()) { for (Map.Entry configEntry : cached.config().entrySet()) { @@ -420,16 +424,16 @@ public abstract class AbstractPackManager implements PackManager { parser.parseSection(cached.pack(), cached.filePath(), id, plugin.templateManager().applyTemplates(configSection1)); } } else { - this.plugin.logger().warn(cached.filePath(), "Configuration section is required for " + parser.sectionId() + "." + configEntry.getKey() + " - "); + this.plugin.logger().warn(cached.filePath(), "Configuration section is required for " + parser.sectionId()[0] + "." + configEntry.getKey() + " - "); } } } catch (Exception e) { - this.plugin.logger().warn(cached.filePath(), "Error loading " + parser.sectionId() + "." + key, e); + this.plugin.logger().warn(cached.filePath(), "Error loading " + parser.sectionId()[0] + "." + key, e); } } } long t2 = System.nanoTime(); - this.plugin.logger().info("Loaded " + parser.sectionId() + " in " + String.format("%.2f", ((t2 - t1) / 1_000_000.0)) + " ms"); + this.plugin.logger().info("Loaded " + parser.sectionId()[0] + " in " + String.format("%.2f", ((t2 - t1) / 1_000_000.0)) + " ms"); } this.cachedConfigs.clear(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java b/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java index 75754ff22..a7036e56f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java @@ -13,4 +13,5 @@ public class LoadingSequence { public static final int SOUND = 90; public static final int JUKEBOX_SONG = 100; public static final int VANILLA_LOOTS = 110; + public static final int EMOJI = 120; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java index 4916f9568..ee8a19e90 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java @@ -16,8 +16,10 @@ public interface PackManager extends Reloadable { boolean unregisterConfigSectionParser(String id); - default boolean unregisterConfigSectionParser(ConfigSectionParser parser) { - return this.unregisterConfigSectionParser(parser.sectionId()); + default void unregisterConfigSectionParser(ConfigSectionParser parser) { + for (String id : parser.sectionId()) { + unregisterConfigSectionParser(id); + } } void delayedInit(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/command/AbstractCommandManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/command/AbstractCommandManager.java index 25ea6843b..99292096b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/command/AbstractCommandManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/command/AbstractCommandManager.java @@ -75,7 +75,7 @@ public abstract class AbstractCommandManager implements CraftEngineCommandMan injectExceptionHandler(CommandExecutionException.class, MinecraftExceptionHandler.createDefaultCommandExecutionHandler(), StandardCaptionKeys.EXCEPTION_UNEXPECTED); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "rawtypes"}) private void injectExceptionHandler(Class type, MinecraftExceptionHandler.MessageFactory factory, Caption key) { getCommandManager().exceptionController().registerHandler(type, ctx -> { final @Nullable ComponentLike message = factory.message(captionFormatter, (ExceptionContext) ctx); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/command/parser/BlockStateParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/command/parser/BlockStateParser.java index ccd5998b0..6830d19bd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/command/parser/BlockStateParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/command/parser/BlockStateParser.java @@ -13,6 +13,7 @@ import org.incendo.cloud.parser.ArgumentParseResult; import org.incendo.cloud.parser.ArgumentParser; import org.incendo.cloud.parser.ParserDescriptor; import org.incendo.cloud.suggestion.BlockingSuggestionProvider; +import org.incendo.cloud.suggestion.Suggestion; public class BlockStateParser implements ArgumentParser, BlockingSuggestionProvider.Strings { @@ -36,9 +37,7 @@ public class BlockStateParser implements ArgumentParser stringSuggestions(@NonNull CommandContext commandContext, @NonNull CommandInput input) { - return CraftEngine.instance().blockManager().cachedSuggestions().stream().map(it -> { - return it.suggestion(); - }).toList(); + return CraftEngine.instance().blockManager().cachedSuggestions().stream().map(Suggestion::suggestion).toList(); } public static final class BlockStateParseException extends ParserException { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java index dec473b6c..c847db6f5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java @@ -9,7 +9,7 @@ import java.util.Map; public interface ConfigSectionParser extends Comparable { - String sectionId(); + String[] sectionId(); void parseSection(Pack pack, Path path, Key id, Map section); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java index b63811fc7..0c629784c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java @@ -11,13 +11,13 @@ import java.util.Map; import java.util.regex.Pattern; public interface TemplateManager extends Reloadable, ConfigSectionParser { - String CONFIG_SECTION_NAME = "templates"; + String[] CONFIG_SECTION_NAME = new String[] {"templates", "template"}; Pattern PATTERN = Pattern.compile("\\{[^{}]+}"); String TEMPLATE = "template"; String OVERRIDES = "overrides"; String ARGUMENTS = "arguments"; - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java index 9586fb7ad..8add417e5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java @@ -17,11 +17,11 @@ import java.util.TreeSet; import static java.util.Objects.requireNonNull; public interface ItemBrowserManager extends Reloadable, ConfigSectionParser { - String CONFIG_SECTION_NAME = "categories"; + String[] CONFIG_SECTION_NAME = new String[] {"categories", "category"}; int MAX_RECIPE_DEPTH = 16; String GET_ITEM_PERMISSION = "craftengine.browser.get_item"; - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java index cbc5458d2..7380b2f5c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java @@ -38,7 +38,7 @@ public interface ClientLangManager extends Reloadable, ConfigSectionParser { Collectors.mapping(split -> split[1], Collectors.toUnmodifiableList()) )); - String CONFIG_SECTION_NAME = "lang"; + String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"}; Map langData(); @@ -48,7 +48,7 @@ public interface ClientLangManager extends Reloadable, ConfigSectionParser { } @Override - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java index 2447e768f..721eeadf2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java @@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Locale; public interface TranslationManager extends Reloadable, ConfigSectionParser { - String CONFIG_SECTION_NAME = "i18n"; + String[] CONFIG_SECTION_NAME = new String[] {"i18n", "internationalization", "translation", "translations"}; static TranslationManager instance() { return TranslationManagerImpl.instance; @@ -44,7 +44,7 @@ public interface TranslationManager extends Reloadable, ConfigSectionParser { } @Override - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java index 2fa986932..230e03650 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.util.Key; import java.util.Map; public interface SoundManager extends Reloadable, ConfigSectionParser { - String CONFIG_SECTION_NAME = "sounds"; + String[] CONFIG_SECTION_NAME = new String[] {"sounds", "sound"}; void delayedLoad(); @@ -23,7 +23,7 @@ public interface SoundManager extends Reloadable, ConfigSectionParser { } @Override - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java index f1f992411..52448fefd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; public interface JukeboxSongManager extends Reloadable, ConfigSectionParser { - String CONFIG_SECTION_NAME = "jukebox_songs"; + String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "song", "songs", "jukebox", "jukebox_song"}; @Override default int loadingSequence() { @@ -13,7 +13,7 @@ public interface JukeboxSongManager extends Reloadable, ConfigSectionParser { } @Override - default String sectionId() { + default String[] sectionId() { return CONFIG_SECTION_NAME; } From a2e9d2caf8cf6b18457f67334cfcf27d7872485d Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Thu, 3 Apr 2025 21:03:34 +0800 Subject: [PATCH 07/37] =?UTF-8?q?feat(network):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E6=96=B9=E5=9D=97=E5=B1=95=E7=A4=BA=E5=AE=9E=E4=BD=93=E6=98=A0?= =?UTF-8?q?=E5=B0=84=E6=96=B9=E5=9D=97=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 1 + .../plugin/network/PacketConsumers.java | 37 +++++++++++++++++ .../craftengine/bukkit/util/Reflections.java | 41 +++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index d55ca3054..e095aba81 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -128,6 +128,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, Reflections.clazz$ServerboundSignUpdatePacket); registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, Reflections.clazz$ServerboundEditBookPacket); registerNMSPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD, Reflections.clazz$ServerboundCustomPayloadPacket); + registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_DATA, Reflections.clazz$ClientboundSetEntityDataPacket); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.LEVEL_PARTICLE, this.packetIds.clientboundLevelParticlesPacket()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 0b2d8cdb9..78145a505 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -961,4 +961,41 @@ public class PacketConsumers { CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e); } }; + + @SuppressWarnings("unchecked") + public static final TriConsumer SET_ENTITY_DATA = (user, event, packet) -> { + try { + int id = (int) Reflections.field$ClientboundSetEntityDataPacket$id.get(packet); + Object player = user.serverPlayer(); + Object level = Reflections.method$Entity$level.invoke(player); + Object entityLookup = Reflections.method$Level$moonrise$getEntityLookup.invoke(level); + Object entity = Reflections.method$EntityLookup$get.invoke(entityLookup, id); + if (entity == null) return; + Object entityType = Reflections.method$Entity$getType.invoke(entity); + if (entityType != Reflections.instance$EntityType$BLOCK_DISPLAY) return; + List packedItems = (List) Reflections.field$ClientboundSetEntityDataPacket$packedItems.get(packet); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = (int) Reflections.field$SynchedEntityData$DataValue$id.get(packedItem); + if ((VersionHelper.isVersionNewerThan1_20_2() && entityDataId != 23) + || (!VersionHelper.isVersionNewerThan1_20_2() && entityDataId != 22)) { + continue; + } + Object blockState = Reflections.field$SynchedEntityData$DataValue$value.get(packedItem); + Object serializer = Reflections.field$SynchedEntityData$DataValue$serializer.get(packedItem); + int stateId = BlockStateUtils.blockStateToId(blockState); + int newStateId; + if (!user.clientModEnabled()) { + newStateId = remap(stateId); + } else { + newStateId = remapMOD(stateId); + } + packedItems.set(i, Reflections.constructor$SynchedEntityData$DataValue.newInstance( + entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId) + )); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e); + } + }; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 3da93b0fd..0a1abb9ca 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -809,6 +809,12 @@ public class Reflections { ) ); + public static final Field field$SynchedEntityData$DataValue$serializer = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$SynchedEntityData$DataValue, 1 + ) + ); + public static final Field field$SynchedEntityData$DataValue$value = requireNonNull( ReflectionUtils.getDeclaredField( clazz$SynchedEntityData$DataValue, 2 @@ -3666,6 +3672,7 @@ public class Reflections { public static final Object instance$EntityType$TEXT_DISPLAY; public static final Object instance$EntityType$ITEM_DISPLAY; + public static final Object instance$EntityType$BLOCK_DISPLAY; public static final Object instance$EntityType$FALLING_BLOCK; public static final Object instance$EntityType$INTERACTION; public static final Object instance$EntityType$SHULKER; @@ -3676,6 +3683,8 @@ public class Reflections { instance$EntityType$TEXT_DISPLAY = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, textDisplay); Object itemDisplay = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "item_display"); instance$EntityType$ITEM_DISPLAY = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, itemDisplay); + Object blockDisplay = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "block_display"); + instance$EntityType$BLOCK_DISPLAY = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, blockDisplay); Object fallingBlock = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "falling_block"); instance$EntityType$FALLING_BLOCK = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, fallingBlock); Object interaction = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "interaction"); @@ -6056,4 +6065,36 @@ public class Reflections { clazz$ClientboundMoveEntityPacket$Pos, int.class, short.class, short.class, short.class, boolean.class ) ); + + public static final Method method$Entity$getType = requireNonNull( + ReflectionUtils.getMethod( + clazz$Entity, clazz$EntityType + ) + ); + + public static final Constructor constructor$SynchedEntityData$DataValue = requireNonNull( + ReflectionUtils.getConstructor( + clazz$SynchedEntityData$DataValue, int.class, clazz$EntityDataSerializer, Object.class + ) + ); + + public static final Class clazz$EntityLookup = requireNonNull( + ReflectionUtils.getClazz( + "ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup", + "io.papermc.paper.chunk.system.entity.EntityLookup" + ) + ); + + public static final Method method$Level$moonrise$getEntityLookup = requireNonNull( + ReflectionUtils.getMethod( + VersionHelper.isVersionNewerThan1_21() ? clazz$Level : clazz$ServerLevel, + clazz$EntityLookup + ) + ); + + public static final Method method$EntityLookup$get = requireNonNull( + ReflectionUtils.getMethod( + clazz$EntityLookup, clazz$Entity, int.class + ) + ); } From 0e45cad3f03f5a03d7fdce7e7467671cbe985975 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 3 Apr 2025 21:10:22 +0800 Subject: [PATCH 08/37] change methods --- .../bukkit/item/recipe/BukkitRecipeManager.java | 2 +- .../craftengine/core/block/BlockManager.java | 12 ++++-------- .../core/entity/furniture/FurnitureManager.java | 4 ---- .../craftengine/core/font/ImageManager.java | 4 ---- .../craftengine/core/item/ItemManager.java | 2 -- .../craftengine/core/item/recipe/RecipeManager.java | 4 +--- .../craftengine/core/loot/VanillaLootManager.java | 2 -- .../craftengine/core/pack/PackManager.java | 2 -- .../craftengine/core/plugin/CraftEngine.java | 2 +- .../craftengine/core/plugin/Reloadable.java | 6 ++++++ .../craftengine/core/plugin/gui/GuiManager.java | 2 -- .../core/plugin/locale/ClientLangManager.java | 2 -- .../core/plugin/locale/TranslationManager.java | 2 -- .../craftengine/core/sound/SoundManager.java | 2 -- .../core/sound/song/JukeboxSongManager.java | 2 -- .../craftengine/core/world/WorldManager.java | 2 -- 16 files changed, 13 insertions(+), 39 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index a6d749316..6501e49aa 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -420,7 +420,7 @@ public class BukkitRecipeManager implements RecipeManager { } @Override - public CompletableFuture delayedLoad() { + public CompletableFuture asyncDelayedLoad() { if (!ConfigManager.enableRecipeSystem()) return CompletableFuture.completedFuture(null); return this.processVanillaRecipes().thenRun(() -> { try { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java index 3ff93fd51..4b20d0e78 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java @@ -20,6 +20,10 @@ public interface BlockManager extends Reloadable, ModelGenerator, ConfigSectionP return CONFIG_SECTION_NAME; } + default int loadingSequence() { + return LoadingSequence.BLOCK; + } + Collection modelsToGenerate(); Map> blockOverrides(); @@ -35,12 +39,4 @@ public interface BlockManager extends Reloadable, ModelGenerator, ConfigSectionP Map soundMapper(); void initSuggestions(); - - void delayedLoad(); - - void delayedInit(); - - default int loadingSequence() { - return LoadingSequence.BLOCK; - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java index e14dd5836..8f053198c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java @@ -13,14 +13,10 @@ public interface FurnitureManager extends Reloadable, ConfigSectionParser { String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; String FURNITURE_ADMIN_NODE = "craftengine.furniture.admin"; - void delayedLoad(); - void initSuggestions(); Collection cachedSuggestions(); - void delayedInit(); - @Override default String[] sectionId() { return CONFIG_SECTION_NAME; diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java index 357d80795..cf398ddf2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java @@ -24,10 +24,6 @@ public interface ImageManager extends Reloadable, ConfigSectionParser { return CONFIG_SECTION_NAME; } - void delayedLoad(); - - void delayedInit(); - default int loadingSequence() { return LoadingSequence.FONT; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index 0e9829e5e..5279003cd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -85,7 +85,5 @@ public interface ItemManager extends Reloadable, ModelGenerator, ConfigSectio Collection cachedSuggestions(); - void delayedInit(); - Object encodeJava(Key componentType, @Nullable Object component); } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java index 6e5ef3d37..55556118f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java @@ -35,9 +35,7 @@ public interface RecipeManager extends Reloadable, ConfigSectionParser { @Nullable Recipe getRecipe(Key type, RecipeInput input, @Nullable Key lastRecipe); - CompletableFuture delayedLoad(); - - void delayedInit(); + CompletableFuture asyncDelayedLoad(); default int loadingSequence() { return LoadingSequence.RECIPE; diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java index 97c2b0d59..b1d672f65 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java @@ -19,7 +19,5 @@ public interface VanillaLootManager extends ConfigSectionParser, Reloadable { return CONFIG_SECTION_NAME; } - void delayedInit(); - Optional getBlockLoot(int blockState); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java index ee8a19e90..958bd219a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java @@ -22,8 +22,6 @@ public interface PackManager extends Reloadable { } } - void delayedInit(); - void generateResourcePack(); Path resourcePackPath(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 684fee835..32ce2432b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -132,7 +132,7 @@ public abstract class CraftEngine implements Plugin { this.debugger = (s) -> {}; } } finally { - this.recipeManager.delayedLoad().thenRun(() -> this.isReloading = false); + this.recipeManager.asyncDelayedLoad().thenRun(() -> this.isReloading = false); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Reloadable.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Reloadable.java index 01fae3bee..a589ffbb1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Reloadable.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Reloadable.java @@ -19,4 +19,10 @@ public interface Reloadable { default void disable() { unload(); } + + default void delayedLoad() { + } + + default void delayedInit() { + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java index 8cca44c58..4e2287eb5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java @@ -5,6 +5,4 @@ import net.momirealms.craftengine.core.plugin.Reloadable; public interface GuiManager extends Reloadable { Inventory createInventory(Gui gui, int size); - - void delayedInit(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java index 7380b2f5c..575ff8904 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java @@ -53,6 +53,4 @@ public interface ClientLangManager extends Reloadable, ConfigSectionParser { } void addTranslation(String langId, Map translations); - - void delayedLoad(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java index 721eeadf2..52cf9559c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java @@ -24,8 +24,6 @@ public interface TranslationManager extends Reloadable, ConfigSectionParser { void forcedLocale(Locale locale); - void delayedLoad(); - String miniMessageTranslation(String key, @Nullable Locale locale); default Component render(Component component) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java index 230e03650..56aceec51 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java @@ -11,8 +11,6 @@ import java.util.Map; public interface SoundManager extends Reloadable, ConfigSectionParser { String[] CONFIG_SECTION_NAME = new String[] {"sounds", "sound"}; - void delayedLoad(); - Map sounds(); JukeboxSongManager jukeboxSongManager(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java index 52448fefd..25d6ca26b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java @@ -16,6 +16,4 @@ public interface JukeboxSongManager extends Reloadable, ConfigSectionParser { default String[] sectionId() { return CONFIG_SECTION_NAME; } - - void delayedLoad(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java index 58db10caf..5cfef4fd5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java @@ -13,8 +13,6 @@ public interface WorldManager extends Reloadable { CEWorld getWorld(UUID uuid); - void delayedInit(); - void loadWorld(World world); void loadWorld(CEWorld world); From a842a4abec7b027dc7cc5d7a2b12f4dfcaadd1ed Mon Sep 17 00:00:00 2001 From: iqtester Date: Thu, 3 Apr 2025 22:06:56 +0800 Subject: [PATCH 09/37] Implement totem animation feature --- bukkit/loader/src/main/resources/commands.yml | 7 ++ .../src/main/resources/translations/en.yml | 3 +- .../src/main/resources/translations/es.yml | 3 +- .../src/main/resources/translations/zh_cn.yml | 3 +- .../src/main/resources/translations/zh_tw.yml | 3 +- .../bukkit/item/BukkitItemManager.java | 2 + .../plugin/command/BukkitCommandManager.java | 3 +- .../plugin/command/feature/TotemCommand.java | 73 +++++++++++++++++++ .../craftengine/bukkit/util/PlayerUtils.java | 31 ++++++++ .../craftengine/bukkit/util/Reflections.java | 26 +++++++ .../core/item/AbstractItemManager.java | 7 ++ .../craftengine/core/item/ItemManager.java | 2 + .../core/plugin/locale/MessageConstants.java | 1 + 13 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java diff --git a/bukkit/loader/src/main/resources/commands.yml b/bukkit/loader/src/main/resources/commands.yml index 1e4acc716..1e959b731 100644 --- a/bukkit/loader/src/main/resources/commands.yml +++ b/bukkit/loader/src/main/resources/commands.yml @@ -69,6 +69,13 @@ search_recipe_admin: - /craftengine item search-recipe - /ce item search-recipe +totem: + enable: true + permission: ce.command.admin.totem + usage: + - /craftengine totem + - /ce totem + # Debug commands debug_set_block: enable: true diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index eab86ce3f..7ddd21f54 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -52,4 +52,5 @@ command.item.give.failure.not_exist: "No recipe found for this item" command.search_usage.not_found: "No usage found for this item" command.search_recipe.no_item: "Please hold an item before running this command" -command.search_usage.no_item: "Please hold an item before running this command" \ No newline at end of file +command.search_usage.no_item: "Please hold an item before running this command" +command.totem.not_totem: "'' is not type of totem_of_undying" \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/es.yml b/bukkit/loader/src/main/resources/translations/es.yml index b716978d9..23de3a017 100644 --- a/bukkit/loader/src/main/resources/translations/es.yml +++ b/bukkit/loader/src/main/resources/translations/es.yml @@ -52,4 +52,5 @@ command.item.give.failure.not_exist: "No se encontró ninguna receta para este objeto" command.search_usage.not_found: "No se encontró ningún uso para este objeto" command.search_recipe.no_item: "Por favor, sostén un objeto antes de ejecutar este comando" -command.search_usage.no_item: "Por favor, sostén un objeto antes de ejecutar este comando" \ No newline at end of file +command.search_usage.no_item: "Por favor, sostén un objeto antes de ejecutar este comando" +command.totem.not_totem: "'' no es del tipo totem_of_undying" \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 3de54b7d3..29cb7a370 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -52,4 +52,5 @@ command.item.give.failure.not_exist: "找不到此物品的配方" command.search_usage.not_found: "找不到此物品的用途" command.search_recipe.no_item: "请手持物品后再执行此命令" -command.search_usage.no_item: "请手持物品后再执行此命令" \ No newline at end of file +command.search_usage.no_item: "请手持物品后再执行此命令" +command.totem.not_totem: "'' 不是 totem_of_undying 类型" \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_tw.yml b/bukkit/loader/src/main/resources/translations/zh_tw.yml index 8a48c57d8..37aae210f 100644 --- a/bukkit/loader/src/main/resources/translations/zh_tw.yml +++ b/bukkit/loader/src/main/resources/translations/zh_tw.yml @@ -52,4 +52,5 @@ command.item.give.failure.not_exist: "找不到此物品的配方" command.search_usage.not_found: "找不到此物品的用途" command.search_recipe.no_item: "執行此命令前請手持物品" -command.search_usage.no_item: "執行此命令前請手持物品" \ No newline at end of file +command.search_usage.no_item: "執行此命令前請手持物品" +command.totem.not_totem: "'' 不是 totem_of_undying 類型" \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index bba404771..ef2df937e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -256,6 +256,8 @@ public class BukkitItemManager extends AbstractItemManager { CustomItem customItem = itemBuilder.build(); this.customItems.put(id, customItem); this.cachedSuggestions.add(Suggestion.suggestion(id.toString())); + if (material == Material.TOTEM_OF_UNDYING) + this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); // post process // register tags diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java index ec38a6f81..f83af185c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java @@ -45,7 +45,8 @@ public class BukkitCommandManager extends AbstractCommandManager new DebugItemDataCommand(this, plugin), new DebugSetBlockCommand(this, plugin), new DebugSpawnFurnitureCommand(this, plugin), - new DebugTargetBlockCommand(this, plugin) + new DebugTargetBlockCommand(this, plugin), + new TotemCommand(this, plugin) )); final LegacyPaperCommandManager manager = (LegacyPaperCommandManager) getCommandManager(); manager.settings().set(ManagerSetting.ALLOW_UNSAFE_REGISTRATION, true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java new file mode 100644 index 000000000..72e8a64db --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java @@ -0,0 +1,73 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.util.MaterialUtils; +import net.momirealms.craftengine.bukkit.util.PlayerUtils; +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.plugin.command.FlagKeys; +import net.momirealms.craftengine.core.plugin.locale.MessageConstants; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.bukkit.data.MultiplePlayerSelector; +import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; +import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.util.concurrent.CompletableFuture; + +public class TotemCommand extends BukkitCommandFeature { + + public TotemCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .flag(FlagKeys.SILENT_FLAG) + .required("players", MultiplePlayerSelectorParser.multiplePlayerSelectorParser()) + .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return CompletableFuture.completedFuture(plugin().itemManager().cachedTotemSuggestions()); + } + })) + .handler(context -> { + NamespacedKey namespacedKey = context.get("id"); + Key key = Key.of(namespacedKey.namespace(), namespacedKey.value()); + CustomItem item = plugin().itemManager().getCustomItem(key).orElse(null); + if (item == null) { + handleFeedback(context, MessageConstants.COMMAND_ITEM_GET_FAILURE_NOT_EXIST, Component.text(key.toString())); + return; + } + if (MaterialUtils.getMaterial(item.material()) != Material.TOTEM_OF_UNDYING) { + handleFeedback(context, MessageConstants.COMMAND_TOTEM_NOT_TOTEM, Component.text(key.toString())); + return; + } + + ItemStack totem = item.buildItemStack(); + MultiplePlayerSelector selector = context.get("players"); + for (Player player : selector.values()) { + PlayerUtils.sendTotemAnimation(player, totem); + } + }); + } + + @Override + public String getFeatureID() { + return "totem"; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java index 0030b1a93..dfe9436ff 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java @@ -1,5 +1,9 @@ package net.momirealms.craftengine.bukkit.util; +import com.mojang.datafixers.util.Pair; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.core.util.RandomUtils; import org.bukkit.Location; import org.bukkit.entity.Item; @@ -11,6 +15,9 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + import static java.util.Objects.requireNonNull; public class PlayerUtils { @@ -140,4 +147,28 @@ public class PlayerUtils { return actualAmount; } + + public static void sendTotemAnimation(Player player, ItemStack totem) { + ItemStack offhandItem = player.getInventory().getItemInOffHand(); + List packets = new ArrayList<>(); + try { + Object previousItem = Reflections.method$CraftItemStack$asNMSCopy.invoke(null, offhandItem); + Object totemItem = Reflections.method$CraftItemStack$asNMSCopy.invoke(null, totem); + + Object packet1 = Reflections.constructor$ClientboundSetEquipmentPacket + .newInstance(player.getEntityId(), List.of(Pair.of(Reflections.instance$EquipmentSlot$OFFHAND, totemItem))); + Object packet2 = Reflections.constructor$ClientboundEntityEventPacket + .newInstance(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player), (byte) 35); + Object packet3 = Reflections.constructor$ClientboundSetEquipmentPacket + .newInstance(player.getEntityId(), List.of(Pair.of(Reflections.instance$EquipmentSlot$OFFHAND, previousItem))); + packets.add(packet1); + packets.add(packet2); + packets.add(packet3); + + Object bundlePacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); + BukkitNetworkManager.instance().sendPacket(player, bundlePacket); + } catch (ReflectiveOperationException e) { + BukkitCraftEngine.instance().logger().warn("Failed to send totem animation"); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 0a1abb9ca..04f752199 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -3033,6 +3033,32 @@ public class Reflections { } } + public static final Class clazz$ClientboundSetEquipmentPacket = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundSetEquipmentPacket"), + BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayOutEntityEquipment") + ) + ); + + public static final Constructor constructor$ClientboundSetEquipmentPacket = requireNonNull( + ReflectionUtils.getConstructor( + clazz$ClientboundSetEquipmentPacket, int.class, List.class + ) + ); + + public static final Class clazz$ClientboundEntityEventPacket = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundEntityEventPacket"), + BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayOutEntityStatus") + ) + ); + + public static final Constructor constructor$ClientboundEntityEventPacket = requireNonNull( + ReflectionUtils.getConstructor( + clazz$ClientboundEntityEventPacket, clazz$Entity, byte.class + ) + ); + public static final Method method$Block$defaultBlockState = requireNonNull( ReflectionUtils.getMethod( clazz$Block, clazz$BlockState diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index eb8d76b67..f796f74c9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -35,6 +35,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected final Set equipmentsToGenerate; // Cached command suggestions protected final List cachedSuggestions = new ArrayList<>(); + protected final List cachedTotemSuggestions = new ArrayList<>(); protected void registerDataFunction(Function> function, String... alias) { for (String a : alias) { @@ -65,6 +66,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl super.clearModelsToGenerate(); this.customItems.clear(); this.cachedSuggestions.clear(); + this.cachedTotemSuggestions.clear(); this.legacyOverrides.clear(); this.modernOverrides.clear(); this.customItemTags.clear(); @@ -120,6 +122,11 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return Collections.unmodifiableCollection(this.cachedSuggestions); } + @Override + public Collection cachedTotemSuggestions() { + return Collections.unmodifiableCollection(this.cachedTotemSuggestions); + } + @Override public Optional> getItemBehavior(Key key) { Optional> customItemOptional = getCustomItem(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index 5279003cd..c032cb13e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -85,5 +85,7 @@ public interface ItemManager extends Reloadable, ModelGenerator, ConfigSectio Collection cachedSuggestions(); + Collection cachedTotemSuggestions(); + Object encodeJava(Key componentType, @Nullable Object component); } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java index ec3b8b640..bef7dd276 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java @@ -20,4 +20,5 @@ public interface MessageConstants { TranslatableComponent.Builder COMMAND_SEARCH_RECIPE_NO_ITEM = Component.translatable().key("command.search_recipe.no_item"); TranslatableComponent.Builder COMMAND_SEARCH_USAGE_NOT_FOUND = Component.translatable().key("command.search_usage.not_found"); TranslatableComponent.Builder COMMAND_SEARCH_USAGE_NO_ITEM = Component.translatable().key("command.search_usage.no_item"); + TranslatableComponent.Builder COMMAND_TOTEM_NOT_TOTEM = Component.translatable().key("command.totem.not_totem"); } From 6cadf524e459036718fafd56cdecf8907f229e56 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 00:45:44 +0800 Subject: [PATCH 10/37] refactor images --- .../src/main/resources/translations/en.yml | 12 +- .../bukkit/api/CraftEngineBlocks.java | 2 - .../bukkit/block/BlockEventListener.java | 6 +- .../block/behavior/CropBlockBehavior.java | 6 +- ...ageManager.java => BukkitFontManager.java} | 14 +- .../bukkit/plugin/BukkitCraftEngine.java | 6 +- .../plugin/command/BukkitSenderFactory.java | 7 + .../plugin/network/PacketConsumers.java | 22 +- .../core/font/AbstractFontManager.java | 243 ++++++++++++++++++ .../core/font/AbstractImageManager.java | 172 ------------- .../craftengine/core/font/BitmapImage.java | 20 +- .../craftengine/core/font/Font.java | 10 +- .../{ImageManager.java => FontManager.java} | 29 +-- .../craftengine/core/font/FontProvider.java | 4 +- .../core/font/FontTagFormatter.java | 6 + .../core/font/emoji/AbstractEmojiManager.java | 13 - .../core/font/emoji/EmojiManager.java | 17 -- .../core/pack/AbstractPackManager.java | 4 +- .../core/pack/LoadingSequence.java | 2 +- .../craftengine/core/pack/PackManager.java | 6 + .../core/pack/ResourceLocation.java | 39 +++ .../craftengine/core/plugin/CraftEngine.java | 16 +- .../craftengine/core/plugin/Plugin.java | 4 +- .../plugin/command/sender/SenderFactory.java | 8 + .../plugin/locale/TranslationManager.java | 2 + .../plugin/locale/TranslationManagerImpl.java | 8 + 26 files changed, 397 insertions(+), 281 deletions(-) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/{BukkitImageManager.java => BukkitFontManager.java} (90%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/font/AbstractImageManager.java rename core/src/main/java/net/momirealms/craftengine/core/font/{ImageManager.java => FontManager.java} (65%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/font/FontTagFormatter.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/font/emoji/AbstractEmojiManager.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/font/emoji/EmojiManager.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 7ddd21f54..8d5ad85c2 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -53,4 +53,14 @@ command.search_recipe.not_found: "No recipe found for this item" command.search_usage.not_found: "No usage found for this item" command.search_recipe.no_item: "Please hold an item before running this command" command.search_usage.no_item: "Please hold an item before running this command" -command.totem.not_totem: "'' is not type of totem_of_undying" \ No newline at end of file +command.totem.not_totem: "'' is not type of totem_of_undying" + +warning.config.image.lack_height: "Issue found in file - The image '' is missing the required 'height' argument." +warning.config.image.height_smaller_than_ascent: "Issue found in file - The image '' violates the bitmap image rule: 'height' should be no lower than 'ascent'." +warning.config.image.no_file: "Issue found in file - The image '' is missing the required 'file' argument." +warning.config.image.invalid_resource_location: "Issue found in file - The image '' has a 'file' argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" +warning.config.image.invalid_font_name: "Issue found in file - The image '' has a 'font' argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" +warning.config.image.lack_char: "Issue found in file - The image '' is missing the required 'char' argument." +warning.config.image.codepoint_in_use: "Issue found in file - The image '' is using a character[()] in font that has been used by another image ''." +warning.config.image.invalid_codepoint_grid: "Issue found in file - Image '' has an invalid 'chars' codepoint grind." +warning.config.image.file_not_exist: "Issue found in file - PNG file not found for image ''." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index 3618b8d43..61d50a512 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -6,7 +6,6 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; -import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; @@ -14,7 +13,6 @@ import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.parameter.LootParameters; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.Vec3d; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 3bc68b877..353cd94a8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -8,7 +8,6 @@ import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.block.PushReaction; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.item.Item; @@ -29,7 +28,10 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.block.*; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockExplodeEvent; +import org.bukkit.event.block.BlockPhysicsEvent; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.world.GenericGameEvent; import org.bukkit.inventory.ItemStack; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index cb2651ba5..979d8aff0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -13,14 +13,13 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.loot.LootContext; +import net.momirealms.craftengine.core.loot.number.NumberProvider; +import net.momirealms.craftengine.core.loot.number.NumberProviders; import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.Tuple; -import net.momirealms.craftengine.core.loot.number.NumberProvider; -import net.momirealms.craftengine.core.loot.number.NumberProviders; import net.momirealms.craftengine.core.util.context.ContextHolder; -import net.momirealms.craftengine.core.util.context.ContextKey; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.Vec3i; import net.momirealms.craftengine.shared.block.BlockBehavior; @@ -29,7 +28,6 @@ import org.bukkit.World; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Map; -import java.util.Random; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ThreadLocalRandom; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitImageManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java similarity index 90% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitImageManager.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java index 6dcd6e430..3f8056e54 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitImageManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java @@ -4,8 +4,8 @@ import io.papermc.paper.event.player.AsyncChatCommandDecorateEvent; import io.papermc.paper.event.player.AsyncChatDecorateEvent; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.Reflections; -import net.momirealms.craftengine.core.font.AbstractImageManager; -import net.momirealms.craftengine.core.font.ImageManager; +import net.momirealms.craftengine.core.font.AbstractFontManager; +import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.util.CharacterUtils; import org.bukkit.Bukkit; @@ -19,11 +19,11 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent; import java.lang.reflect.InvocationTargetException; import java.util.function.Consumer; -public class BukkitImageManager extends AbstractImageManager implements Listener { +public class BukkitFontManager extends AbstractFontManager implements Listener { private final BukkitCraftEngine plugin; private final Object serializer; - public BukkitImageManager(BukkitCraftEngine plugin) { + public BukkitFontManager(BukkitCraftEngine plugin) { super(plugin); this.plugin = plugin; try { @@ -63,7 +63,7 @@ public class BukkitImageManager extends AbstractImageManager implements Listener public void onCommand(PlayerCommandPreprocessEvent event) { if (!ConfigManager.filterCommand()) return; if (!this.isDefaultFontInUse()) return; - if (event.getPlayer().hasPermission(ImageManager.BYPASS_COMMAND)) { + if (event.getPlayer().hasPermission(FontManager.BYPASS_COMMAND)) { return; } runIfContainsIllegalCharacter(event.getMessage(), event::setMessage); @@ -74,7 +74,7 @@ public class BukkitImageManager extends AbstractImageManager implements Listener Player player = event.player(); if (player == null) return; if (!this.isDefaultFontInUse()) return; - if (player.hasPermission(ImageManager.BYPASS_CHAT)) { + if (player.hasPermission(FontManager.BYPASS_CHAT)) { return; } try { @@ -101,7 +101,7 @@ public class BukkitImageManager extends AbstractImageManager implements Listener boolean hasIllegal = false; for (int i = 0; i < codepoints.length; i++) { int codepoint = codepoints[i]; - if (!isIllegalCharacter(codepoint)) { + if (!isIllegalCodepoint(codepoint)) { newCodepoints[i] = codepoint; } else { newCodepoints[i] = '*'; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index 29c2b98dc..9b755b212 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors; import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes; -import net.momirealms.craftengine.bukkit.font.BukkitImageManager; +import net.momirealms.craftengine.bukkit.font.BukkitFontManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.BukkitItemBehaviors; import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager; @@ -154,7 +154,7 @@ public class BukkitCraftEngine extends CraftEngine { super.worldManager = new BukkitWorldManager(this); super.soundManager = new BukkitSoundManager(this); super.vanillaLootManager = new BukkitVanillaLootManager(this); - this.imageManager = new BukkitImageManager(this); + this.fontManager = new BukkitFontManager(this); super.enable(); // tick task if (VersionHelper.isFolia()) { @@ -216,7 +216,7 @@ public class BukkitCraftEngine extends CraftEngine { // register template parser this.packManager.registerConfigSectionParser(this.templateManager); // register font parser - this.packManager.registerConfigSectionParser(this.imageManager); + this.packManager.registerConfigSectionParsers(this.fontManager.parsers()); // register item parser this.packManager.registerConfigSectionParser(this.itemManager); // register furniture parser diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java index 57985118a..df890ee5d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitSenderFactory.java @@ -7,6 +7,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.core.plugin.command.sender.Sender; import net.momirealms.craftengine.core.plugin.command.sender.SenderFactory; import net.momirealms.craftengine.core.util.Tristate; +import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.RemoteConsoleCommandSender; @@ -79,6 +80,12 @@ public class BukkitSenderFactory extends SenderFactory C consoleCommandSender() { + return (C) Bukkit.getConsoleSender(); + } + @Override public void close() { super.close(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 78145a505..f7df2d8ab 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -18,7 +18,7 @@ import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.InteractionHand; -import net.momirealms.craftengine.core.font.ImageManager; +import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.plugin.network.ConnectionState; @@ -777,10 +777,10 @@ public class PacketConsumers { if (!ConfigManager.filterAnvil()) return; String message = (String) Reflections.field$ServerboundRenameItemPacket$name.get(packet); if (message != null && !message.isEmpty()) { - ImageManager manager = CraftEngine.instance().imageManager(); + FontManager manager = CraftEngine.instance().imageManager(); if (!manager.isDefaultFontInUse()) return; // check bypass - if (((BukkitServerPlayer) user).hasPermission(ImageManager.BYPASS_ANVIL)) { + if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_ANVIL)) { return; } runIfContainsIllegalCharacter(message, manager, (s) -> { @@ -801,10 +801,10 @@ public class PacketConsumers { try { if (!ConfigManager.filterSign()) return; String[] lines = (String[]) Reflections.field$ServerboundSignUpdatePacket$lines.get(packet); - ImageManager manager = CraftEngine.instance().imageManager(); + FontManager manager = CraftEngine.instance().imageManager(); if (!manager.isDefaultFontInUse()) return; // check bypass - if (((BukkitServerPlayer) user).hasPermission(ImageManager.BYPASS_SIGN)) { + if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_SIGN)) { return; } for (int i = 0; i < lines.length; i++) { @@ -827,10 +827,10 @@ public class PacketConsumers { public static final TriConsumer EDIT_BOOK = (user, event, packet) -> { try { if (!ConfigManager.filterBook()) return; - ImageManager manager = CraftEngine.instance().imageManager(); + FontManager manager = CraftEngine.instance().imageManager(); if (!manager.isDefaultFontInUse()) return; // check bypass - if (((BukkitServerPlayer) user).hasPermission(ImageManager.BYPASS_BOOK)) { + if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_BOOK)) { return; } @@ -879,7 +879,7 @@ public class PacketConsumers { } }; - private static Pair processClientString(String original, ImageManager manager) { + private static Pair processClientString(String original, FontManager manager) { if (original.isEmpty()) { return Pair.of(false, original); } @@ -888,7 +888,7 @@ public class PacketConsumers { boolean hasIllegal = false; for (int i = 0; i < codepoints.length; i++) { int codepoint = codepoints[i]; - if (manager.isIllegalCharacter(codepoint)) { + if (manager.isIllegalCodepoint(codepoint)) { newCodepoints[i] = '*'; hasIllegal = true; } else { @@ -898,14 +898,14 @@ public class PacketConsumers { return hasIllegal ? Pair.of(true, new String(newCodepoints, 0, newCodepoints.length)) : Pair.of(false, original); } - private static void runIfContainsIllegalCharacter(String string, ImageManager manager, Consumer callback) { + private static void runIfContainsIllegalCharacter(String string, FontManager manager, Consumer callback) { if (string.isEmpty()) return; int[] codepoints = CharacterUtils.charsToCodePoints(string.toCharArray()); int[] newCodepoints = new int[codepoints.length]; boolean hasIllegal = false; for (int i = 0; i < codepoints.length; i++) { int codepoint = codepoints[i]; - if (!manager.isIllegalCharacter(codepoint)) { + if (!manager.isIllegalCodepoint(codepoint)) { newCodepoints[i] = codepoint; } else { newCodepoints[i] = '*'; diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java new file mode 100644 index 000000000..fdd4f93a5 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -0,0 +1,243 @@ +package net.momirealms.craftengine.core.font; + +import net.momirealms.craftengine.core.pack.LoadingSequence; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.ResourceLocation; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.util.CharacterUtils; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +public abstract class AbstractFontManager implements FontManager { + private final CraftEngine plugin; + // namespace:font font + private final Map fonts = new HashMap<>(); + // namespace:id image + private final Map images = new HashMap<>(); + private final Set illegalChars = new HashSet<>(); + private final ImageParser imageParser; + private final EmojiParser emojiParser; + + private OffsetFont offsetFont; + + public AbstractFontManager(CraftEngine plugin) { + this.plugin = plugin; + this.imageParser = new ImageParser(); + this.emojiParser = new EmojiParser(); + } + + @Override + public void load() { + this.offsetFont = Optional.ofNullable(plugin.configManager().settings().getSection("offset-characters")) + .map(OffsetFont::new) + .orElse(null); + } + + @Override + public void unload() { + this.fonts.clear(); + this.images.clear(); + this.illegalChars.clear(); + } + + @Override + public ConfigSectionParser[] parsers() { + return new ConfigSectionParser[] {this.imageParser, this.emojiParser}; + } + + @Override + public void delayedLoad() { + Optional.ofNullable(this.fonts.get(DEFAULT_FONT)).ifPresent(font -> this.illegalChars.addAll(font.codepointsInUse())); + } + + @Override + public boolean isDefaultFontInUse() { + return !this.illegalChars.isEmpty(); + } + + @Override + public boolean isIllegalCodepoint(int codepoint) { + return this.illegalChars.contains(codepoint); + } + + @Override + public Collection fonts() { + return new ArrayList<>(this.fonts.values()); + } + + @Override + public Optional bitmapImageByCodepoint(Key font, int codepoint) { + return fontById(font).map(f -> f.bitmapImageByCodepoint(codepoint)); + } + + @Override + public Optional bitmapImageByImageId(Key id) { + return Optional.ofNullable(this.images.get(id)); + } + + @Override + public int codepointByImageId(Key key, int x, int y) { + BitmapImage image = this.images.get(key); + if (image == null) return -1; + return image.codepointAt(x, y); + } + + @Override + public String createOffsets(int offset, FontTagFormatter tagFormatter) { + return Optional.ofNullable(this.offsetFont).map(it -> it.createOffset(offset, tagFormatter)).orElse(""); + } + + @Override + public Optional fontById(Key id) { + return Optional.ofNullable(this.fonts.get(id)); + } + + private Font getOrCreateFont(Key key) { + return this.fonts.computeIfAbsent(key, Font::new); + } + + public class EmojiParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"emoji", "emojis"}; + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public int loadingSequence() { + return LoadingSequence.EMOJI; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + + } + } + + public class ImageParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"images", "image"}; + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public int loadingSequence() { + return LoadingSequence.IMAGE; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + Object heightObj = section.get("height"); + if (heightObj == null) { + TranslationManager.instance().log("warning.config.image.lack_height", path.toString(), id.toString()); + return; + } + + int height = MiscUtils.getAsInt(heightObj); + int ascent = MiscUtils.getAsInt(section.getOrDefault("ascent", height - 1)); + if (height < ascent) { + TranslationManager.instance().log("warning.config.image.height_smaller_than_ascent", path.toString(), id.toString()); + return; + } + + Object file = section.get("file"); + if (file == null) { + TranslationManager.instance().log("warning.config.image.no_file", path.toString(), id.toString()); + return; + } + + String resourceLocation = file.toString().replace("\\", "/"); + if (!ResourceLocation.isValid(resourceLocation)) { + TranslationManager.instance().log("warning.config.image.invalid_resource_location", path.toString(), id.toString(), resourceLocation); + return; + } + + String fontName = (String) section.getOrDefault("font", "minecraft:default"); + if (!ResourceLocation.isValid(fontName)) { + TranslationManager.instance().log("warning.config.image.invalid_font_name", path.toString(), id.toString(), fontName); + return; + } + + Key fontKey = Key.withDefaultNamespace(fontName, id.namespace()); + Font font = getOrCreateFont(fontKey); + List chars; + if (section.containsKey("chars")) { + chars = MiscUtils.getAsStringList(section.get("chars")).stream().map(it -> { + if (it.startsWith("\\u")) { + return CharacterUtils.decodeUnicodeToChars(it); + } else { + return it.toCharArray(); + } + }).toList(); + } else { + String character = (String) section.get("char"); + if (character == null) { + TranslationManager.instance().log("warning.config.image.lack_char", path.toString(), id.toString()); + return; + } + if (character.length() == 1) { + chars = List.of(character.toCharArray()); + } else { + chars = List.of(CharacterUtils.decodeUnicodeToChars(character)); + } + } + + int size = -1; + int[][] codepointGrid = new int[chars.size()][]; + for (int i = 0; i < chars.size(); ++i) { + int[] codepoints = CharacterUtils.charsToCodePoints(chars.get(i)); + for (int codepoint : codepoints) { + if (font.isCodepointInUse(codepoint)) { + BitmapImage image = font.bitmapImageByCodepoint(codepoint); + TranslationManager.instance().log("warning.config.image.codepoint_in_use", + path.toString(), + id.toString(), + fontKey.toString(), + CharacterUtils.encodeCharsToUnicode(Character.toChars(codepoint)), + new String(Character.toChars(codepoint)), + image.id().toString() + ); + return; + } + } + codepointGrid[i] = codepoints; + if (size == -1) size = codepoints.length; + if (size != codepoints.length) { + TranslationManager.instance().log("warning.config.image.invalid_codepoint_grid", path.toString(), id.toString()); + return; + } + } + + if (!resourceLocation.endsWith(".png")) resourceLocation += ".png"; + Key namespacedPath = Key.of(resourceLocation); + Path targetImagePath = pack.resourcePackFolder() + .resolve("assets") + .resolve(namespacedPath.namespace()) + .resolve("textures") + .resolve(namespacedPath.value()); + + if (!Files.exists(targetImagePath)) { + TranslationManager.instance().log("warning.config.image.file_not_exist", path.toString(), id.toString(), targetImagePath.toString()); + // DO NOT RETURN, JUST GIVE WARNINGS + } + + BitmapImage bitmapImage = new BitmapImage(id, fontKey, height, ascent, resourceLocation, codepointGrid); + for (int[] y : codepointGrid) { + for (int x : y) { + font.addBitMapImage(x, bitmapImage); + } + } + + AbstractFontManager.this.images.put(id, bitmapImage); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractImageManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractImageManager.java deleted file mode 100644 index 1d81246b8..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractImageManager.java +++ /dev/null @@ -1,172 +0,0 @@ -package net.momirealms.craftengine.core.font; - -import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.CharacterUtils; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.PreConditions; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.function.BiFunction; - -public abstract class AbstractImageManager implements ImageManager { - private final CraftEngine plugin; - // namespace:font font - private final HashMap fonts = new HashMap<>(); - // namespace:id image - private final HashMap images = new HashMap<>(); - private final Set illegalChars = new HashSet<>(); - - private OffsetFont offsetFont; - - public AbstractImageManager(CraftEngine plugin) { - this.plugin = plugin; - } - - @Override - public void load() { - this.offsetFont = Optional.ofNullable(plugin.configManager().settings().getSection("offset-characters")) - .map(OffsetFont::new) - .orElse(null); - } - - @Override - public void unload() { - this.fonts.clear(); - this.images.clear(); - this.illegalChars.clear(); - } - - @Override - public void delayedLoad() { - Optional.ofNullable(this.fonts.get(DEFAULT_FONT)).ifPresent(font -> { - this.illegalChars.addAll(font.codepointsInUse()); - }); - } - - @Override - public boolean isDefaultFontInUse() { - return !this.illegalChars.isEmpty(); - } - - @Override - public boolean isIllegalCharacter(int codepoint) { - return this.illegalChars.contains(codepoint); - } - - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - int height = MiscUtils.getAsInt(section.get("height")); - int ascent = MiscUtils.getAsInt(section.get("ascent")); - if (PreConditions.runIfTrue(height < ascent, - () -> this.plugin.logger().warn(path, "Illegal ascent found at " + id + ". Height should be no lower than ascent"))) return; - - String file = (String) section.get("file"); - if (PreConditions.isNull(file, - () -> this.plugin.logger().warn(path, "`file` option is not set in image " + id))) return; - - String fontName = (String) section.getOrDefault("font", "minecraft:default"); - if (PreConditions.isNull(fontName, - () -> this.plugin.logger().warn(path, "`font` option is not set in image " + id))) return; - - Key fontKey = Key.withDefaultNamespace(fontName, id.namespace()); - // get the font - Font font = this.getOrCreateFont(fontKey); - List chars; - if (section.containsKey("chars")) { - chars = MiscUtils.getAsStringList(section.get("chars")).stream().map(it -> { - if (it.startsWith("\\u")) { - return CharacterUtils.decodeUnicodeToChars(it); - } else { - return it.toCharArray(); - } - }).toList(); - } else { - String character = (String) section.get("char"); - if (PreConditions.isNull(character, - () -> this.plugin.logger().warn(path, "`char` option is not set in image " + id))) return; - if (character.length() == 1) { - chars = List.of(character.toCharArray()); - } else { - chars = List.of(CharacterUtils.decodeUnicodeToChars(character)); - } - } - - int size = -1; - int[][] codepointGrid = new int[chars.size()][]; - for (int i = 0; i < chars.size(); ++i) { - int[] codepoints = CharacterUtils.charsToCodePoints(chars.get(i)); - for (int codepoint : codepoints) { - if (PreConditions.runIfTrue(font.isCodepointInUse(codepoint), - () -> this.plugin.logger().warn(path, String.format("Codepoint [%s (%s)] is already used in font [%s]", CharacterUtils.encodeCharsToUnicode(Character.toChars(codepoint)), new String(Character.toChars(codepoint)), font.key().toString())))) return; - } - codepointGrid[i] = codepoints; - if (size == -1) size = codepoints.length; - if (PreConditions.runIfTrue(size != codepoints.length, - () -> this.plugin.logger().warn(path, "Illegal chars format found at " + id))) return; - } - - if (PreConditions.runIfTrue(size == -1, - () -> this.plugin.logger().warn(path, "Illegal chars format found at " + id))) return; - - if (!file.endsWith(".png")) file += ".png"; - file = file.replace("\\", "/"); - Key namespacedPath = Key.of(file); - Path targetImageFile = pack.resourcePackFolder() - .resolve("assets") - .resolve(namespacedPath.namespace()) - .resolve("textures") - .resolve(namespacedPath.value()); - - if (PreConditions.runIfTrue(!Files.exists(targetImageFile), - () -> this.plugin.logger().warn(targetImageFile, "PNG file not found for image " + id))) return; - - BitmapImage bitmapImage = new BitmapImage(id, fontKey, height, ascent, file, codepointGrid); - for (int[] y : codepointGrid) { - for (int x : y) { - font.registerCodepoint(x, bitmapImage); - } - } - - this.images.put(id, bitmapImage); - } - - @Override - public Collection fontsInUse() { - return new ArrayList<>(this.fonts.values()); - } - - @Override - public Optional bitmapImageByCodepoint(Key font, int codepoint) { - return getFontInUse(font).map(f -> f.getImageByCodepoint(codepoint)); - } - - @Override - public Optional bitmapImageByImageId(Key id) { - return Optional.ofNullable(this.images.get(id)); - } - - @Override - public int codepointByImageId(Key key, int x, int y) { - BitmapImage image = this.images.get(key); - if (image == null) return -1; - return image.codepointAt(x, y); - } - - @Override - public String createOffsets(int offset, BiFunction tagFormatter) { - return Optional.ofNullable(this.offsetFont).map(it -> it.createOffset(offset, tagFormatter)).orElse(""); - } - - @Override - public Optional getFontInUse(Key key) { - return Optional.ofNullable(fonts.get(key)); - } - - private Font getOrCreateFont(Key key) { - return this.fonts.computeIfAbsent(key, Font::new); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/BitmapImage.java b/core/src/main/java/net/momirealms/craftengine/core/font/BitmapImage.java index bc96bd66b..b7ec00095 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/BitmapImage.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/BitmapImage.java @@ -7,15 +7,15 @@ import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.Key; public class BitmapImage implements FontProvider { - private final Key imageId; + private final Key id; private final Key font; private final int height; private final int ascent; private final String file; private final int[][] codepointGrid; - public BitmapImage(Key imageId, Key font, int height, int ascent, String file, int[][] codepointGrid) { - this.imageId = imageId; + public BitmapImage(Key id, Key font, int height, int ascent, String file, int[][] codepointGrid) { + this.id = id; this.font = font; this.height = height; this.ascent = ascent; @@ -39,16 +39,16 @@ public class BitmapImage implements FontProvider { return font; } - public Key imageId() { - return imageId; + public Key id() { + return id; } public int[][] codepointGrid() { - return codepointGrid; + return codepointGrid.clone(); } public int codepointAt(int row, int column) { - if (row < 0 || row >= codepointGrid.length || column < 0 || column >= codepointGrid[row].length) { + if (!isValidCoordinate(row, column)) { throw new IndexOutOfBoundsException("Invalid index: (" + row + ", " + column + ")"); } return codepointGrid[row][column]; @@ -69,16 +69,16 @@ public class BitmapImage implements FontProvider { if (this == object) return true; if (object == null || getClass() != object.getClass()) return false; BitmapImage image = (BitmapImage) object; - return imageId.equals(image.imageId); + return id.equals(image.id); } @Override public int hashCode() { - return imageId.hashCode(); + return id.hashCode(); } @Override - public JsonObject getJson() { + public JsonObject get() { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("type", "bitmap"); jsonObject.addProperty("height", height); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/Font.java b/core/src/main/java/net/momirealms/craftengine/core/font/Font.java index eb6ebc802..cfc1cfab9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/Font.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/Font.java @@ -4,12 +4,12 @@ import net.momirealms.craftengine.core.util.Key; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.Map; public class Font { private final Key key; - private final HashMap idToCodepoint = new LinkedHashMap<>(); + private final Map idToCodepoint = new LinkedHashMap<>(); public Font(Key key) { this.key = key; @@ -24,11 +24,11 @@ public class Font { return Collections.unmodifiableCollection(this.idToCodepoint.keySet()); } - public BitmapImage getImageByCodepoint(int codepoint) { + public BitmapImage bitmapImageByCodepoint(int codepoint) { return this.idToCodepoint.get(codepoint); } - public void registerCodepoint(int codepoint, BitmapImage image) { + public void addBitMapImage(int codepoint, BitmapImage image) { this.idToCodepoint.put(codepoint, image); } @@ -37,7 +37,7 @@ public class Font { } public Collection bitmapImages() { - return idToCodepoint.values().stream().distinct().toList(); + return this.idToCodepoint.values().stream().distinct().toList(); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java similarity index 65% rename from core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java rename to core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java index cf398ddf2..345f63f29 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.core.font; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.CharacterUtils; @@ -9,10 +8,8 @@ import net.momirealms.craftengine.core.util.Key; import java.util.Collection; import java.util.Optional; -import java.util.function.BiFunction; -public interface ImageManager extends Reloadable, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"images", "image"}; +public interface FontManager extends Reloadable { Key DEFAULT_FONT = Key.of("minecraft:default"); String BYPASS_BOOK = "craftengine.filter.bypass.book"; String BYPASS_SIGN = "craftengine.filter.bypass.sign"; @@ -20,29 +17,23 @@ public interface ImageManager extends Reloadable, ConfigSectionParser { String BYPASS_COMMAND = "craftengine.filter.bypass.command"; String BYPASS_ANVIL = "craftengine.filter.bypass.anvil"; - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } - - default int loadingSequence() { - return LoadingSequence.FONT; - } + ConfigSectionParser[] parsers(); boolean isDefaultFontInUse(); - boolean isIllegalCharacter(int codepoint); + boolean isIllegalCodepoint(int codepoint); - Collection fontsInUse(); + Collection fonts(); Optional bitmapImageByCodepoint(Key font, int codepoint); - default Optional getBitmapImageByChars(Key font, char[] chars) { + default Optional bitmapImageByChars(Key font, char[] chars) { return bitmapImageByCodepoint(font, CharacterUtils.charsToCodePoint(chars)); } Optional bitmapImageByImageId(Key imageId); - Optional getFontInUse(Key font); + Optional fontById(Key font); int codepointByImageId(Key imageId, int x, int y); @@ -50,15 +41,15 @@ public interface ImageManager extends Reloadable, ConfigSectionParser { return this.codepointByImageId(imageId, 0, 0); } - default char[] getCharsByImageId(Key imageId) { - return getCharsByImageId(imageId, 0, 0); + default char[] charsByImageId(Key imageId) { + return charsByImageId(imageId, 0, 0); } - default char[] getCharsByImageId(Key imageId, int x, int y) { + default char[] charsByImageId(Key imageId, int x, int y) { return Character.toChars(this.codepointByImageId(imageId, x, y)); } - String createOffsets(int offset, BiFunction tagFormatter); + String createOffsets(int offset, FontTagFormatter tagFormatter); default String createMiniMessageOffsets(int offset) { return createOffsets(offset, FormatUtils::miniMessageFont); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/FontProvider.java b/core/src/main/java/net/momirealms/craftengine/core/font/FontProvider.java index 1a2621a38..7055a82b4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/FontProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/FontProvider.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.font; import com.google.gson.JsonObject; -public interface FontProvider { +import java.util.function.Supplier; - JsonObject getJson(); +public interface FontProvider extends Supplier { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/FontTagFormatter.java b/core/src/main/java/net/momirealms/craftengine/core/font/FontTagFormatter.java new file mode 100644 index 000000000..6f2394060 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/font/FontTagFormatter.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.font; + +import java.util.function.BiFunction; + +public interface FontTagFormatter extends BiFunction { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/emoji/AbstractEmojiManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/emoji/AbstractEmojiManager.java deleted file mode 100644 index 1b670a458..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/font/emoji/AbstractEmojiManager.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.momirealms.craftengine.core.font.emoji; - -import net.momirealms.craftengine.core.plugin.CraftEngine; - -public abstract class AbstractEmojiManager implements EmojiManager { - protected CraftEngine plugin; - - public AbstractEmojiManager(CraftEngine plugin) { - this.plugin = plugin; - } - - -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/emoji/EmojiManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/emoji/EmojiManager.java deleted file mode 100644 index 04c105dce..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/font/emoji/EmojiManager.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.momirealms.craftengine.core.font.emoji; - -import net.momirealms.craftengine.core.pack.LoadingSequence; -import net.momirealms.craftengine.core.plugin.Reloadable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; - -public interface EmojiManager extends Reloadable, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"emoji", "emojis"}; - - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } - - default int loadingSequence() { - return LoadingSequence.EMOJI; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index c0fe2ed1c..7b7c042b2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -1024,7 +1024,7 @@ public abstract class AbstractPackManager implements PackManager { private void generateFonts(Path generatedPackPath) { // generate image font json - for (Font font : plugin.imageManager().fontsInUse()) { + for (Font font : plugin.imageManager().fonts()) { Key namespacedKey = font.key(); Path fontPath = generatedPackPath.resolve("assets") .resolve(namespacedKey.namespace()) @@ -1058,7 +1058,7 @@ public abstract class AbstractPackManager implements PackManager { } for (BitmapImage image : font.bitmapImages()) { - providers.add(image.getJson()); + providers.add(image.get()); } try (FileWriter fileWriter = new FileWriter(fontPath.toFile())) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java b/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java index a7036e56f..110a1db86 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java @@ -7,7 +7,7 @@ public class LoadingSequence { public static final int BLOCK = 30; public static final int ITEM = 40; public static final int FURNITURE = 50; - public static final int FONT = 60; + public static final int IMAGE = 60; public static final int RECIPE = 70; public static final int CATEGORY = 80; public static final int SOUND = 90; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java index 958bd219a..d80d2d540 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java @@ -14,6 +14,12 @@ public interface PackManager extends Reloadable { boolean registerConfigSectionParser(ConfigSectionParser parser); + default void registerConfigSectionParsers(ConfigSectionParser[] parsers) { + for (ConfigSectionParser parser : parsers) { + registerConfigSectionParser(parser); + } + } + boolean unregisterConfigSectionParser(String id); default void unregisterConfigSectionParser(ConfigSectionParser parser) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java b/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java new file mode 100644 index 000000000..5885168b9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java @@ -0,0 +1,39 @@ +package net.momirealms.craftengine.core.pack; + +public class ResourceLocation { + + public static boolean isValid(final String resourceLocation) { + int index = resourceLocation.indexOf(":"); + if (index == -1) { + return isValidPath(resourceLocation); + } else { + return isValidNamespace(resourceLocation.substring(0, index)) && isValidPath(resourceLocation.substring(index + 1)); + } + } + + public static boolean validPathChar(char character) { + return character == '_' || character == '-' || character >= 'a' && character <= 'z' || character >= '0' && character <= '9' || character == '/' || character == '.'; + } + + private static boolean validNamespaceChar(char character) { + return character == '_' || character == '-' || character >= 'a' && character <= 'z' || character >= '0' && character <= '9' || character == '.'; + } + + private static boolean isValidNamespace(String namespace) { + for(int i = 0; i < namespace.length(); ++i) { + if (!validNamespaceChar(namespace.charAt(i))) { + return false; + } + } + return true; + } + + private static boolean isValidPath(String path) { + for(int i = 0; i < path.length(); ++i) { + if (!validPathChar(path.charAt(i))) { + return false; + } + } + return true; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 32ce2432b..1f9d9826c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.plugin; import net.momirealms.craftengine.core.block.BlockManager; import net.momirealms.craftengine.core.entity.furniture.FurnitureManager; -import net.momirealms.craftengine.core.font.ImageManager; +import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.item.recipe.RecipeManager; import net.momirealms.craftengine.core.loot.VanillaLootManager; @@ -45,7 +45,7 @@ public abstract class CraftEngine implements Plugin { protected SchedulerAdapter scheduler; protected NetworkManager networkManager; protected ClassPathAppender classPathAppender; - protected ImageManager imageManager; + protected FontManager fontManager; protected PackManager packManager; protected ConfigManager configManager; protected ItemManager itemManager; @@ -106,7 +106,7 @@ public abstract class CraftEngine implements Plugin { this.translationManager.reload(); this.templateManager.reload(); this.furnitureManager.reload(); - this.imageManager.reload(); + this.fontManager.reload(); this.itemManager.reload(); this.soundManager.reload(); this.recipeManager.reload(); @@ -124,7 +124,7 @@ public abstract class CraftEngine implements Plugin { this.furnitureManager.delayedLoad(); this.itemBrowserManager.delayedLoad(); this.soundManager.delayedLoad(); - this.imageManager.delayedLoad(); + this.fontManager.delayedLoad(); // reset debugger if (ConfigManager.debug()) { this.debugger = (s) -> logger.info("[Debug] " + s.get()); @@ -153,7 +153,7 @@ public abstract class CraftEngine implements Plugin { this.worldManager.delayedInit(); this.packManager.delayedInit(); this.furnitureManager.delayedInit(); - this.imageManager.delayedInit(); + this.fontManager.delayedInit(); this.vanillaLootManager.delayedInit(); this.delayedEnable(); }); @@ -164,7 +164,7 @@ public abstract class CraftEngine implements Plugin { if (this.senderFactory != null) this.senderFactory.close(); if (this.commandManager != null) this.commandManager.unregisterFeatures(); if (this.networkManager != null) this.networkManager.shutdown(); - if (this.imageManager != null) this.imageManager.disable(); + if (this.fontManager != null) this.fontManager.disable(); if (this.packManager != null) this.packManager.disable(); if (this.itemManager != null) this.itemManager.disable(); if (this.blockManager != null) this.blockManager.disable(); @@ -241,8 +241,8 @@ public abstract class CraftEngine implements Plugin { } @Override - public ImageManager imageManager() { - return imageManager; + public FontManager imageManager() { + return fontManager; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java index fa760fadc..4f158bacf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.plugin; import net.momirealms.craftengine.core.block.BlockManager; import net.momirealms.craftengine.core.entity.furniture.FurnitureManager; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.font.ImageManager; +import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.item.recipe.RecipeManager; import net.momirealms.craftengine.core.loot.VanillaLootManager; @@ -55,7 +55,7 @@ public interface Plugin extends Reloadable { NetworkManager networkManager(); - ImageManager imageManager(); + FontManager imageManager(); ConfigManager configManager(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/command/sender/SenderFactory.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/command/sender/SenderFactory.java index f08a3caf1..a9d6f4eb8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/command/sender/SenderFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/command/sender/SenderFactory.java @@ -10,9 +10,11 @@ import java.util.UUID; public abstract class SenderFactory

{ private final P plugin; + private final Sender console; public SenderFactory(P plugin) { this.plugin = plugin; + this.console = wrap(consoleCommandSender()); } protected P plugin() { @@ -35,10 +37,16 @@ public abstract class SenderFactory

{ protected abstract boolean isConsole(T sender); + protected abstract C consoleCommandSender(); + protected boolean consoleHasAllPermissions() { return true; } + public Sender console() { + return console; + } + public Sender wrap(C sender) { Objects.requireNonNull(sender, "sender"); return new AbstractSender<>(this.plugin, this, sender); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java index 52cf9559c..edb9526b0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java @@ -45,4 +45,6 @@ public interface TranslationManager extends Reloadable, ConfigSectionParser { default String[] sectionId() { return CONFIG_SECTION_NAME; } + + void log(String id, String... args); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index b68f07a4e..b6c30d3f2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -7,6 +7,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.Plugin; import net.momirealms.craftengine.core.plugin.PluginProperties; import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; +import net.momirealms.craftengine.core.plugin.text.minimessage.IndexedArgumentTag; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Pair; import org.jetbrains.annotations.Nullable; @@ -235,6 +236,13 @@ public class TranslationManagerImpl implements TranslationManager { return clientLangManager; } + @Override + public void log(String id, String... args) { + String translation = miniMessageTranslation(id); + if (translation == null) translation = id; + this.plugin.senderFactory().console().sendMessage(AdventureHelper.miniMessage().deserialize(translation, new IndexedArgumentTag(Arrays.stream(args).map(Component::text).toList()))); + } + private Map updateLangFile(Map previous, Path translationFile) throws IOException { DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); From 30588d86eb4d92a1d6ebb67bd99f123b1d2a1186 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 03:21:35 +0800 Subject: [PATCH 11/37] refactor recipes --- .../src/main/resources/translations/en.yml | 3 +- .../api/event/CraftEngineReloadEvent.java | 1 + .../item/recipe/BukkitRecipeConvertor.java | 10 + .../item/recipe/BukkitRecipeManager.java | 1115 +++++++---------- .../item/recipe/CrafterEventListener.java | 4 +- .../item/recipe/RecipeEventListener.java | 20 +- .../bukkit/plugin/BukkitCraftEngine.java | 32 +- .../plugin/command/feature/ReloadCommand.java | 49 +- .../feature/SearchRecipeAdminCommand.java | 2 +- .../feature/SearchRecipePlayerCommand.java | 2 +- .../feature/SearchUsageAdminCommand.java | 2 +- .../feature/SearchUsagePlayerCommand.java | 2 +- .../plugin/injector/BukkitInjector.java | 46 +- .../bukkit/util/InteractUtils.java | 4 +- .../core/font/AbstractFontManager.java | 2 +- .../item/recipe/AbstractRecipeManager.java | 183 +++ .../core/item/recipe/RecipeManager.java | 28 +- .../craftengine/core/plugin/CraftEngine.java | 93 +- .../gui/category/ItemBrowserManagerImpl.java | 50 +- 19 files changed, 828 insertions(+), 820 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 8d5ad85c2..851f3889d 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -63,4 +63,5 @@ warning.config.image.invalid_font_name: "Issue found in file - T warning.config.image.lack_char: "Issue found in file - The image '' is missing the required 'char' argument." warning.config.image.codepoint_in_use: "Issue found in file - The image '' is using a character[()] in font that has been used by another image ''." warning.config.image.invalid_codepoint_grid: "Issue found in file - Image '' has an invalid 'chars' codepoint grind." -warning.config.image.file_not_exist: "Issue found in file - PNG file not found for image ''." \ No newline at end of file +warning.config.image.file_not_exist: "Issue found in file - PNG file not found for image ''." +warning.config.recipe.duplicated: "Issue found in file - Duplicated recipe ''." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java index 58d5dea02..e56d98aa1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java @@ -10,6 +10,7 @@ public class CraftEngineReloadEvent extends Event { private final BukkitCraftEngine plugin; public CraftEngineReloadEvent(BukkitCraftEngine plugin) { + super(true); this.plugin = plugin; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java new file mode 100644 index 000000000..c899ca4df --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.bukkit.item.recipe; + +import net.momirealms.craftengine.core.item.recipe.Recipe; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.inventory.ItemStack; + +public interface BukkitRecipeConvertor> { + + Runnable convert(Key id, T recipe); +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 6501e49aa..fc0fe0577 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -14,19 +14,13 @@ import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.*; -import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.vanilla.*; -import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20; -import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20_5; -import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_21_2; -import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.HeptaFunction; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.PentaFunction; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -35,247 +29,249 @@ import org.bukkit.event.HandlerList; import org.bukkit.inventory.*; import org.bukkit.inventory.recipe.CookingBookCategory; import org.bukkit.inventory.recipe.CraftingBookCategory; -import org.jetbrains.annotations.Nullable; import java.io.Reader; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Path; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiConsumer; import java.util.function.Consumer; -public class BukkitRecipeManager implements RecipeManager { - private static final Map>> BUKKIT_RECIPE_FACTORIES = new HashMap<>(); - private static Object minecraftRecipeManager; - private static final List injectedIngredients = new ArrayList<>(); - private static final IdentityHashMap, Object> recipeToMcRecipeHolder = new IdentityHashMap<>(); +public class BukkitRecipeManager extends AbstractRecipeManager { private static BukkitRecipeManager instance; + // 将自定义配方转为“广义”配方,接受更加宽容的输入 + // 部分过程借助bukkit完成,部分直接通过nms方法注册 + private static final Map>> MIXED_RECIPE_CONVERTORS = new HashMap<>(); + private static Object nmsRecipeManager; + private static final List injectedIngredients = new ArrayList<>(); + private static final IdentityHashMap, Object> recipeToMcRecipeHolder = new IdentityHashMap<>(); + + private static void registerNMSSmithingRecipe(Object recipe) { + try { + Reflections.method$RecipeManager$addRecipe.invoke(nmsRecipeManager(), recipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register smithing recipe", e); + } + } + + private static void registerBukkitShapedRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftShapedRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register shaped recipe", e); + } + } + + private static void registerBukkitShapelessRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftShapelessRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register shapeless recipe", e); + } + } + + private static void registerBukkitSmeltingRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftFurnaceRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register smelting recipe", e); + } + } + + private static void registerBukkitSmokingRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftSmokingRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register smoking recipe", e); + } + } + + private static void registerBukkitBlastingRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftBlastingRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register blasting recipe", e); + } + } + + private static void registerBukkitCampfireRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftCampfireRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register campfire recipe", e); + } + } + + private static void registerBukkitStoneCuttingRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftStonecuttingRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register stonecutting recipe", e); + } + } + static { - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SMITHING_TRANSFORM, (key, recipe) -> { - CustomSmithingTransformRecipe ceRecipe = (CustomSmithingTransformRecipe) recipe; - ceRecipe.addition(); - // bukkit api doesn't allow empty material choices, that's why we do this + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMITHING_TRANSFORM, (BukkitRecipeConvertor>) (id, recipe) -> { try { - Object smithingRecipe = createMinecraftSmithingTransformRecipe(ceRecipe); + Object nmsRecipe = createMinecraftSmithingTransformRecipe(recipe); if (VersionHelper.isVersionNewerThan1_21_2()) { - smithingRecipe = Reflections.constructor$RecipeHolder.newInstance(Reflections.method$CraftRecipe$toMinecraft.invoke(null, key), smithingRecipe); + nmsRecipe = Reflections.constructor$RecipeHolder.newInstance( + Reflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())), nmsRecipe); } else if (VersionHelper.isVersionNewerThan1_20_2()) { - smithingRecipe = Reflections.constructor$RecipeHolder.newInstance(Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, key.namespace(), key.value()), smithingRecipe); + nmsRecipe = Reflections.constructor$RecipeHolder.newInstance( + Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, id.namespace(), id.value()), nmsRecipe); + } else { + return () -> {}; } - Reflections.method$RecipeManager$addRecipe.invoke(minecraftRecipeManager(), smithingRecipe); + Object finalNmsRecipe = nmsRecipe; + return () -> registerNMSSmithingRecipe(finalNmsRecipe); } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert transform recipe", e); + CraftEngine.instance().logger().warn("Failed to convert smithing transform recipe", e); + return null; } }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SHAPED, (key, recipe) -> { - CustomShapedRecipe ceRecipe = (CustomShapedRecipe) recipe; - ShapedRecipe shapedRecipe = new ShapedRecipe(key, ceRecipe.result(ItemBuildContext.EMPTY)); - if (ceRecipe.group() != null) { - shapedRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - shapedRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - shapedRecipe.shape(ceRecipe.pattern().pattern()); - for (Map.Entry> entry : ceRecipe.pattern().ingredients().entrySet()) { + // TODO DO NOT USE BUKKIT RECIPE AS BRIDGE IN FUTURE VERSIONS, WE SHOULD DIRECTLY CONSTRUCT THOSE NMS RECIPES + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SHAPED, (BukkitRecipeConvertor>) (id, recipe) -> { + ShapedRecipe shapedRecipe = new ShapedRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY)); + if (recipe.group() != null) shapedRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) shapedRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + shapedRecipe.shape(recipe.pattern().pattern()); + for (Map.Entry> entry : recipe.pattern().ingredients().entrySet()) { shapedRecipe.setIngredient(entry.getKey(), ingredientToBukkitRecipeChoice(entry.getValue())); } - try { - Object craftRecipe = Reflections.method$CraftShapedRecipe$fromBukkitRecipe.invoke(null, shapedRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectShapedRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert shaped recipe", e); - } + return () -> { + registerBukkitShapedRecipe(shapedRecipe); + injectShapedRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SHAPELESS, (key, recipe) -> { - CustomShapelessRecipe ceRecipe = (CustomShapelessRecipe) recipe; - ShapelessRecipe shapelessRecipe = new ShapelessRecipe(key, ceRecipe.result(ItemBuildContext.EMPTY)); - if (ceRecipe.group() != null) { - shapelessRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - shapelessRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - for (Ingredient ingredient : ceRecipe.ingredientsInUse()) { + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SHAPELESS, (BukkitRecipeConvertor>) (id, recipe) -> { + ShapelessRecipe shapelessRecipe = new ShapelessRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY)); + if (recipe.group() != null) shapelessRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) shapelessRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + for (Ingredient ingredient : recipe.ingredientsInUse()) { shapelessRecipe.addIngredient(ingredientToBukkitRecipeChoice(ingredient)); } - try { - Object craftRecipe = Reflections.method$CraftShapelessRecipe$fromBukkitRecipe.invoke(null, shapelessRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectShapelessRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert shapeless recipe", e); - } + return () -> { + registerBukkitShapelessRecipe(shapelessRecipe); + injectShapelessRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SMELTING, (key, recipe) -> { - CustomSmeltingRecipe ceRecipe = (CustomSmeltingRecipe) recipe; + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMELTING, (BukkitRecipeConvertor>) (id, recipe) -> { FurnaceRecipe furnaceRecipe = new FurnaceRecipe( - key, ceRecipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), - ceRecipe.experience(), ceRecipe.cookingTime() + new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), + ingredientToBukkitRecipeChoice(recipe.ingredient()), + recipe.experience(), recipe.cookingTime() ); - if (ceRecipe.group() != null) { - furnaceRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - furnaceRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - try { - Object craftRecipe = Reflections.method$CraftFurnaceRecipe$fromBukkitRecipe.invoke(null, furnaceRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectCookingRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert smelting recipe", e); - } + if (recipe.group() != null) furnaceRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) furnaceRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + return () -> { + registerBukkitSmeltingRecipe(furnaceRecipe); + injectCookingRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SMOKING, (key, recipe) -> { - CustomSmokingRecipe ceRecipe = (CustomSmokingRecipe) recipe; + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMOKING, (BukkitRecipeConvertor>) (id, recipe) -> { SmokingRecipe smokingRecipe = new SmokingRecipe( - key, ceRecipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), - ceRecipe.experience(), ceRecipe.cookingTime() + new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), + ingredientToBukkitRecipeChoice(recipe.ingredient()), + recipe.experience(), recipe.cookingTime() ); - if (ceRecipe.group() != null) { - smokingRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - smokingRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - try { - Object craftRecipe = Reflections.method$CraftSmokingRecipe$fromBukkitRecipe.invoke(null, smokingRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectCookingRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert smoking recipe", e); - } + if (recipe.group() != null) smokingRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) smokingRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + return () -> { + registerBukkitSmokingRecipe(smokingRecipe); + injectCookingRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.BLASTING, (key, recipe) -> { - CustomBlastingRecipe ceRecipe = (CustomBlastingRecipe) recipe; + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.BLASTING, (BukkitRecipeConvertor>) (id, recipe) -> { BlastingRecipe blastingRecipe = new BlastingRecipe( - key, ceRecipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), - ceRecipe.experience(), ceRecipe.cookingTime() + new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), + ingredientToBukkitRecipeChoice(recipe.ingredient()), + recipe.experience(), recipe.cookingTime() ); - if (ceRecipe.group() != null) { - blastingRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - blastingRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - try { - Object craftRecipe = Reflections.method$CraftBlastingRecipe$fromBukkitRecipe.invoke(null, blastingRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectCookingRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert blasting recipe", e); - } + if (recipe.group() != null) blastingRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) blastingRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + return () -> { + registerBukkitBlastingRecipe(blastingRecipe); + injectCookingRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.CAMPFIRE_COOKING, (key, recipe) -> { - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) recipe; + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.CAMPFIRE_COOKING, (BukkitRecipeConvertor>) (id, recipe) -> { CampfireRecipe campfireRecipe = new CampfireRecipe( - key, ceRecipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), - ceRecipe.experience(), ceRecipe.cookingTime() + new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), + ingredientToBukkitRecipeChoice(recipe.ingredient()), + recipe.experience(), recipe.cookingTime() ); - if (ceRecipe.group() != null) { - campfireRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - campfireRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - try { - Object craftRecipe = Reflections.method$CraftCampfireRecipe$fromBukkitRecipe.invoke(null, campfireRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectCookingRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert campfire recipe", e); - } + if (recipe.group() != null) campfireRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) campfireRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + return () -> { + registerBukkitCampfireRecipe(campfireRecipe); + injectCookingRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.STONECUTTING, (key, recipe) -> { - CustomStoneCuttingRecipe ceRecipe = (CustomStoneCuttingRecipe) recipe; + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.STONECUTTING, (BukkitRecipeConvertor>) (id, recipe) -> { List itemStacks = new ArrayList<>(); - for (Holder item : ceRecipe.ingredient().items()) { + for (Holder item : recipe.ingredient().items()) { itemStacks.add(BukkitItemManager.instance().buildItemStack(item.value(), null)); } StonecuttingRecipe stonecuttingRecipe = new StonecuttingRecipe( - key, ceRecipe.result(ItemBuildContext.EMPTY), + new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), new RecipeChoice.ExactChoice(itemStacks) ); - if (ceRecipe.group() != null) { - stonecuttingRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - try { - Object craftRecipe = Reflections.method$CraftStonecuttingRecipe$fromBukkitRecipe.invoke(null, stonecuttingRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert stone cutting recipe", e); - } + if (recipe.group() != null) stonecuttingRecipe.setGroup(Objects.requireNonNull(recipe.group())); + return () -> { + registerBukkitStoneCuttingRecipe(stonecuttingRecipe); + }; }); } + /* + * 注册全过程: + * + * 0.准备阶段偷取flag以减少注册的性能开销 + * 1.先读取用户配置自定义配方 + * 2.延迟加载中为自定义配方生成转换为nms配方的任务 + * 3.读取全部的数据包配方并转换为自定义配方,对必要的含有tag配方添加先移除后注册nms配方的任务 + * 4.主线程完成剩余任务 + * 5.归还flag + */ + private final BukkitCraftEngine plugin; private final RecipeEventListener recipeEventListener; private final CrafterEventListener crafterEventListener; - private final Map>> byType; - private final Map> byId; - private final Map>> byResult; - private final Map>> byIngredient; - private final VanillaRecipeReader recipeReader; - private final List injectedDataPackRecipes; - private final List registeredCustomRecipes; - // data pack recipe resource locations [minecraft:xxx] - private final Set dataPackRecipes; - + // To optimize recipes loading, will return the flag later private Object stolenFeatureFlagSet; + // Some delayed tasks on main thread + private final List delayedTasksOnMainThread = new ArrayList<>(); public BukkitRecipeManager(BukkitCraftEngine plugin) { instance = this; this.plugin = plugin; - this.byType = new HashMap<>(); - this.byId = new HashMap<>(); - this.byIngredient = new HashMap<>(); - this.byResult = new HashMap<>(); - this.injectedDataPackRecipes = new ArrayList<>(); - this.registeredCustomRecipes = new ArrayList<>(); - this.dataPackRecipes = new HashSet<>(); this.recipeEventListener = new RecipeEventListener(plugin, this, plugin.itemManager()); - if (VersionHelper.isVersionNewerThan1_21()) { - this.crafterEventListener = new CrafterEventListener(plugin, this, plugin.itemManager()); - } else { - this.crafterEventListener = null; - } - if (VersionHelper.isVersionNewerThan1_21_2()) { - this.recipeReader = new VanillaRecipeReader1_21_2(); - } else if (VersionHelper.isVersionNewerThan1_20_5()) { - this.recipeReader = new VanillaRecipeReader1_20_5(); - } else { - this.recipeReader = new VanillaRecipeReader1_20(); - } + this.crafterEventListener = VersionHelper.isVersionNewerThan1_21() ? new CrafterEventListener(plugin, this, plugin.itemManager()) : null; try { - minecraftRecipeManager = Reflections.method$MinecraftServer$getRecipeManager.invoke(Reflections.method$MinecraftServer$getServer.invoke(null)); + nmsRecipeManager = Reflections.method$MinecraftServer$getRecipeManager.invoke(Reflections.method$MinecraftServer$getServer.invoke(null)); } catch (ReflectiveOperationException e) { plugin.logger().warn("Failed to get minecraft recipe manager", e); } } - @Override - public boolean isDataPackRecipe(Key key) { - return this.dataPackRecipes.contains(key); + public Object nmsRecipeHolderByRecipe(Recipe recipe) { + return recipeToMcRecipeHolder.get(recipe); } - @Override - public boolean isCustomRecipe(Key key) { - return this.byId.containsKey(key); + public static Object nmsRecipeManager() { + return nmsRecipeManager; } - @Override - public Optional> getRecipeById(Key key) { - return Optional.ofNullable(this.byId.get(key)); + public static BukkitRecipeManager instance() { + return instance; } @Override @@ -291,8 +287,8 @@ public class BukkitRecipeManager implements RecipeManager { if (!ConfigManager.enableRecipeSystem()) return; if (VersionHelper.isVersionNewerThan1_21_2()) { try { - this.stolenFeatureFlagSet = Reflections.field$RecipeManager$featureflagset.get(minecraftRecipeManager); - Reflections.field$RecipeManager$featureflagset.set(minecraftRecipeManager, null); + this.stolenFeatureFlagSet = Reflections.field$RecipeManager$featureflagset.get(nmsRecipeManager); + Reflections.field$RecipeManager$featureflagset.set(nmsRecipeManager, null); } catch (ReflectiveOperationException e) { this.plugin.logger().warn("Failed to steal featureflagset", e); } @@ -301,370 +297,235 @@ public class BukkitRecipeManager implements RecipeManager { @Override public void unload() { - this.byType.clear(); - this.byId.clear(); - this.byResult.clear(); - this.byIngredient.clear(); - this.dataPackRecipes.clear(); - + super.unload(); try { - // do not unregister them -// for (NamespacedKey key : this.injectedDataPackRecipes) { -// unregisterRecipe(key); -// } - for (NamespacedKey key : this.registeredCustomRecipes) { - unregisterRecipe(key); - } if (VersionHelper.isVersionNewerThan1_21_2()) { - Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(minecraftRecipeManager); + Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager); } } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to unregister recipes", e); + this.plugin.logger().warn("Failed to unregister recipes", e); } - - this.registeredCustomRecipes.clear(); - this.injectedDataPackRecipes.clear(); - recipeToMcRecipeHolder.clear(); } + @Override + public void delayedLoad() { + this.injectDataPackRecipes(); + } + @Override public void disable() { + unload(); HandlerList.unregisterAll(this.recipeEventListener); if (this.crafterEventListener != null) { HandlerList.unregisterAll(this.crafterEventListener); } - unload(); - } - - private void unregisterRecipe(NamespacedKey key) throws ReflectiveOperationException { - if (VersionHelper.isVersionNewerThan1_21_2()) { - Object recipeMap = Reflections.field$RecipeManager$recipes.get(minecraftRecipeManager); - Reflections.method$RecipeMap$removeRecipe.invoke(recipeMap, Reflections.method$CraftRecipe$toMinecraft.invoke(null, key)); - } else { - Bukkit.removeRecipe(key); - } } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - if (!ConfigManager.enableRecipeSystem()) return; - if (this.byId.containsKey(id)) { - this.plugin.logger().warn(path, "Duplicated recipe " + id); - return; - } - Recipe recipe = RecipeTypes.fromMap(id, section); - NamespacedKey key = NamespacedKey.fromString(id.toString()); - BUKKIT_RECIPE_FACTORIES.get(recipe.type()).accept(key, recipe); + protected void unregisterPlatformRecipe(Key key) { + unregisterNMSRecipe(new NamespacedKey(key.namespace(), key.value())); + } + + @Override + protected void registerPlatformRecipe(Key id, Recipe recipe) { try { - this.registeredCustomRecipes.add(key); - addInternalRecipe(id, recipe); + Runnable converted = findNMSRecipeConvertor(recipe).convert(id, recipe); + if (converted != null) { + this.delayedTasksOnMainThread.add(converted); + } } catch (Exception e) { - plugin.logger().warn("Failed to add custom recipe " + id, e); + this.plugin.logger().warn("Failed to convert recipe " + id, e); } } - @Override - public List> getRecipes(Key type) { - return this.byType.getOrDefault(type, List.of()); - } - - @Override - public List> getRecipeByResult(Key result) { - return this.byResult.getOrDefault(result, List.of()); - } - - @Override - public List> getRecipeByIngredient(Key ingredient) { - return this.byIngredient.getOrDefault(ingredient, List.of()); - } - - private void addInternalRecipe(Key id, Recipe recipe) { - this.byType.computeIfAbsent(recipe.type(), k -> new ArrayList<>()).add(recipe); - this.byId.put(id, recipe); - this.byResult.computeIfAbsent(recipe.result().item().id(), k -> new ArrayList<>()).add(recipe); - HashSet usedKeys = new HashSet<>(); - for (Ingredient ingredient : recipe.ingredientsInUse()) { - for (Holder holder : ingredient.items()) { - Key key = holder.value(); - if (usedKeys.add(key)) { - this.byIngredient.computeIfAbsent(key, k -> new ArrayList<>()).add(recipe); - } - } - } - } - - @Nullable - @Override - public Recipe getRecipe(Key type, RecipeInput input) { - List> recipes = this.byType.get(type); - if (recipes == null) return null; - for (Recipe recipe : recipes) { - if (recipe.matches(input)) { - return recipe; - } - } - return null; - } - - @Nullable - @Override - public Recipe getRecipe(Key type, RecipeInput input, Key lastRecipe) { - if (lastRecipe != null) { - Recipe last = byId.get(lastRecipe); - if (last != null && last.matches(input)) { - return last; - } - } - return getRecipe(type, input); - } - - @Override - public CompletableFuture asyncDelayedLoad() { - if (!ConfigManager.enableRecipeSystem()) return CompletableFuture.completedFuture(null); - return this.processVanillaRecipes().thenRun(() -> { - try { - // give flags back on 1.21.2+ - if (VersionHelper.isVersionNewerThan1_21_2() && this.stolenFeatureFlagSet != null) { - Reflections.field$RecipeManager$featureflagset.set(minecraftRecipeManager, this.stolenFeatureFlagSet); - this.stolenFeatureFlagSet = false; - } - - // refresh recipes - if (VersionHelper.isVersionNewerThan1_21_2()) { - Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(minecraftRecipeManager); - } - - // send to players - Reflections.method$DedicatedPlayerList$reloadRecipes.invoke(Reflections.field$CraftServer$playerList.get(Bukkit.getServer())); - - // now we need to remove the fake `exact` - if (VersionHelper.isVersionNewerThan1_21_4()) { - for (Object ingredient : injectedIngredients) { - Reflections.field$Ingredient$itemStacks1_21_4.set(ingredient, null); - } - } else if (VersionHelper.isVersionNewerThan1_21_2()) { - for (Object ingredient : injectedIngredients) { - Reflections.field$Ingredient$itemStacks1_21_2.set(ingredient, null); - } - } - - // clear cache - injectedIngredients.clear(); - } catch (Exception e) { - this.plugin.logger().warn("Failed to run delayed recipe tasks", e); - } - }); - } - @SuppressWarnings("unchecked") - private CompletableFuture processVanillaRecipes() { - CompletableFuture future = new CompletableFuture<>(); + private > BukkitRecipeConvertor findNMSRecipeConvertor(T recipe) { + return (BukkitRecipeConvertor) MIXED_RECIPE_CONVERTORS.get(recipe.type()); + } + + private void unregisterNMSRecipe(NamespacedKey key) { try { - List injectLogics = new ArrayList<>(); - plugin.scheduler().async().execute(() -> { - try { - Object fileToIdConverter = Reflections.method$FileToIdConverter$json.invoke(null, VersionHelper.isVersionNewerThan1_21() ? "recipe" : "recipes"); - Object minecraftServer = Reflections.method$MinecraftServer$getServer.invoke(null); - Object packRepository = Reflections.method$MinecraftServer$getPackRepository.invoke(minecraftServer); - List selected = (List) Reflections.field$PackRepository$selected.get(packRepository); - List packResources = new ArrayList<>(); - for (Object pack : selected) { - packResources.add(Reflections.method$Pack$open.invoke(pack)); - } - try (AutoCloseable resourceManager = (AutoCloseable) Reflections.constructor$MultiPackResourceManager.newInstance(Reflections.instance$PackType$SERVER_DATA, packResources)) { - Map scannedResources = (Map) Reflections.method$FileToIdConverter$listMatchingResources.invoke(fileToIdConverter, resourceManager); - for (Map.Entry entry : scannedResources.entrySet()) { - Key id = extractKeyFromResourceLocation(entry.getKey().toString()); - this.dataPackRecipes.add(id); - // Maybe it's unregistered by other plugins - if (Bukkit.getRecipe(new NamespacedKey(id.namespace(), id.value())) == null) { - continue; - } - Reader reader = (Reader) Reflections.method$Resource$openAsReader.invoke(entry.getValue()); - JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); - String type = jsonObject.get("type").getAsString(); - switch (type) { - case "minecraft:crafting_shaped" -> { - VanillaShapedRecipe recipe = this.recipeReader.readShaped(jsonObject); - handleDataPackShapedRecipe(id, recipe, (injectLogics::add)); - } - case "minecraft:crafting_shapeless" -> { - VanillaShapelessRecipe recipe = this.recipeReader.readShapeless(jsonObject); - handleDataPackShapelessRecipe(id, recipe, (injectLogics::add)); - } - case "minecraft:smelting" -> { - VanillaSmeltingRecipe recipe = this.recipeReader.readSmelting(jsonObject); - handleDataPackCookingRecipe(id, recipe, FurnaceRecipe::new, CustomSmeltingRecipe::new, Reflections.method$CraftFurnaceRecipe$fromBukkitRecipe, (injectLogics::add)); - } - case "minecraft:blasting" -> { - VanillaBlastingRecipe recipe = this.recipeReader.readBlasting(jsonObject); - handleDataPackCookingRecipe(id, recipe, BlastingRecipe::new, CustomBlastingRecipe::new, Reflections.method$CraftBlastingRecipe$fromBukkitRecipe, (injectLogics::add)); - } - case "minecraft:smoking" -> { - VanillaSmokingRecipe recipe = this.recipeReader.readSmoking(jsonObject); - handleDataPackCookingRecipe(id, recipe, SmokingRecipe::new, CustomSmokingRecipe::new, Reflections.method$CraftSmokingRecipe$fromBukkitRecipe, (injectLogics::add)); - } - case "minecraft:campfire_cooking" -> { - VanillaCampfireRecipe recipe = this.recipeReader.readCampfire(jsonObject); - handleDataPackCookingRecipe(id, recipe, CampfireRecipe::new, CustomCampfireRecipe::new, Reflections.method$CraftCampfireRecipe$fromBukkitRecipe, (injectLogics::add)); - } - case "minecraft:stonecutting" -> { - VanillaStoneCuttingRecipe recipe = this.recipeReader.readStoneCutting(jsonObject); - handleDataPackStoneCuttingRecipe(id, recipe); - } - case "minecraft:smithing_transform" -> { - VanillaSmithingTransformRecipe recipe = this.recipeReader.readSmithingTransform(jsonObject); - handleDataPackSmithingTransform(id, recipe, (injectLogics::add)); - } - } - } - } - } catch (Exception e) { - plugin.logger().warn("Failed to read data pack recipes", e); - } finally { - plugin.scheduler().sync().run(() -> { - try { - for (Runnable runnable : injectLogics) { - runnable.run(); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to register recipes", e); - } finally { - future.complete(null); - } - }); - } - }); - } catch (Exception e) { - this.plugin.logger().warn("Failed to inject vanilla recipes", e); - } - return future; - } - - private boolean readVanillaIngredients(boolean hasCustomItemInTag, List ingredients, Consumer materialConsumer, Consumer> holderConsumer) { - for (String item : ingredients) { - if (item.charAt(0) == '#') { - Key tag = Key.from(item.substring(1)); - for (Material material : tagToMaterials(tag)) { - materialConsumer.accept(material); - } - if (!hasCustomItemInTag) { - if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { - hasCustomItemInTag = true; - } - } - for (Holder holder : plugin.itemManager().tagToItems(tag)) { - holderConsumer.accept(holder); - } + if (VersionHelper.isVersionNewerThan1_21_2()) { + Object recipeMap = Reflections.field$RecipeManager$recipes.get(nmsRecipeManager); + Reflections.method$RecipeMap$removeRecipe.invoke(recipeMap, Reflections.method$CraftRecipe$toMinecraft.invoke(null, key)); } else { - materialConsumer.accept(MaterialUtils.getMaterial(item)); - holderConsumer.accept(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); + Bukkit.removeRecipe(key); } + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to unregister nms recipes", e); } - return hasCustomItemInTag; } - private void handleDataPackShapelessRecipe(Key id, VanillaShapelessRecipe recipe, Consumer callback) { - NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); - ItemStack result = createResultStack(recipe.result()); - ShapelessRecipe shapelessRecipe = new ShapelessRecipe(key, result); - if (recipe.group() != null) { - shapelessRecipe.setGroup(recipe.group()); - } - if (recipe.category() != null) { - shapelessRecipe.setCategory(CraftingBookCategory.valueOf(recipe.category().name())); - } - - boolean hasCustomItemInTag = false; - List> ingredientList = new ArrayList<>(); - for (List list : recipe.ingredients()) { - Set materials = new HashSet<>(); - Set> holders = new HashSet<>(); - for (String item : list) { - if (item.charAt(0) == '#') { - Key tag = Key.of(item.substring(1)); - materials.addAll(tagToMaterials(tag)); - if (!hasCustomItemInTag) { - if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { - hasCustomItemInTag = true; + @SuppressWarnings("unchecked") + private void injectDataPackRecipes() { + try { + Object fileToIdConverter = Reflections.method$FileToIdConverter$json.invoke(null, VersionHelper.isVersionNewerThan1_21() ? "recipe" : "recipes"); + Object minecraftServer = Reflections.method$MinecraftServer$getServer.invoke(null); + Object packRepository = Reflections.method$MinecraftServer$getPackRepository.invoke(minecraftServer); + List selected = (List) Reflections.field$PackRepository$selected.get(packRepository); + List packResources = new ArrayList<>(); + for (Object pack : selected) { + packResources.add(Reflections.method$Pack$open.invoke(pack)); + } + try (AutoCloseable resourceManager = (AutoCloseable) Reflections.constructor$MultiPackResourceManager.newInstance(Reflections.instance$PackType$SERVER_DATA, packResources)) { + Map scannedResources = (Map) Reflections.method$FileToIdConverter$listMatchingResources.invoke(fileToIdConverter, resourceManager); + for (Map.Entry entry : scannedResources.entrySet()) { + Key id = extractKeyFromResourceLocation(entry.getKey().toString()); + // Maybe it's unregistered by other plugins + if (Bukkit.getRecipe(new NamespacedKey(id.namespace(), id.value())) == null) { + continue; + } + markAsDataPackRecipe(id); + Reader reader = (Reader) Reflections.method$Resource$openAsReader.invoke(entry.getValue()); + JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); + String type = jsonObject.get("type").getAsString(); + switch (type) { + case "minecraft:crafting_shaped" -> { + VanillaShapedRecipe recipe = this.recipeReader.readShaped(jsonObject); + handleDataPackShapedRecipe(id, recipe, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:crafting_shapeless" -> { + VanillaShapelessRecipe recipe = this.recipeReader.readShapeless(jsonObject); + handleDataPackShapelessRecipe(id, recipe, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:smelting" -> { + VanillaSmeltingRecipe recipe = this.recipeReader.readSmelting(jsonObject); + handleDataPackCookingRecipe(id, recipe, CustomSmeltingRecipe::new, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:blasting" -> { + VanillaBlastingRecipe recipe = this.recipeReader.readBlasting(jsonObject); + handleDataPackCookingRecipe(id, recipe, CustomBlastingRecipe::new, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:smoking" -> { + VanillaSmokingRecipe recipe = this.recipeReader.readSmoking(jsonObject); + handleDataPackCookingRecipe(id, recipe, CustomSmokingRecipe::new, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:campfire_cooking" -> { + VanillaCampfireRecipe recipe = this.recipeReader.readCampfire(jsonObject); + handleDataPackCookingRecipe(id, recipe, CustomCampfireRecipe::new, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:smithing_transform" -> { + VanillaSmithingTransformRecipe recipe = this.recipeReader.readSmithingTransform(jsonObject); + handleDataPackSmithingTransform(id, recipe, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:stonecutting" -> { + VanillaStoneCuttingRecipe recipe = this.recipeReader.readStoneCutting(jsonObject); + handleDataPackStoneCuttingRecipe(id, recipe); } } - holders.addAll(plugin.itemManager().tagToItems(tag)); - } else { - materials.add(MaterialUtils.getMaterial(item)); - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); } } - shapelessRecipe.addIngredient(new RecipeChoice.MaterialChoice(new ArrayList<>(materials))); - ingredientList.add(Ingredient.of(holders)); + } catch (Exception e) { + plugin.logger().warn("Failed to read data pack recipes", e); } + } - CustomShapelessRecipe ceRecipe = new CustomShapelessRecipe<>( - id, - recipe.category(), - recipe.group(), - ingredientList, - new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), result), recipe.result().count()) - ); - if (hasCustomItemInTag) { - callback.accept(() -> { - try { - unregisterRecipe(key); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(Reflections.method$CraftShapelessRecipe$fromBukkitRecipe.invoke(null, shapelessRecipe)); - injectShapelessRecipe(id, ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert shapeless recipe", e); + @Override + public void runSyncTasks() { + try { + // run delayed tasks + for (Runnable r : this.delayedTasksOnMainThread) { + r.run(); + } + this.delayedTasksOnMainThread.clear(); + + // give flags back on 1.21.2+ + if (VersionHelper.isVersionNewerThan1_21_2() && this.stolenFeatureFlagSet != null) { + Reflections.field$RecipeManager$featureflagset.set(nmsRecipeManager, this.stolenFeatureFlagSet); + this.stolenFeatureFlagSet = false; + } + + // refresh recipes + if (VersionHelper.isVersionNewerThan1_21_2()) { + Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager); + } + + // send to players + Reflections.method$DedicatedPlayerList$reloadRecipes.invoke(Reflections.field$CraftServer$playerList.get(Bukkit.getServer())); + + // now we need to remove the fake `exact` + if (VersionHelper.isVersionNewerThan1_21_4()) { + for (Object ingredient : injectedIngredients) { + Reflections.field$Ingredient$itemStacks1_21_4.set(ingredient, null); } - }); - this.injectedDataPackRecipes.add(key); + } else if (VersionHelper.isVersionNewerThan1_21_2()) { + for (Object ingredient : injectedIngredients) { + Reflections.field$Ingredient$itemStacks1_21_2.set(ingredient, null); + } + } + + // clear cache + injectedIngredients.clear(); + } catch (Exception e) { + this.plugin.logger().warn("Failed to run delayed recipe tasks", e); } - this.addInternalRecipe(id, ceRecipe); } private void handleDataPackStoneCuttingRecipe(Key id, VanillaStoneCuttingRecipe recipe) { ItemStack result = createResultStack(recipe.result()); Set> holders = new HashSet<>(); - for (String item : recipe.ingredient()) { if (item.charAt(0) == '#') { Key tag = Key.from(item.substring(1)); - holders.addAll(plugin.itemManager().tagToItems(tag)); + holders.addAll(this.plugin.itemManager().tagToItems(tag)); } else { holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); } } - CustomStoneCuttingRecipe ceRecipe = new CustomStoneCuttingRecipe<>( - id, - recipe.group(), - Ingredient.of(holders), + id, recipe.group(), Ingredient.of(holders), new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), result), recipe.result().count()) ); - this.addInternalRecipe(id, ceRecipe); + this.registerInternalRecipe(id, ceRecipe); } - private void handleDataPackShapedRecipe(Key id, VanillaShapedRecipe recipe, Consumer callback) { + private void handleDataPackShapelessRecipe(Key id, VanillaShapelessRecipe recipe, Consumer callback) { NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); ItemStack result = createResultStack(recipe.result()); - ShapedRecipe shapedRecipe = new ShapedRecipe(key, result); - if (recipe.group() != null) { - shapedRecipe.setGroup(recipe.group()); - } - if (recipe.category() != null) { - shapedRecipe.setCategory(CraftingBookCategory.valueOf(recipe.category().name())); - } - shapedRecipe.shape(recipe.pattern()); - boolean hasCustomItemInTag = false; - Map> ingredients = new HashMap<>(); - for (Map.Entry> entry : recipe.ingredients().entrySet()) { - Set materials = new HashSet<>(); + List> ingredientList = new ArrayList<>(); + for (List list : recipe.ingredients()) { Set> holders = new HashSet<>(); - for (String item : entry.getValue()) { + for (String item : list) { if (item.charAt(0) == '#') { - Key tag = Key.from(item.substring(1)); - materials.addAll(tagToMaterials(tag)); + Key tag = Key.of(item.substring(1)); + if (!hasCustomItemInTag) { + if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { + hasCustomItemInTag = true; + } + } + holders.addAll(plugin.itemManager().tagToItems(tag)); + } else { + holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); + } + } + ingredientList.add(Ingredient.of(holders)); + } + CustomShapelessRecipe ceRecipe = new CustomShapelessRecipe<>( + id, recipe.category(), recipe.group(), ingredientList, + new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), result), recipe.result().count()) + ); + if (hasCustomItemInTag) { + Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); + callback.accept(() -> { + unregisterNMSRecipe(key); + converted.run(); + }); + } + this.registerInternalRecipe(id, ceRecipe); + } + + private void handleDataPackShapedRecipe(Key id, VanillaShapedRecipe recipe, Consumer callback) { + NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); + ItemStack result = createResultStack(recipe.result()); + boolean hasCustomItemInTag = false; + Map> ingredients = new HashMap<>(); + for (Map.Entry> entry : recipe.ingredients().entrySet()) { + Set> holders = new HashSet<>(); + for (String item : entry.getValue()) { + if (item.charAt(0) == '#') { + Key tag = Key.from(item.substring(1)); if (!hasCustomItemInTag) { if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { hasCustomItemInTag = true; @@ -672,79 +533,48 @@ public class BukkitRecipeManager implements RecipeManager { } holders.addAll(plugin.itemManager().tagToItems(tag)); } else { - materials.add(MaterialUtils.getMaterial(item)); holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); } } - shapedRecipe.setIngredient(entry.getKey(), new RecipeChoice.MaterialChoice(new ArrayList<>(materials))); ingredients.put(entry.getKey(), Ingredient.of(holders)); } - CustomShapedRecipe ceRecipe = new CustomShapedRecipe<>( - id, - recipe.category(), - recipe.group(), + id, recipe.category(), recipe.group(), new CustomShapedRecipe.Pattern<>(recipe.pattern(), ingredients), new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), result), recipe.result().count()) ); if (hasCustomItemInTag) { + Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - try { - unregisterRecipe(key); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(Reflections.method$CraftShapedRecipe$fromBukkitRecipe.invoke(null, shapedRecipe)); - injectShapedRecipe(id, ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert shaped recipe", e); - } + unregisterNMSRecipe(key); + converted.run(); }); - this.injectedDataPackRecipes.add(key); } - this.addInternalRecipe(id, ceRecipe); + this.registerInternalRecipe(id, ceRecipe); } private void handleDataPackCookingRecipe(Key id, VanillaCookingRecipe recipe, - PentaFunction> constructor1, HeptaFunction, Integer, Float, CustomRecipeResult, CustomCookingRecipe> constructor2, - Method fromBukkitRecipeMethod, Consumer callback) { NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); ItemStack result = createResultStack(recipe.result()); - - Set materials = new HashSet<>(); Set> holders = new HashSet<>(); - - boolean hasCustomItemInTag = readVanillaIngredients(false, recipe.ingredient(), materials::add, holders::add); - org.bukkit.inventory.CookingRecipe cookingRecipe = constructor1.apply(key, result, new RecipeChoice.MaterialChoice(new ArrayList<>(materials)), recipe.experience(), recipe.cookingTime()); - if (recipe.group() != null) { - cookingRecipe.setGroup(recipe.group()); - } - if (recipe.category() != null) { - cookingRecipe.setCategory(CookingBookCategory.valueOf(recipe.category().name())); - } - + boolean hasCustomItemInTag = readVanillaIngredients(false, recipe.ingredient(), holders::add); CustomCookingRecipe ceRecipe = constructor2.apply( - id, - recipe.category(), - recipe.group(), + id, recipe.category(), recipe.group(), Ingredient.of(holders), - recipe.cookingTime(), - recipe.experience(), + recipe.cookingTime(), recipe.experience(), new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), result), recipe.result().count()) ); if (hasCustomItemInTag) { + Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - try { - unregisterRecipe(key); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(fromBukkitRecipeMethod.invoke(null, cookingRecipe)); - injectCookingRecipe(id, ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert smelting recipe", e); - } + unregisterNMSRecipe(key); + converted.run(); }); - this.injectedDataPackRecipes.add(key); } - this.addInternalRecipe(id, ceRecipe); + this.registerInternalRecipe(id, ceRecipe); } private void handleDataPackSmithingTransform(Key id, VanillaSmithingTransformRecipe recipe, Consumer callback) { @@ -752,17 +582,12 @@ public class BukkitRecipeManager implements RecipeManager { ItemStack result = createResultStack(recipe.result()); boolean hasCustomItemInTag; - Set additionMaterials = new HashSet<>(); Set> additionHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionMaterials::add, additionHolders::add); - - Set templateMaterials = new HashSet<>(); + hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionHolders::add); Set> templateHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateMaterials::add, templateHolders::add); - - Set baseMaterials = new HashSet<>(); + hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateHolders::add); Set> baseHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseMaterials::add, baseHolders::add); + hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseHolders::add); CustomSmithingTransformRecipe ceRecipe = new CustomSmithingTransformRecipe<>( id, @@ -774,43 +599,33 @@ public class BukkitRecipeManager implements RecipeManager { List.of() ); - SmithingTransformRecipe transformRecipe = new SmithingTransformRecipe(key, result, - new RecipeChoice.MaterialChoice(new ArrayList<>(templateMaterials)), - new RecipeChoice.MaterialChoice(new ArrayList<>(baseMaterials)), - new RecipeChoice.MaterialChoice(new ArrayList<>(additionMaterials)) - ); - if (hasCustomItemInTag) { + Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - try { - unregisterRecipe(key); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(Reflections.method$CraftSmithingTransformRecipe$fromBukkitRecipe.invoke(null, transformRecipe)); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert transform recipe", e); - } + unregisterNMSRecipe(key); + converted.run(); }); - this.injectedDataPackRecipes.add(key); } - this.addInternalRecipe(id, ceRecipe); + this.registerInternalRecipe(id, ceRecipe); } - private List tagToMaterials(Key tag) { - Set materials = new HashSet<>(); - List> holders = this.plugin.itemManager().tagToVanillaItems(tag); - if (holders != null) { - for (Holder holder : holders) { - materials.add(MaterialUtils.getMaterial(holder.value())); + private boolean readVanillaIngredients(boolean hasCustomItemInTag, List ingredients, Consumer> holderConsumer) { + for (String item : ingredients) { + if (item.charAt(0) == '#') { + Key tag = Key.from(item.substring(1)); + if (!hasCustomItemInTag) { + if (!this.plugin.itemManager().tagToCustomItems(tag).isEmpty()) { + hasCustomItemInTag = true; + } + } + for (Holder holder : this.plugin.itemManager().tagToItems(tag)) { + holderConsumer.accept(holder); + } + } else { + holderConsumer.accept(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); } } - List> customItems = this.plugin.itemManager().tagToCustomItems(tag); - if (customItems != null) { - for (Holder holder : customItems) { - this.plugin.itemManager().getCustomItem(holder.value()).ifPresent(it -> { - materials.add(MaterialUtils.getMaterial(it.material())); - }); - } - } - return new ArrayList<>(materials); + return hasCustomItemInTag; } private ItemStack createResultStack(RecipeResult result) { @@ -870,66 +685,81 @@ public class BukkitRecipeManager implements RecipeManager { return itemStacks; } - private static void injectShapedRecipe(Key id, CustomShapedRecipe recipe) throws ReflectiveOperationException { - List> actualIngredients = recipe.parsedPattern().ingredients() - .stream() - .filter(Optional::isPresent) - .map(Optional::get) - .toList(); + // 无论是什么注入什么配方类型的方法,其本质都是注入ingredient + private static void injectShapedRecipe(Key id, CustomShapedRecipe recipe) { + try { + List> actualIngredients = recipe.parsedPattern().ingredients() + .stream() + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); - Object shapedRecipe = getNMSRecipe(id); - recipeToMcRecipeHolder.put(recipe, shapedRecipe); - if (VersionHelper.isVersionNewerThan1_20_2()) { - shapedRecipe = Reflections.field$RecipeHolder$recipe.get(shapedRecipe); - } + Object shapedRecipe = getNMSRecipe(id); + recipeToMcRecipeHolder.put(recipe, shapedRecipe); + if (VersionHelper.isVersionNewerThan1_20_2()) { + shapedRecipe = Reflections.field$RecipeHolder$recipe.get(shapedRecipe); + } - if (VersionHelper.isVersionNewerThan1_21_2()) { - Reflections.field$ShapedRecipe$placementInfo.set(shapedRecipe, null); + if (VersionHelper.isVersionNewerThan1_21_2()) { + Reflections.field$ShapedRecipe$placementInfo.set(shapedRecipe, null); + } + + List ingredients = RecipeUtils.getIngredientsFromShapedRecipe(shapedRecipe); + injectIngredients(ingredients, actualIngredients); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to inject shaped recipe", e); } - List ingredients = RecipeUtils.getIngredientsFromShapedRecipe(shapedRecipe); - injectIngredients(ingredients, actualIngredients); } - @SuppressWarnings("unchecked") - private static void injectShapelessRecipe(Key id, CustomShapelessRecipe recipe) throws ReflectiveOperationException { - List> actualIngredients = recipe.ingredientsInUse(); + private static void injectShapelessRecipe(Key id, CustomShapelessRecipe recipe) { + try { + List> actualIngredients = recipe.ingredientsInUse(); - Object shapelessRecipe = getNMSRecipe(id); - recipeToMcRecipeHolder.put(recipe, shapelessRecipe); - if (VersionHelper.isVersionNewerThan1_20_2()) { - shapelessRecipe = Reflections.field$RecipeHolder$recipe.get(shapelessRecipe); - } + Object shapelessRecipe = getNMSRecipe(id); + recipeToMcRecipeHolder.put(recipe, shapelessRecipe); + if (VersionHelper.isVersionNewerThan1_20_2()) { + shapelessRecipe = Reflections.field$RecipeHolder$recipe.get(shapelessRecipe); + } - if (VersionHelper.isVersionNewerThan1_21_2()) { - Reflections.field$ShapelessRecipe$placementInfo.set(shapelessRecipe, null); + if (VersionHelper.isVersionNewerThan1_21_2()) { + Reflections.field$ShapelessRecipe$placementInfo.set(shapelessRecipe, null); + } + @SuppressWarnings("unchecked") + List ingredients = (List) Reflections.field$ShapelessRecipe$ingredients.get(shapelessRecipe); + injectIngredients(ingredients, actualIngredients); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to inject shapeless recipe", e); } - List ingredients = (List) Reflections.field$ShapelessRecipe$ingredients.get(shapelessRecipe); - injectIngredients(ingredients, actualIngredients); } - private static void injectCookingRecipe(Key id, CustomCookingRecipe recipe) throws ReflectiveOperationException { - Ingredient actualIngredient = recipe.ingredient(); - Object smeltingRecipe = getNMSRecipe(id); - recipeToMcRecipeHolder.put(recipe, smeltingRecipe); - if (VersionHelper.isVersionNewerThan1_20_2()) { - smeltingRecipe = Reflections.field$RecipeHolder$recipe.get(smeltingRecipe); - } + private static void injectCookingRecipe(Key id, CustomCookingRecipe recipe) { + try { + Ingredient actualIngredient = recipe.ingredient(); + Object smeltingRecipe = getNMSRecipe(id); + recipeToMcRecipeHolder.put(recipe, smeltingRecipe); + if (VersionHelper.isVersionNewerThan1_20_2()) { + smeltingRecipe = Reflections.field$RecipeHolder$recipe.get(smeltingRecipe); + } - Object ingredient; - if (VersionHelper.isVersionNewerThan1_21_2()) { - ingredient = Reflections.field$SingleItemRecipe$input.get(smeltingRecipe); - } else { - ingredient = Reflections.field$AbstractCookingRecipe$input.get(smeltingRecipe); + Object ingredient; + if (VersionHelper.isVersionNewerThan1_21_2()) { + ingredient = Reflections.field$SingleItemRecipe$input.get(smeltingRecipe); + } else { + ingredient = Reflections.field$AbstractCookingRecipe$input.get(smeltingRecipe); + } + injectIngredients(List.of(ingredient), List.of(actualIngredient)); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to inject cooking recipe", e); } - injectIngredients(List.of(ingredient), List.of(actualIngredient)); } + // 获取nms配方,请注意1.20.1获取配方本身,而1.20.2+获取的是配方的holder // recipe on 1.20.1 and holder on 1.20.2+ private static Object getNMSRecipe(Key id) throws ReflectiveOperationException { if (VersionHelper.isVersionNewerThan1_21_2()) { Object resourceKey = Reflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())); @SuppressWarnings("unchecked") - Optional optional = (Optional) Reflections.method$RecipeManager$byKey.invoke(minecraftRecipeManager, resourceKey); + Optional optional = (Optional) Reflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceKey); if (optional.isEmpty()) { throw new IllegalArgumentException("Recipe " + id + " not found"); } @@ -937,7 +767,7 @@ public class BukkitRecipeManager implements RecipeManager { } else { Object resourceLocation = Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, id.namespace(), id.value()); @SuppressWarnings("unchecked") - Optional optional = (Optional) Reflections.method$RecipeManager$byKey.invoke(minecraftRecipeManager, resourceLocation); + Optional optional = (Optional) Reflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceLocation); if (optional.isEmpty()) { throw new IllegalArgumentException("Recipe " + id + " not found"); } @@ -945,12 +775,14 @@ public class BukkitRecipeManager implements RecipeManager { } } - private static void injectIngredients(List ingredients, List> actualIngredients) throws ReflectiveOperationException { - if (ingredients.size() != actualIngredients.size()) { + // 注入原料,这个方法受不同服务端fork和版本影响极大,需要每个版本测试 + // 此过程是为了避免自己处理“广义”配方与客户端的注册通讯 + private static void injectIngredients(List fakeIngredients, List> actualIngredients) throws ReflectiveOperationException { + if (fakeIngredients.size() != actualIngredients.size()) { throw new IllegalArgumentException("Ingredient count mismatch"); } - for (int i = 0; i < ingredients.size(); i++) { - Object ingredient = ingredients.get(i); + for (int i = 0; i < fakeIngredients.size(); i++) { + Object ingredient = fakeIngredients.get(i); Ingredient actualIngredient = actualIngredients.get(i); List items = getIngredientLooks(actualIngredient.items()); if (VersionHelper.isVersionNewerThan1_21_4()) { @@ -996,48 +828,37 @@ public class BukkitRecipeManager implements RecipeManager { return Reflections.constructor$TransmuteResult.newInstance(nmsItem); } - private static Object createMinecraftSmithingTransformRecipe(CustomSmithingTransformRecipe ceRecipe) throws ReflectiveOperationException { + // create nms smithing recipe for different versions + private static Object createMinecraftSmithingTransformRecipe(CustomSmithingTransformRecipe recipe) throws ReflectiveOperationException { if (VersionHelper.isVersionNewerThan1_21_5()) { return Reflections.constructor$SmithingTransformRecipe.newInstance( - toOptionalMinecraftIngredient(ceRecipe.template()), - toMinecraftIngredient(ceRecipe.base()), - toOptionalMinecraftIngredient(ceRecipe.addition()), - toTransmuteResult(ceRecipe.result(ItemBuildContext.EMPTY)) + toOptionalMinecraftIngredient(recipe.template()), + toMinecraftIngredient(recipe.base()), + toOptionalMinecraftIngredient(recipe.addition()), + toTransmuteResult(recipe.result(ItemBuildContext.EMPTY)) ); } else if (VersionHelper.isVersionNewerThan1_21_2()) { return Reflections.constructor$SmithingTransformRecipe.newInstance( - toOptionalMinecraftIngredient(ceRecipe.template()), - toOptionalMinecraftIngredient(ceRecipe.base()), - toOptionalMinecraftIngredient(ceRecipe.addition()), - Reflections.method$CraftItemStack$asNMSCopy.invoke(null, ceRecipe.result(ItemBuildContext.EMPTY)) + toOptionalMinecraftIngredient(recipe.template()), + toOptionalMinecraftIngredient(recipe.base()), + toOptionalMinecraftIngredient(recipe.addition()), + Reflections.method$CraftItemStack$asNMSCopy.invoke(null, recipe.result(ItemBuildContext.EMPTY)) ); } else if (VersionHelper.isVersionNewerThan1_20_2()) { return Reflections.constructor$SmithingTransformRecipe.newInstance( - toMinecraftIngredient(ceRecipe.template()), - toMinecraftIngredient(ceRecipe.base()), - toMinecraftIngredient(ceRecipe.addition()), - Reflections.method$CraftItemStack$asNMSCopy.invoke(null, ceRecipe.result(ItemBuildContext.EMPTY)) + toMinecraftIngredient(recipe.template()), + toMinecraftIngredient(recipe.base()), + toMinecraftIngredient(recipe.addition()), + Reflections.method$CraftItemStack$asNMSCopy.invoke(null, recipe.result(ItemBuildContext.EMPTY)) ); } else { return Reflections.constructor$SmithingTransformRecipe.newInstance( - Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, ceRecipe.id().namespace(), ceRecipe.id().value()), - toMinecraftIngredient(ceRecipe.template()), - toMinecraftIngredient(ceRecipe.base()), - toMinecraftIngredient(ceRecipe.addition()), - Reflections.method$CraftItemStack$asNMSCopy.invoke(null, ceRecipe.result(ItemBuildContext.EMPTY)) + Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, recipe.id().namespace(), recipe.id().value()), + toMinecraftIngredient(recipe.template()), + toMinecraftIngredient(recipe.base()), + toMinecraftIngredient(recipe.addition()), + Reflections.method$CraftItemStack$asNMSCopy.invoke(null, recipe.result(ItemBuildContext.EMPTY)) ); } } - - public Object getRecipeHolderByRecipe(Recipe recipe) { - return recipeToMcRecipeHolder.get(recipe); - } - - public static Object minecraftRecipeManager() { - return minecraftRecipeManager; - } - - public static BukkitRecipeManager instance() { - return instance; - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java index d24bdec79..8d51b8b04 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java @@ -82,12 +82,12 @@ public class CrafterEventListener implements Listener { return; } - Recipe ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SHAPELESS, input); + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input); if (ceRecipe != null) { event.setResult(ceRecipe.result(ItemBuildContext.EMPTY)); return; } - ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SHAPED, input); + ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input); if (ceRecipe != null) { event.setResult(ceRecipe.result(ItemBuildContext.EMPTY)); return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 2a2f64bc8..de3dc7564 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -85,7 +85,7 @@ public class RecipeEventListener implements Listener { recipeType = RecipeTypes.SMOKING; } - Recipe ceRecipe = recipeManager.getRecipe(recipeType, input); + Recipe ceRecipe = recipeManager.recipeByInput(recipeType, input); // The item is an ingredient, we should never consider it as fuel firstly if (ceRecipe != null) return; @@ -345,7 +345,7 @@ public class RecipeEventListener implements Listener { try { @SuppressWarnings("unchecked") Optional optionalMCRecipe = (Optional) Reflections.method$RecipeManager$getRecipeFor1.invoke( - BukkitRecipeManager.minecraftRecipeManager(), + BukkitRecipeManager.nmsRecipeManager(), Reflections.instance$RecipeType$CAMPFIRE_COOKING, Reflections.constructor$SingleRecipeInput.newInstance(Reflections.method$CraftItemStack$asNMSCopy.invoke(null, itemStack)), FastNMS.INSTANCE.field$CraftWorld$ServerLevel(event.getPlayer().getWorld()), @@ -360,7 +360,7 @@ public class RecipeEventListener implements Listener { return; } SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input); + CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setCancelled(true); } @@ -392,7 +392,7 @@ public class RecipeEventListener implements Listener { } SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input); + CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setTotalCookTime(Integer.MAX_VALUE); return; @@ -427,7 +427,7 @@ public class RecipeEventListener implements Listener { } SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input); + CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setCancelled(true); return; @@ -802,14 +802,14 @@ public class RecipeEventListener implements Listener { BukkitServerPlayer serverPlayer = this.plugin.adapt(player); Key lastRecipe = serverPlayer.lastUsedRecipe(); - Recipe ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SHAPELESS, input, lastRecipe); + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input, lastRecipe); if (ceRecipe != null) { inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); serverPlayer.setLastUsedRecipe(ceRecipe.id()); correctCraftingRecipeUsed(inventory, ceRecipe); return; } - ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SHAPED, input, lastRecipe); + ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input, lastRecipe); if (ceRecipe != null) { inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); serverPlayer.setLastUsedRecipe(ceRecipe.id()); @@ -821,7 +821,7 @@ public class RecipeEventListener implements Listener { } private void correctCraftingRecipeUsed(CraftingInventory inventory, Recipe recipe) { - Object holderOrRecipe = recipeManager.getRecipeHolderByRecipe(recipe); + Object holderOrRecipe = recipeManager.nmsRecipeHolderByRecipe(recipe); if (holderOrRecipe == null) { // it's a vanilla recipe but not injected return; @@ -857,7 +857,7 @@ public class RecipeEventListener implements Listener { getOptimizedIDItem(addition) ); - Recipe ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SMITHING_TRANSFORM, input); + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SMITHING_TRANSFORM, input); if (ceRecipe == null) { event.setResult(null); return; @@ -878,7 +878,7 @@ public class RecipeEventListener implements Listener { } private void correctSmithingRecipeUsed(SmithingInventory inventory, Recipe recipe) { - Object holderOrRecipe = recipeManager.getRecipeHolderByRecipe(recipe); + Object holderOrRecipe = recipeManager.nmsRecipeHolderByRecipe(recipe); if (holderOrRecipe == null) { // it's a vanilla recipe but not injected return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index 9b755b212..e42e271d5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -200,8 +200,10 @@ public class BukkitCraftEngine extends CraftEngine { @Override public void reload() { super.reload(); - CraftEngineReloadEvent event = new CraftEngineReloadEvent(this); - EventUtils.fireAndForget(event); + scheduler.async().execute(() -> { + CraftEngineReloadEvent event = new CraftEngineReloadEvent(this); + EventUtils.fireAndForget(event); + }); } @Override @@ -211,32 +213,6 @@ public class BukkitCraftEngine extends CraftEngine { } } - @Override - protected void registerParsers() { - // register template parser - this.packManager.registerConfigSectionParser(this.templateManager); - // register font parser - this.packManager.registerConfigSectionParsers(this.fontManager.parsers()); - // register item parser - this.packManager.registerConfigSectionParser(this.itemManager); - // register furniture parser - this.packManager.registerConfigSectionParser(this.furnitureManager); - // register block parser - this.packManager.registerConfigSectionParser(this.blockManager); - // register recipe parser - this.packManager.registerConfigSectionParser(this.recipeManager); - // register category parser - this.packManager.registerConfigSectionParser(this.itemBrowserManager); - // register translation parser - this.packManager.registerConfigSectionParser(this.translationManager); - this.packManager.registerConfigSectionParser(this.translationManager.clientLangManager()); - // register sound parser - this.packManager.registerConfigSectionParser(this.soundManager); - this.packManager.registerConfigSectionParser(this.soundManager.jukeboxSongManager()); - // register vanilla loot parser - this.packManager.registerConfigSectionParser(this.vanillaLootManager); - } - @Override public InputStream resourceStream(String filePath) { return bootstrap.getResource(filePath.replace("\\", "/")); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java index cab37225a..e6fff1b0b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java @@ -34,16 +34,18 @@ public class ReloadCommand extends BukkitCommandFeature { argument = optional.get(); } if (argument == ReloadArgument.CONFIG) { - try { - RELOAD_PACK_FLAG = true; - long time1 = System.currentTimeMillis(); - plugin().reload(); - long time2 = System.currentTimeMillis(); - handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_SUCCESS, Component.text(time2 - time1)); - } catch (Exception e) { - handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_FAILURE); - plugin().logger().warn("Failed to reload config", e); - } + plugin().scheduler().executeAsync(() -> { + try { + RELOAD_PACK_FLAG = true; + long time1 = System.currentTimeMillis(); + plugin().reload(); + long time2 = System.currentTimeMillis(); + handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_SUCCESS, Component.text(time2 - time1)); + } catch (Exception e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_FAILURE); + plugin().logger().warn("Failed to reload config", e); + } + }); } else if (argument == ReloadArgument.PACK) { plugin().scheduler().executeAsync(() -> { try { @@ -57,23 +59,18 @@ public class ReloadCommand extends BukkitCommandFeature { } }); } else if (argument == ReloadArgument.ALL) { - long time1 = System.currentTimeMillis(); - try { + plugin().scheduler().executeAsync(() -> { + long time1 = System.currentTimeMillis(); plugin().reload(); - plugin().scheduler().executeAsync(() -> { - try { - plugin().packManager().generateResourcePack(); - long time2 = System.currentTimeMillis(); - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_SUCCESS, Component.text(time2 - time1)); - } catch (Exception e) { - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); - plugin().logger().warn("Failed to generate resource pack", e); - } - }); - } catch (Exception e) { - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); - plugin().logger().warn("Failed to reload config", e); - } + try { + plugin().packManager().generateResourcePack(); + long time2 = System.currentTimeMillis(); + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_SUCCESS, Component.text(time2 - time1)); + } catch (Exception e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); + plugin().logger().warn("Failed to generate resource pack", e); + } + }); } }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java index 5c4dfee42..c5c7847f5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java @@ -47,7 +47,7 @@ public class SearchRecipeAdminCommand extends BukkitCommandFeature> inRecipes = plugin().recipeManager().getRecipeByResult(itemId); + List> inRecipes = plugin().recipeManager().recipeByResult(itemId); if (!inRecipes.isEmpty()) { plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipePlayerCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipePlayerCommand.java index 82fc61cff..1082e366a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipePlayerCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipePlayerCommand.java @@ -35,7 +35,7 @@ public class SearchRecipePlayerCommand extends BukkitCommandFeature> inRecipes = plugin().recipeManager().getRecipeByResult(itemId); + List> inRecipes = plugin().recipeManager().recipeByResult(itemId); if (!inRecipes.isEmpty()) { plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java index 313fbe932..034be222d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java @@ -47,7 +47,7 @@ public class SearchUsageAdminCommand extends BukkitCommandFeature for (Player player : players) { BukkitServerPlayer serverPlayer = plugin().adapt(player); Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value()); - List> inRecipes = plugin().recipeManager().getRecipeByIngredient(itemId); + List> inRecipes = plugin().recipeManager().recipeByIngredient(itemId); if (!inRecipes.isEmpty()) { plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java index 3494cfd3e..26e28808b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java @@ -35,7 +35,7 @@ public class SearchUsagePlayerCommand extends BukkitCommandFeature> inRecipes = plugin().recipeManager().getRecipeByIngredient(itemId); + List> inRecipes = plugin().recipeManager().recipeByIngredient(itemId); if (!inRecipes.isEmpty()) { plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java index 5be2a0711..74794df67 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java @@ -357,7 +357,7 @@ public class BukkitInjector { @SuppressWarnings("unchecked") @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); + Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object type = injectedCacheCheck.recipeType(); Object lastRecipe = injectedCacheCheck.lastRecipe(); @@ -394,13 +394,13 @@ public class BukkitInjector { CustomCookingRecipe ceRecipe; Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.BLASTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$CAMPFIRE_COOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); } else { return Optional.empty(); } @@ -412,7 +412,7 @@ public class BukkitInjector { injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all injectedCacheCheck.lastRecipe(resourceLocation); - return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(pair.getSecond())); + return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(pair.getSecond())); } else { return Optional.empty(); } @@ -425,7 +425,7 @@ public class BukkitInjector { @SuppressWarnings("unchecked") @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); + Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object type = injectedCacheCheck.recipeType(); Object lastRecipe = injectedCacheCheck.lastRecipe(); @@ -462,13 +462,13 @@ public class BukkitInjector { CustomCookingRecipe ceRecipe; Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.BLASTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$CAMPFIRE_COOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); } else { return Optional.empty(); } @@ -480,7 +480,7 @@ public class BukkitInjector { injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all injectedCacheCheck.lastRecipe(id); - return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(holder)); + return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder)); } else { return Optional.empty(); } @@ -493,7 +493,7 @@ public class BukkitInjector { @SuppressWarnings("unchecked") @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); + Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object type = injectedCacheCheck.recipeType(); Object lastRecipe = injectedCacheCheck.lastRecipe(); @@ -522,13 +522,13 @@ public class BukkitInjector { CustomCookingRecipe ceRecipe; Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.BLASTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$CAMPFIRE_COOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); } else { return Optional.empty(); } @@ -540,7 +540,7 @@ public class BukkitInjector { injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all injectedCacheCheck.lastRecipe(id); - return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(holder)); + return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder)); } else { return Optional.empty(); } @@ -553,7 +553,7 @@ public class BukkitInjector { @SuppressWarnings("unchecked") @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); + Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object type = injectedCacheCheck.recipeType(); Object lastRecipe = injectedCacheCheck.lastRecipe(); @@ -583,11 +583,11 @@ public class BukkitInjector { CustomCookingRecipe ceRecipe; Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.BLASTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); } else { return Optional.empty(); } @@ -599,7 +599,7 @@ public class BukkitInjector { injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all injectedCacheCheck.lastRecipe(id); - return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(holder)); + return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder)); } else { return Optional.empty(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java index f41f5437a..eeed1b749 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java @@ -79,14 +79,14 @@ public class InteractUtils { register(BlockKeys.SOUL_CAMPFIRE, (player, item, blockState, result) -> { if (!ConfigManager.enableRecipeSystem()) return false; Optional> optional = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(item.id()); - return optional.filter(keyReference -> BukkitRecipeManager.instance().getRecipe(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( + return optional.filter(keyReference -> BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( keyReference, item.getItem() ))) != null).isPresent(); }); register(BlockKeys.CAMPFIRE, (player, item, blockState, result) -> { if (!ConfigManager.enableRecipeSystem()) return false; Optional> optional = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(item.id()); - return optional.filter(keyReference -> BukkitRecipeManager.instance().getRecipe(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( + return optional.filter(keyReference -> BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( keyReference, item.getItem() ))) != null).isPresent(); }); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index fdd4f93a5..2f51310ce 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -68,7 +68,7 @@ public abstract class AbstractFontManager implements FontManager { @Override public Collection fonts() { - return new ArrayList<>(this.fonts.values()); + return Collections.unmodifiableCollection(this.fonts.values()); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java new file mode 100644 index 000000000..627900416 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java @@ -0,0 +1,183 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; +import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaRecipeReader; +import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20; +import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20_5; +import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_21_2; +import net.momirealms.craftengine.core.pack.LoadingSequence; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.*; + +public abstract class AbstractRecipeManager implements RecipeManager { + protected final VanillaRecipeReader recipeReader; + protected final Map>> byType = new HashMap<>(); + protected final Map> byId = new HashMap<>(); + protected final Map>> byResult = new HashMap<>(); + protected final Map>> byIngredient = new HashMap<>(); + protected final Set dataPackRecipes = new HashSet<>(); + protected final Set customRecipes = new HashSet<>(); + private final RecipeParser recipeParser; + + public AbstractRecipeManager() { + this.recipeReader = initVanillaRecipeReader(); + this.recipeParser = new RecipeParser(); + } + + @Override + public ConfigSectionParser parser() { + return this.recipeParser; + } + + private VanillaRecipeReader initVanillaRecipeReader() { + if (VersionHelper.isVersionNewerThan1_21_2()) { + return new VanillaRecipeReader1_21_2(); + } else if (VersionHelper.isVersionNewerThan1_20_5()) { + return new VanillaRecipeReader1_20_5(); + } else { + return new VanillaRecipeReader1_20(); + } + } + + @Override + public void unload() { + this.dataPackRecipes.clear(); + this.byType.clear(); + this.byId.clear(); + this.byResult.clear(); + this.byIngredient.clear(); + for (Key key : this.customRecipes) { + unregisterPlatformRecipe(key); + } + this.customRecipes.clear(); + } + + protected void markAsDataPackRecipe(Key key) { + this.dataPackRecipes.add(key); + } + + protected void markAsCustomRecipe(Key key) { + this.customRecipes.add(key); + } + + @Override + public boolean isDataPackRecipe(Key key) { + return this.dataPackRecipes.contains(key); + } + + @Override + public boolean isCustomRecipe(Key key) { + return this.byId.containsKey(key); + } + + @Override + public Optional> recipeById(Key key) { + return Optional.ofNullable(this.byId.get(key)); + } + + @Override + public List> recipesByType(Key type) { + return this.byType.getOrDefault(type, List.of()); + } + + @Override + public List> recipeByResult(Key result) { + return this.byResult.getOrDefault(result, List.of()); + } + + @Override + public List> recipeByIngredient(Key ingredient) { + return this.byIngredient.getOrDefault(ingredient, List.of()); + } + + @Nullable + @Override + public Recipe recipeByInput(Key type, RecipeInput input) { + List> recipes = this.byType.get(type); + if (recipes == null) return null; + for (Recipe recipe : recipes) { + if (recipe.matches(input)) { + return recipe; + } + } + return null; + } + + @Nullable + @Override + public Recipe recipeByInput(Key type, RecipeInput input, Key lastRecipe) { + if (lastRecipe != null) { + Recipe last = byId.get(lastRecipe); + if (last != null && last.matches(input)) { + return last; + } + } + return recipeByInput(type, input); + } + + protected void registerInternalRecipe(Key id, Recipe recipe) { + this.byType.computeIfAbsent(recipe.type(), k -> new ArrayList<>()).add(recipe); + this.byId.put(id, recipe); + this.byResult.computeIfAbsent(recipe.result().item().id(), k -> new ArrayList<>()).add(recipe); + HashSet usedKeys = new HashSet<>(); + for (Ingredient ingredient : recipe.ingredientsInUse()) { + for (Holder holder : ingredient.items()) { + Key key = holder.value(); + if (usedKeys.add(key)) { + this.byIngredient.computeIfAbsent(key, k -> new ArrayList<>()).add(recipe); + } + } + } + } + + public class RecipeParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"recipes", "recipe"}; + + @Override + public int loadingSequence() { + return LoadingSequence.RECIPE; + } + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + if (!ConfigManager.enableRecipeSystem()) return; + if (AbstractRecipeManager.this.byId.containsKey(id)) { + TranslationManager.instance().log("warning.config.recipe.duplicated", path.toString(), id.toString()); + return; + } + Recipe recipe; + try { + recipe = RecipeTypes.fromMap(id, section); + } catch (Exception e) { + CraftEngine.instance().logger().warn(path, "Failed to create recipe: " + id, e); + return; + } + try { + markAsCustomRecipe(id); + registerInternalRecipe(id, recipe); + registerPlatformRecipe(id, recipe); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to register custom recipe " + id, e); + } + } + } + + protected abstract void unregisterPlatformRecipe(Key key); + + protected abstract void registerPlatformRecipe(Key key, Recipe recipe); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java index 55556118f..3573ec789 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.Key; @@ -9,35 +8,28 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Optional; -import java.util.concurrent.CompletableFuture; -public interface RecipeManager extends Reloadable, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"recipes", "recipe"}; +public interface RecipeManager extends Reloadable { - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } + ConfigSectionParser parser(); boolean isDataPackRecipe(Key key); boolean isCustomRecipe(Key key); - Optional> getRecipeById(Key id); + Optional> recipeById(Key id); - List> getRecipes(Key type); + List> recipesByType(Key type); - List> getRecipeByResult(Key result); + List> recipeByResult(Key result); - List> getRecipeByIngredient(Key ingredient); + List> recipeByIngredient(Key ingredient); @Nullable - Recipe getRecipe(Key type, RecipeInput input); + Recipe recipeByInput(Key type, RecipeInput input); - @Nullable Recipe getRecipe(Key type, RecipeInput input, @Nullable Key lastRecipe); + @Nullable + Recipe recipeByInput(Key type, RecipeInput input, @Nullable Key lastRecipe); - CompletableFuture asyncDelayedLoad(); - - default int loadingSequence() { - return LoadingSequence.RECIPE; - } + void runSyncTasks(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 1f9d9826c..767a9edc0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -101,39 +101,43 @@ public abstract class CraftEngine implements Plugin { public void reload() { if (this.isReloading) return; this.isReloading = true; - try { - this.configManager.reload(); - this.translationManager.reload(); - this.templateManager.reload(); - this.furnitureManager.reload(); - this.fontManager.reload(); - this.itemManager.reload(); - this.soundManager.reload(); - this.recipeManager.reload(); - this.itemBrowserManager.reload(); - this.blockManager.reload(); - this.worldManager.reload(); - this.vanillaLootManager.reload(); - // load configs here - this.packManager.reload(); - // load at last - this.guiManager.reload(); - // delayed load - this.translationManager.delayedLoad(); - this.blockManager.delayedLoad(); - this.furnitureManager.delayedLoad(); - this.itemBrowserManager.delayedLoad(); - this.soundManager.delayedLoad(); - this.fontManager.delayedLoad(); - // reset debugger - if (ConfigManager.debug()) { - this.debugger = (s) -> logger.info("[Debug] " + s.get()); - } else { - this.debugger = (s) -> {}; - } - } finally { - this.recipeManager.asyncDelayedLoad().thenRun(() -> this.isReloading = false); + this.configManager.reload(); + this.translationManager.reload(); + this.templateManager.reload(); + this.furnitureManager.reload(); + this.fontManager.reload(); + this.itemManager.reload(); + this.soundManager.reload(); + this.recipeManager.reload(); + this.itemBrowserManager.reload(); + this.blockManager.reload(); + this.worldManager.reload(); + this.vanillaLootManager.reload(); + // load configs here + this.packManager.reload(); + // load at last + this.guiManager.reload(); + // delayed load + this.translationManager.delayedLoad(); + this.blockManager.delayedLoad(); + this.furnitureManager.delayedLoad(); + this.itemBrowserManager.delayedLoad(); + this.soundManager.delayedLoad(); + this.fontManager.delayedLoad(); + this.recipeManager.delayedLoad(); + // reset debugger + if (ConfigManager.debug()) { + this.debugger = (s) -> logger.info("[Debug] " + s.get()); + } else { + this.debugger = (s) -> {}; } + scheduler().sync().run(() -> { + try { + this.recipeManager.runSyncTasks(); + } finally { + this.isReloading = false; + } + }); } @Override @@ -181,7 +185,30 @@ public abstract class CraftEngine implements Plugin { ResourcePackHost.instance().disable(); } - protected abstract void registerParsers(); + protected void registerParsers() { + // register template parser + this.packManager.registerConfigSectionParser(this.templateManager); + // register font parser + this.packManager.registerConfigSectionParsers(this.fontManager.parsers()); + // register item parser + this.packManager.registerConfigSectionParser(this.itemManager); + // register furniture parser + this.packManager.registerConfigSectionParser(this.furnitureManager); + // register block parser + this.packManager.registerConfigSectionParser(this.blockManager); + // register recipe parser + this.packManager.registerConfigSectionParser(this.recipeManager.parser()); + // register category parser + this.packManager.registerConfigSectionParser(this.itemBrowserManager); + // register translation parser + this.packManager.registerConfigSectionParser(this.translationManager); + this.packManager.registerConfigSectionParser(this.translationManager.clientLangManager()); + // register sound parser + this.packManager.registerConfigSectionParser(this.soundManager); + this.packManager.registerConfigSectionParser(this.soundManager.jukeboxSongManager()); + // register vanilla loot parser + this.packManager.registerConfigSectionParser(this.vanillaLootManager); + } protected abstract void delayedEnable(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index cc496f346..4368de433 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -239,7 +239,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(itemId); + List> inRecipes = this.plugin.recipeManager().recipeByResult(itemId); player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); @@ -247,7 +247,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, itemId, e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(itemId); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(itemId); player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); @@ -288,7 +288,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { item.count(item.maxStackSize()); c.setItemOnCursor(item); } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(result); player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, true); @@ -377,7 +377,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(result); + List> inRecipes = this.plugin.recipeManager().recipeByResult(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -386,7 +386,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, result, e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -460,7 +460,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -469,7 +469,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -493,7 +493,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -502,7 +502,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -526,7 +526,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -535,7 +535,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -584,7 +584,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(result); + List> inRecipes = this.plugin.recipeManager().recipeByResult(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -593,7 +593,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, result, e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -620,7 +620,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -629,7 +629,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -717,7 +717,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(result); + List> inRecipes = this.plugin.recipeManager().recipeByResult(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -726,7 +726,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, result, e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -759,7 +759,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -768,7 +768,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -862,7 +862,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(result); + List> inRecipes = this.plugin.recipeManager().recipeByResult(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -871,7 +871,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, result, e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -954,7 +954,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -963,7 +963,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -997,7 +997,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -1006,7 +1006,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { From a3f7780902b1cfd94aef78adbec4fda9442bee8a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 03:36:27 +0800 Subject: [PATCH 12/37] refactor translation --- .../src/main/resources/translations/en.yml | 4 +- .../core/pack/AbstractPackManager.java | 2 +- .../core/pack/obfuscation/ObfC.java | 2 +- .../craftengine/core/plugin/CraftEngine.java | 3 +- .../core/plugin/dependency/Dependency.java | 2 +- .../core/plugin/locale/ClientLangManager.java | 56 -------- .../plugin/locale/ClientLangMangerImpl.java | 63 --------- .../plugin/locale/TranslationManager.java | 49 +++++-- .../plugin/locale/TranslationManagerImpl.java | 128 ++++++++++++++---- 9 files changed, 141 insertions(+), 168 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangMangerImpl.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 851f3889d..3c2e1dbed 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -54,7 +54,6 @@ command.search_usage.not_found: "No usage found for this item" command.search_recipe.no_item: "Please hold an item before running this command" command.search_usage.no_item: "Please hold an item before running this command" command.totem.not_totem: "'' is not type of totem_of_undying" - warning.config.image.lack_height: "Issue found in file - The image '' is missing the required 'height' argument." warning.config.image.height_smaller_than_ascent: "Issue found in file - The image '' violates the bitmap image rule: 'height' should be no lower than 'ascent'." warning.config.image.no_file: "Issue found in file - The image '' is missing the required 'file' argument." @@ -64,4 +63,5 @@ warning.config.image.lack_char: "Issue found in file - The image warning.config.image.codepoint_in_use: "Issue found in file - The image '' is using a character[()] in font that has been used by another image ''." warning.config.image.invalid_codepoint_grid: "Issue found in file - Image '' has an invalid 'chars' codepoint grind." warning.config.image.file_not_exist: "Issue found in file - PNG file not found for image ''." -warning.config.recipe.duplicated: "Issue found in file - Duplicated recipe ''." \ No newline at end of file +warning.config.recipe.duplicated: "Issue found in file - Duplicated recipe ''." +warning.config.i18n.unknown_locale: "Issue found in file - Unknown locale ''." \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 7b7c042b2..a15a65564 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -603,7 +603,7 @@ public abstract class AbstractPackManager implements PackManager { } private void generateClientLang(Path generatedPackPath) { - for (Map.Entry entry : this.plugin.translationManager().clientLangManager().langData().entrySet()) { + for (Map.Entry entry : this.plugin.translationManager().clientLangData().entrySet()) { JsonObject json = new JsonObject(); for (Map.Entry pair : entry.getValue().translations.entrySet()) { json.addProperty(pair.getKey(), pair.getValue()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfC.java b/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfC.java index ba8bb566e..8b9915326 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfC.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfC.java @@ -46,7 +46,7 @@ public class ObfC { } private static String normalizeCharset(String input) { - return input.toLowerCase(Locale.ROOT); + return input.toLowerCase(Locale.ENGLISH); } private static String generateDefaultCharset() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 767a9edc0..85633973f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -201,8 +201,7 @@ public abstract class CraftEngine implements Plugin { // register category parser this.packManager.registerConfigSectionParser(this.itemBrowserManager); // register translation parser - this.packManager.registerConfigSectionParser(this.translationManager); - this.packManager.registerConfigSectionParser(this.translationManager.clientLangManager()); + this.packManager.registerConfigSectionParsers(this.translationManager.parsers()); // register sound parser this.packManager.registerConfigSectionParser(this.soundManager); this.packManager.registerConfigSectionParser(this.soundManager.jukeboxSongManager()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependency.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependency.java index 0bf50cb9d..6a6c7e4b4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependency.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/Dependency.java @@ -55,7 +55,7 @@ public class Dependency { } public String fileName(String classifier) { - String name = customArtifactID.toLowerCase(Locale.ROOT).replace('_', '-'); + String name = customArtifactID.toLowerCase(Locale.ENGLISH).replace('_', '-'); String extra = classifier == null || classifier.isEmpty() ? "" : "-" + classifier; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java deleted file mode 100644 index 575ff8904..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangManager.java +++ /dev/null @@ -1,56 +0,0 @@ -package net.momirealms.craftengine.core.plugin.locale; - -import net.momirealms.craftengine.core.pack.LoadingSequence; -import net.momirealms.craftengine.core.plugin.Reloadable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; - -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -public interface ClientLangManager extends Reloadable, ConfigSectionParser { - Set ALL_LANG = Set.of( - "af_za", "ar_sa", "ast_es", "az_az", "ba_ru", "bar", "be_by", "be_latn", - "bg_bg", "br_fr", "brb", "bs_ba", "ca_es", "cs_cz", "cy_gb", "da_dk", - "de_at", "de_ch", "de_de", "el_gr", "en_au", "en_ca", "en_gb", "en_nz", - "en_pt", "en_ud", "en_us", "enp", "enws", "eo_uy", "es_ar", "es_cl", - "es_ec", "es_es", "es_mx", "es_uy", "es_ve", "esan", "et_ee", "eu_es", - "fa_ir", "fi_fi", "fil_ph", "fo_fo", "fr_ca", "fr_fr", "fra_de", "fur_it", - "fy_nl", "ga_ie", "gd_gb", "gl_es", "haw_us", "he_il", "hi_in", "hn_no", - "hr_hr", "hu_hu", "hy_am", "id_id", "ig_ng", "io_en", "is_is", "isv", - "it_it", "ja_jp", "jbo_en", "ka_ge", "kk_kz", "kn_in", "ko_kr", "ksh", - "kw_gb", "ky_kg", "la_la", "lb_lu", "li_li", "lmo", "lo_la", "lol_us", "lt_lt", - "lv_lv", "lzh", "mk_mk", "mn_mn", "ms_my", "mt_mt", "nah", "nds_de", - "nl_be", "nl_nl", "nn_no", "no_no", "oc_fr", "ovd", "pl_pl", "pls", - "pt_br", "pt_pt", "qya_aa", "ro_ro", "rpr", "ru_ru", "ry_ua", "sah_sah", - "se_no", "sk_sk", "sl_si", "so_so", "sq_al", "sr_cs", "sr_sp", "sv_se", - "sxu", "szl", "ta_in", "th_th", "tl_ph", "tlh_aa", "tok", "tr_tr", - "tt_ru", "tzo_mx", "uk_ua", "val_es", "vec_it", "vi_vn", "vp_vl", "yi_de", - "yo_ng", "zh_cn", "zh_hk", "zh_tw", "zlm_arab" - ); - - Map> LOCALE_2_COUNTRIES = ALL_LANG.stream() - .map(lang -> lang.split("_")) - .filter(split -> split.length >= 2) - .collect(Collectors.groupingBy( - split -> split[0], - Collectors.mapping(split -> split[1], Collectors.toUnmodifiableList()) - )); - - String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"}; - - Map langData(); - - @Override - default int loadingSequence() { - return LoadingSequence.LANG; - } - - @Override - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } - - void addTranslation(String langId, Map translations); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangMangerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangMangerImpl.java deleted file mode 100644 index 01f7c138e..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/ClientLangMangerImpl.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.momirealms.craftengine.core.plugin.locale; - -import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.util.Key; - -import java.nio.file.Path; -import java.util.*; -import java.util.stream.Collectors; - -public class ClientLangMangerImpl implements ClientLangManager { - private final Map i18nData = new HashMap<>(); - - protected ClientLangMangerImpl() {} - - @Override - public void reload() { - this.i18nData.clear(); - } - - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - String langId = id.value().toLowerCase(Locale.ROOT); - - Map sectionData = section.entrySet().stream() - .collect(Collectors.toMap( - Map.Entry::getKey, - entry -> String.valueOf(entry.getValue()) - )); - - addTranslation(langId, sectionData); - } - - @Override - public Map langData() { - return Collections.unmodifiableMap(this.i18nData); - } - - @Override - public void addTranslation(String langId, Map translations) { - if ("all".equals(langId)) { - ALL_LANG.forEach(lang -> this.i18nData.computeIfAbsent(lang, k -> new I18NData()) - .addTranslations(translations)); - return; - } - - if (ALL_LANG.contains(langId)) { - this.i18nData.computeIfAbsent(langId, k -> new I18NData()) - .addTranslations(translations); - return; - } - - List langCountries = LOCALE_2_COUNTRIES.getOrDefault(langId, Collections.emptyList()); - for (String lang : langCountries) { - this.i18nData.computeIfAbsent(langId + "_" + lang, k -> new I18NData()) - .addTranslations(translations); - } - } - - @Override - public void delayedLoad() { - this.i18nData.values().forEach(I18NData::processTranslations); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java index edb9526b0..5c91c1397 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java @@ -7,16 +7,45 @@ import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import org.jetbrains.annotations.Nullable; +import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; -public interface TranslationManager extends Reloadable, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"i18n", "internationalization", "translation", "translations"}; +public interface TranslationManager extends Reloadable { + Set ALL_LANG = Set.of( + "af_za", "ar_sa", "ast_es", "az_az", "ba_ru", "bar", "be_by", "be_latn", + "bg_bg", "br_fr", "brb", "bs_ba", "ca_es", "cs_cz", "cy_gb", "da_dk", + "de_at", "de_ch", "de_de", "el_gr", "en_au", "en_ca", "en_gb", "en_nz", + "en_pt", "en_ud", "en_us", "enp", "enws", "eo_uy", "es_ar", "es_cl", + "es_ec", "es_es", "es_mx", "es_uy", "es_ve", "esan", "et_ee", "eu_es", + "fa_ir", "fi_fi", "fil_ph", "fo_fo", "fr_ca", "fr_fr", "fra_de", "fur_it", + "fy_nl", "ga_ie", "gd_gb", "gl_es", "haw_us", "he_il", "hi_in", "hn_no", + "hr_hr", "hu_hu", "hy_am", "id_id", "ig_ng", "io_en", "is_is", "isv", + "it_it", "ja_jp", "jbo_en", "ka_ge", "kk_kz", "kn_in", "ko_kr", "ksh", + "kw_gb", "ky_kg", "la_la", "lb_lu", "li_li", "lmo", "lo_la", "lol_us", "lt_lt", + "lv_lv", "lzh", "mk_mk", "mn_mn", "ms_my", "mt_mt", "nah", "nds_de", + "nl_be", "nl_nl", "nn_no", "no_no", "oc_fr", "ovd", "pl_pl", "pls", + "pt_br", "pt_pt", "qya_aa", "ro_ro", "rpr", "ru_ru", "ry_ua", "sah_sah", + "se_no", "sk_sk", "sl_si", "so_so", "sq_al", "sr_cs", "sr_sp", "sv_se", + "sxu", "szl", "ta_in", "th_th", "tl_ph", "tlh_aa", "tok", "tr_tr", + "tt_ru", "tzo_mx", "uk_ua", "val_es", "vec_it", "vi_vn", "vp_vl", "yi_de", + "yo_ng", "zh_cn", "zh_hk", "zh_tw", "zlm_arab" + ); + Map> LOCALE_2_COUNTRIES = ALL_LANG.stream() + .map(lang -> lang.split("_")) + .filter(split -> split.length >= 2) + .collect(Collectors.groupingBy( + split -> split[0], + Collectors.mapping(split -> split[1], Collectors.toUnmodifiableList()) + )); static TranslationManager instance() { return TranslationManagerImpl.instance; } - ClientLangManager clientLangManager(); + ConfigSectionParser[] parsers(); default String miniMessageTranslation(String key) { return miniMessageTranslation(key, null); @@ -36,15 +65,9 @@ public interface TranslationManager extends Reloadable, ConfigSectionParser { return locale == null || locale.isEmpty() ? null : Translator.parseLocale(locale); } - @Override - default int loadingSequence() { - return LoadingSequence.TRANSLATION; - } - - @Override - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } - void log(String id, String... args); + + Map clientLangData(); + + void addClientTranslation(String langId, Map translations); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index b6c30d3f2..a3cb5abff 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -2,10 +2,12 @@ package net.momirealms.craftengine.core.plugin.locale; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.Plugin; import net.momirealms.craftengine.core.plugin.PluginProperties; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; import net.momirealms.craftengine.core.plugin.text.minimessage.IndexedArgumentTag; import net.momirealms.craftengine.core.util.AdventureHelper; @@ -34,22 +36,24 @@ public class TranslationManagerImpl implements TranslationManager { private final Plugin plugin; private final Set installed = ConcurrentHashMap.newKeySet(); private final Path translationsDirectory; - private final ClientLangManager clientLangManager; private final String langVersion; private final String[] supportedLanguages; private final Map translationFallback = new LinkedHashMap<>(); private Locale forcedLocale = null; private Locale selectedLocale = DEFAULT_LOCALE; private MiniMessageTranslationRegistry registry; + private final Map clientLangData = new HashMap<>(); + private final LangParser langParser; + private final I18NParser i18nParser; public TranslationManagerImpl(Plugin plugin) { + instance = this; this.plugin = plugin; this.translationsDirectory = this.plugin.dataFolderPath().resolve("translations"); - this.clientLangManager = new ClientLangMangerImpl(); this.langVersion = PluginProperties.getValue("lang-version"); this.supportedLanguages = PluginProperties.getValue("supported-languages").split(","); - instance = this; - + this.langParser = new LangParser(); + this.i18nParser = new I18NParser(); Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); try (InputStream is = plugin.resourceStream("translations/en.yml")) { this.translationFallback.putAll(yaml.load(is)); @@ -58,6 +62,11 @@ public class TranslationManagerImpl implements TranslationManager { } } + @Override + public ConfigSectionParser[] parsers() { + return new ConfigSectionParser[] {this.langParser, this.i18nParser}; + } + @Override public void forcedLocale(Locale locale) { this.forcedLocale = locale; @@ -65,13 +74,13 @@ public class TranslationManagerImpl implements TranslationManager { @Override public void delayedLoad() { - this.clientLangManager.delayedLoad(); + this.clientLangData.values().forEach(I18NData::processTranslations); } @Override public void reload() { // clear old data - this.clientLangManager.reload(); + this.clientLangData.clear(); // remove any previous registry if (this.registry != null) { @@ -109,7 +118,7 @@ public class TranslationManagerImpl implements TranslationManager { return; } - this.plugin.logger().warn(localLocale.toString().toLowerCase(Locale.ENGLISH) + ".yml not exists, using " + DEFAULT_LOCALE.toString().toLowerCase(Locale.ENGLISH) + ".yml as default locale."); + this.plugin.logger().warn("translations/" + localLocale.toString().toLowerCase(Locale.ENGLISH) + ".yml not exists, using " + DEFAULT_LOCALE.toString().toLowerCase(Locale.ENGLISH) + ".yml as default locale."); this.selectedLocale = DEFAULT_LOCALE; } @@ -214,28 +223,6 @@ public class TranslationManagerImpl implements TranslationManager { return Pair.of(locale, bundle); } - @Override - public void parseSection(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Map section) { - Locale locale = TranslationManager.parseLocale(id.value()); - if (locale == null) { - throw new IllegalStateException("Unknown locale '" + id.value() + "' - unable to register."); - } - - Map bundle = new HashMap<>(); - for (Map.Entry entry : section.entrySet()) { - String key = entry.getKey(); - bundle.put(key, entry.getValue().toString()); - } - - this.registry.registerAll(locale, bundle); - this.installed.add(locale); - } - - @Override - public ClientLangManager clientLangManager() { - return clientLangManager; - } - @Override public void log(String id, String... args) { String translation = miniMessageTranslation(id); @@ -263,4 +250,87 @@ public class TranslationManagerImpl implements TranslationManager { return newFileContents; } } + + @Override + public Map clientLangData() { + return Collections.unmodifiableMap(this.clientLangData); + } + + @Override + public void addClientTranslation(String langId, Map translations) { + if ("all".equals(langId)) { + ALL_LANG.forEach(lang -> this.clientLangData.computeIfAbsent(lang, k -> new I18NData()) + .addTranslations(translations)); + return; + } + + if (ALL_LANG.contains(langId)) { + this.clientLangData.computeIfAbsent(langId, k -> new I18NData()) + .addTranslations(translations); + return; + } + + List langCountries = LOCALE_2_COUNTRIES.getOrDefault(langId, Collections.emptyList()); + for (String lang : langCountries) { + this.clientLangData.computeIfAbsent(langId + "_" + lang, k -> new I18NData()) + .addTranslations(translations); + } + } + + public class I18NParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"i18n", "internationalization", "translation", "translations"}; + + @Override + public int loadingSequence() { + return LoadingSequence.TRANSLATION; + } + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public void parseSection(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Map section) { + Locale locale = TranslationManager.parseLocale(id.value()); + if (locale == null) { + log("warning.config.i18n.unknown_locale", path.toString(), id.value()); + return; + } + + Map bundle = new HashMap<>(); + for (Map.Entry entry : section.entrySet()) { + String key = entry.getKey(); + bundle.put(key, entry.getValue().toString()); + } + + TranslationManagerImpl.this.registry.registerAll(locale, bundle); + TranslationManagerImpl.this.installed.add(locale); + } + } + + public class LangParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"}; + + @Override + public int loadingSequence() { + return LoadingSequence.LANG; + } + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public void parseSection(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Map section) { + String langId = id.value().toLowerCase(Locale.ENGLISH); + Map sectionData = section.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> String.valueOf(entry.getValue()) + )); + TranslationManagerImpl.this.addClientTranslation(langId, sectionData); + } + } } From 0385343b2a55adec540e86f11ee783f29f04588a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 03:46:14 +0800 Subject: [PATCH 13/37] refactor template & item browser --- .../textures/entity/shulker/shulker.png | Bin 1493 -> 0 bytes .../core/pack/AbstractPackManager.java | 6 +- .../craftengine/core/plugin/CraftEngine.java | 17 +++--- .../plugin/config/ConfigSectionParser.java | 4 ++ .../config/template/TemplateManager.java | 15 ++--- .../config/template/TemplateManagerImpl.java | 31 +++++++++-- .../gui/category/ItemBrowserManager.java | 13 +---- .../gui/category/ItemBrowserManagerImpl.java | 52 +++++++++++++----- .../plugin/locale/TranslationManager.java | 1 - 9 files changed, 84 insertions(+), 55 deletions(-) delete mode 100644 bukkit/loader/src/main/resources/internal/textures/entity/shulker/shulker.png diff --git a/bukkit/loader/src/main/resources/internal/textures/entity/shulker/shulker.png b/bukkit/loader/src/main/resources/internal/textures/entity/shulker/shulker.png deleted file mode 100644 index b6c9cade65e26d91b8960d68a50230ea2405b91c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1493 zcmbu9{WsGK7{I^Gdt9!rbiB5_oNMVtb>+4Y5v#@WI*iTGPR0ylM)kF**=;sSzD2(3 zj@!Bww`k->yJ%AyP9v6dMG6tJS}5-B{TJ?Y&hvbp=cng<&U4Pg#RUbJ7+Dzs0APX% z^b65&|G#N~(A26X_KXHvnIQqbKwXc`lxBE}!-o0uNqkMawzl?m{`Tuhkz$}i)=}Id zW;N8O-x5)U*+L;hD9jMTnJ}CI!|5~_Ea7-Xb z5(p9n{6xMWLBLPo^W*uN6})&JkHq7}@wg-|C!WJ4aycXphsfc?aX17HCx!zOKz1}6 zi~-qEY%m%Gqd*W3f{`E?0Wu?*%y1?%jL8gPGI2~gj!qAz(}U==U>Y4ur(tQd!!+6< z+P^~myL2`1V}t~S{^z98`acnnz+(V_4h7@q6NW!C8!=lhbT_UAhn@G|k?Y(&@GRBZ zRUw~uyN9_HHKYbbac_C1t}{_ubBmuHEIW)pa7m?caAEQJcWYRjUoURf*8- zde)%r@%Mql<&9MCt(#()c_Y)Bl!S44mSco0PCbSwi{^Tihlub7J~E}|l+MVcnzAQ< zQkRb8-#fGNCDuh!vXz2xKq_OK0!s;?iN!g9+xlm9(i!zBU znFya2wi2M5q}boI-t@(sF~MhV8#BESvz2Xk!O5rZaqNWk^@*;%94MMTIphkQL(I@-D)-SaIl z9$}vNUeY*YY$K61X5sNax73ev#TR>*7n=KZ#=;u(mG0fr05W!d(=hL=bAg`BvD@8V ztmL?Myzn5)w0lvN*hl@WJcsLV=2=gdE}Q^5{2c#kNeUaNygdOVL9 zt=d=f(dwy`(Q(DQ*t~0N3sYa@Wb%tsPBhbRJ5=8o>cN&dZ9+)BVa>WWA7S#AUhe^i-A?@F`bvK+mI|!O>5t-p+g2Of{HkvNJ}L z^-kJL^3SCM8T$Djt9mUx_+X*gS{S{+vMJZvMG z@)j|vIF$QnWgDPFdf@XGO_nh3Uy<3^<+}IIsY6-!=L zSu-%d6qp$w&)r-zHfcO>*1&x%NpnNHz5+fQ9xU>;@EIRuq*XAc8vN@nJ#?HPdYBe= z--$L_SZsNce%3(SQ2!`^>^)kQ)p^nCllMXYfLVt|6V#r_6ID(xy*AdGiau}1n6wb} z<=*gZ~e_$^Ph7X%2Odm^(AXMqeQ&n W$6`k3g9ObB12FzUes#X2)BgZLH}CTR diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index a15a65564..508cce6dd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -50,7 +50,6 @@ public abstract class AbstractPackManager implements PackManager { public static final Set VANILLA_ITEM_TEXTURES = new HashSet<>(); public static final Set VANILLA_BLOCK_TEXTURES = new HashSet<>(); public static final Set VANILLA_FONT_TEXTURES = new HashSet<>(); - public static final List SHULKER_PNG = new ArrayList<>(1); private final CraftEngine plugin; private final BiConsumer eventDispatcher; @@ -86,8 +85,6 @@ public abstract class AbstractPackManager implements PackManager { loadInternalList("internal/textures/block/_list.json", VANILLA_BLOCK_TEXTURES::add); loadInternalList("internal/textures/item/_list.json", VANILLA_ITEM_TEXTURES::add); loadInternalList("internal/textures/font/_list.json", VANILLA_FONT_TEXTURES::add); - - loadInternalPng("internal/textures/entity/shulker/shulker.png", SHULKER_PNG::add); } private void loadInternalData(String path, BiConsumer callback) { @@ -408,14 +405,13 @@ public abstract class AbstractPackManager implements PackManager { this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); for (Map.Entry> entry : this.cachedConfigs.entrySet()) { ConfigSectionParser parser = entry.getKey(); - boolean isTemplate = parser.sectionId()[0].equals(TemplateManager.CONFIG_SECTION_NAME[0]); long t1 = System.nanoTime(); for (CachedConfig cached : entry.getValue()) { for (Map.Entry configEntry : cached.config().entrySet()) { String key = configEntry.getKey(); try { Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); - if (isTemplate) { + if (parser.isTemplate()) { ((TemplateManager) parser).addTemplate(cached.pack(), cached.filePath(), id, configEntry.getValue()); } else { if (configEntry.getValue() instanceof Map configSection0) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 85633973f..c38b79ff6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -96,12 +96,17 @@ public abstract class CraftEngine implements Plugin { this.configManager = new ConfigManager(this); } - // TODO Make most things async @Override public void reload() { if (this.isReloading) return; this.isReloading = true; this.configManager.reload(); + // reset debugger + if (ConfigManager.debug()) { + this.debugger = (s) -> logger.info("[Debug] " + s.get()); + } else { + this.debugger = (s) -> {}; + } this.translationManager.reload(); this.templateManager.reload(); this.furnitureManager.reload(); @@ -125,12 +130,6 @@ public abstract class CraftEngine implements Plugin { this.soundManager.delayedLoad(); this.fontManager.delayedLoad(); this.recipeManager.delayedLoad(); - // reset debugger - if (ConfigManager.debug()) { - this.debugger = (s) -> logger.info("[Debug] " + s.get()); - } else { - this.debugger = (s) -> {}; - } scheduler().sync().run(() -> { try { this.recipeManager.runSyncTasks(); @@ -187,7 +186,7 @@ public abstract class CraftEngine implements Plugin { protected void registerParsers() { // register template parser - this.packManager.registerConfigSectionParser(this.templateManager); + this.packManager.registerConfigSectionParser(this.templateManager.parser()); // register font parser this.packManager.registerConfigSectionParsers(this.fontManager.parsers()); // register item parser @@ -199,7 +198,7 @@ public abstract class CraftEngine implements Plugin { // register recipe parser this.packManager.registerConfigSectionParser(this.recipeManager.parser()); // register category parser - this.packManager.registerConfigSectionParser(this.itemBrowserManager); + this.packManager.registerConfigSectionParser(this.itemBrowserManager.parser()); // register translation parser this.packManager.registerConfigSectionParsers(this.translationManager.parsers()); // register sound parser diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java index c847db6f5..3b5f9ef92 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigSectionParser.java @@ -15,6 +15,10 @@ public interface ConfigSectionParser extends Comparable { int loadingSequence(); + default boolean isTemplate() { + return false; + } + @Override default int compareTo(@NotNull ConfigSectionParser another) { return Integer.compare(loadingSequence(), another.loadingSequence()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java index 0c629784c..8b44c1a99 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.core.plugin.config.template; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; @@ -10,22 +9,18 @@ import java.nio.file.Path; import java.util.Map; import java.util.regex.Pattern; -public interface TemplateManager extends Reloadable, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"templates", "template"}; - Pattern PATTERN = Pattern.compile("\\{[^{}]+}"); +public interface TemplateManager extends Reloadable { + Pattern ARGUMENT_PATTERN = Pattern.compile("\\{[^{}]+}"); + String LEFT_BRACKET = "{"; + String RIGHT_BRACKET = "}"; String TEMPLATE = "template"; String OVERRIDES = "overrides"; String ARGUMENTS = "arguments"; - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } + ConfigSectionParser parser(); void addTemplate(Pack pack, Path path, Key id, Object obj); Map applyTemplates(Map input); - default int loadingSequence() { - return LoadingSequence.TEMPLATE; - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java index 7afd0daf1..9f577e83c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java @@ -1,7 +1,9 @@ package net.momirealms.craftengine.core.plugin.config.template; +import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -17,14 +19,33 @@ import java.util.regex.Matcher; import static net.momirealms.craftengine.core.util.MiscUtils.castToMap; public class TemplateManagerImpl implements TemplateManager { - private static final String LEFT_BRACKET = "{"; - private static final String RIGHT_BRACKET = "}"; private final CraftEngine plugin; private final Map templates = new HashMap<>(); private final static Set NON_TEMPLATE_KEY = new HashSet<>(Set.of(TEMPLATE, ARGUMENTS, OVERRIDES)); + private final TemplateParser templateParser; public TemplateManagerImpl(CraftEngine plugin) { this.plugin = plugin; + this.templateParser = new TemplateParser(); + } + + public class TemplateParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"templates", "template"}; + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public int loadingSequence() { + return LoadingSequence.TEMPLATE; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + addTemplate(pack, path, id, section); + } } @Override @@ -33,8 +54,8 @@ public class TemplateManagerImpl implements TemplateManager { } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - addTemplate(pack, path, id, section); + public ConfigSectionParser parser() { + return this.templateParser; } @Override @@ -233,7 +254,7 @@ public class TemplateManagerImpl implements TemplateManager { // 将某个输入变成最终的结果,可以是string->string,也可以是string->map/list private Object applyArgument(String input, Map arguments) { StringBuilder result = new StringBuilder(); - Matcher matcher = PATTERN.matcher(input); + Matcher matcher = ARGUMENT_PATTERN.matcher(input); boolean first = true; while (matcher.find()) { String placeholder = matcher.group(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java index 8add417e5..6e28cbc74 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java @@ -16,20 +16,11 @@ import java.util.TreeSet; import static java.util.Objects.requireNonNull; -public interface ItemBrowserManager extends Reloadable, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"categories", "category"}; +public interface ItemBrowserManager extends Reloadable { int MAX_RECIPE_DEPTH = 16; String GET_ITEM_PERMISSION = "craftengine.browser.get_item"; - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } - - default int loadingSequence() { - return LoadingSequence.CATEGORY; - } - - void delayedLoad(); + ConfigSectionParser parser(); void addExternalCategoryMember(Key item, List category); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index 4368de433..81460d345 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -5,8 +5,10 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.recipe.*; +import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.gui.Ingredient; import net.momirealms.craftengine.core.plugin.gui.*; import net.momirealms.craftengine.core.registry.Holder; @@ -29,12 +31,14 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { private final Map byId; private final TreeSet categoryOnMainPage; private final Map> externalMembers; + private final CategoryParser categoryParser; public ItemBrowserManagerImpl(CraftEngine plugin) { this.plugin = plugin; this.byId = new HashMap<>(); this.externalMembers = new HashMap<>(); this.categoryOnMainPage = new TreeSet<>(); + this.categoryParser = new CategoryParser(); } @Override @@ -43,6 +47,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { this.categoryOnMainPage.clear(); } + @Override public void delayedLoad() { for (Map.Entry> entry : this.externalMembers.entrySet()) { Key item = entry.getKey(); @@ -60,6 +65,11 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { Constants.load(); } + @Override + public ConfigSectionParser parser() { + return this.categoryParser; + } + @Override public void addExternalCategoryMember(Key item, List category) { List categories = this.externalMembers.computeIfAbsent(item, k -> new ArrayList<>()); @@ -71,20 +81,6 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openItemBrowser(player); } - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - String name = section.getOrDefault("name", id).toString(); - List members = MiscUtils.getAsStringList(section.getOrDefault("list", List.of())); - Key icon = Key.of(section.getOrDefault("icon", ItemKeys.STONE).toString()); - int priority = MiscUtils.getAsInt(section.getOrDefault("priority", 0)); - Category category = new Category(id, name, MiscUtils.getAsStringList(section.getOrDefault("lore", List.of())), icon, members.stream().distinct().toList(), priority, (boolean) section.getOrDefault("hidden", false)); - if (this.byId.containsKey(id)) { - this.byId.get(id).merge(category); - } else { - this.byId.put(id, category); - } - } - @Override public TreeSet categories() { return categoryOnMainPage; @@ -95,6 +91,34 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return Optional.ofNullable(this.byId.get(key)); } + public class CategoryParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"categories", "category"}; + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public int loadingSequence() { + return LoadingSequence.CATEGORY; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + String name = section.getOrDefault("name", id).toString(); + List members = MiscUtils.getAsStringList(section.getOrDefault("list", List.of())); + Key icon = Key.of(section.getOrDefault("icon", ItemKeys.STONE).toString()); + int priority = MiscUtils.getAsInt(section.getOrDefault("priority", 0)); + Category category = new Category(id, name, MiscUtils.getAsStringList(section.getOrDefault("lore", List.of())), icon, members.stream().distinct().toList(), priority, (boolean) section.getOrDefault("hidden", false)); + if (ItemBrowserManagerImpl.this.byId.containsKey(id)) { + ItemBrowserManagerImpl.this.byId.get(id).merge(category); + } else { + ItemBrowserManagerImpl.this.byId.put(id, category); + } + } + } + public void openItemBrowser(Player player) { GuiLayout layout = new GuiLayout( "AAAAAAAAA", diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java index 5c91c1397..90671d485 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.plugin.locale; import net.kyori.adventure.text.Component; import net.kyori.adventure.translation.Translator; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import org.jetbrains.annotations.Nullable; From 4e945f2af2083183feddb5fb20edab35474bf22a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 03:57:55 +0800 Subject: [PATCH 14/37] refactor vanilla loots --- .../src/main/resources/translations/en.yml | 5 +- .../bukkit/loot/BukkitVanillaLootManager.java | 105 ++++++++++-------- .../core/loot/AbstractVanillaLootManager.java | 30 +++++ .../core/loot/VanillaLootManager.java | 17 +-- .../craftengine/core/plugin/CraftEngine.java | 4 +- .../config/template/TemplateManagerImpl.java | 10 +- 6 files changed, 105 insertions(+), 66 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/loot/AbstractVanillaLootManager.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 3c2e1dbed..b926499ff 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -64,4 +64,7 @@ warning.config.image.codepoint_in_use: "Issue found in file - Th warning.config.image.invalid_codepoint_grid: "Issue found in file - Image '' has an invalid 'chars' codepoint grind." warning.config.image.file_not_exist: "Issue found in file - PNG file not found for image ''." warning.config.recipe.duplicated: "Issue found in file - Duplicated recipe ''." -warning.config.i18n.unknown_locale: "Issue found in file - Unknown locale ''." \ No newline at end of file +warning.config.i18n.unknown_locale: "Issue found in file - Unknown locale ''." +warning.config.template.duplicated: "Issue found in file - Duplicated template ''." +warning.config.vanilla_loot.type_not_exist: "Issue found in file - 'type' not set for vanilla loot ''." +warning.config.vanilla_loot.block.invalid_target: "Issue found in file - Invalid block target [] in vanilla loot ''." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index 9a47edb92..93dd5d2d8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -8,11 +8,15 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.AbstractVanillaLootManager; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.loot.VanillaLoot; import net.momirealms.craftengine.core.loot.VanillaLootManager; import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.PreConditions; @@ -33,15 +37,13 @@ import java.nio.file.Path; import java.util.*; // note: block listeners are in BlockEventListener to reduce performance cost -public class BukkitVanillaLootManager implements VanillaLootManager, Listener { +public class BukkitVanillaLootManager extends AbstractVanillaLootManager implements Listener { private final BukkitCraftEngine plugin; - private final Map blockLoots; - private final Map entityLoots; + private final VanillaLootParser vanillaLootParser; public BukkitVanillaLootManager(BukkitCraftEngine plugin) { this.plugin = plugin; - this.blockLoots = new HashMap<>(); - this.entityLoots = new HashMap<>(); + this.vanillaLootParser = new VanillaLootParser(); } @Override @@ -54,17 +56,6 @@ public class BukkitVanillaLootManager implements VanillaLootManager, Listener { HandlerList.unregisterAll(this); } - @Override - public void unload() { - this.blockLoots.clear(); - this.entityLoots.clear(); - } - - @Override - public Optional getBlockLoot(int vanillaBlockState) { - return Optional.ofNullable(this.blockLoots.get(vanillaBlockState)); - } - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onEntityDeath(EntityDeathEvent event) { Entity entity = event.getEntity(); @@ -97,45 +88,65 @@ public class BukkitVanillaLootManager implements VanillaLootManager, Listener { } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - String type = (String) section.get("type"); - if (PreConditions.isNull(type, () -> this.plugin.logger().warn(path, "`type` option is required for vanilla-loot " + id))) { - return; + public ConfigSectionParser parser() { + return this.vanillaLootParser; + } + + public class VanillaLootParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot", "loots", "loot"}; + + @Override + public int loadingSequence() { + return LoadingSequence.VANILLA_LOOTS; } - VanillaLoot.Type typeEnum = VanillaLoot.Type.valueOf(type.toUpperCase(Locale.ENGLISH)); - boolean override = (boolean) section.getOrDefault("override", false); - List targets = MiscUtils.getAsStringList(section.getOrDefault("target", List.of())); - LootTable lootTable = LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), false)); - switch (typeEnum) { - case BLOCK -> { - for (String target : targets) { - if (target.endsWith("]") && target.contains("[")) { - java.lang.Object blockState = BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(target)); - if (blockState == Reflections.instance$Blocks$AIR$defaultState) { - this.plugin.logger().warn(path, "Failed to load " + id + ". Invalid target " + target); - return; - } - VanillaLoot vanillaLoot = this.blockLoots.computeIfAbsent(BlockStateUtils.blockStateToId(blockState), k -> new VanillaLoot(VanillaLoot.Type.BLOCK)); - vanillaLoot.addLootTable(lootTable); - } else { - for (Object blockState : BlockStateUtils.getAllVanillaBlockStates(Key.of(target))) { + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + String type = (String) section.get("type"); + if (type == null) { + TranslationManager.instance().log("warning.config.vanilla_loot.type_not_exist", path.toString(), id.toString()); + return; + } + VanillaLoot.Type typeEnum = VanillaLoot.Type.valueOf(type.toUpperCase(Locale.ENGLISH)); + boolean override = (boolean) section.getOrDefault("override", false); + List targets = MiscUtils.getAsStringList(section.getOrDefault("target", List.of())); + LootTable lootTable = LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), false)); + switch (typeEnum) { + case BLOCK -> { + for (String target : targets) { + if (target.endsWith("]") && target.contains("[")) { + java.lang.Object blockState = BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(target)); if (blockState == Reflections.instance$Blocks$AIR$defaultState) { - this.plugin.logger().warn(path, "Failed to load " + id + ". Invalid target " + target); + TranslationManager.instance().log("warning.config.vanilla_loot.block.invalid_target", path.toString(), id.toString(), target); return; } - VanillaLoot vanillaLoot = this.blockLoots.computeIfAbsent(BlockStateUtils.blockStateToId(blockState), k -> new VanillaLoot(VanillaLoot.Type.BLOCK)); - if (override) vanillaLoot.override(true); + VanillaLoot vanillaLoot = blockLoots.computeIfAbsent(BlockStateUtils.blockStateToId(blockState), k -> new VanillaLoot(VanillaLoot.Type.BLOCK)); vanillaLoot.addLootTable(lootTable); + } else { + for (Object blockState : BlockStateUtils.getAllVanillaBlockStates(Key.of(target))) { + if (blockState == Reflections.instance$Blocks$AIR$defaultState) { + TranslationManager.instance().log("warning.config.vanilla_loot.block.invalid_target", path.toString(), id.toString(), target); + return; + } + VanillaLoot vanillaLoot = blockLoots.computeIfAbsent(BlockStateUtils.blockStateToId(blockState), k -> new VanillaLoot(VanillaLoot.Type.BLOCK)); + if (override) vanillaLoot.override(true); + vanillaLoot.addLootTable(lootTable); + } } } } - } - case ENTITY -> { - for (String target : targets) { - Key key = Key.of(target); - VanillaLoot vanillaLoot = this.entityLoots.computeIfAbsent(key, k -> new VanillaLoot(VanillaLoot.Type.ENTITY)); - vanillaLoot.addLootTable(lootTable); - if (override) vanillaLoot.override(true); + case ENTITY -> { + for (String target : targets) { + Key key = Key.of(target); + VanillaLoot vanillaLoot = entityLoots.computeIfAbsent(key, k -> new VanillaLoot(VanillaLoot.Type.ENTITY)); + vanillaLoot.addLootTable(lootTable); + if (override) vanillaLoot.override(true); + } } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/AbstractVanillaLootManager.java b/core/src/main/java/net/momirealms/craftengine/core/loot/AbstractVanillaLootManager.java new file mode 100644 index 000000000..ae9b199d9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/AbstractVanillaLootManager.java @@ -0,0 +1,30 @@ +package net.momirealms.craftengine.core.loot; + +import net.momirealms.craftengine.core.util.Key; + +import java.util.*; + +public abstract class AbstractVanillaLootManager implements VanillaLootManager { + protected final Map blockLoots = new HashMap<>(); + // TODO More entity NBT + protected final Map entityLoots = new HashMap<>(); + + public AbstractVanillaLootManager() { + } + + @Override + public void unload() { + this.blockLoots.clear(); + this.entityLoots.clear(); + } + + @Override + public Optional getBlockLoot(int vanillaBlockState) { + return Optional.ofNullable(this.blockLoots.get(vanillaBlockState)); + } + + @Override + public Optional getEntityLoot(Key entity) { + return Optional.ofNullable(this.entityLoots.get(entity)); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java index b1d672f65..5e301e286 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java @@ -1,23 +1,16 @@ package net.momirealms.craftengine.core.loot; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.util.Key; import java.util.Optional; -public interface VanillaLootManager extends ConfigSectionParser, Reloadable { - String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot", "loots", "loot"}; +public interface VanillaLootManager extends Reloadable { - @Override - default int loadingSequence() { - return LoadingSequence.VANILLA_LOOTS; - } - - @Override - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } + ConfigSectionParser parser(); Optional getBlockLoot(int blockState); + + Optional getEntityLoot(Key entity); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index c38b79ff6..020145b62 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -142,7 +142,7 @@ public abstract class CraftEngine implements Plugin { @Override public void enable() { this.networkManager.enable(); - this.templateManager = new TemplateManagerImpl(this); + this.templateManager = new TemplateManagerImpl(); this.itemBrowserManager = new ItemBrowserManagerImpl(this); this.commandManager.registerDefaultFeatures(); // delay the reload so other plugins can register some parsers @@ -205,7 +205,7 @@ public abstract class CraftEngine implements Plugin { this.packManager.registerConfigSectionParser(this.soundManager); this.packManager.registerConfigSectionParser(this.soundManager.jukeboxSongManager()); // register vanilla loot parser - this.packManager.registerConfigSectionParser(this.vanillaLootManager); + this.packManager.registerConfigSectionParser(this.vanillaLootManager.parser()); } protected abstract void delayedEnable(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java index 9f577e83c..5b7560860 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -19,13 +20,11 @@ import java.util.regex.Matcher; import static net.momirealms.craftengine.core.util.MiscUtils.castToMap; public class TemplateManagerImpl implements TemplateManager { - private final CraftEngine plugin; private final Map templates = new HashMap<>(); private final static Set NON_TEMPLATE_KEY = new HashSet<>(Set.of(TEMPLATE, ARGUMENTS, OVERRIDES)); private final TemplateParser templateParser; - public TemplateManagerImpl(CraftEngine plugin) { - this.plugin = plugin; + public TemplateManagerImpl() { this.templateParser = new TemplateParser(); } @@ -60,7 +59,10 @@ public class TemplateManagerImpl implements TemplateManager { @Override public void addTemplate(Pack pack, Path path, Key id, Object obj) { - if (PreConditions.runIfTrue(this.templates.containsKey(id), () -> this.plugin.logger().warn(path, "Template duplicates: " + id))) return; + if (this.templates.containsKey(id)) { + TranslationManager.instance().log("warning.config.template.duplicated", path.toString(), id.toString()); + return; + } this.templates.put(id, obj); } From 74d532025118d4db0b87c38408f47824bac371c7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 04:06:44 +0800 Subject: [PATCH 15/37] refactor sounds --- .../src/main/resources/translations/en.yml | 4 +- .../bukkit/loot/BukkitVanillaLootManager.java | 7 +- .../sound/BukkitJukeboxSongManager.java | 58 -------- .../bukkit/sound/BukkitSoundManager.java | 47 ++++++- .../core/loot/AbstractVanillaLootManager.java | 4 +- .../craftengine/core/plugin/CraftEngine.java | 3 +- .../config/template/TemplateManagerImpl.java | 2 - .../gui/category/ItemBrowserManager.java | 1 - .../core/sound/AbstractSoundManager.java | 127 ++++++++++++------ .../core/sound/{song => }/JukeboxSong.java | 2 +- .../craftengine/core/sound/SoundManager.java | 19 +-- .../song/AbstractJukeboxSongManager.java | 53 -------- .../core/sound/song/JukeboxSongManager.java | 19 --- 13 files changed, 146 insertions(+), 200 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitJukeboxSongManager.java rename core/src/main/java/net/momirealms/craftengine/core/sound/{song => }/JukeboxSong.java (80%) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/sound/song/AbstractJukeboxSongManager.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index b926499ff..66632d11f 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -67,4 +67,6 @@ warning.config.recipe.duplicated: "Issue found in file - Duplica warning.config.i18n.unknown_locale: "Issue found in file - Unknown locale ''." warning.config.template.duplicated: "Issue found in file - Duplicated template ''." warning.config.vanilla_loot.type_not_exist: "Issue found in file - 'type' not set for vanilla loot ''." -warning.config.vanilla_loot.block.invalid_target: "Issue found in file - Invalid block target [] in vanilla loot ''." \ No newline at end of file +warning.config.vanilla_loot.block.invalid_target: "Issue found in file - Invalid block target [] in vanilla loot ''." +warning.config.sound.duplicated: "Issue found in file - Duplicated sound ''." +warning.config.jukebox_song.duplicated: "Issue found in file - Duplicated jukebox song ''." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index 93dd5d2d8..6a36cca25 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -11,7 +11,6 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.AbstractVanillaLootManager; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.loot.VanillaLoot; -import net.momirealms.craftengine.core.loot.VanillaLootManager; import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; @@ -19,7 +18,6 @@ import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.PreConditions; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.Vec3d; @@ -34,7 +32,10 @@ import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDeathEvent; import java.nio.file.Path; -import java.util.*; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; // note: block listeners are in BlockEventListener to reduce performance cost public class BukkitVanillaLootManager extends AbstractVanillaLootManager implements Listener { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitJukeboxSongManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitJukeboxSongManager.java deleted file mode 100644 index c1279b3fd..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitJukeboxSongManager.java +++ /dev/null @@ -1,58 +0,0 @@ -package net.momirealms.craftengine.bukkit.sound; - -import net.momirealms.craftengine.bukkit.util.ComponentUtils; -import net.momirealms.craftengine.bukkit.util.Reflections; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.sound.song.AbstractJukeboxSongManager; -import net.momirealms.craftengine.core.sound.song.JukeboxSong; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.VersionHelper; - -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -public class BukkitJukeboxSongManager extends AbstractJukeboxSongManager { - - public BukkitJukeboxSongManager(CraftEngine plugin) { - super(plugin); - } - - @Override - protected void registerSongs(Map songs) { - if (songs.isEmpty()) return; - try { - unfreezeRegistry(); - for (Map.Entry entry : songs.entrySet()) { - Key id = entry.getKey(); - JukeboxSong jukeboxSong = entry.getValue(); - Object resourceLocation = Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, id.namespace(), id.value()); - Object soundId = Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, jukeboxSong.sound().namespace(), jukeboxSong.sound().value()); - Object song = Reflections.method$Registry$get.invoke(Reflections.instance$InternalRegistries$JUKEBOX_SONG, resourceLocation); - - Object soundEvent = VersionHelper.isVersionNewerThan1_21_2() ? - Reflections.constructor$SoundEvent.newInstance(soundId, Optional.of(jukeboxSong.range())) : - Reflections.constructor$SoundEvent.newInstance(soundId, jukeboxSong.range(), false); - Object soundHolder = Reflections.method$Holder$direct.invoke(null, soundEvent); - - if (song == null) { - song = Reflections.constructor$JukeboxSong.newInstance(soundHolder, ComponentUtils.adventureToMinecraft(jukeboxSong.description()), jukeboxSong.lengthInSeconds(), jukeboxSong.comparatorOutput()); - Object holder = Reflections.method$Registry$registerForHolder.invoke(null, Reflections.instance$InternalRegistries$JUKEBOX_SONG, resourceLocation, song); - Reflections.method$Holder$Reference$bindValue.invoke(holder, song); - Reflections.field$Holder$Reference$tags.set(holder, Set.of()); - } - } - freezeRegistry(); - } catch (Exception e) { - plugin.logger().warn("Failed to register jukebox songs.", e); - } - } - - private void unfreezeRegistry() throws IllegalAccessException { - Reflections.field$MappedRegistry$frozen.set(Reflections.instance$InternalRegistries$JUKEBOX_SONG, false); - } - - private void freezeRegistry() throws IllegalAccessException { - Reflections.field$MappedRegistry$frozen.set(Reflections.instance$InternalRegistries$JUKEBOX_SONG, true); - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java index e3f4d769f..e17dd3702 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java @@ -1,8 +1,16 @@ package net.momirealms.craftengine.bukkit.sound; +import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.sound.AbstractSoundManager; -import net.momirealms.craftengine.core.sound.song.JukeboxSongManager; +import net.momirealms.craftengine.core.sound.JukeboxSong; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; + +import java.util.Map; +import java.util.Optional; +import java.util.Set; public class BukkitSoundManager extends AbstractSoundManager { @@ -11,7 +19,40 @@ public class BukkitSoundManager extends AbstractSoundManager { } @Override - protected JukeboxSongManager createJukeboxSongManager() { - return new BukkitJukeboxSongManager(super.plugin); + protected void registerSongs(Map songs) { + if (songs.isEmpty()) return; + try { + unfreezeRegistry(); + for (Map.Entry entry : songs.entrySet()) { + Key id = entry.getKey(); + JukeboxSong jukeboxSong = entry.getValue(); + Object resourceLocation = Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, id.namespace(), id.value()); + Object soundId = Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, jukeboxSong.sound().namespace(), jukeboxSong.sound().value()); + Object song = Reflections.method$Registry$get.invoke(Reflections.instance$InternalRegistries$JUKEBOX_SONG, resourceLocation); + + Object soundEvent = VersionHelper.isVersionNewerThan1_21_2() ? + Reflections.constructor$SoundEvent.newInstance(soundId, Optional.of(jukeboxSong.range())) : + Reflections.constructor$SoundEvent.newInstance(soundId, jukeboxSong.range(), false); + Object soundHolder = Reflections.method$Holder$direct.invoke(null, soundEvent); + + if (song == null) { + song = Reflections.constructor$JukeboxSong.newInstance(soundHolder, ComponentUtils.adventureToMinecraft(jukeboxSong.description()), jukeboxSong.lengthInSeconds(), jukeboxSong.comparatorOutput()); + Object holder = Reflections.method$Registry$registerForHolder.invoke(null, Reflections.instance$InternalRegistries$JUKEBOX_SONG, resourceLocation, song); + Reflections.method$Holder$Reference$bindValue.invoke(holder, song); + Reflections.field$Holder$Reference$tags.set(holder, Set.of()); + } + } + freezeRegistry(); + } catch (Exception e) { + plugin.logger().warn("Failed to register jukebox songs.", e); + } + } + + private void unfreezeRegistry() throws IllegalAccessException { + Reflections.field$MappedRegistry$frozen.set(Reflections.instance$InternalRegistries$JUKEBOX_SONG, false); + } + + private void freezeRegistry() throws IllegalAccessException { + Reflections.field$MappedRegistry$frozen.set(Reflections.instance$InternalRegistries$JUKEBOX_SONG, true); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/AbstractVanillaLootManager.java b/core/src/main/java/net/momirealms/craftengine/core/loot/AbstractVanillaLootManager.java index ae9b199d9..fbacf55cb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/AbstractVanillaLootManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/AbstractVanillaLootManager.java @@ -2,7 +2,9 @@ package net.momirealms.craftengine.core.loot; import net.momirealms.craftengine.core.util.Key; -import java.util.*; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; public abstract class AbstractVanillaLootManager implements VanillaLootManager { protected final Map blockLoots = new HashMap<>(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 020145b62..db7667305 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -202,8 +202,7 @@ public abstract class CraftEngine implements Plugin { // register translation parser this.packManager.registerConfigSectionParsers(this.translationManager.parsers()); // register sound parser - this.packManager.registerConfigSectionParser(this.soundManager); - this.packManager.registerConfigSectionParser(this.soundManager.jukeboxSongManager()); + this.packManager.registerConfigSectionParsers(this.soundManager.parsers()); // register vanilla loot parser this.packManager.registerConfigSectionParser(this.vanillaLootManager.parser()); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java index 5b7560860..29f0d36da 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java @@ -2,13 +2,11 @@ package net.momirealms.craftengine.core.plugin.config.template; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.PreConditions; import org.jetbrains.annotations.NotNull; import java.nio.file.Path; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java index 6e28cbc74..112abbb25 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.plugin.gui.category; import dev.dejvokep.boostedyaml.block.implementation.Section; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.recipe.Recipe; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java index 26a55876f..88621064b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java @@ -1,66 +1,48 @@ package net.momirealms.craftengine.core.sound; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.sound.song.JukeboxSongManager; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.VersionHelper; import java.nio.file.Path; import java.util.*; public abstract class AbstractSoundManager implements SoundManager { protected final CraftEngine plugin; - protected final Map byId; - protected final Map> byNamespace; - protected final JukeboxSongManager jukeboxSongManager; + protected final Map byId = new HashMap<>(); + protected final Map> byNamespace = new HashMap<>(); + protected final Map songs = new HashMap<>(); + protected final SoundParser soundParser; + protected final SongParser songParser; public AbstractSoundManager(CraftEngine plugin) { this.plugin = plugin; - this.jukeboxSongManager = createJukeboxSongManager(); - this.byId = new HashMap<>(); - this.byNamespace = new HashMap<>(); + this.soundParser = new SoundParser(); + this.songParser = new SongParser(); } - protected abstract JukeboxSongManager createJukeboxSongManager(); + @Override + public ConfigSectionParser[] parsers() { + return new ConfigSectionParser[] { this.soundParser, this.songParser }; + } @Override public void unload() { this.byId.clear(); this.byNamespace.clear(); - this.jukeboxSongManager.unload(); - } - - @Override - public void load() { - this.jukeboxSongManager.load(); } @Override public void delayedLoad() { - this.jukeboxSongManager.delayedLoad(); - } - - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - if (this.byId.containsKey(id)) { - this.plugin.logger().warn(path, "Sound " + id + " already exists"); - return; - } - boolean replace = (boolean) section.getOrDefault("replace", false); - String subtitle = (String) section.get("subtitle"); - List soundList = (List) section.get("sounds"); - List sounds = new ArrayList<>(); - for (Object sound : soundList) { - if (sound instanceof String soundPath) { - sounds.add(Sound.path(soundPath)); - } else if (sound instanceof Map map) { - sounds.add(Sound.SoundFile.fromMap(MiscUtils.castToMap(map, false))); - } - } - SoundEvent event = new SoundEvent(id, replace, subtitle, sounds); - this.byId.put(id, event); - this.byNamespace.computeIfAbsent(id.namespace(), k -> new ArrayList<>()).add(event); + if (!VersionHelper.isVersionNewerThan1_21()) return; + this.registerSongs(this.songs); } @Override @@ -72,8 +54,73 @@ public abstract class AbstractSoundManager implements SoundManager { return Collections.unmodifiableMap(this.byNamespace); } - @Override - public JukeboxSongManager jukeboxSongManager() { - return this.jukeboxSongManager; + protected abstract void registerSongs(Map songs); + + public class SongParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "song", "songs", "jukebox", "jukebox_song"}; + + @Override + public int loadingSequence() { + return LoadingSequence.JUKEBOX_SONG; + } + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + if (AbstractSoundManager.this.songs.containsKey(id)) { + TranslationManager.instance().log("warning.config.jukebox_song.duplicated", path.toString(), id.toString()); + return; + } + String sound = (String) section.get("sound"); + if (sound == null) { + AbstractSoundManager.this.plugin.logger().warn(path, "No sound specified"); + return; + } + Component description = AdventureHelper.miniMessage(section.getOrDefault("description", "").toString()); + float length = MiscUtils.getAsFloat(section.get("length")); + int comparatorOutput = MiscUtils.getAsInt(section.getOrDefault("comparator-output", 15)); + JukeboxSong song = new JukeboxSong(Key.of(sound), description, length, comparatorOutput, MiscUtils.getAsFloat(section.getOrDefault("range", 32f))); + AbstractSoundManager.this.songs.put(id, song); + } + } + + public class SoundParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"sounds", "sound"}; + + @Override + public int loadingSequence() { + return LoadingSequence.SOUND; + } + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + if (AbstractSoundManager.this.byId.containsKey(id)) { + TranslationManager.instance().log("warning.config.sound.duplicated", path.toString(), id.toString()); + return; + } + boolean replace = (boolean) section.getOrDefault("replace", false); + String subtitle = (String) section.get("subtitle"); + List soundList = (List) section.get("sounds"); + List sounds = new ArrayList<>(); + for (Object sound : soundList) { + if (sound instanceof String soundPath) { + sounds.add(Sound.path(soundPath)); + } else if (sound instanceof Map map) { + sounds.add(Sound.SoundFile.fromMap(MiscUtils.castToMap(map, false))); + } + } + SoundEvent event = new SoundEvent(id, replace, subtitle, sounds); + AbstractSoundManager.this.byId.put(id, event); + AbstractSoundManager.this.byNamespace.computeIfAbsent(id.namespace(), k -> new ArrayList<>()).add(event); + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSong.java b/core/src/main/java/net/momirealms/craftengine/core/sound/JukeboxSong.java similarity index 80% rename from core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSong.java rename to core/src/main/java/net/momirealms/craftengine/core/sound/JukeboxSong.java index b9ff3a313..48c0b1816 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSong.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/JukeboxSong.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.sound.song; +package net.momirealms.craftengine.core.sound; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.util.Key; diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java index 56aceec51..97c81ff31 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java @@ -1,27 +1,14 @@ package net.momirealms.craftengine.core.sound; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; -import net.momirealms.craftengine.core.sound.song.JukeboxSongManager; import net.momirealms.craftengine.core.util.Key; import java.util.Map; -public interface SoundManager extends Reloadable, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"sounds", "sound"}; +public interface SoundManager extends Reloadable { + + ConfigSectionParser[] parsers(); Map sounds(); - - JukeboxSongManager jukeboxSongManager(); - - @Override - default int loadingSequence() { - return LoadingSequence.SOUND; - } - - @Override - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/song/AbstractJukeboxSongManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/song/AbstractJukeboxSongManager.java deleted file mode 100644 index c78682f3d..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/song/AbstractJukeboxSongManager.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.momirealms.craftengine.core.sound.song; - -import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.VersionHelper; - -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; - -public abstract class AbstractJukeboxSongManager implements JukeboxSongManager { - protected final Map songs = new HashMap<>(); - protected CraftEngine plugin; - - public AbstractJukeboxSongManager(CraftEngine plugin) { - this.plugin = plugin; - } - - @Override - public void unload() { - this.songs.clear(); - } - - @Override - public void delayedLoad() { - if (!VersionHelper.isVersionNewerThan1_21()) return; - this.registerSongs(this.songs); - } - - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - if (this.songs.containsKey(id)) { - this.plugin.logger().warn("Duplicate song id: " + id); - return; - } - String sound = (String) section.get("sound"); - if (sound == null) { - this.plugin.logger().warn(path, "No sound specified"); - return; - } - Component description = AdventureHelper.miniMessage(section.getOrDefault("description", "").toString()); - float length = MiscUtils.getAsFloat(section.get("length")); - int comparatorOutput = MiscUtils.getAsInt(section.getOrDefault("comparator-output", 15)); - JukeboxSong song = new JukeboxSong(Key.of(sound), description, length, comparatorOutput, MiscUtils.getAsFloat(section.getOrDefault("range", 32f))); - this.songs.put(id, song); - } - - protected abstract void registerSongs(Map songs); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java deleted file mode 100644 index 25d6ca26b..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/song/JukeboxSongManager.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.momirealms.craftengine.core.sound.song; - -import net.momirealms.craftengine.core.pack.LoadingSequence; -import net.momirealms.craftengine.core.plugin.Reloadable; -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; - -public interface JukeboxSongManager extends Reloadable, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "song", "songs", "jukebox", "jukebox_song"}; - - @Override - default int loadingSequence() { - return LoadingSequence.JUKEBOX_SONG; - } - - @Override - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } -} From 72f49eccc0b662f626631b01048c2a8396cc069c Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 04:25:45 +0800 Subject: [PATCH 16/37] refactor furniture --- .../bukkit/api/CraftEngineFurniture.java | 12 +- .../furniture/BukkitFurnitureManager.java | 277 ++++++++---------- .../entity/furniture/LoadedFurniture.java | 50 ++-- .../item/behavior/FurnitureItemBehavior.java | 4 +- .../feature/DebugSpawnFurnitureCommand.java | 2 +- .../plugin/network/PacketConsumers.java | 8 +- .../furniture/AbstractFurnitureManager.java | 40 +++ .../core/entity/furniture/Furniture.java | 49 ++++ .../entity/furniture/FurnitureManager.java | 33 ++- .../craftengine/core/plugin/CraftEngine.java | 2 +- 10 files changed, 280 insertions(+), 197 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java index 436f677b3..fca21a6cc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java @@ -34,7 +34,7 @@ public class CraftEngineFurniture { * @return the custom furniture */ public static CustomFurniture byId(@NotNull Key id) { - return BukkitFurnitureManager.instance().getFurniture(id).orElse(null); + return BukkitFurnitureManager.instance().furnitureById(id).orElse(null); } /** @@ -139,7 +139,7 @@ public class CraftEngineFurniture { */ @Nullable public static LoadedFurniture getLoadedFurnitureByBaseEntity(@NotNull Entity baseEntity) { - return BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(baseEntity.getEntityId()); + return BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(baseEntity.getEntityId()); } /** @@ -152,7 +152,7 @@ public class CraftEngineFurniture { public static LoadedFurniture getLoadedFurnitureBySeat(@NotNull Entity seat) { Integer baseEntityId = seat.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); if (baseEntityId == null) return null; - return BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(baseEntityId); + return BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(baseEntityId); } /** @@ -163,7 +163,7 @@ public class CraftEngineFurniture { */ public static boolean remove(@NotNull Entity furniture) { if (!isFurniture(furniture)) return false; - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(furniture.getEntityId()); + LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(furniture.getEntityId()); if (loadedFurniture == null) return false; loadedFurniture.destroy(); return true; @@ -181,7 +181,7 @@ public class CraftEngineFurniture { boolean dropLoot, boolean playSound) { if (!isFurniture(furniture)) return false; - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(furniture.getEntityId()); + LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(furniture.getEntityId()); if (loadedFurniture == null) return false; remove(loadedFurniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound); return true; @@ -201,7 +201,7 @@ public class CraftEngineFurniture { boolean dropLoot, boolean playSound) { if (!isFurniture(furniture)) return false; - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(furniture.getEntityId()); + LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(furniture.getEntityId()); if (loadedFurniture == null) return false; remove(loadedFurniture, player, dropLoot, playSound); return true; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index c499b31c8..4e1878aeb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -10,13 +10,15 @@ import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.loot.LootTable; +import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.ConfigManager; -import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.Vec3d; import org.bukkit.*; import org.bukkit.entity.*; import org.bukkit.event.HandlerList; @@ -31,35 +33,35 @@ import java.nio.file.Path; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -public class BukkitFurnitureManager implements FurnitureManager { +public class BukkitFurnitureManager extends AbstractFurnitureManager { public static final NamespacedKey FURNITURE_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:furniture_id")); public static final NamespacedKey FURNITURE_ANCHOR_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:anchor_type")); public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:seat_to_base_entity")); public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:seat_vector")); private static BukkitFurnitureManager instance; private final BukkitCraftEngine plugin; - - private final Map byId = new HashMap<>(); - + private final FurnitureParser furnitureParser; private final Map furnitureByRealEntityId = new ConcurrentHashMap<>(256, 0.5f); private final Map furnitureByEntityId = new ConcurrentHashMap<>(512, 0.5f); // Event listeners private final Listener dismountListener; private final FurnitureEventListener furnitureEventListener; - // tick task - private SchedulerTask tickTask; - // Cached command suggestions - private final List cachedSuggestions = new ArrayList<>(); public static BukkitFurnitureManager instance() { return instance; } public BukkitFurnitureManager(BukkitCraftEngine plugin) { + instance = this; this.plugin = plugin; + this.furnitureParser = new FurnitureParser(); this.furnitureEventListener = new FurnitureEventListener(this); this.dismountListener = VersionHelper.isVersionNewerThan1_20_3() ? new DismountListener1_20_3(this) : new DismountListener1_20(this::handleDismount); - instance = this; + } + + @Override + public Furniture place(CustomFurniture furniture, Vec3d vec3d, net.momirealms.craftengine.core.world.World world, AnchorType anchorType, boolean playSound) { + return this.place(furniture, new Location((World) world.platformWorld(), vec3d.x(), vec3d.y(), vec3d.z()), anchorType, playSound); } public LoadedFurniture place(CustomFurniture furniture, Location location, AnchorType anchorType, boolean playSound) { @@ -77,151 +79,131 @@ public class BukkitFurnitureManager implements FurnitureManager { SoundData data = furniture.settings().sounds().placeSound(); location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume(), data.pitch()); } - return getLoadedFurnitureByRealEntityId(furnitureEntity.getEntityId()); + return loadedFurnitureByRealEntityId(furnitureEntity.getEntityId()); } @Override - public void delayedLoad() { - this.initSuggestions(); + public ConfigSectionParser parser() { + return this.furnitureParser; } - @Override - public void initSuggestions() { - this.cachedSuggestions.clear(); - for (Key key : this.byId.keySet()) { - this.cachedSuggestions.add(Suggestion.suggestion(key.toString())); - } - } + public class FurnitureParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; - @Override - public Collection cachedSuggestions() { - return Collections.unmodifiableCollection(this.cachedSuggestions); - } - - @SuppressWarnings("unchecked") - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - Map lootMap = MiscUtils.castToMap(section.get("loot"), true); - Map settingsMap = MiscUtils.castToMap(section.get("settings"), true); - Map placementMap = MiscUtils.castToMap(section.get("placement"), true); - EnumMap placements = new EnumMap<>(AnchorType.class); - if (placementMap == null) { - throw new IllegalArgumentException("Missing required parameter 'placement' for furniture " + id); + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; } - for (Map.Entry entry : placementMap.entrySet()) { - // anchor type - AnchorType anchorType = AnchorType.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH)); - Map placementArguments = MiscUtils.castToMap(entry.getValue(), true); + @Override + public int loadingSequence() { + return LoadingSequence.FURNITURE; + } - // furniture display elements - List elements = new ArrayList<>(); - List> elementConfigs = (List>) placementArguments.getOrDefault("elements", List.of()); - for (Map element : elementConfigs) { - String key = (String) element.get("item"); - if (key == null) { - throw new IllegalArgumentException("Missing required parameter 'item' for furniture " + id); + @SuppressWarnings("unchecked") + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + Map lootMap = MiscUtils.castToMap(section.get("loot"), true); + Map settingsMap = MiscUtils.castToMap(section.get("settings"), true); + Map placementMap = MiscUtils.castToMap(section.get("placement"), true); + EnumMap placements = new EnumMap<>(AnchorType.class); + if (placementMap == null) { + throw new IllegalArgumentException("Missing required parameter 'placement' for furniture " + id); + } + + for (Map.Entry entry : placementMap.entrySet()) { + // anchor type + AnchorType anchorType = AnchorType.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH)); + Map placementArguments = MiscUtils.castToMap(entry.getValue(), true); + + // furniture display elements + List elements = new ArrayList<>(); + List> elementConfigs = (List>) placementArguments.getOrDefault("elements", List.of()); + for (Map element : elementConfigs) { + String key = (String) element.get("item"); + if (key == null) { + throw new IllegalArgumentException("Missing required parameter 'item' for furniture " + id); + } + ItemDisplayContext transform = ItemDisplayContext.valueOf(element.getOrDefault("transform", "NONE").toString().toUpperCase(Locale.ENGLISH)); + Billboard billboard = Billboard.valueOf(element.getOrDefault("billboard", "FIXED").toString().toUpperCase(Locale.ENGLISH)); + FurnitureElement furnitureElement = new BukkitFurnitureElement(Key.of(key), billboard, transform, + MiscUtils.getVector3f(element.getOrDefault("scale", "1")), + MiscUtils.getVector3f(element.getOrDefault("translation", "0")), + MiscUtils.getVector3f(element.getOrDefault("position", "0")), + MiscUtils.getQuaternionf(element.getOrDefault("rotation", "0")) + ); + elements.add(furnitureElement); + } + + // add colliders + List colliders = new ArrayList<>(); + + // external model providers + Optional externalModel; + if (placementArguments.containsKey("model-engine")) { + externalModel = Optional.of(new ModelEngineModel(placementArguments.get("model-engine").toString())); + } else if (placementArguments.containsKey("better-model")) { + externalModel = Optional.of(new BetterModelModel(placementArguments.get("better-model").toString())); + } else { + externalModel = Optional.empty(); + } + + // add hitboxes + List> hitboxConfigs = (List>) placementArguments.getOrDefault("hitboxes", List.of()); + List hitboxes = new ArrayList<>(); + for (Map config : hitboxConfigs) { + HitBox hitBox = HitBoxTypes.fromMap(config); + hitboxes.add(hitBox); + hitBox.optionalCollider().ifPresent(colliders::add); + } + if (hitboxes.isEmpty() && externalModel.isEmpty()) { + hitboxes.add(InteractionHitBox.DEFAULT); + } + + // rules + Map ruleSection = MiscUtils.castToMap(placementArguments.get("rules"), true); + if (ruleSection != null) { + RotationRule rotationRule = Optional.ofNullable((String) ruleSection.get("rotation")) + .map(it -> RotationRule.valueOf(it.toUpperCase(Locale.ENGLISH))) + .orElse(RotationRule.ANY); + AlignmentRule alignmentRule = Optional.ofNullable((String) ruleSection.get("alignment")) + .map(it -> AlignmentRule.valueOf(it.toUpperCase(Locale.ENGLISH))) + .orElse(AlignmentRule.CENTER); + placements.put(anchorType, new CustomFurniture.Placement( + elements.toArray(new FurnitureElement[0]), + hitboxes.toArray(new HitBox[0]), + colliders.toArray(new Collider[0]), + rotationRule, + alignmentRule, + externalModel + )); + } else { + placements.put(anchorType, new CustomFurniture.Placement( + elements.toArray(new FurnitureElement[0]), + hitboxes.toArray(new HitBox[0]), + colliders.toArray(new Collider[0]), + RotationRule.ANY, + AlignmentRule.CENTER, + externalModel + )); } - ItemDisplayContext transform = ItemDisplayContext.valueOf(element.getOrDefault("transform", "NONE").toString().toUpperCase(Locale.ENGLISH)); - Billboard billboard = Billboard.valueOf(element.getOrDefault("billboard", "FIXED").toString().toUpperCase(Locale.ENGLISH)); - FurnitureElement furnitureElement = new BukkitFurnitureElement(Key.of(key), billboard, transform, - MiscUtils.getVector3f(element.getOrDefault("scale", "1")), - MiscUtils.getVector3f(element.getOrDefault("translation", "0")), - MiscUtils.getVector3f(element.getOrDefault("position", "0")), - MiscUtils.getQuaternionf(element.getOrDefault("rotation", "0")) - ); - elements.add(furnitureElement); } - // add colliders - List colliders = new ArrayList<>(); -// List> colliderConfigs = (List>) placementArguments.getOrDefault("colliders", List.of()); -// for (Map config : colliderConfigs) { -// if (!config.containsKey("position")) { -// colliders.add(new Collider( -// (boolean) config.getOrDefault("can-be-hit-by-projectile", false), -// MiscUtils.getVector3d(config.getOrDefault("point-1", "0")), -// MiscUtils.getVector3d(config.getOrDefault("point-2", "0")) -// )); -// } else { -// colliders.add(new Collider( -// (boolean) config.getOrDefault("can-be-hit-by-projectile", false), -// MiscUtils.getVector3f(config.getOrDefault("position", "0")), -// MiscUtils.getAsFloat(config.getOrDefault("width", "1")), -// MiscUtils.getAsFloat(config.getOrDefault("height", "1")) -// )); -// } -// } + CustomFurniture furniture = new CustomFurniture( + id, + FurnitureSettings.fromMap(settingsMap), + placements, + lootMap == null ? null : LootTable.fromMap(lootMap) + ); - // external model providers - Optional externalModel; - if (placementArguments.containsKey("model-engine")) { - externalModel = Optional.of(new ModelEngineModel(placementArguments.get("model-engine").toString())); - } else if (placementArguments.containsKey("better-model")) { - externalModel = Optional.of(new BetterModelModel(placementArguments.get("better-model").toString())); - } else { - externalModel = Optional.empty(); - } - - // add hitboxes - List> hitboxConfigs = (List>) placementArguments.getOrDefault("hitboxes", List.of()); - List hitboxes = new ArrayList<>(); - for (Map config : hitboxConfigs) { - HitBox hitBox = HitBoxTypes.fromMap(config); - hitboxes.add(hitBox); - hitBox.optionalCollider().ifPresent(colliders::add); - } - if (hitboxes.isEmpty() && externalModel.isEmpty()) { - hitboxes.add(InteractionHitBox.DEFAULT); - } - - // rules - Map ruleSection = MiscUtils.castToMap(placementArguments.get("rules"), true); - if (ruleSection != null) { - RotationRule rotationRule = Optional.ofNullable((String) ruleSection.get("rotation")) - .map(it -> RotationRule.valueOf(it.toUpperCase(Locale.ENGLISH))) - .orElse(RotationRule.ANY); - AlignmentRule alignmentRule = Optional.ofNullable((String) ruleSection.get("alignment")) - .map(it -> AlignmentRule.valueOf(it.toUpperCase(Locale.ENGLISH))) - .orElse(AlignmentRule.CENTER); - placements.put(anchorType, new CustomFurniture.Placement( - elements.toArray(new FurnitureElement[0]), - hitboxes.toArray(new HitBox[0]), - colliders.toArray(new Collider[0]), - rotationRule, - alignmentRule, - externalModel - )); - } else { - placements.put(anchorType, new CustomFurniture.Placement( - elements.toArray(new FurnitureElement[0]), - hitboxes.toArray(new HitBox[0]), - colliders.toArray(new Collider[0]), - RotationRule.ANY, - AlignmentRule.CENTER, - externalModel - )); - } + byId.put(id, furniture); } - - CustomFurniture furniture = new CustomFurniture( - id, - FurnitureSettings.fromMap(settingsMap), - placements, - lootMap == null ? null : LootTable.fromMap(lootMap) - ); - - this.byId.put(id, furniture); - } - - public void tick() { } @Override public void delayedInit() { Bukkit.getPluginManager().registerEvents(this.dismountListener, this.plugin.bootstrap()); Bukkit.getPluginManager().registerEvents(this.furnitureEventListener, this.plugin.bootstrap()); - this.tickTask = plugin.scheduler().sync().runRepeating(this::tick, 1, 1); for (World world : Bukkit.getWorlds()) { List entities = world.getEntities(); for (Entity entity : entities) { @@ -230,18 +212,10 @@ public class BukkitFurnitureManager implements FurnitureManager { } } - @Override - public void unload() { - this.byId.clear(); - } - @Override public void disable() { HandlerList.unregisterAll(this.dismountListener); HandlerList.unregisterAll(this.furnitureEventListener); - if (tickTask != null && !tickTask.cancelled()) { - tickTask.cancel(); - } unload(); for (Player player : Bukkit.getOnlinePlayers()) { Entity vehicle = player.getVehicle(); @@ -251,23 +225,20 @@ public class BukkitFurnitureManager implements FurnitureManager { } } - @Override - public Optional getFurniture(Key id) { - return Optional.ofNullable(this.byId.get(id)); - } - @Override public boolean isFurnitureRealEntity(int entityId) { return this.furnitureByRealEntityId.containsKey(entityId); } @Nullable - public LoadedFurniture getLoadedFurnitureByRealEntityId(int entityId) { + @Override + public LoadedFurniture loadedFurnitureByRealEntityId(int entityId) { return this.furnitureByRealEntityId.get(entityId); } + @Override @Nullable - public LoadedFurniture getLoadedFurnitureByEntityId(int entityId) { + public LoadedFurniture loadedFurnitureByEntityId(int entityId) { return this.furnitureByEntityId.get(entityId); } @@ -296,7 +267,7 @@ public class BukkitFurnitureManager implements FurnitureManager { String id = entity.getPersistentDataContainer().get(FURNITURE_KEY, PersistentDataType.STRING); if (id == null) return; Key key = Key.of(id); - Optional optionalFurniture = getFurniture(key); + Optional optionalFurniture = furnitureById(key); if (optionalFurniture.isEmpty()) return; CustomFurniture customFurniture = optionalFurniture.get(); LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); @@ -318,7 +289,7 @@ public class BukkitFurnitureManager implements FurnitureManager { String id = entity.getPersistentDataContainer().get(FURNITURE_KEY, PersistentDataType.STRING); if (id == null) return; Key key = Key.of(id); - Optional optionalFurniture = getFurniture(key); + Optional optionalFurniture = furnitureById(key); if (optionalFurniture.isPresent()) { CustomFurniture customFurniture = optionalFurniture.get(); LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); @@ -375,7 +346,7 @@ public class BukkitFurnitureManager implements FurnitureManager { Integer baseFurniture = vehicle.getPersistentDataContainer().get(FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); if (baseFurniture == null) return; vehicle.remove(); - LoadedFurniture furniture = getLoadedFurnitureByRealEntityId(baseFurniture); + LoadedFurniture furniture = loadedFurnitureByRealEntityId(baseFurniture); if (furniture == null) { return; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index 668c35060..74862a595 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -6,12 +6,15 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils; import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.ArrayUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.QuaternionUtils; import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; import org.bukkit.Location; import org.bukkit.attribute.Attribute; import org.bukkit.entity.*; @@ -24,7 +27,7 @@ import org.joml.Vector3f; import java.lang.ref.WeakReference; import java.util.*; -public class LoadedFurniture { +public class LoadedFurniture implements Furniture { private final Key id; private final CustomFurniture furniture; private final AnchorType anchorType; @@ -144,6 +147,7 @@ public class LoadedFurniture { } } + @Override public void initializeColliders() { Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.location.getWorld()); for (CollisionEntity entity : this.collisionEntities) { @@ -161,6 +165,16 @@ public class LoadedFurniture { } } + @Override + public Vec3d position() { + return new Vec3d(location.getX(), location.getY(), location.getZ()); + } + + @Override + public World world() { + return new BukkitWorld(this.location.getWorld()); + } + @NotNull public Location location() { return this.location.clone(); @@ -175,10 +189,12 @@ public class LoadedFurniture { return entity; } + @Override public boolean isValid() { return baseEntity().isValid(); } + @Override public void destroy() { if (!isValid()) { return; @@ -197,6 +213,7 @@ public class LoadedFurniture { this.seats.clear(); } + @Override public void destroySeats() { for (Entity entity : this.seats) { entity.remove(); @@ -204,6 +221,7 @@ public class LoadedFurniture { this.seats.clear(); } + @Override public Optional findFirstAvailableSeat(int targetEntityId) { HitBox hitbox = hitBoxes.get(targetEntityId); if (hitbox == null) return Optional.empty(); @@ -216,14 +234,12 @@ public class LoadedFurniture { .findFirst(); } + @Override public boolean removeOccupiedSeat(Vector3f seat) { return this.occupiedSeats.remove(seat); } - public boolean removeOccupiedSeat(Seat seat) { - return this.removeOccupiedSeat(seat.offset()); - } - + @Override public boolean tryOccupySeat(Seat seat) { if (this.occupiedSeats.contains(seat.offset())) { return false; @@ -232,10 +248,12 @@ public class LoadedFurniture { return true; } + @Override public UUID uuid() { return this.baseEntity().getUniqueId(); } + @Override public int baseEntityId() { return this.baseEntityId; } @@ -254,31 +272,29 @@ public class LoadedFurniture { return this.collisionEntities; } - @NotNull - public AnchorType anchorType() { + @Override + public @NotNull AnchorType anchorType() { return this.anchorType; } - @NotNull - public Key id() { + @Override + public @NotNull Key id() { return this.id; } - @NotNull - public CustomFurniture config() { + @Override + public @NotNull CustomFurniture config() { return this.furniture; } + @Override public boolean hasExternalModel() { return hasExternalModel; } - public CustomFurniture.Placement placement() { - return this.placement; - } - - public Map hitBoxes() { - return this.hitBoxes; + @Override + public void spawnSeatEntityForPlayer(net.momirealms.craftengine.core.entity.player.Player player, Seat seat) { + spawnSeatEntityForPlayer((Player) player.platformPlayer(), seat); } public void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java index f0dec7311..76f777fbd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java @@ -47,7 +47,7 @@ public class FurnitureItemBehavior extends ItemBehavior { } public InteractionResult place(UseOnContext context) { - Optional optionalCustomFurniture = BukkitFurnitureManager.instance().getFurniture(this.id); + Optional optionalCustomFurniture = BukkitFurnitureManager.instance().furnitureById(this.id); if (optionalCustomFurniture.isEmpty()) { CraftEngine.instance().logger().warn("Furniture " + this.id + " not found"); return InteractionResult.FAIL; @@ -139,7 +139,7 @@ public class FurnitureItemBehavior extends ItemBehavior { throw new IllegalArgumentException("Missing required parameter 'furniture' for furniture_item behavior"); } if (id instanceof Map map) { - BukkitFurnitureManager.instance().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitFurnitureManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); return new FurnitureItemBehavior(key); } else { return new FurnitureItemBehavior(Key.of(id.toString())); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java index f5bbb5a8f..df390ccf2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java @@ -47,7 +47,7 @@ public class DebugSpawnFurnitureCommand extends BukkitCommandFeature optionalCustomFurniture = furnitureManager.getFurniture(id); + Optional optionalCustomFurniture = furnitureManager.furnitureById(id); if (optionalCustomFurniture.isEmpty()) { return; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index f7df2d8ab..42372cd01 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -563,7 +563,7 @@ public class PacketConsumers { public static final TriConsumer PICK_ITEM_FROM_ENTITY = (user, event, packet) -> { try { int entityId = (int) Reflections.field$ServerboundPickItemFromEntityPacket$id.get(packet); - LoadedFurniture furniture = BukkitFurnitureManager.instance().getLoadedFurnitureByEntityId(entityId); + LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); if (furniture == null) return; Player player = (Player) user.platformPlayer(); if (player == null) return; @@ -622,7 +622,7 @@ public class PacketConsumers { } else if (entityType == Reflections.instance$EntityType$ITEM_DISPLAY) { // Furniture int entityId = (int) Reflections.field$ClientboundAddEntityPacket$entityId.get(packet); - LoadedFurniture furniture = BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(entityId); + LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); if (furniture != null) { user.furnitureView().computeIfAbsent(furniture.baseEntityId(), k -> new ArrayList<>()).addAll(furniture.fakeEntityIds()); user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); @@ -633,7 +633,7 @@ public class PacketConsumers { } else if (entityType == Reflections.instance$EntityType$SHULKER) { // Cancel collider entity packet int entityId = (int) Reflections.field$ClientboundAddEntityPacket$entityId.get(packet); - LoadedFurniture furniture = BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(entityId); + LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); if (furniture != null) { event.setCancelled(true); } @@ -694,7 +694,7 @@ public class PacketConsumers { Object action = Reflections.field$ServerboundInteractPacket$action.get(packet); Object actionType = Reflections.method$ServerboundInteractPacket$Action$getType.invoke(action); if (actionType == null) return; - LoadedFurniture furniture = BukkitFurnitureManager.instance().getLoadedFurnitureByEntityId(entityId); + LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); if (furniture == null) return; Location location = furniture.baseEntity().getLocation(); BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java new file mode 100644 index 000000000..c9839cb60 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import net.momirealms.craftengine.core.util.Key; +import org.incendo.cloud.suggestion.Suggestion; + +import java.util.*; + +public abstract class AbstractFurnitureManager implements FurnitureManager { + protected final Map byId = new HashMap<>(); + // Cached command suggestions + private final List cachedSuggestions = new ArrayList<>(); + + @Override + public void delayedLoad() { + this.initSuggestions(); + } + + @Override + public void initSuggestions() { + this.cachedSuggestions.clear(); + for (Key key : this.byId.keySet()) { + this.cachedSuggestions.add(Suggestion.suggestion(key.toString())); + } + } + + @Override + public Collection cachedSuggestions() { + return Collections.unmodifiableCollection(this.cachedSuggestions); + } + + @Override + public Optional furnitureById(Key id) { + return Optional.ofNullable(this.byId.get(id)); + } + + @Override + public void unload() { + this.byId.clear(); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java new file mode 100644 index 000000000..42998e48b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/Furniture.java @@ -0,0 +1,49 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3f; + +import java.util.Optional; +import java.util.UUID; + +public interface Furniture { + void initializeColliders(); + + Vec3d position(); + + World world(); + + boolean isValid(); + + void destroy(); + + void destroySeats(); + + Optional findFirstAvailableSeat(int targetEntityId); + + boolean removeOccupiedSeat(Vector3f seat); + + default boolean removeOccupiedSeat(Seat seat) { + return this.removeOccupiedSeat(seat.offset()); + } + + boolean tryOccupySeat(Seat seat); + + UUID uuid(); + + int baseEntityId(); + + @NotNull AnchorType anchorType(); + + @NotNull Key id(); + + @NotNull CustomFurniture config(); + + boolean hasExternalModel(); + + void spawnSeatEntityForPlayer(Player player, Seat seat); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java index 8f053198c..0985250f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java @@ -1,33 +1,40 @@ package net.momirealms.craftengine.core.entity.furniture; -import net.momirealms.craftengine.core.pack.LoadingSequence; +import net.momirealms.craftengine.core.entity.Entity; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; import org.incendo.cloud.suggestion.Suggestion; +import javax.annotation.Nullable; import java.util.Collection; import java.util.Optional; -public interface FurnitureManager extends Reloadable, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; +public interface FurnitureManager extends Reloadable { String FURNITURE_ADMIN_NODE = "craftengine.furniture.admin"; + ConfigSectionParser parser(); + void initSuggestions(); Collection cachedSuggestions(); - @Override - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } + Furniture place(CustomFurniture furniture, Vec3d vec3d, World world, AnchorType anchorType, boolean playSound); - @Override - default int loadingSequence() { - return LoadingSequence.FURNITURE; - } - - Optional getFurniture(Key id); + Optional furnitureById(Key id); boolean isFurnitureRealEntity(int entityId); + + @Nullable + Furniture loadedFurnitureByRealEntityId(int entityId); + + @Nullable + default Furniture loadedFurnitureByRealEntity(Entity entity) { + return loadedFurnitureByRealEntityId(entity.entityID()); + } + + @Nullable + Furniture loadedFurnitureByEntityId(int entityId); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index db7667305..bce65b429 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -192,7 +192,7 @@ public abstract class CraftEngine implements Plugin { // register item parser this.packManager.registerConfigSectionParser(this.itemManager); // register furniture parser - this.packManager.registerConfigSectionParser(this.furnitureManager); + this.packManager.registerConfigSectionParser(this.furnitureManager.parser()); // register block parser this.packManager.registerConfigSectionParser(this.blockManager); // register recipe parser From 83af6892681114a1b5b6a6702c729b806c9e0fb1 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 04:46:12 +0800 Subject: [PATCH 17/37] refactor items --- .../src/main/resources/translations/en.yml | 11 +- .../furniture/BukkitFurnitureManager.java | 13 +- .../bukkit/item/BukkitItemManager.java | 343 ++++++++++-------- .../craftengine/core/item/ItemManager.java | 12 +- .../craftengine/core/plugin/CraftEngine.java | 2 +- 5 files changed, 217 insertions(+), 164 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 66632d11f..37c7bea86 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -69,4 +69,13 @@ warning.config.template.duplicated: "Issue found in file - Dupli warning.config.vanilla_loot.type_not_exist: "Issue found in file - 'type' not set for vanilla loot ''." warning.config.vanilla_loot.block.invalid_target: "Issue found in file - Invalid block target [] in vanilla loot ''." warning.config.sound.duplicated: "Issue found in file - Duplicated sound ''." -warning.config.jukebox_song.duplicated: "Issue found in file - Duplicated jukebox song ''." \ No newline at end of file +warning.config.jukebox_song.duplicated: "Issue found in file - Duplicated jukebox song ''." +warning.config.furniture.duplicated: "Issue found in file - Duplicated furniture ''." +warning.config.furniture.lack_placement: "Issue found in file - The furniture '' is missing the required 'placement' argument." +warning.config.furniture.element.lack_item: "Issue found in file - The furniture '' is missing the required 'item' argument for one of its elements." +warning.config.item.duplicated: "Issue found in file - Duplicated item ''." +warning.config.item.lack_material: "Issue found in file - The item '' is missing the required 'material' argument." +warning.config.item.invalid_material: "Issue found in file - The item '' is using an invalid material type ''." +warning.config.item.bad_custom_model_data_value: "Issue found in file - The item '' is using a custom model data [] that is too large. It's recommended to use a value lower than 16,777,216." +warning.config.item.custom_model_data_conflict: "Issue found in file - The item '' is using a custom model data [] that has been occupied by item ''" +warning.config.item.lack_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index 4e1878aeb..8d1d3f857 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -24,7 +25,6 @@ import org.bukkit.entity.*; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.persistence.PersistentDataType; -import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; @@ -103,12 +103,18 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { @SuppressWarnings("unchecked") @Override public void parseSection(Pack pack, Path path, Key id, Map section) { + if (byId.containsKey(id)) { + TranslationManager.instance().log("warning.config.furniture.duplicated", path.toString(), id.toString()); + return; + } + Map lootMap = MiscUtils.castToMap(section.get("loot"), true); Map settingsMap = MiscUtils.castToMap(section.get("settings"), true); Map placementMap = MiscUtils.castToMap(section.get("placement"), true); EnumMap placements = new EnumMap<>(AnchorType.class); if (placementMap == null) { - throw new IllegalArgumentException("Missing required parameter 'placement' for furniture " + id); + TranslationManager.instance().log("warning.config.furniture.lack_placement", path.toString(), id.toString()); + return; } for (Map.Entry entry : placementMap.entrySet()) { @@ -122,7 +128,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { for (Map element : elementConfigs) { String key = (String) element.get("item"); if (key == null) { - throw new IllegalArgumentException("Missing required parameter 'item' for furniture " + id); + TranslationManager.instance().log("warning.config.furniture.element.lack_item", path.toString(), id.toString()); + return; } ItemDisplayContext transform = ItemDisplayContext.valueOf(element.getOrDefault("transform", "NONE").toString().toUpperCase(Locale.ENGLISH)); Billboard billboard = Billboard.valueOf(element.getOrDefault("billboard", "FIXED").toString().toUpperCase(Locale.ENGLISH)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index ef2df937e..f5097fb49 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -18,13 +18,17 @@ import net.momirealms.craftengine.core.item.modifier.CustomModelDataModifier; import net.momirealms.craftengine.core.item.modifier.IdModifier; import net.momirealms.craftengine.core.item.modifier.ItemModelModifier; import net.momirealms.craftengine.core.pack.LegacyOverridesModel; +import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; import net.momirealms.craftengine.core.pack.model.*; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.select.ChargeTypeSelectProperty; import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectProperty; import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.WritableRegistry; @@ -59,6 +63,7 @@ public class BukkitItemManager extends AbstractItemManager { private final BukkitCraftEngine plugin; private final ItemEventListener itemEventListener; private final DebugStickListener debugStickListener; + private final ItemParser itemParser; public BukkitItemManager(BukkitCraftEngine plugin) { super(plugin); @@ -66,6 +71,7 @@ public class BukkitItemManager extends AbstractItemManager { this.factory = BukkitItemFactory.create(plugin); this.itemEventListener = new ItemEventListener(plugin); this.debugStickListener = new DebugStickListener(plugin); + this.itemParser = new ItemParser(); this.registerAllVanillaItems(); instance = this; } @@ -120,6 +126,11 @@ public class BukkitItemManager extends AbstractItemManager { HandlerList.unregisterAll(this.debugStickListener); } + @Override + public ConfigSectionParser parser() { + return this.itemParser; + } + @Override public ItemStack buildCustomItemStack(Key id, Player player) { return Optional.ofNullable(customItems.get(id)).map(it -> it.buildItemStack(new ItemBuildContext(player, ContextHolder.EMPTY), 1)).orElse(null); @@ -176,175 +187,209 @@ public class BukkitItemManager extends AbstractItemManager { return wrapped.id(); } - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - // just register for recipes - Holder.Reference holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(id) - .orElseGet(() -> ((WritableRegistry) BuiltInRegistries.OPTIMIZED_ITEM_ID) - .register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), id), id)); + public class ItemParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; - String materialStringId = (String) section.get("material"); - Material material = MaterialUtils.getMaterial(materialStringId); - if (material == null) { - plugin.logger().warn(path, "material " + Optional.ofNullable(materialStringId).map(it -> it + " ").orElse("") + "does not exist for item " + id); - return; - } - Key materialId = Key.of(material.getKey().namespace(), material.getKey().value()); - - int customModelData = MiscUtils.getAsInt(section.getOrDefault("custom-model-data", 0)); - Key itemModelKey = null; - - CustomItem.Builder itemBuilder = BukkitCustomItem.builder().id(id).material(materialId); - itemBuilder.modifier(new IdModifier<>(id)); - - boolean hasItemModelSection = section.containsKey("item-model"); - - // To get at least one model provider - // Sets some basic model info - if (customModelData != 0) { - itemBuilder.modifier(new CustomModelDataModifier<>(customModelData)); - } - // Requires the item to have model before apply item-model - else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isVersionNewerThan1_21_2()) { - // check server version here because components require 1.21.2+ - // customize or use the id - itemModelKey = Key.from(section.getOrDefault("item-model", id.toString()).toString()); - itemBuilder.modifier(new ItemModelModifier<>(itemModelKey)); + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; } - if (hasItemModelSection) { - itemModelKey = Key.from(section.get("item-model").toString()); - itemBuilder.modifier(new ItemModelModifier<>(itemModelKey)); + @Override + public int loadingSequence() { + return LoadingSequence.ITEM; } - // Get item behaviors - Object behaviorConfig = section.get("behavior"); - if (behaviorConfig instanceof List) { - @SuppressWarnings("unchecked") - List> behavior = (List>) behaviorConfig; - List behaviors = new ArrayList<>(); - for (Map behaviorMap : behavior) { - behaviors.add(ItemBehaviors.fromMap(pack, path, id, behaviorMap)); - } - itemBuilder.behavior(behaviors); - } else if (behaviorConfig instanceof Map) { - Map behaviorSection = MiscUtils.castToMap(section.get("behavior"), true); - if (behaviorSection != null) { - itemBuilder.behavior(ItemBehaviors.fromMap(pack, path, id, behaviorSection)); - } - } - - // Get item data - Map dataSection = MiscUtils.castToMap(section.get("data"), true); - if (dataSection != null) { - for (Map.Entry dataEntry : dataSection.entrySet()) { - Optional.ofNullable(dataFunctions.get(dataEntry.getKey())).ifPresent(function -> { - try { - itemBuilder.modifier(function.apply(dataEntry.getValue())); - } catch (IllegalArgumentException e) { - plugin.logger().warn("Invalid data format", e); - } - }); - } - } - - if (section.containsKey("settings")) { - Map settings = MiscUtils.castToMap(section.get("settings"), false); - itemBuilder.settings(ItemSettings.fromMap(settings)); - } - - CustomItem customItem = itemBuilder.build(); - this.customItems.put(id, customItem); - this.cachedSuggestions.add(Suggestion.suggestion(id.toString())); - if (material == Material.TOTEM_OF_UNDYING) - this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); - - // post process - // register tags - Set tags = customItem.settings().tags(); - for (Key tag : tags) { - this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(holder); - } - - // create trims - EquipmentGeneration equipment = customItem.settings().equipment(); - if (equipment != null) { - EquipmentData modern = equipment.modernData(); - // 1.21.2+ - if (modern != null) { - this.equipmentsToGenerate.add(equipment); - } - // TODO 1.20 - } - - // add it to category - if (section.containsKey("category")) { - this.plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); - } - - // model part, can be null - // but if it exists, either custom model data or item model should be configured - Map modelSection = MiscUtils.castToMap(section.get("model"), true); - if (modelSection == null) { - return; - } - - boolean hasModel = false; - if (customModelData != 0) { - hasModel= true; - // use custom model data - // check conflict - Map conflict = this.cmdConflictChecker.computeIfAbsent(materialId, k -> new HashMap<>()); - if (conflict.containsKey(customModelData)) { - plugin.logger().warn(path, "Failed to create model for " + id + " because custom-model-data " + customModelData + " already occupied by item " + conflict.get(customModelData).toString()); + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + if (customItems.containsKey(id)) { + TranslationManager.instance().log("warning.config.item.duplicated", path.toString(), id.toString()); return; } - conflict.put(customModelData, id); + // just register for recipes + Holder.Reference holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(id) + .orElseGet(() -> ((WritableRegistry) BuiltInRegistries.OPTIMIZED_ITEM_ID) + .register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), id), id)); - // Parse models - ItemModel model = ItemModels.fromMap(modelSection); - for (ModelGeneration generation : model.modelsToGenerate()) { - prepareModelGeneration(generation); + String materialStringId = (String) section.get("material"); + if (materialStringId == null) { + TranslationManager.instance().log("warning.config.item.lack_material", path.toString(), id.toString()); + return; } - if (ConfigManager.packMaxVersion() > 21.39f) { - TreeMap map = this.modernOverrides.computeIfAbsent(materialId, k -> new TreeMap<>()); - map.put(customModelData, model); + Material material = MaterialUtils.getMaterial(materialStringId); + if (material == null) { + TranslationManager.instance().log("warning.config.item.invalid_material", path.toString(), id.toString(), materialStringId); + return; + } + + Key materialId = Key.of(material.getKey().namespace(), material.getKey().value()); + int customModelData = MiscUtils.getAsInt(section.getOrDefault("custom-model-data", 0)); + Key itemModelKey = null; + + CustomItem.Builder itemBuilder = BukkitCustomItem.builder().id(id).material(materialId); + itemBuilder.modifier(new IdModifier<>(id)); + + boolean hasItemModelSection = section.containsKey("item-model"); + + // To get at least one model provider + // Sets some basic model info + if (customModelData != 0) { + itemBuilder.modifier(new CustomModelDataModifier<>(customModelData)); + } + // Requires the item to have model before apply item-model + else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isVersionNewerThan1_21_2()) { + // check server version here because components require 1.21.2+ + // customize or use the id + itemModelKey = Key.from(section.getOrDefault("item-model", id.toString()).toString()); + if (ResourceLocation.isValid(itemModelKey.toString())) { + itemBuilder.modifier(new ItemModelModifier<>(itemModelKey)); + } else { + itemModelKey = null; + } } - if (ConfigManager.packMinVersion() < 21.39f) { - List legacyOverridesModels = new ArrayList<>(); - processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, customModelData); - TreeSet lom = this.legacyOverrides.computeIfAbsent(materialId, k -> new TreeSet<>()); - lom.addAll(legacyOverridesModels); - } - } - if (itemModelKey != null) { - hasModel = true; - // use components - ItemModel model = ItemModels.fromMap(modelSection); - for (ModelGeneration generation : model.modelsToGenerate()) { - prepareModelGeneration(generation); + if (hasItemModelSection) { + itemModelKey = Key.from(section.get("item-model").toString()); + itemBuilder.modifier(new ItemModelModifier<>(itemModelKey)); } - if (ConfigManager.packMaxVersion() > 21.39f) { - this.modernItemModels1_21_4.put(itemModelKey, model); + // Get item behaviors + Object behaviorConfig = section.get("behavior"); + if (behaviorConfig instanceof List) { + @SuppressWarnings("unchecked") + List> behavior = (List>) behaviorConfig; + List behaviors = new ArrayList<>(); + for (Map behaviorMap : behavior) { + behaviors.add(ItemBehaviors.fromMap(pack, path, id, behaviorMap)); + } + itemBuilder.behavior(behaviors); + } else if (behaviorConfig instanceof Map) { + Map behaviorSection = MiscUtils.castToMap(section.get("behavior"), true); + if (behaviorSection != null) { + itemBuilder.behavior(ItemBehaviors.fromMap(pack, path, id, behaviorSection)); + } } - if (ConfigManager.packMaxVersion() > 21.19f && ConfigManager.packMinVersion() < 21.39f) { - List legacyOverridesModels = new ArrayList<>(); - processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, 0); - if (legacyOverridesModels.isEmpty()) { - plugin.logger().warn(path, "Can't convert " + id + "'s model to legacy format."); + // Get item data + Map dataSection = MiscUtils.castToMap(section.get("data"), true); + if (dataSection != null) { + for (Map.Entry dataEntry : dataSection.entrySet()) { + Optional.ofNullable(dataFunctions.get(dataEntry.getKey())).ifPresent(function -> { + try { + itemBuilder.modifier(function.apply(dataEntry.getValue())); + } catch (IllegalArgumentException e) { + plugin.logger().warn("Invalid data format", e); + } + }); + } + } + + if (section.containsKey("settings")) { + Map settings = MiscUtils.castToMap(section.get("settings"), false); + itemBuilder.settings(ItemSettings.fromMap(settings)); + } + + CustomItem customItem = itemBuilder.build(); + customItems.put(id, customItem); + + // cache command suggestions + cachedSuggestions.add(Suggestion.suggestion(id.toString())); + if (material == Material.TOTEM_OF_UNDYING) + cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); + + // post process + // register tags + Set tags = customItem.settings().tags(); + for (Key tag : tags) { + customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(holder); + } + + // create trims + EquipmentGeneration equipment = customItem.settings().equipment(); + if (equipment != null) { + EquipmentData modern = equipment.modernData(); + // 1.21.2+ + if (modern != null) { + equipmentsToGenerate.add(equipment); + } + // TODO 1.20 + } + + // add it to category + if (section.containsKey("category")) { + plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); + } + + // model part, can be null + // but if it exists, either custom model data or item model should be configured + Map modelSection = MiscUtils.castToMap(section.get("model"), true); + if (modelSection == null) { + return; + } + + boolean hasModel = false; + if (customModelData != 0) { + hasModel= true; + // use custom model data + // check conflict + Map conflict = cmdConflictChecker.computeIfAbsent(materialId, k -> new HashMap<>()); + if (conflict.containsKey(customModelData)) { + TranslationManager.instance().log("warning.config.item.custom_model_data_conflict", path.toString(), id.toString(), String.valueOf(customModelData), conflict.get(customModelData).toString()); return; } - legacyOverridesModels.sort(LegacyOverridesModel::compareTo); - this.modernItemModels1_21_2.put(itemModelKey, legacyOverridesModels); + + if (customModelData > 16_777_216) { + TranslationManager.instance().log("warning.config.item.bad_custom_model_data_value", path.toString(), id.toString(), String.valueOf(customModelData)); + } + + conflict.put(customModelData, id); + + // Parse models + ItemModel model = ItemModels.fromMap(modelSection); + for (ModelGeneration generation : model.modelsToGenerate()) { + prepareModelGeneration(generation); + } + + if (ConfigManager.packMaxVersion() > 21.39f) { + TreeMap map = modernOverrides.computeIfAbsent(materialId, k -> new TreeMap<>()); + map.put(customModelData, model); + } + + if (ConfigManager.packMinVersion() < 21.39f) { + List legacyOverridesModels = new ArrayList<>(); + processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, customModelData); + TreeSet lom = legacyOverrides.computeIfAbsent(materialId, k -> new TreeSet<>()); + lom.addAll(legacyOverridesModels); + } + } + if (itemModelKey != null) { + hasModel = true; + // use components + ItemModel model = ItemModels.fromMap(modelSection); + for (ModelGeneration generation : model.modelsToGenerate()) { + prepareModelGeneration(generation); + } + + if (ConfigManager.packMaxVersion() > 21.39f) { + modernItemModels1_21_4.put(itemModelKey, model); + } + + if (ConfigManager.packMaxVersion() > 21.19f && ConfigManager.packMinVersion() < 21.39f) { + List legacyOverridesModels = new ArrayList<>(); + processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, 0); + if (!legacyOverridesModels.isEmpty()) { + legacyOverridesModels.sort(LegacyOverridesModel::compareTo); + modernItemModels1_21_2.put(itemModelKey, legacyOverridesModels); + } else { + plugin.debug(() -> "Can't convert " + id + "'s model to legacy format."); + } + } + } + if (!hasModel) { + TranslationManager.instance().log("warning.config.item.lack_model_id", path.toString(), id.toString()); } - } - if (!hasModel) { - plugin.logger().warn(path, "No custom-model-data/item-model configured for " + id); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index c032cb13e..5362e6d3a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.pack.LegacyOverridesModel; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; import net.momirealms.craftengine.core.pack.model.ItemModel; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; @@ -16,12 +15,9 @@ import org.incendo.cloud.suggestion.Suggestion; import javax.annotation.Nullable; import java.util.*; -public interface ItemManager extends Reloadable, ModelGenerator, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; +public interface ItemManager extends Reloadable, ModelGenerator { - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } + ConfigSectionParser parser(); Map> legacyItemOverrides(); @@ -79,10 +75,6 @@ public interface ItemManager extends Reloadable, ModelGenerator, ConfigSectio int fuelTime(Key id); - default int loadingSequence() { - return LoadingSequence.ITEM; - } - Collection cachedSuggestions(); Collection cachedTotemSuggestions(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index bce65b429..88e5967fd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -190,7 +190,7 @@ public abstract class CraftEngine implements Plugin { // register font parser this.packManager.registerConfigSectionParsers(this.fontManager.parsers()); // register item parser - this.packManager.registerConfigSectionParser(this.itemManager); + this.packManager.registerConfigSectionParser(this.itemManager.parser()); // register furniture parser this.packManager.registerConfigSectionParser(this.furnitureManager.parser()); // register block parser From f8fd3f7743d330907e5ea264d4dfcaaf7884a494 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 05:18:50 +0800 Subject: [PATCH 18/37] refactor items --- .../src/main/resources/translations/en.yml | 16 +- .../src/main/resources/translations/es.yml | 4 +- .../src/main/resources/translations/zh_cn.yml | 4 +- .../src/main/resources/translations/zh_tw.yml | 4 +- .../bukkit/block/BukkitBlockManager.java | 243 +++++++++++------- .../item/behavior/BlockItemBehavior.java | 2 +- .../LiquidCollisionBlockItemBehavior.java | 2 +- .../plugin/command/feature/ReloadCommand.java | 26 +- .../craftengine/core/block/BlockManager.java | 11 +- .../core/font/AbstractFontManager.java | 5 + .../craftengine/core/plugin/CraftEngine.java | 12 +- 11 files changed, 196 insertions(+), 133 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 37c7bea86..ef65e98c7 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -38,11 +38,11 @@ argument.parse.failure.aggregate.missing: "Missing component ''Invalid component '': " argument.parse.failure.either: "Could not resolve or from ''" argument.parse.failure.namedtextcolor: "'' is not a named text color" -command.reload.config.success: "Configs reloaded in ms." +command.reload.config.success: "Configs reloaded in ms. (Async: ms | Sync: ms)" command.reload.config.failure: "Config reload failed. Check console logs." command.reload.pack.success: "Resource pack reloaded in ms." command.reload.pack.failure: "Resource pack reload failed. Check console logs." -command.reload.all.success: "Reload completed in ms." +command.reload.all.success: "Reload completed in ms. (Async: ms | Sync: ms | Pack: ms)" command.reload.all.failure: "Reload failed. Check console logs." command.item.get.success: "Got " command.item.get.failure.not_exist: "'>" @@ -54,6 +54,7 @@ command.search_usage.not_found: "No usage found for this item" command.search_recipe.no_item: "Please hold an item before running this command" command.search_usage.no_item: "Please hold an item before running this command" command.totem.not_totem: "'' is not type of totem_of_undying" +warning.config.image.duplicated: "Issue found in file - Duplicated image ''." warning.config.image.lack_height: "Issue found in file - The image '' is missing the required 'height' argument." warning.config.image.height_smaller_than_ascent: "Issue found in file - The image '' violates the bitmap image rule: 'height' should be no lower than 'ascent'." warning.config.image.no_file: "Issue found in file - The image '' is missing the required 'file' argument." @@ -78,4 +79,13 @@ warning.config.item.lack_material: "Issue found in file - The it warning.config.item.invalid_material: "Issue found in file - The item '' is using an invalid material type ''." warning.config.item.bad_custom_model_data_value: "Issue found in file - The item '' is using a custom model data [] that is too large. It's recommended to use a value lower than 16,777,216." warning.config.item.custom_model_data_conflict: "Issue found in file - The item '' is using a custom model data [] that has been occupied by item ''" -warning.config.item.lack_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." \ No newline at end of file +warning.config.item.lack_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." +warning.config.block.duplicated: "Issue found in file - Duplicated block ''." +warning.config.block.lack_state: "Issue found in file - The block '' is missing the required 'state' argument." +warning.config.block.lack_real_id: "Issue found in file - The block '' is missing the required 'id' argument for 'state'." +warning.config.block.state.lack_state: "Issue found in file - The block '' is missing the required 'state' argument for 'state'." +warning.config.block.state.lack_properties: "Issue found in file - The block '' is missing the required 'properties' section for 'states'." +warning.config.block.state.lack_appearances: "Issue found in file - The block '' is missing the required 'appearances' section for 'states'." +warning.config.block.state.lack_variants: "Issue found in file - The block '' is missing the required 'variants' section for 'states'." +warning.config.block.state.variant.lack_appearance: "Issue found in file - The block '' is missing the required 'appearance' argument for variant ''." +warning.config.block.state.variant.invalid_appearance: "Issue found in file - The block '' has an error that the variant '' is using a non-existing appearance ''." \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/es.yml b/bukkit/loader/src/main/resources/translations/es.yml index 23de3a017..f04f051a0 100644 --- a/bukkit/loader/src/main/resources/translations/es.yml +++ b/bukkit/loader/src/main/resources/translations/es.yml @@ -38,11 +38,11 @@ argument.parse.failure.aggregate.missing: "Componente Faltante ''Componente Invalido '': " argument.parse.failure.either: "No se ha podido resolver o de ''" argument.parse.failure.namedtextcolor: "'' no es un color de texto con nombre" -command.reload.config.success: "Recargado. Tomó ms." +command.reload.config.success: "Recargado. Tomó ms. (Async: ms | Sync: ms)" command.reload.config.failure: "Error al recargar la configuración. Por favor, revisa el registro de la consola." command.reload.pack.success: "Paquete de recursos recargado. Tomó ms." command.reload.pack.failure: "Error al recargar el paquete de recursos. Por favor, revisa el registro de la consola." -command.reload.all.success: "Todo recargado. Tomó ms." +command.reload.all.success: "Todo recargado. Tomó ms. (Async: ms | Sync: ms | Pack: ms)" command.reload.all.failure: "Error al recargar. Por favor, revisa el registro de la consola." command.item.get.success: "Obtener " command.item.get.failure.not_exist: "'>" diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 29cb7a370..498ebfe90 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -38,11 +38,11 @@ argument.parse.failure.aggregate.missing: "缺少组件 ''" argument.parse.failure.aggregate.failure: "无效的组件 '': " argument.parse.failure.either: "无法从 '' 解析 " argument.parse.failure.namedtextcolor: "'' 不是颜色代码" -command.reload.config.success: "重新加载配置完成. 耗时 毫秒" +command.reload.config.success: "重新加载配置完成. 耗时 毫秒 (异步: ms | 同步: ms)" command.reload.config.failure: "重新加载配置失败,请检查控制台日志。" command.reload.pack.success: "资源包重新加载完成. 耗时 毫秒" command.reload.pack.failure: "重新加载资源包失败,请检查控制台日志。" -command.reload.all.success: "全部重新加载完成. 耗时 毫秒" +command.reload.all.success: "全部重新加载完成. 耗时 毫秒 (异步: ms | 同步: ms | 资源包: ms)" command.reload.all.failure: "重新加载失败,请检查控制台日志。" command.item.get.success: "获得" command.item.get.failure.not_exist: "'>" diff --git a/bukkit/loader/src/main/resources/translations/zh_tw.yml b/bukkit/loader/src/main/resources/translations/zh_tw.yml index 37aae210f..b0d1da410 100644 --- a/bukkit/loader/src/main/resources/translations/zh_tw.yml +++ b/bukkit/loader/src/main/resources/translations/zh_tw.yml @@ -38,11 +38,11 @@ argument.parse.failure.aggregate.missing: "缺少元件 ''" argument.parse.failure.aggregate.failure: "無效的元件 '': " argument.parse.failure.either: "無法從 '' 解析 " argument.parse.failure.namedtextcolor: "'' 不是顏色代碼" -command.reload.config.success: "重新加載配置完成. 耗時 毫秒" +command.reload.config.success: "重新加載配置完成. 耗時 毫秒 (非同步: ms | 同步: ms)" command.reload.config.failure: "重新加載配置失敗,請檢查控制台日誌。" command.reload.pack.success: "資源包重新加載完成. 耗時 毫秒" command.reload.pack.failure: "重新加載資源包失敗,請檢查控制台日誌。" -command.reload.all.success: "全部重新加載完成. 耗時 毫秒" +command.reload.all.success: "全部重新加載完成. 耗時 毫秒 (非同步: ms | 同步: ms | 資源包: ms)" command.reload.all.failure: "重新加載失敗,請檢查控制台日誌。" command.item.get.success: "獲得" command.item.get.failure.not_exist: "'>" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 0757e0cf4..071cade69 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -19,10 +19,13 @@ import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.properties.Properties; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.loot.LootTable; +import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.WritableRegistry; @@ -45,6 +48,7 @@ import java.util.*; public class BukkitBlockManager extends AbstractBlockManager { private static BukkitBlockManager instance; private final BukkitCraftEngine plugin; + private final BlockParser blockParser; // A temporary map used to detect whether the same block state corresponds to multiple models. private final Map tempRegistryIdConflictMap = new HashMap<>(); @@ -57,7 +61,7 @@ public class BukkitBlockManager extends AbstractBlockManager { private int customBlockCount; // CraftEngine objects - private final Map id2CraftEngineBlocks = new HashMap<>(); + private final Map byId = new HashMap<>(); private final ImmutableBlockState[] stateId2ImmutableBlockStates; // Minecraft objects @@ -96,6 +100,7 @@ public class BukkitBlockManager extends AbstractBlockManager { public BukkitBlockManager(BukkitCraftEngine plugin) { super(plugin); this.plugin = plugin; + this.blockParser = new BlockParser(); this.initVanillaRegistry(); this.loadMappingsAndAdditionalBlocks(); if (plugin.hasMod() && plugin.requiresRestart()) { @@ -150,7 +155,7 @@ public class BukkitBlockManager extends AbstractBlockManager { super.clearModelsToGenerate(); this.clearCache(); this.appearanceToRealState.clear(); - this.id2CraftEngineBlocks.clear(); + this.byId.clear(); this.cachedSuggestions.clear(); this.blockStateOverrides.clear(); this.modBlockStates.clear(); @@ -221,6 +226,11 @@ public class BukkitBlockManager extends AbstractBlockManager { return Collections.unmodifiableMap(this.modBlockStates); } + @Override + public ConfigSectionParser parser() { + return this.blockParser; + } + @Override public Map> blockOverrides() { return Collections.unmodifiableMap(this.blockStateOverrides); @@ -228,12 +238,12 @@ public class BukkitBlockManager extends AbstractBlockManager { @Override public Map blocks() { - return Collections.unmodifiableMap(this.id2CraftEngineBlocks); + return Collections.unmodifiableMap(this.byId); } @Override public Optional getBlock(Key key) { - return Optional.ofNullable(this.id2CraftEngineBlocks.get(key)); + return Optional.ofNullable(this.byId.get(key)); } @Override @@ -246,7 +256,7 @@ public class BukkitBlockManager extends AbstractBlockManager { this.cachedSuggestions.clear(); this.namespacesInUse.clear(); Set states = new HashSet<>(); - for (CustomBlock block : this.id2CraftEngineBlocks.values()) { + for (CustomBlock block : this.byId.values()) { states.add(block.id().toString()); this.namespacesInUse.add(block.id().namespace()); for (ImmutableBlockState state : block.variantProvider().states()) { @@ -368,100 +378,134 @@ public class BukkitBlockManager extends AbstractBlockManager { } } - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - // read block settings - BlockSettings settings = BlockSettings.fromMap(MiscUtils.castToMap(section.getOrDefault("settings", Map.of()), false)); - // read loot table - LootTable lootTable = LootTable.fromMap(MiscUtils.castToMap(section.getOrDefault("loot", Map.of()), false)); - // read states - Map> properties; - Map appearances; - Map variants; - Map stateSection = MiscUtils.castToMap(section.get("state"), true); - if (stateSection != null) { - properties = Map.of(); - int internalId = MiscUtils.getAsInt(stateSection.getOrDefault("id", -1)); - if (PreConditions.runIfTrue(internalId < 0, () -> plugin.logger().warn(path, "No state id configured for block " + id))) return; - Pair pair = parseAppearanceSection(path, stateSection, id); - if (pair == null) return; - appearances = Map.of("default", pair.right()); - Key internalBlockId = Key.of(CraftEngine.NAMESPACE, pair.left().value() + "_" + internalId); - int internalBlockRegistryId = MiscUtils.getAsInt(this.internalId2StateId.getOrDefault(internalBlockId, -1)); - if (internalBlockRegistryId == -1) { - plugin.logger().warn(path, "Failed to register " + id + " because id " + internalId + " is not a value between 0~" + (MiscUtils.getAsInt(this.registeredRealBlockSlots.get(pair.left()))-1) + - ". Consider editing additional-real-blocks.yml if the number of real block IDs is insufficient while there are still available appearances"); - return; - } - variants = Map.of("", new VariantState("default", settings, internalBlockRegistryId)); - } else { - Map statesSection = MiscUtils.castToMap(section.get("states"), true); - if (statesSection == null) { - plugin.logger().warn(path, "No states configured for block " + id); - return; - } - Map propertySection = MiscUtils.castToMap(statesSection.get("properties"), true); - if (PreConditions.isNull(propertySection, () -> plugin.logger().warn(path, "No properties configured for block " + id))) return; - properties = parseProperties(path, propertySection); - Map appearancesSection = MiscUtils.castToMap(statesSection.get("appearances"), true); - if (PreConditions.isNull(appearancesSection, () -> plugin.logger().warn(path, "No appearances configured for block " + id))) return; - appearances = new HashMap<>(); - Map tempTypeMap = new HashMap<>(); - for (Map.Entry appearanceEntry : appearancesSection.entrySet()) { - if (appearanceEntry.getValue() instanceof Map appearanceSection) { - Pair pair = parseAppearanceSection(path, MiscUtils.castToMap(appearanceSection, false), id); - if (pair == null) return; - appearances.put(appearanceEntry.getKey(), pair.right()); - tempTypeMap.put(appearanceEntry.getKey(), pair.left()); - } - } - Map variantsSection = MiscUtils.castToMap(statesSection.get("variants"), true); - if (PreConditions.isNull(variantsSection, () -> plugin.logger().warn(path, "No variants configured for block " + id))) return; - variants = new HashMap<>(); - for (Map.Entry variantEntry : variantsSection.entrySet()) { - if (variantEntry.getValue() instanceof Map variantSection0) { - Map variantSection = MiscUtils.castToMap(variantSection0, false); - String variantName = variantEntry.getKey(); - String appearance = (String) variantSection.get("appearance"); - if (appearance == null) { - plugin.logger().warn(path, "No appearance configured for variant " + variantName); - return; - } - if (!appearances.containsKey(appearance)) { - plugin.logger().warn(path, appearance + " is not a valid appearance for block " + id); - return; - } - int internalId = MiscUtils.getAsInt(variantSection.getOrDefault("id", -1)); - Key baseBlock = tempTypeMap.get(appearance); - Key internalBlockId = Key.of(CraftEngine.NAMESPACE, baseBlock.value() + "_" + internalId); - int internalBlockRegistryId = MiscUtils.getAsInt(this.internalId2StateId.getOrDefault(internalBlockId, -1)); - if (internalBlockRegistryId == -1) { - plugin.logger().warn(path, "Failed to register " + id + " because id " + internalId + " is not a value between 0~" + (MiscUtils.getAsInt(this.registeredRealBlockSlots.getOrDefault(baseBlock, 1))-1) + - ". Consider editing additional-real-blocks.yml if the number of real block IDs is insufficient while there are still available appearances"); - return; - } - Map anotherSetting = MiscUtils.castToMap(variantSection.get("settings"), true); - variants.put(variantName, new VariantState(appearance, anotherSetting == null ? settings : BlockSettings.ofFullCopy(settings, anotherSetting), internalBlockRegistryId)); - } - } + public class BlockParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"blocks", "block"}; + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; } - // create or get block holder - Holder.Reference holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() -> - ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id))); - // create block - Map behaviorSection = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); - BukkitCustomBlock block = new BukkitCustomBlock(id, holder, properties, appearances, variants, settings, behaviorSection, lootTable); + @Override + public int loadingSequence() { + return LoadingSequence.BLOCK; + } - // bind appearance - bindAppearance(block); - this.id2CraftEngineBlocks.put(id, block); + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + if (byId.containsKey(id)) { + TranslationManager.instance().log("warning.config.block.duplicated", path.toString(), id.toString()); + return; + } - // generate mod assets - if (ConfigManager.generateModAssets()) { - for (ImmutableBlockState state : block.variantProvider().states()) { - Key realBlockId = BlockStateUtils.getBlockOwnerIdFromState(state.customBlockState()); - this.modBlockStates.put(realBlockId, this.tempVanillaBlockStateModels.get(state.vanillaBlockState().registryId())); + // read block settings + BlockSettings settings = BlockSettings.fromMap(MiscUtils.castToMap(section.getOrDefault("settings", Map.of()), false)); + // read loot table + LootTable lootTable = LootTable.fromMap(MiscUtils.castToMap(section.getOrDefault("loot", Map.of()), false)); + // read states + Map> properties; + Map appearances; + Map variants; + Map stateSection = MiscUtils.castToMap(section.get("state"), true); + if (stateSection != null) { + properties = Map.of(); + int internalId = MiscUtils.getAsInt(stateSection.getOrDefault("id", -1)); + if (internalId < 0) { + TranslationManager.instance().log("warning.config.block.lack_real_id", path.toString(), id.toString()); + return; + } + Pair pair = parseAppearanceSection(path, id, stateSection); + if (pair == null) return; + appearances = Map.of("default", pair.right()); + Key internalBlockId = Key.of(CraftEngine.NAMESPACE, pair.left().value() + "_" + internalId); + int internalBlockRegistryId = MiscUtils.getAsInt(internalId2StateId.getOrDefault(internalBlockId, -1)); + if (internalBlockRegistryId == -1) { + plugin.logger().warn(path, "Failed to register " + id + " because id " + internalId + " is not a value between 0~" + (MiscUtils.getAsInt(registeredRealBlockSlots.get(pair.left()))-1) + + ". Consider editing additional-real-blocks.yml if the number of real block IDs is insufficient while there are still available appearances"); + return; + } + variants = Map.of("", new VariantState("default", settings, internalBlockRegistryId)); + } else { + Map statesSection = MiscUtils.castToMap(section.get("states"), true); + if (statesSection == null) { + TranslationManager.instance().log("warning.config.block.lack_state", path.toString(), id.toString()); + return; + } + Map propertySection = MiscUtils.castToMap(statesSection.get("properties"), true); + if (propertySection == null) { + TranslationManager.instance().log("warning.config.block.state.lack_properties", path.toString(), id.toString()); + return; + } + properties = parseProperties(path, propertySection); + Map appearancesSection = MiscUtils.castToMap(statesSection.get("appearances"), true); + if (appearancesSection == null) { + TranslationManager.instance().log("warning.config.block.state.lack_appearances", path.toString(), id.toString()); + return; + } + + appearances = new HashMap<>(); + Map tempTypeMap = new HashMap<>(); + for (Map.Entry appearanceEntry : appearancesSection.entrySet()) { + if (appearanceEntry.getValue() instanceof Map appearanceSection) { + Pair pair = parseAppearanceSection(path, id, MiscUtils.castToMap(appearanceSection, false)); + if (pair == null) return; + appearances.put(appearanceEntry.getKey(), pair.right()); + tempTypeMap.put(appearanceEntry.getKey(), pair.left()); + } + } + + Map variantsSection = MiscUtils.castToMap(statesSection.get("variants"), true); + if (variantsSection == null) { + TranslationManager.instance().log("warning.config.block.state.lack_variants", path.toString(), id.toString()); + return; + } + + variants = new HashMap<>(); + for (Map.Entry variantEntry : variantsSection.entrySet()) { + if (variantEntry.getValue() instanceof Map variantSection0) { + Map variantSection = MiscUtils.castToMap(variantSection0, false); + String variantName = variantEntry.getKey(); + String appearance = (String) variantSection.get("appearance"); + if (appearance == null) { + TranslationManager.instance().log("warning.config.block.state.variant.lack_appearance", path.toString(), id.toString(), variantName); + return; + } + if (!appearances.containsKey(appearance)) { + TranslationManager.instance().log("warning.config.block.state.variant.invalid_appearance", path.toString(), id.toString(), variantName, appearance); + return; + } + int internalId = MiscUtils.getAsInt(variantSection.getOrDefault("id", -1)); + Key baseBlock = tempTypeMap.get(appearance); + Key internalBlockId = Key.of(CraftEngine.NAMESPACE, baseBlock.value() + "_" + internalId); + int internalBlockRegistryId = MiscUtils.getAsInt(internalId2StateId.getOrDefault(internalBlockId, -1)); + if (internalBlockRegistryId == -1) { + plugin.logger().warn(path, "Failed to register " + id + " because id " + internalId + " is not a value between 0~" + (MiscUtils.getAsInt(registeredRealBlockSlots.getOrDefault(baseBlock, 1))-1) + + ". Consider editing additional-real-blocks.yml if the number of real block IDs is insufficient while there are still available appearances"); + return; + } + Map anotherSetting = MiscUtils.castToMap(variantSection.get("settings"), true); + variants.put(variantName, new VariantState(appearance, anotherSetting == null ? settings : BlockSettings.ofFullCopy(settings, anotherSetting), internalBlockRegistryId)); + } + } + } + // create or get block holder + Holder.Reference holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() -> + ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id))); + // create block + Map behaviorSection = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); + + BukkitCustomBlock block = new BukkitCustomBlock(id, holder, properties, appearances, variants, settings, behaviorSection, lootTable); + + // bind appearance + bindAppearance(block); + byId.put(id, block); + + // generate mod assets + if (ConfigManager.generateModAssets()) { + for (ImmutableBlockState state : block.variantProvider().states()) { + Key realBlockId = BlockStateUtils.getBlockOwnerIdFromState(state.customBlockState()); + modBlockStates.put(realBlockId, tempVanillaBlockStateModels.get(state.vanillaBlockState().registryId())); + } } } } @@ -493,10 +537,13 @@ public class BukkitBlockManager extends AbstractBlockManager { } @Nullable - private Pair parseAppearanceSection(Path path, Map section, Key id) { + private Pair parseAppearanceSection(Path path, Key id, Map section) { String vanillaStateString = (String) section.get("state"); - if (PreConditions.isNull(vanillaStateString, - () -> this.plugin.logger().warn(path, "No block state found for: " + id))) return null; + if (vanillaStateString == null) { + TranslationManager.instance().log("warning.config.block.state.lack_state", path.toString(), id.toString()); + return null; + } + int vanillaStateRegistryId; try { vanillaStateRegistryId = parseVanillaStateRegistryId(vanillaStateString); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index 511a3845b..40b96fe9d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -176,7 +176,7 @@ public class BlockItemBehavior extends ItemBehavior { throw new IllegalArgumentException("Missing required parameter 'block' for block_item behavior"); } if (id instanceof Map map) { - BukkitBlockManager.instance().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); return new BlockItemBehavior(key); } else { return new BlockItemBehavior(Key.of(id.toString())); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java index 1163a1ab8..09a8575b3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java @@ -67,7 +67,7 @@ public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior { } int offset = MiscUtils.getAsInt(arguments.getOrDefault("y-offset", 1)); if (id instanceof Map map) { - BukkitBlockManager.instance().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); return new LiquidCollisionBlockItemBehavior(key, offset); } else { return new LiquidCollisionBlockItemBehavior(Key.of(id.toString()), offset); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java index e6fff1b0b..bac46d3a0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java @@ -37,10 +37,7 @@ public class ReloadCommand extends BukkitCommandFeature { plugin().scheduler().executeAsync(() -> { try { RELOAD_PACK_FLAG = true; - long time1 = System.currentTimeMillis(); - plugin().reload(); - long time2 = System.currentTimeMillis(); - handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_SUCCESS, Component.text(time2 - time1)); + plugin().reload((a, b) -> handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_SUCCESS, Component.text(a + b), Component.text(a), Component.text(b))); } catch (Exception e) { handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_FAILURE); plugin().logger().warn("Failed to reload config", e); @@ -60,16 +57,17 @@ public class ReloadCommand extends BukkitCommandFeature { }); } else if (argument == ReloadArgument.ALL) { plugin().scheduler().executeAsync(() -> { - long time1 = System.currentTimeMillis(); - plugin().reload(); - try { - plugin().packManager().generateResourcePack(); - long time2 = System.currentTimeMillis(); - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_SUCCESS, Component.text(time2 - time1)); - } catch (Exception e) { - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); - plugin().logger().warn("Failed to generate resource pack", e); - } + plugin().reload((a, b) -> { + try { + long time1 = System.currentTimeMillis(); + plugin().packManager().generateResourcePack(); + long time2 = System.currentTimeMillis(); + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_SUCCESS, Component.text(a + b + time2 - time1), Component.text(a), Component.text(b), Component.text(time2 - time1)); + } catch (Exception e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); + plugin().logger().warn("Failed to generate resource pack", e); + } + }); }); } }); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java index 4b20d0e78..7b5d27868 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java @@ -13,16 +13,9 @@ import java.util.Collection; import java.util.Map; import java.util.Optional; -public interface BlockManager extends Reloadable, ModelGenerator, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"blocks", "block"}; +public interface BlockManager extends Reloadable, ModelGenerator { - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } - - default int loadingSequence() { - return LoadingSequence.BLOCK; - } + ConfigSectionParser parser(); Collection modelsToGenerate(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 2f51310ce..988dc9228 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -136,6 +136,11 @@ public abstract class AbstractFontManager implements FontManager { @Override public void parseSection(Pack pack, Path path, Key id, Map section) { + if (images.containsKey(id)) { + TranslationManager.instance().log("warning.config.image.duplicated", path.toString(), id.toString()); + return; + } + Object heightObj = section.get("height"); if (heightObj == null) { TranslationManager.instance().log("warning.config.image.lack_height", path.toString(), id.toString()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 88e5967fd..e6c8b01f5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -34,6 +34,8 @@ import org.apache.logging.log4j.LogManager; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; @@ -98,7 +100,12 @@ public abstract class CraftEngine implements Plugin { @Override public void reload() { + reload((a, b) -> {}); + } + + public void reload(BiConsumer time) { if (this.isReloading) return; + long time1 = System.currentTimeMillis(); this.isReloading = true; this.configManager.reload(); // reset debugger @@ -130,9 +137,12 @@ public abstract class CraftEngine implements Plugin { this.soundManager.delayedLoad(); this.fontManager.delayedLoad(); this.recipeManager.delayedLoad(); + long time2 = System.currentTimeMillis(); scheduler().sync().run(() -> { try { this.recipeManager.runSyncTasks(); + long time3 = System.currentTimeMillis(); + time.accept(time2 - time1, time3 - time2); } finally { this.isReloading = false; } @@ -194,7 +204,7 @@ public abstract class CraftEngine implements Plugin { // register furniture parser this.packManager.registerConfigSectionParser(this.furnitureManager.parser()); // register block parser - this.packManager.registerConfigSectionParser(this.blockManager); + this.packManager.registerConfigSectionParser(this.blockManager.parser()); // register recipe parser this.packManager.registerConfigSectionParser(this.recipeManager.parser()); // register category parser From 6ea0b1e9a64ea17700cc853e00e4bd1b91a7feb6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 05:22:28 +0800 Subject: [PATCH 19/37] fix templates --- .../resources/resources/default/configuration/templates.yml | 6 +++--- .../core/plugin/config/template/TemplateManagerImpl.java | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml b/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml index 641bf7396..08e34f0a2 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml @@ -471,15 +471,15 @@ templates#settings#sounds: arguments: block_type: bamboo default:sound/vine: - template: default:block + template: default:sound/block_template arguments: block_type: vine default:sound/lantern: - template: default:block + template: default:sound/block_template arguments: block_type: lantern default:sound/amethyst_block: - template: default:block + template: default:sound/block_template arguments: block_type: amethyst_block diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java index 29f0d36da..06d916542 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java @@ -39,6 +39,11 @@ public class TemplateManagerImpl implements TemplateManager { return LoadingSequence.TEMPLATE; } + @Override + public boolean isTemplate() { + return true; + } + @Override public void parseSection(Pack pack, Path path, Key id, Map section) { addTemplate(pack, path, id, section); From 81fc801bd9717db31a0ffac5ecf22bd810a7258f Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 05:27:29 +0800 Subject: [PATCH 20/37] more fix --- .../plugin/command/feature/ReloadCommand.java | 20 ++++++++++--------- .../core/pack/AbstractPackManager.java | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java index bac46d3a0..f77586c8f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java @@ -58,15 +58,17 @@ public class ReloadCommand extends BukkitCommandFeature { } else if (argument == ReloadArgument.ALL) { plugin().scheduler().executeAsync(() -> { plugin().reload((a, b) -> { - try { - long time1 = System.currentTimeMillis(); - plugin().packManager().generateResourcePack(); - long time2 = System.currentTimeMillis(); - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_SUCCESS, Component.text(a + b + time2 - time1), Component.text(a), Component.text(b), Component.text(time2 - time1)); - } catch (Exception e) { - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); - plugin().logger().warn("Failed to generate resource pack", e); - } + plugin().scheduler().async().execute(() -> { + try { + long time1 = System.currentTimeMillis(); + plugin().packManager().generateResourcePack(); + long time2 = System.currentTimeMillis(); + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_SUCCESS, Component.text(a + b + time2 - time1), Component.text(a), Component.text(b), Component.text(time2 - time1)); + } catch (Exception e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); + plugin().logger().warn("Failed to generate resource pack", e); + } + }); }); }); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 508cce6dd..5b4a60db3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -412,7 +412,7 @@ public abstract class AbstractPackManager implements PackManager { try { Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); if (parser.isTemplate()) { - ((TemplateManager) parser).addTemplate(cached.pack(), cached.filePath(), id, configEntry.getValue()); + this.plugin.templateManager().addTemplate(cached.pack(), cached.filePath(), id, configEntry.getValue()); } else { if (configEntry.getValue() instanceof Map configSection0) { Map configSection1 = castToMap(configSection0, false); From 7947f404352482c8ad624cadc915c1ac5feac98c Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 4 Apr 2025 08:17:01 +0800 Subject: [PATCH 21/37] =?UTF-8?q?perf(bukkit):=20=E4=BC=98=E5=8C=96=20Bloc?= =?UTF-8?q?kDisplay=20=E5=AE=9E=E4=BD=93=E7=9A=84=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 42372cd01..b4d9ff905 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -972,28 +972,31 @@ public class PacketConsumers { Object entity = Reflections.method$EntityLookup$get.invoke(entityLookup, id); if (entity == null) return; Object entityType = Reflections.method$Entity$getType.invoke(entity); - if (entityType != Reflections.instance$EntityType$BLOCK_DISPLAY) return; - List packedItems = (List) Reflections.field$ClientboundSetEntityDataPacket$packedItems.get(packet); - for (int i = 0; i < packedItems.size(); i++) { - Object packedItem = packedItems.get(i); - int entityDataId = (int) Reflections.field$SynchedEntityData$DataValue$id.get(packedItem); - if ((VersionHelper.isVersionNewerThan1_20_2() && entityDataId != 23) - || (!VersionHelper.isVersionNewerThan1_20_2() && entityDataId != 22)) { - continue; + if (entityType == Reflections.instance$EntityType$BLOCK_DISPLAY) { + List packedItems = (List) Reflections.field$ClientboundSetEntityDataPacket$packedItems.get(packet); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = (int) Reflections.field$SynchedEntityData$DataValue$id.get(packedItem); + if ((VersionHelper.isVersionNewerThan1_20_2() && entityDataId != 23) + || (!VersionHelper.isVersionNewerThan1_20_2() && entityDataId != 22)) { + continue; + } + Object blockState = Reflections.field$SynchedEntityData$DataValue$value.get(packedItem); + Object serializer = Reflections.field$SynchedEntityData$DataValue$serializer.get(packedItem); + int stateId = BlockStateUtils.blockStateToId(blockState); + int newStateId; + if (!user.clientModEnabled()) { + newStateId = remap(stateId); + } else { + newStateId = remapMOD(stateId); + } + packedItems.set(i, Reflections.constructor$SynchedEntityData$DataValue.newInstance( + entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId) + )); + break; } - Object blockState = Reflections.field$SynchedEntityData$DataValue$value.get(packedItem); - Object serializer = Reflections.field$SynchedEntityData$DataValue$serializer.get(packedItem); - int stateId = BlockStateUtils.blockStateToId(blockState); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = remap(stateId); - } else { - newStateId = remapMOD(stateId); - } - packedItems.set(i, Reflections.constructor$SynchedEntityData$DataValue.newInstance( - entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId) - )); } + // todo修改其他实体的物品的方块谓词 } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e); } From 01525db5c78322c419e2f9de059bf9eb71002240 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 4 Apr 2025 08:21:57 +0800 Subject: [PATCH 22/37] =?UTF-8?q?translate(bukkit.loader):=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E7=AE=80=E4=BD=93=E4=B8=AD=E6=96=87=E7=BF=BB=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/zh_cn.yml | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 498ebfe90..9e458de6c 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -39,11 +39,11 @@ argument.parse.failure.aggregate.failure: "无效的组件 '': 无法从 '' 解析 " argument.parse.failure.namedtextcolor: "'' 不是颜色代码" command.reload.config.success: "重新加载配置完成. 耗时 毫秒 (异步: ms | 同步: ms)" -command.reload.config.failure: "重新加载配置失败,请检查控制台日志。" +command.reload.config.failure: "重新加载配置失败,请检查控制台日志" command.reload.pack.success: "资源包重新加载完成. 耗时 毫秒" -command.reload.pack.failure: "重新加载资源包失败,请检查控制台日志。" +command.reload.pack.failure: "重新加载资源包失败,请检查控制台日志" command.reload.all.success: "全部重新加载完成. 耗时 毫秒 (异步: ms | 同步: ms | 资源包: ms)" -command.reload.all.failure: "重新加载失败,请检查控制台日志。" +command.reload.all.failure: "重新加载失败,请检查控制台日志" command.item.get.success: "获得" command.item.get.failure.not_exist: "'>" command.item.give.success.single: "':'':''>" @@ -53,4 +53,39 @@ command.search_recipe.not_found: "找不到此物品的配方" command.search_usage.not_found: "找不到此物品的用途" command.search_recipe.no_item: "请手持物品后再执行此命令" command.search_usage.no_item: "请手持物品后再执行此命令" -command.totem.not_totem: "'' 不是 totem_of_undying 类型" \ No newline at end of file +command.totem.not_totem: "'' 不是 totem_of_undying 类型" +warning.config.image.duplicated: "在文件 中发现问题 - 图片 '' 重复定义" +warning.config.image.lack_height: "在文件 中发现问题 - 图片 '' 缺少必要的 'height' 高度参数" +warning.config.image.height_smaller_than_ascent: "在文件 中发现问题 - 图片 '' 违反位图规则:'height' 高度值不应小于 'ascent' 基准线高度" +warning.config.image.no_file: "在文件 中发现问题 - 图片 '' 缺少必要的 'file' 文件参数" +warning.config.image.invalid_resource_location: "在文件 中发现问题 - 图片 '' 的 'file' 参数 [] 包含非法字符,请参考资源路径规范:https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" +warning.config.image.invalid_font_name: "在文件 中发现问题 - 图片 '' 的 'font' 字体参数 [] 包含非法字符,请参考资源路径规范:https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" +warning.config.image.lack_char: "在文件 中发现问题 - 图片 '' 缺少必要的 'char' 字符参数" +warning.config.image.codepoint_in_use: "在文件 中发现问题 - 图片 '' 使用的字体 字符 [()] 已被其他图片 '' 占用" +warning.config.image.invalid_codepoint_grid: "在文件 中发现问题 - 图片 '' 的 'chars' 码位网格配置无效" +warning.config.image.file_not_exist: "在文件 中发现问题 - 图片 '' 对应的PNG文件 不存在" +warning.config.recipe.duplicated: "在文件 中发现问题 - 配方 '' 重复定义" +warning.config.i18n.unknown_locale: "在文件 中发现问题 - 未知的语言区域 ''" +warning.config.template.duplicated: "在文件 中发现问题 - 模板 '' 重复定义" +warning.config.vanilla_loot.type_not_exist: "在文件 中发现问题 - 原版战利品 '' 未设置 'type' 类型参数" +warning.config.vanilla_loot.block.invalid_target: "在文件 中发现问题 - 原版战利品 '' 中的方块目标 [] 无效" +warning.config.sound.duplicated: "在文件 中发现问题 - 音效 '' 重复定义" +warning.config.jukebox_song.duplicated: "在文件 中发现问题 - 唱片机歌曲 '' 重复定义" +warning.config.furniture.duplicated: "在文件 中发现问题 - 家具 '' 重复定义" +warning.config.furniture.lack_placement: "在文件 中发现问题 - 家具 '' 缺少必要的 'placement' 放置参数" +warning.config.furniture.element.lack_item: "在文件 中发现问题 - 家具 '' 的某个元素缺少必要的 'item' 物品参数" +warning.config.item.duplicated: "在文件 中发现问题 - 物品 '' 重复定义" +warning.config.item.lack_material: "在文件 中发现问题 - 物品 '' 缺少必要的 'material' 材料参数" +warning.config.item.invalid_material: "在文件 中发现问题 - 物品 '' 使用了无效的材料类型 ''" +warning.config.item.bad_custom_model_data_value: "在文件 中发现问题 - 物品 '' 的自定义模型数据值 [] 过大,建议使用低于16,777,216的值" +warning.config.item.custom_model_data_conflict: "在文件 中发现问题 - 物品 '' 的自定义模型数据 [] 与物品 '' 发生冲突" +warning.config.item.lack_model_id: "在文件 中发现问题 - 物品 '' 缺少必要的 'custom-model-data' 或 'item-model' 模型标识参数" +warning.config.block.duplicated: "在文件 中发现问题 - 方块 '' 重复定义" +warning.config.block.lack_state: "在文件 中发现问题 - 方块 '' 缺少必要的 'state' 状态参数" +warning.config.block.lack_real_id: "在文件 中发现问题 - 方块 '' 的 'state' 配置缺少必要的 'id' 标识参数" +warning.config.block.state.lack_state: "在文件 中发现问题 - 方块 '' 的 'state' 配置缺少必要的 'state' 状态参数" +warning.config.block.state.lack_properties: "在文件 中发现问题 - 方块 '' 的 'states' 配置缺少必要的 'properties' 属性配置" +warning.config.block.state.lack_appearances: "在文件 中发现问题 - 方块 '' 的 'states' 配置缺少必要的 'appearances' 外观配置" +warning.config.block.state.lack_variants: "在文件 中发现问题 - 方块 '' 的 'states' 配置缺少必要的 'variants' 变体配置" +warning.config.block.state.variant.lack_appearance: "在文件 中发现问题 - 方块 '' 的 '' 变体配置缺少必要的 'appearance' 外观参数" +warning.config.block.state.variant.invalid_appearance: "在文件 中发现问题 - 方块 '' 的 '' 变体引用了不存在的外观配置 ''" \ No newline at end of file From 0e0bc5535730adcaffc551cd18aac52170b42f1b Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 19:00:46 +0800 Subject: [PATCH 23/37] refactor structure --- .../craftengine/bukkit/BukkitBootstrap.java | 6 +- .../api/event/CraftEngineReloadEvent.java | 1 - .../bukkit/block/BlockEventListener.java | 8 +- .../bukkit/block/BukkitBlockManager.java | 13 +- .../furniture/BukkitFurnitureManager.java | 6 +- .../bukkit/font/BukkitFontManager.java | 8 +- .../bukkit/item/BukkitItemManager.java | 10 +- .../item/recipe/BukkitRecipeManager.java | 6 +- .../item/recipe/CrafterEventListener.java | 4 +- .../item/recipe/RecipeEventListener.java | 18 +- .../bukkit/pack/BukkitPackManager.java | 52 ++-- .../bukkit/plugin/BukkitCraftEngine.java | 91 +++---- .../plugin/injector/BukkitInjector.java | 6 +- .../plugin/network/BukkitNetworkManager.java | 135 +++++----- .../plugin/network/PacketConsumers.java | 12 +- .../bukkit/util/InteractUtils.java | 6 +- .../util/NoteBlockChainUpdateUtils.java | 4 +- .../bukkit/world/BukkitCEWorld.java | 4 +- .../bukkit/world/BukkitWorldManager.java | 10 +- .../craftengine/core/block/BlockManager.java | 7 +- .../entity/furniture/FurnitureManager.java | 4 +- .../core/font/AbstractFontManager.java | 2 +- .../craftengine/core/font/FontManager.java | 4 +- .../craftengine/core/item/ItemManager.java | 4 +- .../item/modifier/DisplayNameModifier.java | 4 +- .../core/item/modifier/ItemNameModifier.java | 4 +- .../core/item/modifier/LoreModifier.java | 4 +- .../item/recipe/AbstractRecipeManager.java | 4 +- .../core/item/recipe/RecipeManager.java | 6 +- .../core/loot/VanillaLootManager.java | 4 +- .../core/pack/AbstractPackManager.java | 45 ++-- .../craftengine/core/pack/PackManager.java | 4 +- .../core/pack/host/ResourcePackHost.java | 6 +- .../core/pack/obfuscation/ObfF.java | 2 +- .../craftengine/core/plugin/CraftEngine.java | 243 ++++++++++-------- .../{Reloadable.java => Manageable.java} | 21 +- .../craftengine/core/plugin/Plugin.java | 10 +- .../command/AbstractCommandManager.java | 4 +- .../{ConfigManager.java => Config.java} | 15 +- .../config/template/TemplateManager.java | 5 +- .../core/plugin/gui/GuiManager.java | 4 +- .../gui/category/ItemBrowserManager.java | 8 +- .../plugin/locale/TranslationManager.java | 4 +- .../core/plugin/network/NetworkManager.java | 18 +- .../core/sound/AbstractSoundManager.java | 2 +- .../craftengine/core/sound/SoundManager.java | 4 +- .../craftengine/core/world/WorldManager.java | 4 +- 47 files changed, 446 insertions(+), 400 deletions(-) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{Reloadable.java => Manageable.java} (51%) rename core/src/main/java/net/momirealms/craftengine/core/plugin/config/{ConfigManager.java => Config.java} (98%) diff --git a/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/BukkitBootstrap.java b/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/BukkitBootstrap.java index 27c93a874..3e73cf8ea 100644 --- a/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/BukkitBootstrap.java +++ b/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/BukkitBootstrap.java @@ -12,16 +12,16 @@ public class BukkitBootstrap extends JavaPlugin { @Override public void onLoad() { - this.plugin.load(); + this.plugin.onPluginLoad(); } @Override public void onEnable() { - this.plugin.enable(); + this.plugin.onPluginEnable(); } @Override public void onDisable() { - this.plugin.disable(); + this.plugin.onPluginDisable(); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java index e56d98aa1..58d5dea02 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java @@ -10,7 +10,6 @@ public class CraftEngineReloadEvent extends Event { private final BukkitCraftEngine plugin; public CraftEngineReloadEvent(BukkitCraftEngine plugin) { - super(true); this.plugin = plugin; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 353cd94a8..239bc3e61 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -14,7 +14,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.loot.parameter.LootParameters; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.BlockPos; @@ -60,7 +60,7 @@ public class BlockEventListener implements Listener { player.swingHand(event.getHand()); } // send sound if the placed block's sounds are removed - if (ConfigManager.enableSoundSystem()) { + if (Config.enableSoundSystem()) { Block block = event.getBlock(); Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData()); Object ownerBlock = BlockStateUtils.getBlockOwner(blockState); @@ -171,7 +171,7 @@ public class BlockEventListener implements Listener { }); } // sound system - if (ConfigManager.enableSoundSystem()) { + if (Config.enableSoundSystem()) { Object ownerBlock = BlockStateUtils.getBlockOwner(blockState); if (this.manager.isBlockSoundRemoved(ownerBlock)) { try { @@ -243,7 +243,7 @@ public class BlockEventListener implements Listener { if (!BlockStateUtils.isVanillaBlock(stateId)) { ImmutableBlockState state = manager.getImmutableBlockStateUnsafe(stateId); player.playSound(playerLocation, state.sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.sounds().stepSound().volume(), state.sounds().stepSound().pitch()); - } else if (ConfigManager.enableSoundSystem()) { + } else if (Config.enableSoundSystem()) { Object ownerBlock = BlockStateUtils.getBlockOwner(blockState); if (manager.isBlockSoundRemoved(ownerBlock)) { try { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 071cade69..95bfdcf33 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -23,7 +23,7 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -251,8 +251,7 @@ public class BukkitBlockManager extends AbstractBlockManager { return Collections.unmodifiableCollection(this.cachedSuggestions); } - @Override - public void initSuggestions() { + private void initSuggestions() { this.cachedSuggestions.clear(); this.namespacesInUse.clear(); Set states = new HashSet<>(); @@ -269,7 +268,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } public Set namespacesInUse() { - return Collections.unmodifiableSet(namespacesInUse); + return Collections.unmodifiableSet(this.namespacesInUse); } public ImmutableMap> blockAppearanceArranger() { @@ -501,7 +500,7 @@ public class BukkitBlockManager extends AbstractBlockManager { byId.put(id, block); // generate mod assets - if (ConfigManager.generateModAssets()) { + if (Config.generateModAssets()) { for (ImmutableBlockState state : block.variantProvider().states()) { Key realBlockId = BlockStateUtils.getBlockOwnerIdFromState(state.customBlockState()); modBlockStates.put(realBlockId, tempVanillaBlockStateModels.get(state.vanillaBlockState().registryId())); @@ -650,7 +649,7 @@ public class BukkitBlockManager extends AbstractBlockManager { private void loadMappingsAndAdditionalBlocks() { this.plugin.logger().info("Loading mappings.yml."); File mappingFile = new File(plugin.dataFolderFile(), "mappings.yml"); - YamlDocument mappings = ConfigManager.instance().loadOrCreateYamlData("mappings.yml"); + YamlDocument mappings = Config.instance().loadOrCreateYamlData("mappings.yml"); Map blockStateMappings = loadBlockStateMappings(mappings); this.validateBlockStateMappings(mappingFile, blockStateMappings); Map stateMap = new HashMap<>(); @@ -663,7 +662,7 @@ public class BukkitBlockManager extends AbstractBlockManager { this.blockAppearanceMapper = ImmutableMap.copyOf(appearanceMapper); this.blockAppearanceArranger = ImmutableMap.copyOf(appearanceArranger); this.plugin.logger().info("Freed " + this.blockAppearanceMapper.size() + " block state appearances."); - YamlDocument additionalYaml = ConfigManager.instance().loadOrCreateYamlData("additional-real-blocks.yml"); + YamlDocument additionalYaml = Config.instance().loadOrCreateYamlData("additional-real-blocks.yml"); this.registeredRealBlockSlots = this.buildRegisteredRealBlockSlots(blockTypeCounter, additionalYaml); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index 8d1d3f857..f34fe39e8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -12,7 +12,7 @@ import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.sound.SoundData; @@ -305,8 +305,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { return; } // Remove the entity if it's not a valid furniture - if (ConfigManager.removeInvalidFurniture()) { - if (ConfigManager.furnitureToRemove().isEmpty() || ConfigManager.furnitureToRemove().contains(id)) { + if (Config.removeInvalidFurniture()) { + if (Config.furnitureToRemove().isEmpty() || Config.furnitureToRemove().contains(id)) { entity.remove(); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java index 3f8056e54..0cb61bde3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.font.AbstractFontManager; import net.momirealms.craftengine.core.font.FontManager; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.CharacterUtils; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -48,20 +48,20 @@ public class BukkitFontManager extends AbstractFontManager implements Listener { @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) @SuppressWarnings("UnstableApiUsage") public void onChat(AsyncChatDecorateEvent event) { - if (!ConfigManager.filterChat()) return; + if (!Config.filterChat()) return; this.processChatEvent(event); } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) @SuppressWarnings("UnstableApiUsage") public void onChatCommand(AsyncChatCommandDecorateEvent event) { - if (!ConfigManager.filterChat()) return; + if (!Config.filterChat()) return; this.processChatEvent(event); } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onCommand(PlayerCommandPreprocessEvent event) { - if (!ConfigManager.filterCommand()) return; + if (!Config.filterCommand()) return; if (!this.isDefaultFontInUse()) return; if (event.getPlayer().hasPermission(FontManager.BYPASS_COMMAND)) { return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index f5097fb49..ee8bdb884 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -26,7 +26,7 @@ import net.momirealms.craftengine.core.pack.model.*; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.select.ChargeTypeSelectProperty; import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectProperty; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -352,12 +352,12 @@ public class BukkitItemManager extends AbstractItemManager { prepareModelGeneration(generation); } - if (ConfigManager.packMaxVersion() > 21.39f) { + if (Config.packMaxVersion() > 21.39f) { TreeMap map = modernOverrides.computeIfAbsent(materialId, k -> new TreeMap<>()); map.put(customModelData, model); } - if (ConfigManager.packMinVersion() < 21.39f) { + if (Config.packMinVersion() < 21.39f) { List legacyOverridesModels = new ArrayList<>(); processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, customModelData); TreeSet lom = legacyOverrides.computeIfAbsent(materialId, k -> new TreeSet<>()); @@ -372,11 +372,11 @@ public class BukkitItemManager extends AbstractItemManager { prepareModelGeneration(generation); } - if (ConfigManager.packMaxVersion() > 21.39f) { + if (Config.packMaxVersion() > 21.39f) { modernItemModels1_21_4.put(itemModelKey, model); } - if (ConfigManager.packMaxVersion() > 21.19f && ConfigManager.packMinVersion() < 21.39f) { + if (Config.packMaxVersion() > 21.19f && Config.packMinVersion() < 21.39f) { List legacyOverridesModels = new ArrayList<>(); processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, 0); if (!legacyOverridesModels.isEmpty()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index fc0fe0577..ca09ce9e0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -16,7 +16,7 @@ import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.*; import net.momirealms.craftengine.core.item.recipe.vanilla.*; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.HeptaFunction; @@ -284,7 +284,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { @Override public void load() { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; if (VersionHelper.isVersionNewerThan1_21_2()) { try { this.stolenFeatureFlagSet = Reflections.field$RecipeManager$featureflagset.get(nmsRecipeManager); @@ -422,7 +422,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } @Override - public void runSyncTasks() { + public void runDelayedSyncTasks() { try { // run delayed tasks for (Runnable r : this.delayedTasksOnMainThread) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java index 8d51b8b04..2b2b9d383 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; @@ -39,7 +39,7 @@ public class CrafterEventListener implements Listener { @EventHandler public void onCrafting(CrafterCraftEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; CraftingRecipe recipe = event.getRecipe(); if (!(event.getBlock().getState() instanceof Crafter crafter)) { return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index de3dc7564..fbbeb9100 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -17,7 +17,7 @@ import net.momirealms.craftengine.core.item.recipe.*; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.AdventureHelper; @@ -261,7 +261,7 @@ public class RecipeEventListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onFurnaceInventoryOpen(InventoryOpenEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; if (!(event.getInventory() instanceof FurnaceInventory furnaceInventory)) { return; } @@ -277,7 +277,7 @@ public class RecipeEventListener implements Listener { // for 1.20.1-1.21.1 @EventHandler(ignoreCancelled = true) public void onBlockIgnite(BlockIgniteEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; if (VersionHelper.isVersionNewerThan1_21_2()) return; Block block = event.getBlock(); Material material = block.getType(); @@ -295,7 +295,7 @@ public class RecipeEventListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onPlaceBlock(BlockPlaceEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; Block block = event.getBlock(); Material material = block.getType(); if (material == Material.FURNACE || material == Material.BLAST_FURNACE || material == Material.SMOKER) { @@ -322,7 +322,7 @@ public class RecipeEventListener implements Listener { // for 1.21.2+ @EventHandler(ignoreCancelled = true) public void onPutItemOnCampfire(PlayerInteractEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; if (!VersionHelper.isVersionNewerThan1_21_2()) return; if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; Block clicked = event.getClickedBlock(); @@ -373,7 +373,7 @@ public class RecipeEventListener implements Listener { @SuppressWarnings("UnstableApiUsage") @EventHandler(ignoreCancelled = true) public void onCampfireCook(CampfireStartEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; if (!VersionHelper.isVersionNewerThan1_21_2()) return; CampfireRecipe recipe = event.getRecipe(); Key recipeId = new Key(recipe.getKey().namespace(), recipe.getKey().value()); @@ -404,7 +404,7 @@ public class RecipeEventListener implements Listener { // for 1.21.2+ @EventHandler(ignoreCancelled = true) public void onCampfireCook(BlockCookEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; if (!VersionHelper.isVersionNewerThan1_21_2()) return; Material type = event.getBlock().getType(); if (type != Material.CAMPFIRE && type != Material.SOUL_CAMPFIRE) return; @@ -743,7 +743,7 @@ public class RecipeEventListener implements Listener { @EventHandler(ignoreCancelled = true) public void onCraftingRecipe(PrepareItemCraftEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; org.bukkit.inventory.Recipe recipe = event.getRecipe(); if (recipe == null) return; @@ -836,7 +836,7 @@ public class RecipeEventListener implements Listener { @EventHandler(ignoreCancelled = true) public void onSmithingTransform(PrepareSmithingEvent event) { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; SmithingInventory inventory = event.getInventory(); if (!(inventory.getRecipe() instanceof SmithingTransformRecipe recipe)) return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java index 7901587e6..6a875cb5a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java @@ -11,7 +11,7 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.host.HostMode; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.util.VersionHelper; @@ -52,7 +52,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { @EventHandler(priority = EventPriority.LOW) public void onPlayerJoin(PlayerJoinEvent event) { // for 1.20.1 servers, not recommended to use - if (ConfigManager.sendPackOnJoin() && !VersionHelper.isVersionNewerThan1_20_2()) { + if (Config.sendPackOnJoin() && !VersionHelper.isVersionNewerThan1_20_2()) { this.sendResourcePack(plugin.networkManager().getUser(event.getPlayer()), null); } } @@ -60,7 +60,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { @EventHandler(priority = EventPriority.LOW) public void onResourcePackStatus(PlayerResourcePackStatusEvent event) { // for 1.20.1 servers, not recommended to use - if (ConfigManager.sendPackOnJoin() && ConfigManager.kickOnDeclined() && !VersionHelper.isVersionNewerThan1_20_2()) { + if (Config.sendPackOnJoin() && Config.kickOnDeclined() && !VersionHelper.isVersionNewerThan1_20_2()) { if (event.getStatus() == PlayerResourcePackStatusEvent.Status.DECLINED || event.getStatus() == PlayerResourcePackStatusEvent.Status.FAILED_DOWNLOAD) { event.getPlayer().kick(); } @@ -73,34 +73,34 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { // update server properties if (VersionHelper.isVersionNewerThan1_20_2()) { - if (ConfigManager.hostMode() == HostMode.SELF_HOST) { + if (Config.hostMode() == HostMode.SELF_HOST) { if (Files.exists(resourcePackPath())) { - updateResourcePackSettings(super.packUUID, ResourcePackHost.instance().url(), super.packHash, ConfigManager.kickOnDeclined(), ConfigManager.resourcePackPrompt()); + updateResourcePackSettings(super.packUUID, ResourcePackHost.instance().url(), super.packHash, Config.kickOnDeclined(), Config.resourcePackPrompt()); } - } else if (ConfigManager.hostMode() == HostMode.EXTERNAL_HOST) { - updateResourcePackSettings(ConfigManager.externalPackUUID(), ConfigManager.externalPackUrl(), ConfigManager.externalPackSha1(), ConfigManager.kickOnDeclined(), ConfigManager.resourcePackPrompt()); + } else if (Config.hostMode() == HostMode.EXTERNAL_HOST) { + updateResourcePackSettings(Config.externalPackUUID(), Config.externalPackUrl(), Config.externalPackSha1(), Config.kickOnDeclined(), Config.resourcePackPrompt()); } } - if (ConfigManager.sendPackOnReload()) { + if (Config.sendPackOnReload()) { if (this.previousHostMode == HostMode.SELF_HOST) { this.previousHostUUID = super.packUUID; } // unload packs if user changed to none host - if (ConfigManager.hostMode() == HostMode.NONE && this.previousHostMode != HostMode.NONE) { + if (Config.hostMode() == HostMode.NONE && this.previousHostMode != HostMode.NONE) { unloadResourcePackForOnlinePlayers(this.previousHostUUID); } // load new external resource pack on reload - if (ConfigManager.hostMode() == HostMode.EXTERNAL_HOST) { + if (Config.hostMode() == HostMode.EXTERNAL_HOST) { if (this.previousHostMode == HostMode.NONE) { updateResourcePackForOnlinePlayers(null); } else { updateResourcePackForOnlinePlayers(this.previousHostUUID); } // record previous host uuid here - this.previousHostUUID = ConfigManager.externalPackUUID(); + this.previousHostUUID = Config.externalPackUUID(); } - if (ConfigManager.hostMode() == HostMode.SELF_HOST && this.previousHostMode != HostMode.SELF_HOST) { + if (Config.hostMode() == HostMode.SELF_HOST && this.previousHostMode != HostMode.SELF_HOST) { if (ReloadCommand.RELOAD_PACK_FLAG) { ReloadCommand.RELOAD_PACK_FLAG = false; if (this.previousHostMode == HostMode.NONE) { @@ -111,7 +111,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { } } } - this.previousHostMode = ConfigManager.hostMode(); + this.previousHostMode = Config.hostMode(); } @Override @@ -134,12 +134,12 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { super.generateResourcePack(); // update server properties if (VersionHelper.isVersionNewerThan1_20_2()) { - if (ConfigManager.hostMode() == HostMode.SELF_HOST) { - updateResourcePackSettings(super.packUUID, ResourcePackHost.instance().url(), super.packHash, ConfigManager.kickOnDeclined(), ConfigManager.resourcePackPrompt()); + if (Config.hostMode() == HostMode.SELF_HOST) { + updateResourcePackSettings(super.packUUID, ResourcePackHost.instance().url(), super.packHash, Config.kickOnDeclined(), Config.resourcePackPrompt()); } } // resend packs - if (ConfigManager.hostMode() == HostMode.SELF_HOST && ConfigManager.sendPackOnReload()) { + if (Config.hostMode() == HostMode.SELF_HOST && Config.sendPackOnReload()) { updateResourcePackForOnlinePlayers(this.previousHostUUID); } } @@ -162,7 +162,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { } private void updateResourcePackSettings(UUID uuid, String url, String sha1, boolean required, Component prompt) { - if (!ConfigManager.sendPackOnJoin()) { + if (!Config.sendPackOnJoin()) { resetResourcePackSettings(); return; } @@ -182,36 +182,36 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { } public void sendResourcePack(NetWorkUser user, @Nullable UUID previousPack) { - if (ConfigManager.hostMode() == HostMode.NONE) return; + if (Config.hostMode() == HostMode.NONE) return; String url; String sha1; UUID uuid; - if (ConfigManager.hostMode() == HostMode.SELF_HOST) { + if (Config.hostMode() == HostMode.SELF_HOST) { url = ResourcePackHost.instance().url(); sha1 = super.packHash; uuid = super.packUUID; if (!Files.exists(resourcePackPath())) return; } else { - url = ConfigManager.externalPackUrl(); - sha1 = ConfigManager.externalPackSha1(); - uuid = ConfigManager.externalPackUUID(); + url = Config.externalPackUrl(); + sha1 = Config.externalPackSha1(); + uuid = Config.externalPackUUID(); if (uuid.equals(previousPack)) return; } - Object packPrompt = ComponentUtils.adventureToMinecraft(ConfigManager.resourcePackPrompt()); + Object packPrompt = ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt()); try { Object packPacket; if (VersionHelper.isVersionNewerThan1_20_5()) { packPacket = Reflections.constructor$ClientboundResourcePackPushPacket.newInstance( - uuid, url, sha1, ConfigManager.kickOnDeclined(), Optional.of(packPrompt) + uuid, url, sha1, Config.kickOnDeclined(), Optional.of(packPrompt) ); } else if (VersionHelper.isVersionNewerThan1_20_3()) { packPacket = Reflections.constructor$ClientboundResourcePackPushPacket.newInstance( - uuid, url, sha1, ConfigManager.kickOnDeclined(), packPrompt + uuid, url, sha1, Config.kickOnDeclined(), packPrompt ); } else { packPacket = Reflections.constructor$ClientboundResourcePackPushPacket.newInstance( - url + uuid, sha1, ConfigManager.kickOnDeclined(), packPrompt + url + uuid, sha1, Config.kickOnDeclined(), packPrompt ); } if (user.decoderState() == ConnectionState.PLAY) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index e42e271d5..891850e23 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -29,7 +29,7 @@ import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.classpath.ReflectionClassPathAppender; import net.momirealms.craftengine.core.plugin.command.sender.SenderFactory; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.dependency.Dependencies; import net.momirealms.craftengine.core.plugin.dependency.Dependency; import net.momirealms.craftengine.core.plugin.gui.category.ItemBrowserManagerImpl; @@ -65,17 +65,20 @@ public class BukkitCraftEngine extends CraftEngine { private boolean hasPlaceholderAPI; public BukkitCraftEngine(JavaPlugin bootstrap) { - VersionHelper.init(serverVersion()); + super((p) -> { + CraftEngineReloadEvent event = new CraftEngineReloadEvent((BukkitCraftEngine) p); + EventUtils.fireAndForget(event); + }); instance = this; this.bootstrap = bootstrap; super.classPathAppender = new ReflectionClassPathAppender(this); super.scheduler = new BukkitSchedulerAdapter(this); super.logger = new JavaPluginLogger(bootstrap.getLogger()); + // find mod class if present Class modClass = ReflectionUtils.getClazz(MOD_CLASS); if (modClass != null) { Field isSuccessfullyRegistered = ReflectionUtils.getDeclaredField(modClass, "isSuccessfullyRegistered"); try { - assert isSuccessfullyRegistered != null; requiresRestart = !(boolean) isSuccessfullyRegistered.get(null); hasMod = true; } catch (Exception ignore) { @@ -84,13 +87,11 @@ public class BukkitCraftEngine extends CraftEngine { } @Override - public void load() { - super.load(); + public void onPluginLoad() { + super.onPluginLoad(); Reflections.init(); BukkitInjector.init(); super.networkManager = new BukkitNetworkManager(this); - super.networkManager.init(); - // load mappings and inject blocks super.blockManager = new BukkitBlockManager(this); super.furnitureManager = new BukkitFurnitureManager(this); this.successfullyLoaded = true; @@ -105,8 +106,8 @@ public class BukkitCraftEngine extends CraftEngine { } @Override - public void enable() { - if (successfullyEnabled) { + public void onPluginEnable() { + if (this.successfullyEnabled) { logger().severe(" "); logger().severe(" "); logger().severe(" "); @@ -154,8 +155,37 @@ public class BukkitCraftEngine extends CraftEngine { super.worldManager = new BukkitWorldManager(this); super.soundManager = new BukkitSoundManager(this); super.vanillaLootManager = new BukkitVanillaLootManager(this); - this.fontManager = new BukkitFontManager(this); - super.enable(); + super.fontManager = new BukkitFontManager(this); + super.onPluginEnable(); + // compatibility + // register expansion + if (this.isPluginEnabled("PlaceholderAPI")) { + PlaceholderAPIUtils.registerExpansions(this); + this.hasPlaceholderAPI = true; + } + } + + @Override + public void onPluginDisable() { + super.onPluginDisable(); + if (this.tickTask != null) this.tickTask.cancel(); + if (!Bukkit.getServer().isStopping()) { + logger().severe(" "); + logger().severe(" "); + logger().severe(" "); + logger().severe("Please do not disable plugins at runtime."); + logger().severe(" "); + logger().severe(" "); + logger().severe(" "); + Bukkit.getServer().shutdown(); + } + } + + @Override + public void platformDelayedEnable() { + if (Config.metrics()) { + new Metrics(this.bootstrap(), 24333); + } // tick task if (VersionHelper.isFolia()) { this.tickTask = this.scheduler().sync().runRepeating(() -> { @@ -172,45 +202,6 @@ public class BukkitCraftEngine extends CraftEngine { } }, 1, 1); } - - // compatibility - // register expansion - if (this.isPluginEnabled("PlaceholderAPI")) { - PlaceholderAPIUtils.registerExpansions(this); - this.hasPlaceholderAPI = true; - } - } - - @Override - public void disable() { - super.disable(); - if (this.tickTask != null) this.tickTask.cancel(); - if (!Bukkit.getServer().isStopping()) { - logger().severe(" "); - logger().severe(" "); - logger().severe(" "); - logger().severe("Please do not disable plugins at runtime."); - logger().severe(" "); - logger().severe(" "); - logger().severe(" "); - Bukkit.getServer().shutdown(); - } - } - - @Override - public void reload() { - super.reload(); - scheduler.async().execute(() -> { - CraftEngineReloadEvent event = new CraftEngineReloadEvent(this); - EventUtils.fireAndForget(event); - }); - } - - @Override - public void delayedEnable() { - if (ConfigManager.metrics()) { - new Metrics(this.bootstrap(), 24333); - } } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java index 74794df67..def463fba 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java @@ -32,7 +32,7 @@ import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; @@ -623,14 +623,14 @@ public class BukkitInjector { CESection section = holder.ceSection(); if (BlockStateUtils.isVanillaBlock(stateId)) { section.setBlockState(x, y, z, EmptyBlock.INSTANCE.defaultState()); - if (ConfigManager.enableLightSystem() && ConfigManager.forceUpdateLight()) { + if (Config.enableLightSystem() && Config.forceUpdateLight()) { updateLightIfChanged(holder, previousState, newState, null, y, z, x); } } else { ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); section.setBlockState(x, y, z, immutableBlockState); if (!immutableBlockState.isEmpty()) { - if (ConfigManager.enableLightSystem()) { + if (Config.enableLightSystem()) { updateLightIfChanged(holder, previousState, newState, immutableBlockState.vanillaBlockState().handle(), y, z, x); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index e095aba81..5f556e1ab 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -37,20 +37,21 @@ import java.util.function.BiConsumer; public class BukkitNetworkManager implements NetworkManager, Listener, PluginMessageListener { private static BukkitNetworkManager instance; - private static final Map, TriConsumer> nmsPacketFunctions = new HashMap<>(); - private static final Map> byteBufPacketFunctions = new HashMap<>(); + private static final Map, TriConsumer> NMS_PACKET_HANDLERS = new HashMap<>(); + private static final Map> BYTE_BUFFER_PACKET_HANDLERS = new HashMap<>(); private static void registerNMSPacketConsumer(final TriConsumer function, @Nullable Class packet) { if (packet == null) return; - nmsPacketFunctions.put(packet, function); + NMS_PACKET_HANDLERS.put(packet, function); } private static void registerByteBufPacketConsumer(final BiConsumer function, int id) { - byteBufPacketFunctions.put(id, function); + BYTE_BUFFER_PACKET_HANDLERS.put(id, function); } private final BiConsumer> packetsConsumer; - private final BiConsumer delayedPacketConsumer; + private final BiConsumer> immediatePacketsConsumer; + private final BiConsumer packetConsumer; private final BiConsumer immediatePacketConsumer; private final BukkitCraftEngine plugin; @@ -67,35 +68,22 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static final String PACKET_ENCODER = "craftengine_encoder"; private static final String PACKET_DECODER = "craftengine_decoder"; - private boolean active; - private boolean init; private static boolean hasModelEngine; - public static boolean hasModelEngine() { - return hasModelEngine; - } - public BukkitNetworkManager(BukkitCraftEngine plugin) { + instance = this; + hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; this.plugin = plugin; - if (VersionHelper.isVersionNewerThan1_21_5()) { - this.packetIds = new PacketIds1_21_5(); - } else if (VersionHelper.isVersionNewerThan1_21_2()) { - this.packetIds = new PacketIds1_21_2(); - } else if (VersionHelper.isVersionNewerThan1_20_5()) { - this.packetIds = new PacketIds1_20_5(); - } else if (VersionHelper.isVersionNewerThan1_20_3()) { - this.packetIds = new PacketIds1_20_3(); - } else if (VersionHelper.isVersionNewerThan1_20_2()) { - this.packetIds = new PacketIds1_20_2(); - } else { - this.packetIds = new PacketIds1_20(); - } - this.registerConsumers(); + // set up packet id + this.packetIds = setupPacketIds(); + // register packet handlers + this.registerPacketHandlers(); + // set up packet senders + this.packetConsumer = FastNMS.INSTANCE::sendPacket; this.packetsConsumer = ((serverPlayer, packets) -> { Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); - FastNMS.INSTANCE.sendPacket(serverPlayer, bundle); + packetConsumer.accept(serverPlayer, bundle); }); - this.delayedPacketConsumer = FastNMS.INSTANCE::sendPacket; this.immediatePacketConsumer = (serverPlayer, packet) -> { try { Reflections.method$Connection$sendPacketImmediate.invoke(FastNMS.INSTANCE.field$Player$connection$connection(serverPlayer), packet, null, true); @@ -103,12 +91,47 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes plugin.logger().warn("Failed to invoke send packet", e); } }; - this.active = true; - hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; - instance = this; + this.immediatePacketsConsumer = (serverPlayer, packets) -> { + Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); + this.immediatePacketConsumer.accept(serverPlayer, bundle); + }; + // set up mod channel + this.plugin.bootstrap().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.bootstrap(), MOD_CHANNEL, this); + this.plugin.bootstrap().getServer().getMessenger().registerOutgoingPluginChannel(this.plugin.bootstrap(), MOD_CHANNEL); + // Inject server channel + try { + Object server = Reflections.method$MinecraftServer$getServer.invoke(null); + Object serverConnection = Reflections.field$MinecraftServer$connection.get(server); + @SuppressWarnings("unchecked") + List channels = (List) Reflections.field$ServerConnectionListener$channels.get(serverConnection); + ListMonitor monitor = new ListMonitor<>(channels, (future) -> { + Channel channel = future.channel(); + injectServerChannel(channel); + this.injectedChannels.add(channel); + }, (object) -> {}); + Reflections.field$ServerConnectionListener$channels.set(serverConnection, monitor); + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to init server connection", e); + } } - private void registerConsumers() { + private PacketIds setupPacketIds() { + if (VersionHelper.isVersionNewerThan1_21_5()) { + return new PacketIds1_21_5(); + } else if (VersionHelper.isVersionNewerThan1_21_2()) { + return new PacketIds1_21_2(); + } else if (VersionHelper.isVersionNewerThan1_20_5()) { + return new PacketIds1_20_5(); + } else if (VersionHelper.isVersionNewerThan1_20_3()) { + return new PacketIds1_20_3(); + } else if (VersionHelper.isVersionNewerThan1_20_2()) { + return new PacketIds1_20_2(); + } else { + return new PacketIds1_20(); + } + } + + private void registerPacketHandlers() { registerNMSPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, Reflections.clazz$ClientboundLevelChunkWithLightPacket); registerNMSPacketConsumer(PacketConsumers.PLAYER_ACTION, Reflections.clazz$ServerboundPlayerActionPacket); registerNMSPacketConsumer(PacketConsumers.SWING_HAND, Reflections.clazz$ServerboundSwingPacket); @@ -150,7 +173,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } - @EventHandler + @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerQuit(PlayerQuitEvent event) { Player player = event.getPlayer(); Channel channel = getChannel(player); @@ -170,40 +193,17 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes return this.onlineUserArray; } - @Override // 保留仅注册入频道用 + @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte @NotNull [] message) {} @Override public void init() { - if (init) return; - try { - this.plugin.bootstrap().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.bootstrap(), MOD_CHANNEL, this); - this.plugin.bootstrap().getServer().getMessenger().registerOutgoingPluginChannel(this.plugin.bootstrap(), MOD_CHANNEL); - Object server = Reflections.method$MinecraftServer$getServer.invoke(null); - Object serverConnection = Reflections.field$MinecraftServer$connection.get(server); - @SuppressWarnings("unchecked") - List channels = (List) Reflections.field$ServerConnectionListener$channels.get(serverConnection); - ListMonitor monitor = new ListMonitor<>(channels, (future) -> { - if (!this.active) return; - Channel channel = future.channel(); - injectServerChannel(channel); - this.injectedChannels.add(channel); - }, (object) -> {}); - Reflections.field$ServerConnectionListener$channels.set(serverConnection, monitor); - this.init = true; - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to init server connection", e); - } - } - - @Override - public void enable() { Bukkit.getPluginManager().registerEvents(this, plugin.bootstrap()); } @Override - public void shutdown() { + public void disable() { HandlerList.unregisterAll(this); for (Channel channel : injectedChannels) { uninjectServerChannel(channel); @@ -212,7 +212,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes handleDisconnection(getChannel(player)); } injectedChannels.clear(); - active = false; } @Override @@ -259,16 +258,26 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } + @Override public void sendPacket(@NotNull NetWorkUser player, Object packet, boolean immediately) { if (immediately) { this.immediatePacketConsumer.accept(player.serverPlayer(), packet); } else { - this.delayedPacketConsumer.accept(player.serverPlayer(), packet); + this.packetConsumer.accept(player.serverPlayer(), packet); } } - public void sendPackets(@NotNull NetWorkUser player, List packet) { - this.packetsConsumer.accept(player.serverPlayer(), packet); + @Override + public void sendPackets(@NotNull NetWorkUser player, List packet, boolean immediately) { + if (immediately) { + this.immediatePacketsConsumer.accept(player.serverPlayer(), packet); + } else { + this.packetsConsumer.accept(player.serverPlayer(), packet); + } + } + + public static boolean hasModelEngine() { + return hasModelEngine; } public void receivePacket(@NotNull NetWorkUser player, Object packet) { @@ -543,13 +552,13 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } protected void handleNMSPacket(NetWorkUser user, NMSPacketEvent event, Object packet) { - Optional.ofNullable(nmsPacketFunctions.get(packet.getClass())) + Optional.ofNullable(NMS_PACKET_HANDLERS.get(packet.getClass())) .ifPresent(function -> function.accept(user, event, packet)); } protected void handleByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - Optional.ofNullable(byteBufPacketFunctions.get(packetID)) + Optional.ofNullable(BYTE_BUFFER_PACKET_HANDLERS.get(packetID)) .ifPresent(function -> function.accept(user, event)); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index b4d9ff905..8893933f0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -20,7 +20,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.plugin.network.NetworkManager; @@ -300,7 +300,7 @@ public class PacketConsumers { int stateId = BlockStateUtils.blockStateToId(blockState); // not a custom block if (BlockStateUtils.isVanillaBlock(stateId)) { - if (ConfigManager.enableSoundSystem()) { + if (Config.enableSoundSystem()) { Object blockOwner = Reflections.field$StateHolder$owner.get(blockState); if (BukkitBlockManager.instance().isBlockSoundRemoved(blockOwner)) { player.startMiningBlock(world, pos, blockState, false, null); @@ -626,7 +626,7 @@ public class PacketConsumers { if (furniture != null) { user.furnitureView().computeIfAbsent(furniture.baseEntityId(), k -> new ArrayList<>()).addAll(furniture.fakeEntityIds()); user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); - if (ConfigManager.hideBaseEntity() && !furniture.hasExternalModel()) { + if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { event.setCancelled(true); } } @@ -774,7 +774,7 @@ public class PacketConsumers { // we handle it on packet level to prevent it from being captured by plugins public static final TriConsumer RENAME_ITEM = (user, event, packet) -> { try { - if (!ConfigManager.filterAnvil()) return; + if (!Config.filterAnvil()) return; String message = (String) Reflections.field$ServerboundRenameItemPacket$name.get(packet); if (message != null && !message.isEmpty()) { FontManager manager = CraftEngine.instance().imageManager(); @@ -799,7 +799,7 @@ public class PacketConsumers { // we handle it on packet level to prevent it from being captured by plugins public static final TriConsumer SIGN_UPDATE = (user, event, packet) -> { try { - if (!ConfigManager.filterSign()) return; + if (!Config.filterSign()) return; String[] lines = (String[]) Reflections.field$ServerboundSignUpdatePacket$lines.get(packet); FontManager manager = CraftEngine.instance().imageManager(); if (!manager.isDefaultFontInUse()) return; @@ -826,7 +826,7 @@ public class PacketConsumers { @SuppressWarnings("unchecked") public static final TriConsumer EDIT_BOOK = (user, event, packet) -> { try { - if (!ConfigManager.filterBook()) return; + if (!Config.filterBook()) return; FontManager manager = CraftEngine.instance().imageManager(); if (!manager.isDefaultFontInUse()) return; // check bypass diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java index eeed1b749..ac0bf989c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Direction; @@ -77,14 +77,14 @@ public class InteractUtils { return false; }); register(BlockKeys.SOUL_CAMPFIRE, (player, item, blockState, result) -> { - if (!ConfigManager.enableRecipeSystem()) return false; + if (!Config.enableRecipeSystem()) return false; Optional> optional = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(item.id()); return optional.filter(keyReference -> BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( keyReference, item.getItem() ))) != null).isPresent(); }); register(BlockKeys.CAMPFIRE, (player, item, blockState, result) -> { - if (!ConfigManager.enableRecipeSystem()) return false; + if (!Config.enableRecipeSystem()) return false; Optional> optional = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(item.id()); return optional.filter(keyReference -> BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( keyReference, item.getItem() diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java index 5127e9916..78ed33dc9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java @@ -1,14 +1,14 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; public class NoteBlockChainUpdateUtils { private NoteBlockChainUpdateUtils() {} public static void noteBlockChainUpdate(Object level, Object chunkSource, Object direction, Object blockPos, int times) throws ReflectiveOperationException { - if (times >= ConfigManager.maxChainUpdate()) return; + if (times >= Config.maxChainUpdate()) return; Object relativePos = Reflections.method$BlockPos$relative.invoke(blockPos, direction); Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, relativePos); if (BlockStateUtils.isClientSideNoteBlock(state)) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java index 73ca854da..b9070e694 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.util.LightUtils; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.SectionPosUtils; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.World; @@ -20,7 +20,7 @@ public class BukkitCEWorld extends CEWorld { @Override public void tick() { - if (ConfigManager.enableLightSystem()) { + if (Config.enableLightSystem()) { LightUtils.updateChunkLight((org.bukkit.World) world.platformWorld(), SectionPosUtils.toMap(super.updatedSectionPositions, world.worldHeight().getMinSection() - 1, world.worldHeight().getMaxSection() + 1)); super.updatedSectionPositions.clear(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index 2125528ce..98bb2aec9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.CEWorld; @@ -265,7 +265,7 @@ public class BukkitWorldManager implements WorldManager, Listener { plugin.logger().warn("Failed to write chunk tag at " + chunk.getX() + " " + chunk.getZ(), e); return; } finally { - if (ConfigManager.restoreVanillaBlocks()) { + if (Config.restoreVanillaBlocks()) { CESection[] ceSections = ceChunk.sections(); Object worldServer = FastNMS.INSTANCE.field$CraftChunk$worldServer(chunk); Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); @@ -313,7 +313,7 @@ public class BukkitWorldManager implements WorldManager, Listener { for (int i = 0; i < ceSections.length; i++) { CESection ceSection = ceSections[i]; Object section = sections[i]; - if (ConfigManager.syncCustomBlocks()) { + if (Config.syncCustomBlocks()) { Object statesContainer = FastNMS.INSTANCE.field$LevelChunkSection$states(section); Object data = Reflections.varHandle$PalettedContainer$data.get(statesContainer); Object palette = Reflections.field$PalettedContainer$Data$palette.get(data); @@ -362,7 +362,7 @@ public class BukkitWorldManager implements WorldManager, Listener { } } } - if (ConfigManager.restoreCustomBlocks()) { + if (Config.restoreCustomBlocks()) { if (!ceSection.statesContainer().isEmpty()) { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { @@ -378,7 +378,7 @@ public class BukkitWorldManager implements WorldManager, Listener { } BukkitInjector.injectLevelChunkSection(section, ceSection, ceWorld, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z)); } - if (ConfigManager.enableRecipeSystem()) { + if (Config.enableRecipeSystem()) { @SuppressWarnings("unchecked") Map blockEntities = (Map) FastNMS.INSTANCE.field$ChunkAccess$blockEntities(levelChunk); for (Object blockEntity : blockEntities.values()) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java index 7b5d27868..d21392cea 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java @@ -1,10 +1,9 @@ package net.momirealms.craftengine.core.block; import com.google.gson.JsonElement; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.Key; import org.incendo.cloud.suggestion.Suggestion; @@ -13,7 +12,7 @@ import java.util.Collection; import java.util.Map; import java.util.Optional; -public interface BlockManager extends Reloadable, ModelGenerator { +public interface BlockManager extends Manageable, ModelGenerator { ConfigSectionParser parser(); @@ -30,6 +29,4 @@ public interface BlockManager extends Reloadable, ModelGenerator { Collection cachedSuggestions(); Map soundMapper(); - - void initSuggestions(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java index 0985250f6..d2692164d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.entity.Entity; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.Vec3d; @@ -12,7 +12,7 @@ import javax.annotation.Nullable; import java.util.Collection; import java.util.Optional; -public interface FurnitureManager extends Reloadable { +public interface FurnitureManager extends Manageable { String FURNITURE_ADMIN_NODE = "craftengine.furniture.admin"; ConfigSectionParser parser(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 988dc9228..7d4239f5c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -34,7 +34,7 @@ public abstract class AbstractFontManager implements FontManager { @Override public void load() { - this.offsetFont = Optional.ofNullable(plugin.configManager().settings().getSection("offset-characters")) + this.offsetFont = Optional.ofNullable(plugin.config().settings().getSection("offset-characters")) .map(OffsetFont::new) .orElse(null); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java index 345f63f29..004f8595d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.font; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.FormatUtils; @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.util.Key; import java.util.Collection; import java.util.Optional; -public interface FontManager extends Reloadable { +public interface FontManager extends Manageable { Key DEFAULT_FONT = Key.of("minecraft:default"); String BYPASS_BOOK = "craftengine.filter.bypass.book"; String BYPASS_SIGN = "craftengine.filter.bypass.sign"; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index 5362e6d3a..7b6ed87a1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.pack.LegacyOverridesModel; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; import net.momirealms.craftengine.core.pack.model.ItemModel; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; @@ -15,7 +15,7 @@ import org.incendo.cloud.suggestion.Suggestion; import javax.annotation.Nullable; import java.util.*; -public interface ItemManager extends Reloadable, ModelGenerator { +public interface ItemManager extends Manageable, ModelGenerator { ConfigSectionParser parser(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DisplayNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DisplayNameModifier.java index e73503bbb..b0c1a95cd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DisplayNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DisplayNameModifier.java @@ -2,14 +2,14 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; public class DisplayNameModifier implements ItemModifier { private final String argument; public DisplayNameModifier(String argument) { - this.argument = ConfigManager.nonItalic() ? "" + argument : argument; + this.argument = Config.nonItalic() ? "" + argument : argument; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java index 9a860fe3c..624941d51 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java @@ -2,14 +2,14 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; public class ItemNameModifier implements ItemModifier { private final String argument; public ItemNameModifier(String argument) { - this.argument = ConfigManager.nonItalic() ? "" + argument : argument; + this.argument = Config.nonItalic() ? "" + argument : argument; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java index 066b2ae10..7d8e5d1ae 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.item.modifier; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; import java.util.List; @@ -11,7 +11,7 @@ public class LoreModifier implements ItemModifier { private final List argument; public LoreModifier(List argument) { - this.argument = ConfigManager.nonItalic() ? argument.stream().map(it -> "" + it).toList() : argument; + this.argument = Config.nonItalic() ? argument.stream().map(it -> "" + it).toList() : argument; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java index 627900416..069a4c03f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java @@ -8,7 +8,7 @@ import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeR import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.Holder; @@ -155,7 +155,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { @Override public void parseSection(Pack pack, Path path, Key id, Map section) { - if (!ConfigManager.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem()) return; if (AbstractRecipeManager.this.byId.containsKey(id)) { TranslationManager.instance().log("warning.config.recipe.duplicated", path.toString(), id.toString()); return; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java index 3573ec789..eb59f67ed 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; @@ -9,7 +9,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Optional; -public interface RecipeManager extends Reloadable { +public interface RecipeManager extends Manageable { ConfigSectionParser parser(); @@ -30,6 +30,4 @@ public interface RecipeManager extends Reloadable { @Nullable Recipe recipeByInput(Key type, RecipeInput input, @Nullable Key lastRecipe); - - void runSyncTasks(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java index 5e301e286..c4fabdf8d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java @@ -1,12 +1,12 @@ package net.momirealms.craftengine.core.loot; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.Key; import java.util.Optional; -public interface VanillaLootManager extends Reloadable { +public interface VanillaLootManager extends Manageable { ConfigSectionParser parser(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 5b4a60db3..a342a60d0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -15,10 +15,9 @@ import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; import net.momirealms.craftengine.core.pack.obfuscation.ObfA; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; -import net.momirealms.craftengine.core.plugin.config.template.TemplateManager; import net.momirealms.craftengine.core.plugin.locale.I18NData; import net.momirealms.craftengine.core.sound.AbstractSoundManager; import net.momirealms.craftengine.core.sound.SoundEvent; @@ -140,10 +139,10 @@ public abstract class AbstractPackManager implements PackManager { this.loadPacks(); this.loadConfigs(); this.calculateHash(); - if (ConfigManager.hostMode() == HostMode.SELF_HOST) { - Path path = ConfigManager.hostResourcePackPath().startsWith(".") ? plugin.dataFolderPath().resolve(ConfigManager.hostResourcePackPath()) : Path.of(ConfigManager.hostResourcePackPath()); - ResourcePackHost.instance().enable(ConfigManager.hostIP(), ConfigManager.hostPort(), path); - ResourcePackHost.instance().setRateLimit(ConfigManager.requestRate(), ConfigManager.requestInterval(), TimeUnit.SECONDS); + if (Config.hostMode() == HostMode.SELF_HOST) { + Path path = Config.hostResourcePackPath().startsWith(".") ? plugin.dataFolderPath().resolve(Config.hostResourcePackPath()) : Path.of(Config.hostResourcePackPath()); + ResourcePackHost.instance().enable(Config.hostIP(), Config.hostPort(), path); + ResourcePackHost.instance().setRateLimit(Config.requestRate(), Config.requestInterval(), TimeUnit.SECONDS); } else { ResourcePackHost.instance().disable(); } @@ -206,7 +205,7 @@ public abstract class AbstractPackManager implements PackManager { } public Path selfHostPackPath() { - return ConfigManager.hostResourcePackPath().startsWith(".") ? plugin.dataFolderPath().resolve(ConfigManager.hostResourcePackPath()) : Path.of(ConfigManager.hostResourcePackPath()); + return Config.hostResourcePackPath().startsWith(".") ? plugin.dataFolderPath().resolve(Config.hostResourcePackPath()) : Path.of(Config.hostResourcePackPath()); } private void loadPacks() { @@ -229,7 +228,7 @@ public abstract class AbstractPackManager implements PackManager { String version = null; String author = null; if (Files.exists(metaFile) && Files.isRegularFile(metaFile)) { - YamlDocument metaYML = ConfigManager.instance().loadYamlData(metaFile.toFile()); + YamlDocument metaYML = Config.instance().loadYamlData(metaFile.toFile()); namespace = metaYML.getString("namespace", namespace); description = metaYML.getString("description"); version = metaYML.getString("version"); @@ -466,7 +465,7 @@ public abstract class AbstractPackManager implements PackManager { try { List folders = new ArrayList<>(); folders.addAll(loadedPacks().stream().map(Pack::resourcePackFolder).toList()); - folders.addAll(ConfigManager.foldersToMerge().stream().map(it -> plugin.dataFolderPath().getParent().resolve(it)).filter(Files::exists).toList()); + folders.addAll(Config.foldersToMerge().stream().map(it -> plugin.dataFolderPath().getParent().resolve(it)).filter(Files::exists).toList()); List>> duplicated = mergeFolder(folders, generatedPackPath); if (!duplicated.isEmpty()) { @@ -528,7 +527,7 @@ public abstract class AbstractPackManager implements PackManager { private void generateEquipments(Path generatedPackPath) { for (EquipmentGeneration generator : this.plugin.itemManager().equipmentsToGenerate()) { EquipmentData equipmentData = generator.modernData(); - if (equipmentData != null && ConfigManager.packMaxVersion() >= 21.4f) { + if (equipmentData != null && Config.packMaxVersion() >= 21.4f) { Path equipmentPath = generatedPackPath .resolve("assets") .resolve(equipmentData.assetId().namespace()) @@ -561,7 +560,7 @@ public abstract class AbstractPackManager implements PackManager { this.plugin.logger().severe("Error writing equipment file", e); } } - if (equipmentData != null && ConfigManager.packMaxVersion() >= 21.2f && ConfigManager.packMinVersion() < 21.4f) { + if (equipmentData != null && Config.packMaxVersion() >= 21.2f && Config.packMinVersion() < 21.4f) { Path equipmentPath = generatedPackPath .resolve("assets") .resolve(equipmentData.assetId().namespace()) @@ -663,7 +662,7 @@ public abstract class AbstractPackManager implements PackManager { } private void generateOverrideSounds(Path generatedPackPath) { - if (!ConfigManager.enableSoundSystem()) return; + if (!Config.enableSoundSystem()) return; Path soundPath = generatedPackPath .resolve("assets") @@ -753,7 +752,7 @@ public abstract class AbstractPackManager implements PackManager { private void generateBlockOverrides(Path generatedPackPath) { File blockStatesFile = new File(plugin.dataFolderFile(), "blockstates.yml"); if (!blockStatesFile.exists()) plugin.saveResource("blockstates.yml"); - YamlDocument preset = ConfigManager.instance().loadYamlData(blockStatesFile); + YamlDocument preset = Config.instance().loadYamlData(blockStatesFile); for (Map.Entry> entry : plugin.blockManager().blockOverrides().entrySet()) { Key key = entry.getKey(); Path overridedBlockPath = generatedPackPath @@ -788,7 +787,7 @@ public abstract class AbstractPackManager implements PackManager { } } - if (!ConfigManager.generateModAssets()) return; + if (!Config.generateModAssets()) return; for (Map.Entry entry : plugin.blockManager().modBlockStates().entrySet()) { Key key = entry.getKey(); Path overridedBlockPath = generatedPackPath @@ -815,8 +814,8 @@ public abstract class AbstractPackManager implements PackManager { } private void generateModernItemModels1_21_2(Path generatedPackPath) { - if (ConfigManager.packMaxVersion() < 21.19f) return; - if (ConfigManager.packMinVersion() > 21.39f) return; + if (Config.packMaxVersion() < 21.19f) return; + if (Config.packMinVersion() > 21.39f) return; boolean has = false; for (Map.Entry> entry : plugin.itemManager().modernItemModels1_21_2().entrySet()) { @@ -868,13 +867,13 @@ public abstract class AbstractPackManager implements PackManager { } } - if (ConfigManager.packMinVersion() < 21.19f && has) { - plugin.logger().warn("You are using item-model component for models which requires 1.21.2+. But the min supported version is " + "1." + ConfigManager.packMinVersion()); + if (Config.packMinVersion() < 21.19f && has) { + plugin.logger().warn("You are using item-model component for models which requires 1.21.2+. But the min supported version is " + "1." + Config.packMinVersion()); } } private void generateModernItemModels1_21_4(Path generatedPackPath) { - if (ConfigManager.packMaxVersion() < 21.39f) return; + if (Config.packMaxVersion() < 21.39f) return; for (Map.Entry entry : plugin.itemManager().modernItemModels1_21_4().entrySet()) { Key key = entry.getKey(); Path itemPath = generatedPackPath @@ -907,7 +906,7 @@ public abstract class AbstractPackManager implements PackManager { } private void generateModernItemOverrides(Path generatedPackPath) { - if (ConfigManager.packMaxVersion() < 21.39f) return; + if (Config.packMaxVersion() < 21.39f) return; for (Map.Entry> entry : plugin.itemManager().modernItemOverrides().entrySet()) { Key key = entry.getKey(); Path overridedItemPath = generatedPackPath @@ -967,7 +966,7 @@ public abstract class AbstractPackManager implements PackManager { } private void generateLegacyItemOverrides(Path generatedPackPath) { - if (ConfigManager.packMinVersion() > 21.39f) return; + if (Config.packMinVersion() > 21.39f) return; for (Map.Entry> entry : plugin.itemManager().legacyItemOverrides().entrySet()) { Key key = entry.getKey(); Path overridedItemPath = generatedPackPath @@ -1064,7 +1063,7 @@ public abstract class AbstractPackManager implements PackManager { } } - if (ConfigManager.resourcePack$overrideUniform()) { + if (Config.resourcePack$overrideUniform()) { Path fontPath = generatedPackPath.resolve("assets") .resolve("minecraft") .resolve("font") @@ -1115,7 +1114,7 @@ public abstract class AbstractPackManager implements PackManager { Files.copy(file, targetPath, StandardCopyOption.REPLACE_EXISTING); conflicts.add(file); } else { - for (ConditionalResolution resolution : ConfigManager.resolutions()) { + for (ConditionalResolution resolution : Config.resolutions()) { if (resolution.matcher().test(relative)) { resolution.resolution().run(targetPath, file); return FileVisitResult.CONTINUE; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java index d80d2d540..6af2ca8a7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java @@ -1,13 +1,13 @@ package net.momirealms.craftengine.core.pack; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import org.jetbrains.annotations.NotNull; import java.nio.file.Path; import java.util.Collection; -public interface PackManager extends Reloadable { +public interface PackManager extends Manageable { @NotNull Collection loadedPacks(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHost.java index 48dd33894..be9052f45 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHost.java @@ -4,7 +4,7 @@ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import java.io.IOException; import java.io.OutputStream; @@ -26,7 +26,7 @@ public class ResourcePackHost { private long rateLimitInterval = 1000; public String url() { - return ConfigManager.hostProtocol() + "://" + ip + ":" + port + "/"; + return Config.hostProtocol() + "://" + ip + ":" + port + "/"; } public void enable(String ip, int port, Path resourcePackPath) { @@ -77,7 +77,7 @@ public class ResourcePackHost { private class ResourcePackHandler implements HttpHandler { @Override public void handle(HttpExchange exchange) throws IOException { - if (ConfigManager.denyNonMinecraftRequest()) { + if (Config.denyNonMinecraftRequest()) { String userAgent = exchange.getRequestHeaders().getFirst("User-Agent"); if (userAgent == null || !userAgent.startsWith("Minecraft Java/")) { CraftEngine.instance().debug(() -> "Blocked non-Minecraft Java client. User-Agent: " + userAgent); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfF.java b/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfF.java index 803b735f6..c66880467 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfF.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfF.java @@ -101,7 +101,7 @@ public final class ObfF { } private static Section 九转大肠() { - return CraftEngine.instance().configManager().settings() + return CraftEngine.instance().config().settings() .getSection("resource-pack.protection"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index e6c8b01f5..290acc357 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -11,7 +11,7 @@ import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.plugin.classpath.ClassPathAppender; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.sender.SenderFactory; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.template.TemplateManager; import net.momirealms.craftengine.core.plugin.config.template.TemplateManagerImpl; import net.momirealms.craftengine.core.plugin.dependency.Dependencies; @@ -29,13 +29,14 @@ import net.momirealms.craftengine.core.plugin.logger.filter.LogFilter; import net.momirealms.craftengine.core.plugin.network.NetworkManager; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter; import net.momirealms.craftengine.core.sound.SoundManager; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldManager; import org.apache.logging.log4j.LogManager; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.function.BiConsumer; +import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.Supplier; @@ -43,13 +44,15 @@ public abstract class CraftEngine implements Plugin { public static final String MOD_CLASS = "net.momirealms.craftengine.mod.CraftEnginePlugin"; public static final String NAMESPACE = "craftengine"; private static CraftEngine instance; + protected PluginLogger logger; + protected Consumer> debugger = (s) -> {}; + protected Config config; + protected ClassPathAppender classPathAppender; protected DependencyManager dependencyManager; protected SchedulerAdapter scheduler; protected NetworkManager networkManager; - protected ClassPathAppender classPathAppender; protected FontManager fontManager; protected PackManager packManager; - protected ConfigManager configManager; protected ItemManager itemManager; protected RecipeManager recipeManager; protected BlockManager blockManager; @@ -64,8 +67,7 @@ public abstract class CraftEngine implements Plugin { protected SoundManager soundManager; protected VanillaLootManager vanillaLootManager; - protected PluginLogger logger; - protected Consumer> debugger = (s) -> {}; + private final Consumer reloadEventDispatcher; private boolean isReloading; private String buildByBit = "%%__BUILTBYBIT__%%"; @@ -74,8 +76,10 @@ public abstract class CraftEngine implements Plugin { private String user = "%%__USER__%%"; private String username = "%%__USERNAME__%%"; - protected CraftEngine() { + protected CraftEngine(Consumer reloadEventDispatcher) { instance = this; + this.reloadEventDispatcher = reloadEventDispatcher; + VersionHelper.init(serverVersion()); } public static CraftEngine instance() { @@ -85,8 +89,7 @@ public abstract class CraftEngine implements Plugin { return instance; } - @Override - public void load() { + public void onPluginLoad() { ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).addFilter(new LogFilter()); ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).addFilter(new DisconnectLogFilter()); this.dependencyManager = new DependencyManagerImpl(this); @@ -95,88 +98,119 @@ public abstract class CraftEngine implements Plugin { dependenciesToLoad.addAll(platformDependencies()); this.dependencyManager.loadDependencies(dependenciesToLoad); this.translationManager = new TranslationManagerImpl(this); - this.configManager = new ConfigManager(this); + this.config = new Config(this); } - @Override - public void reload() { - reload((a, b) -> {}); - } + public record ReloadResult(boolean success, long asyncTime, long syncTime) { - public void reload(BiConsumer time) { - if (this.isReloading) return; - long time1 = System.currentTimeMillis(); - this.isReloading = true; - this.configManager.reload(); - // reset debugger - if (ConfigManager.debug()) { - this.debugger = (s) -> logger.info("[Debug] " + s.get()); - } else { - this.debugger = (s) -> {}; + static ReloadResult failure() { + return new ReloadResult(false, -1L, -1L); + } + + static ReloadResult success(long asyncTime, long syncTime) { + return new ReloadResult(true, asyncTime, syncTime); } - this.translationManager.reload(); - this.templateManager.reload(); - this.furnitureManager.reload(); - this.fontManager.reload(); - this.itemManager.reload(); - this.soundManager.reload(); - this.recipeManager.reload(); - this.itemBrowserManager.reload(); - this.blockManager.reload(); - this.worldManager.reload(); - this.vanillaLootManager.reload(); - // load configs here - this.packManager.reload(); - // load at last - this.guiManager.reload(); - // delayed load - this.translationManager.delayedLoad(); - this.blockManager.delayedLoad(); - this.furnitureManager.delayedLoad(); - this.itemBrowserManager.delayedLoad(); - this.soundManager.delayedLoad(); - this.fontManager.delayedLoad(); - this.recipeManager.delayedLoad(); - long time2 = System.currentTimeMillis(); - scheduler().sync().run(() -> { - try { - this.recipeManager.runSyncTasks(); - long time3 = System.currentTimeMillis(); - time.accept(time2 - time1, time3 - time2); - } finally { - this.isReloading = false; - } - }); } - @Override - public void enable() { - this.networkManager.enable(); + public CompletableFuture reloadPlugin(Executor asyncExecutor, Executor syncExecutor, boolean reloadRecipe) { + CompletableFuture future = new CompletableFuture<>(); + asyncExecutor.execute(() -> { + if (this.isReloading) { + future.complete(ReloadResult.failure()); + return; + } + this.isReloading = true; + long time1 = System.currentTimeMillis(); + // firstly reload main config + this.config.load(); + // reset debugger + this.debugger = Config.debug() ? (s) -> logger.info("[Debug] " + s.get()) : (s) -> {}; + // now we reload the translations + this.translationManager.reload(); + // clear the outdated cache by reloading the managers + this.templateManager.reload(); + this.furnitureManager.reload(); + this.fontManager.reload(); + this.itemManager.reload(); + this.soundManager.reload(); + this.itemBrowserManager.reload(); + this.blockManager.reload(); + this.worldManager.reload(); + this.vanillaLootManager.reload(); + this.guiManager.reload(); + if (reloadRecipe) { + this.recipeManager.reload(); + } + // now we load resources + this.packManager.reload(); + // handle some special client lang for instance block_name + this.translationManager.delayedLoad(); + // init suggestions and packet mapper + this.blockManager.delayedLoad(); + // init suggestions + this.furnitureManager.delayedLoad(); + // sort the categories + this.itemBrowserManager.delayedLoad(); + // collect illegal characters from minecraft:default font + this.fontManager.delayedLoad(); + if (reloadRecipe) { + // convert data pack recipes + this.recipeManager.delayedLoad(); + } + long time2 = System.currentTimeMillis(); + long asyncTime = time2 - time1; + syncExecutor.execute(() -> { + try { + // register songs + this.soundManager.runDelayedSyncTasks(); + // register recipes + this.recipeManager.runDelayedSyncTasks(); + long time3 = System.currentTimeMillis(); + long syncTime = time3 - time2; + this.reloadEventDispatcher.accept(this); + future.complete(ReloadResult.success(asyncTime, syncTime)); + } finally { + this.isReloading = false; + } + }); + }); + return future; + } + + public void onPluginEnable() { + this.networkManager.init(); this.templateManager = new TemplateManagerImpl(); this.itemBrowserManager = new ItemBrowserManagerImpl(this); this.commandManager.registerDefaultFeatures(); - // delay the reload so other plugins can register some parsers + // delay the reload so other plugins can register some custom parsers this.scheduler.sync().runDelayed(() -> { - this.registerParsers(); + this.registerDefaultParsers(); + // hook external item plugins this.itemManager.delayedInit(); - this.reload(); + // hook worldedit + this.blockManager.delayedInit(); + // register listeners and tasks this.guiManager.delayedInit(); this.recipeManager.delayedInit(); - this.blockManager.delayedInit(); - this.worldManager.delayedInit(); this.packManager.delayedInit(); - this.furnitureManager.delayedInit(); this.fontManager.delayedInit(); this.vanillaLootManager.delayedInit(); - this.delayedEnable(); + // reload the plugin + try { + this.reloadPlugin(Runnable::run, Runnable::run, true); + } catch (Exception e) { + this.logger.warn("Failed to reload plugin on enable stage", e); + } + // must be after reloading because this process loads furniture + this.worldManager.delayedInit(); + this.furnitureManager.delayedInit(); + // set up some platform extra tasks + this.platformDelayedEnable(); }); } - @Override - public void disable() { - if (this.senderFactory != null) this.senderFactory.close(); - if (this.commandManager != null) this.commandManager.unregisterFeatures(); - if (this.networkManager != null) this.networkManager.shutdown(); + public void onPluginDisable() { + if (this.networkManager != null) this.networkManager.disable(); if (this.fontManager != null) this.fontManager.disable(); if (this.packManager != null) this.packManager.disable(); if (this.itemManager != null) this.itemManager.disable(); @@ -189,12 +223,15 @@ public abstract class CraftEngine implements Plugin { if (this.guiManager != null) this.guiManager.disable(); if (this.soundManager != null) this.soundManager.disable(); if (this.vanillaLootManager != null) this.vanillaLootManager.disable(); + if (this.translationManager != null) this.translationManager.disable(); if (this.scheduler != null) this.scheduler.shutdownScheduler(); if (this.scheduler != null) this.scheduler.shutdownExecutor(); + if (this.commandManager != null) this.commandManager.unregisterFeatures(); + if (this.senderFactory != null) this.senderFactory.close(); ResourcePackHost.instance().disable(); } - protected void registerParsers() { + protected void registerDefaultParsers() { // register template parser this.packManager.registerConfigSectionParser(this.templateManager.parser()); // register font parser @@ -217,7 +254,7 @@ public abstract class CraftEngine implements Plugin { this.packManager.registerConfigSectionParser(this.vanillaLootManager.parser()); } - protected abstract void delayedEnable(); + protected abstract void platformDelayedEnable(); protected abstract List platformDependencies(); @@ -242,11 +279,6 @@ public abstract class CraftEngine implements Plugin { ); } - @Override - public DependencyManager dependencyManager() { - return dependencyManager; - } - @SuppressWarnings("unchecked") @Override public SchedulerAdapter scheduler() { @@ -258,6 +290,33 @@ public abstract class CraftEngine implements Plugin { return classPathAppender; } + @Override + public Config config() { + return config; + } + + @Override + public PluginLogger logger() { + return logger; + } + + @Override + public void debug(Supplier message) { + debugger.accept(message); + } + + @Override + public boolean isReloading() { + return isReloading; + } + + public abstract boolean hasPlaceholderAPI(); + + @Override + public DependencyManager dependencyManager() { + return dependencyManager; + } + @SuppressWarnings("unchecked") @Override public ItemManager itemManager() { @@ -279,16 +338,6 @@ public abstract class CraftEngine implements Plugin { return fontManager; } - @Override - public ConfigManager configManager() { - return configManager; - } - - @Override - public PluginLogger logger() { - return logger; - } - @Override public TranslationManager translationManager() { return translationManager; @@ -315,9 +364,10 @@ public abstract class CraftEngine implements Plugin { return (RecipeManager) recipeManager; } + @SuppressWarnings("unchecked") @Override - public SenderFactory senderFactory() { - return senderFactory; + public

SenderFactory senderFactory() { + return (SenderFactory) senderFactory; } @Override @@ -344,15 +394,4 @@ public abstract class CraftEngine implements Plugin { public VanillaLootManager vanillaLootManager() { return vanillaLootManager; } - - @Override - public void debug(Supplier message) { - debugger.accept(message); - } - - public boolean isReloading() { - return isReloading; - } - - public abstract boolean hasPlaceholderAPI(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Reloadable.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Manageable.java similarity index 51% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/Reloadable.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/Manageable.java index a589ffbb1..d8ae4d046 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Reloadable.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Manageable.java @@ -1,28 +1,39 @@ package net.momirealms.craftengine.core.plugin; -public interface Reloadable { +public interface Manageable { + // on plugin enable + default void init() { + } + + // after all plugins enabled + default void delayedInit() { + } + + // async reload default void reload() { unload(); load(); } - default void enable() { - } - + // async unload default void unload() { } + // async load default void load() { } + // on plugin disable default void disable() { unload(); } + // after all modules reloaded default void delayedLoad() { } - default void delayedInit() { + // delayed tasks on main thread + default void runDelayedSyncTasks() { } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java index 4f158bacf..d34729e3d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java @@ -10,7 +10,7 @@ import net.momirealms.craftengine.core.loot.VanillaLootManager; import net.momirealms.craftengine.core.pack.PackManager; import net.momirealms.craftengine.core.plugin.classpath.ClassPathAppender; import net.momirealms.craftengine.core.plugin.command.sender.SenderFactory; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.template.TemplateManager; import net.momirealms.craftengine.core.plugin.dependency.DependencyManager; import net.momirealms.craftengine.core.plugin.gui.GuiManager; @@ -27,7 +27,7 @@ import java.io.InputStream; import java.nio.file.Path; import java.util.function.Supplier; -public interface Plugin extends Reloadable { +public interface Plugin { InputStream resourceStream(String filePath); @@ -39,6 +39,8 @@ public interface Plugin extends Reloadable { Path dataFolderPath(); + boolean isReloading(); + DependencyManager dependencyManager(); SchedulerAdapter scheduler(); @@ -57,7 +59,7 @@ public interface Plugin extends Reloadable { FontManager imageManager(); - ConfigManager configManager(); + Config config(); TranslationManager translationManager(); @@ -69,7 +71,7 @@ public interface Plugin extends Reloadable { RecipeManager recipeManager(); - SenderFactory senderFactory(); +

SenderFactory senderFactory(); WorldManager worldManager(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/command/AbstractCommandManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/command/AbstractCommandManager.java index 99292096b..f894ff78f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/command/AbstractCommandManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/command/AbstractCommandManager.java @@ -12,7 +12,7 @@ import net.kyori.adventure.text.ComponentLike; import net.kyori.adventure.text.TranslatableComponent; import net.momirealms.craftengine.core.plugin.Plugin; import net.momirealms.craftengine.core.plugin.command.sender.Sender; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.locale.CraftEngineCaptionFormatter; import net.momirealms.craftengine.core.plugin.locale.CraftEngineCaptionProvider; import net.momirealms.craftengine.core.util.ArrayUtils; @@ -126,7 +126,7 @@ public abstract class AbstractCommandManager implements CraftEngineCommandMan @Override public void registerDefaultFeatures() { - YamlDocument document = ConfigManager.instance().loadYamlConfig(commandsFile, + YamlDocument document = Config.instance().loadYamlConfig(commandsFile, GeneralSettings.DEFAULT, LoaderSettings .builder() diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java similarity index 98% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index 46586334c..e0bb910ba 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -14,7 +14,6 @@ import net.momirealms.craftengine.core.pack.conflict.resolution.ConditionalResol import net.momirealms.craftengine.core.pack.host.HostMode; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.PluginProperties; -import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.plugin.logger.filter.DisconnectLogFilter; import net.momirealms.craftengine.core.util.AdventureHelper; @@ -32,8 +31,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.*; -public class ConfigManager implements Reloadable { - private static ConfigManager instance; +public class Config { + private static Config instance; protected final CraftEngine plugin; private final Path configFilePath; private final String configVersion; @@ -116,14 +115,13 @@ public class ConfigManager implements Reloadable { protected boolean image$illegal_characters_filter$sign; protected boolean image$illegal_characters_filter$book; - public ConfigManager(CraftEngine plugin) { + public Config(CraftEngine plugin) { this.plugin = plugin; this.configVersion = PluginProperties.getValue("config"); this.configFilePath = this.plugin.dataFolderPath().resolve("config.yml"); instance = this; } - @Override public void load() { if (Files.exists(this.configFilePath)) { this.config = this.loadYamlData(this.configFilePath.toFile()); @@ -170,11 +168,6 @@ public class ConfigManager implements Reloadable { } } - @Override - public void unload() { - Reloadable.super.unload(); - } - private void loadSettings() { YamlDocument config = settings(); plugin.translationManager().forcedLocale(TranslationManager.parseLocale(config.getString("forced-locale", ""))); @@ -610,7 +603,7 @@ public class ConfigManager implements Reloadable { return config; } - public static ConfigManager instance() { + public static Config instance() { return instance; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java index 8b44c1a99..b6b2b00be 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.plugin.config.template; import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.Key; @@ -9,7 +9,7 @@ import java.nio.file.Path; import java.util.Map; import java.util.regex.Pattern; -public interface TemplateManager extends Reloadable { +public interface TemplateManager extends Manageable { Pattern ARGUMENT_PATTERN = Pattern.compile("\\{[^{}]+}"); String LEFT_BRACKET = "{"; String RIGHT_BRACKET = "}"; @@ -22,5 +22,4 @@ public interface TemplateManager extends Reloadable { void addTemplate(Pack pack, Path path, Key id, Object obj); Map applyTemplates(Map input); - } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java index 4e2287eb5..8c4e25cb1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiManager.java @@ -1,8 +1,8 @@ package net.momirealms.craftengine.core.plugin.gui; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; -public interface GuiManager extends Reloadable { +public interface GuiManager extends Manageable { Inventory createInventory(Gui gui, int size); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java index 112abbb25..e9de45dab 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManager.java @@ -3,8 +3,8 @@ package net.momirealms.craftengine.core.plugin.gui.category; import dev.dejvokep.boostedyaml.block.implementation.Section; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.recipe.Recipe; -import net.momirealms.craftengine.core.plugin.Reloadable; -import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.Manageable; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.gui.Gui; import net.momirealms.craftengine.core.util.Key; @@ -15,7 +15,7 @@ import java.util.TreeSet; import static java.util.Objects.requireNonNull; -public interface ItemBrowserManager extends Reloadable { +public interface ItemBrowserManager extends Manageable { int MAX_RECIPE_DEPTH = 16; String GET_ITEM_PERMISSION = "craftengine.browser.get_item"; @@ -71,7 +71,7 @@ public interface ItemBrowserManager extends Reloadable { public static Key SOUND_CLICK_BUTTON; public static void load() { - Section section = ConfigManager.instance().settings().getSection("gui.browser"); + Section section = Config.instance().settings().getSection("gui.browser"); if (section == null) return; BROWSER_TITLE = getOrThrow(section, "main.title"); BROWSER_NEXT_PAGE_AVAILABLE = Key.of(getOrThrow(section, "main.page-navigation.next.available")); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java index 90671d485..f8bab04f3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.plugin.locale; import net.kyori.adventure.text.Component; import net.kyori.adventure.translation.Translator; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import org.jetbrains.annotations.Nullable; @@ -12,7 +12,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -public interface TranslationManager extends Reloadable { +public interface TranslationManager extends Manageable { Set ALL_LANG = Set.of( "af_za", "ar_sa", "ast_es", "az_az", "ba_ru", "bar", "be_by", "be_latn", "bg_bg", "br_fr", "brb", "bs_ba", "ca_es", "cs_cz", "cy_gb", "da_dk", diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java index 31e6f79e8..9c79a0b4a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java @@ -2,8 +2,12 @@ package net.momirealms.craftengine.core.plugin.network; import io.netty.channel.Channel; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.Manageable; +import org.jetbrains.annotations.NotNull; -public interface NetworkManager { +import java.util.List; + +public interface NetworkManager extends Manageable { String MOD_CHANNEL = "craftengine:payload"; void setUser(Channel channel, NetWorkUser user); @@ -16,9 +20,15 @@ public interface NetworkManager { NetWorkUser[] onlineUsers(); - void init(); + default void sendPacket(@NotNull NetWorkUser player, Object packet) { + sendPacket(player, packet, false); + } - void enable(); + void sendPacket(@NotNull NetWorkUser player, Object packet, boolean immediately); - void shutdown(); + default void sendPackets(@NotNull NetWorkUser player, List packet) { + sendPacket(player, packet, false); + } + + void sendPackets(@NotNull NetWorkUser player, List packet, boolean immediately); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java index 88621064b..951040f2f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java @@ -40,7 +40,7 @@ public abstract class AbstractSoundManager implements SoundManager { } @Override - public void delayedLoad() { + public void runDelayedSyncTasks() { if (!VersionHelper.isVersionNewerThan1_21()) return; this.registerSongs(this.songs); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java index 97c81ff31..367785592 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java @@ -1,12 +1,12 @@ package net.momirealms.craftengine.core.sound; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.Key; import java.util.Map; -public interface SoundManager extends Reloadable { +public interface SoundManager extends Manageable { ConfigSectionParser[] parsers(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java index 5cfef4fd5..5c83b592b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java @@ -1,13 +1,13 @@ package net.momirealms.craftengine.core.world; -import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; import org.jetbrains.annotations.NotNull; import java.util.UUID; -public interface WorldManager extends Reloadable { +public interface WorldManager extends Manageable { void setStorageAdaptor(@NotNull StorageAdaptor storageAdaptor); From 9f77895cfef297f14f0d373751872f467cd1e9fe Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 4 Apr 2025 19:36:43 +0800 Subject: [PATCH 24/37] =?UTF-8?q?refactor(entity):=20=E9=80=82=E9=85=8D=20?= =?UTF-8?q?Minecraft=201.21.5=20=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/entity/data/EntityDataValue.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java index baae1cf12..c5db7a6e3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java @@ -30,6 +30,7 @@ public class EntityDataValue { public static final Object Serializers$OPTIONAL_BLOCK_POS; public static final Object Serializers$DIRECTION; public static final Object Serializers$OPTIONAL_UUID; + public static final Object Serializers$OPTIONAL_LIVING_ENTITY_REFERENCE; public static final Object Serializers$OPTIONAL_GLOBAL_POS; public static final Object Serializers$COMPOUND_TAG; public static final Object Serializers$VILLAGER_DATA; @@ -64,7 +65,10 @@ public class EntityDataValue { Serializers$BLOCK_POS = initSerializersByName("BLOCK_POS"); Serializers$OPTIONAL_BLOCK_POS = initSerializersByName("OPTIONAL_BLOCK_POS"); Serializers$DIRECTION = initSerializersByName("DIRECTION"); - Serializers$OPTIONAL_UUID = initSerializersByName("OPTIONAL_UUID"); + if (!VersionHelper.isVersionNewerThan1_21_5()) Serializers$OPTIONAL_UUID = initSerializersByName("OPTIONAL_UUID"); + else Serializers$OPTIONAL_UUID = null; + if (VersionHelper.isVersionNewerThan1_21_5()) Serializers$OPTIONAL_LIVING_ENTITY_REFERENCE = initSerializersByName("OPTIONAL_LIVING_ENTITY_REFERENCE"); + else Serializers$OPTIONAL_LIVING_ENTITY_REFERENCE = null; Serializers$OPTIONAL_GLOBAL_POS = initSerializersByName("OPTIONAL_GLOBAL_POS"); Serializers$COMPOUND_TAG = initSerializersByName("COMPOUND_TAG"); Serializers$VILLAGER_DATA = initSerializersByName("VILLAGER_DATA"); From f5f504c5a9a38ce099d40746b8c4749efc6d6d88 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 19:53:36 +0800 Subject: [PATCH 25/37] reload --- .../item/recipe/BukkitRecipeManager.java | 6 +- .../plugin/command/feature/ReloadCommand.java | 72 ++++++++++++------- .../core/pack/AbstractPackManager.java | 13 ++-- .../craftengine/core/pack/PackManager.java | 2 + .../craftengine/core/plugin/CraftEngine.java | 8 ++- gradle.properties | 4 +- 6 files changed, 68 insertions(+), 37 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index ca09ce9e0..a026bee0f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -432,13 +432,13 @@ public class BukkitRecipeManager extends AbstractRecipeManager { // give flags back on 1.21.2+ if (VersionHelper.isVersionNewerThan1_21_2() && this.stolenFeatureFlagSet != null) { - Reflections.field$RecipeManager$featureflagset.set(nmsRecipeManager, this.stolenFeatureFlagSet); - this.stolenFeatureFlagSet = false; + Reflections.field$RecipeManager$featureflagset.set(nmsRecipeManager(), this.stolenFeatureFlagSet); + this.stolenFeatureFlagSet = null; } // refresh recipes if (VersionHelper.isVersionNewerThan1_21_2()) { - Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager); + Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager()); } // send to players diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java index f77586c8f..8979f67ae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java @@ -34,43 +34,64 @@ public class ReloadCommand extends BukkitCommandFeature { argument = optional.get(); } if (argument == ReloadArgument.CONFIG) { - plugin().scheduler().executeAsync(() -> { - try { - RELOAD_PACK_FLAG = true; - plugin().reload((a, b) -> handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_SUCCESS, Component.text(a + b), Component.text(a), Component.text(b))); - } catch (Exception e) { - handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_FAILURE); - plugin().logger().warn("Failed to reload config", e); - } - }); + try { + RELOAD_PACK_FLAG = true; + plugin().reloadPlugin(plugin().scheduler().async(), r -> plugin().scheduler().sync().run(r), false).thenAccept(reloadResult -> { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_SUCCESS, + Component.text(reloadResult.asyncTime() + reloadResult.syncTime()), + Component.text(reloadResult.asyncTime()), + Component.text(reloadResult.syncTime()) + ); + }); + } catch (Exception e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_FAILURE); + plugin().logger().warn("Failed to reload config", e); + } + } else if (argument == ReloadArgument.RECIPE) { + try { + RELOAD_PACK_FLAG = true; + plugin().reloadPlugin(plugin().scheduler().async(), r -> plugin().scheduler().sync().run(r), true).thenAccept(reloadResult -> { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_SUCCESS, + Component.text(reloadResult.asyncTime() + reloadResult.syncTime()), + Component.text(reloadResult.asyncTime()), + Component.text(reloadResult.syncTime()) + ); + }); + } catch (Exception e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_FAILURE); + plugin().logger().warn("Failed to reload config", e); + } } else if (argument == ReloadArgument.PACK) { plugin().scheduler().executeAsync(() -> { try { long time1 = System.currentTimeMillis(); plugin().packManager().generateResourcePack(); long time2 = System.currentTimeMillis(); - handleFeedback(context, MessageConstants.COMMAND_RELOAD_PACK_SUCCESS, Component.text(time2 - time1)); + long packTime = time2 - time1; + handleFeedback(context, MessageConstants.COMMAND_RELOAD_PACK_SUCCESS, Component.text(packTime)); } catch (Exception e) { handleFeedback(context, MessageConstants.COMMAND_RELOAD_PACK_FAILURE); plugin().logger().warn("Failed to generate resource pack", e); } }); } else if (argument == ReloadArgument.ALL) { - plugin().scheduler().executeAsync(() -> { - plugin().reload((a, b) -> { - plugin().scheduler().async().execute(() -> { - try { - long time1 = System.currentTimeMillis(); - plugin().packManager().generateResourcePack(); - long time2 = System.currentTimeMillis(); - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_SUCCESS, Component.text(a + b + time2 - time1), Component.text(a), Component.text(b), Component.text(time2 - time1)); - } catch (Exception e) { - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); - plugin().logger().warn("Failed to generate resource pack", e); - } - }); - }); - }); + try { + plugin().reloadPlugin(plugin().scheduler().async(), r -> plugin().scheduler().sync().run(r), true).thenAcceptAsync(reloadResult -> { + long time1 = System.currentTimeMillis(); + plugin().packManager().generateResourcePack(); + long time2 = System.currentTimeMillis(); + long packTime = time2 - time1; + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_SUCCESS, + Component.text(reloadResult.asyncTime() + reloadResult.syncTime() + packTime), + Component.text(reloadResult.asyncTime()), + Component.text(reloadResult.syncTime()), + Component.text(packTime) + ); + }, plugin().scheduler().async()); + } catch (Exception e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); + plugin().logger().warn("Failed to generate resource pack", e); + } } }); } @@ -82,6 +103,7 @@ public class ReloadCommand extends BukkitCommandFeature { public enum ReloadArgument { CONFIG, + RECIPE, PACK, ALL } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index a342a60d0..4c2a241a7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -38,6 +38,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Predicate; import static net.momirealms.craftengine.core.util.MiscUtils.castToMap; @@ -136,8 +137,6 @@ public abstract class AbstractPackManager implements PackManager { @Override public void load() { - this.loadPacks(); - this.loadConfigs(); this.calculateHash(); if (Config.hostMode() == HostMode.SELF_HOST) { Path path = Config.hostResourcePackPath().startsWith(".") ? plugin.dataFolderPath().resolve(Config.hostResourcePackPath()) : Path.of(Config.hostResourcePackPath()); @@ -148,6 +147,12 @@ public abstract class AbstractPackManager implements PackManager { } } + @Override + public void loadResources(boolean recipe) { + this.loadPacks(); + this.loadResourceConfigs(recipe ? (p) -> true : (p) -> p.loadingSequence() != LoadingSequence.RECIPE); + } + @Override public void unload() { this.loadedPacks.clear(); @@ -372,7 +377,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png.mcmeta"); } - private void loadConfigs() { + private void loadResourceConfigs(Predicate predicate) { long o1 = System.nanoTime(); for (Pack pack : loadedPacks()) { Pair, List> files = FileUtils.getConfigsDeeply(pack.configurationFolder()); @@ -412,7 +417,7 @@ public abstract class AbstractPackManager implements PackManager { Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); if (parser.isTemplate()) { this.plugin.templateManager().addTemplate(cached.pack(), cached.filePath(), id, configEntry.getValue()); - } else { + } else if (predicate.test(parser)) { if (configEntry.getValue() instanceof Map configSection0) { Map configSection1 = castToMap(configSection0, false); if ((boolean) configSection1.getOrDefault("enable", true)) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java index 6af2ca8a7..54764ce6a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java @@ -9,6 +9,8 @@ import java.util.Collection; public interface PackManager extends Manageable { + void loadResources(boolean recipe); + @NotNull Collection loadedPacks(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 290acc357..cc76af3ac 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -138,11 +138,12 @@ public abstract class CraftEngine implements Plugin { this.worldManager.reload(); this.vanillaLootManager.reload(); this.guiManager.reload(); + this.packManager.reload(); if (reloadRecipe) { this.recipeManager.reload(); } // now we load resources - this.packManager.reload(); + this.packManager.loadResources(reloadRecipe); // handle some special client lang for instance block_name this.translationManager.delayedLoad(); // init suggestions and packet mapper @@ -161,12 +162,13 @@ public abstract class CraftEngine implements Plugin { long asyncTime = time2 - time1; syncExecutor.execute(() -> { try { + long time3 = System.currentTimeMillis(); // register songs this.soundManager.runDelayedSyncTasks(); // register recipes this.recipeManager.runDelayedSyncTasks(); - long time3 = System.currentTimeMillis(); - long syncTime = time3 - time2; + long time4 = System.currentTimeMillis(); + long syncTime = time4 - time3; this.reloadEventDispatcher.accept(this); future.complete(ReloadResult.success(asyncTime, syncTime)); } finally { diff --git a/gradle.properties b/gradle.properties index 9045e8e41..065750cb4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.42 +project_version=0.0.43 config_version=19 lang_version=3 project_group=net.momirealms @@ -40,7 +40,7 @@ geantyref_version=1.3.16 zstd_version=1.5.7-2 commons_io_version=2.18.0 sparrow_nbt_version=0.3 -sparrow_util_version=0.35 +sparrow_util_version=0.36 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8 From 2f8fe823721202832b90a3b9ffb042a7b166dec9 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 20:02:52 +0800 Subject: [PATCH 26/37] fix bugs --- .../bukkit/plugin/network/BukkitNetworkManager.java | 2 +- .../net/momirealms/craftengine/core/plugin/CraftEngine.java | 4 +++- .../craftengine/core/plugin/network/NetworkManager.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 5f556e1ab..db3caf172 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -82,7 +82,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes this.packetConsumer = FastNMS.INSTANCE::sendPacket; this.packetsConsumer = ((serverPlayer, packets) -> { Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); - packetConsumer.accept(serverPlayer, bundle); + this.packetConsumer.accept(serverPlayer, bundle); }); this.immediatePacketConsumer = (serverPlayer, packet) -> { try { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index cc76af3ac..37964c071 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -166,7 +166,9 @@ public abstract class CraftEngine implements Plugin { // register songs this.soundManager.runDelayedSyncTasks(); // register recipes - this.recipeManager.runDelayedSyncTasks(); + if (reloadRecipe) { + this.recipeManager.runDelayedSyncTasks(); + } long time4 = System.currentTimeMillis(); long syncTime = time4 - time3; this.reloadEventDispatcher.accept(this); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java index 9c79a0b4a..b6bbae960 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java @@ -27,7 +27,7 @@ public interface NetworkManager extends Manageable { void sendPacket(@NotNull NetWorkUser player, Object packet, boolean immediately); default void sendPackets(@NotNull NetWorkUser player, List packet) { - sendPacket(player, packet, false); + sendPackets(player, packet, false); } void sendPackets(@NotNull NetWorkUser player, List packet, boolean immediately); From f5fa5bc1ae96037b1062be9f68adba8b8b228afd Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 21:29:34 +0800 Subject: [PATCH 27/37] add more warnings --- .../src/main/resources/translations/en.yml | 13 +- .../src/main/resources/translations/zh_cn.yml | 2 +- .../bukkit/api/CraftEngineBlocks.java | 2 +- .../bukkit/block/BukkitBlockManager.java | 202 ++++++++---------- .../behavior/ConcretePowderBlockBehavior.java | 2 +- .../bukkit/item/behavior/AxeItemBehavior.java | 2 +- .../item/behavior/BlockItemBehavior.java | 2 +- .../bukkit/util/BlockStateUtils.java | 6 +- .../core/block/AbstractBlockManager.java | 52 +++++ .../craftengine/core/block/BlockManager.java | 2 +- .../core/block/properties/Properties.java | 2 +- .../core/pack/AbstractPackManager.java | 6 +- .../core/pack/ResourceLocation.java | 4 +- .../core/plugin/locale/I18NData.java | 2 +- 14 files changed, 170 insertions(+), 129 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index ef65e98c7..760faf424 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -82,10 +82,19 @@ warning.config.item.custom_model_data_conflict: "Issue found in file Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." warning.config.block.duplicated: "Issue found in file - Duplicated block ''." warning.config.block.lack_state: "Issue found in file - The block '' is missing the required 'state' argument." -warning.config.block.lack_real_id: "Issue found in file - The block '' is missing the required 'id' argument for 'state'." +warning.config.block.state.lack_real_id: "Issue found in file - The block '' is missing the required 'id' argument for 'state'." warning.config.block.state.lack_state: "Issue found in file - The block '' is missing the required 'state' argument for 'state'." warning.config.block.state.lack_properties: "Issue found in file - The block '' is missing the required 'properties' section for 'states'." warning.config.block.state.lack_appearances: "Issue found in file - The block '' is missing the required 'appearances' section for 'states'." warning.config.block.state.lack_variants: "Issue found in file - The block '' is missing the required 'variants' section for 'states'." warning.config.block.state.variant.lack_appearance: "Issue found in file - The block '' is missing the required 'appearance' argument for variant ''." -warning.config.block.state.variant.invalid_appearance: "Issue found in file - The block '' has an error that the variant '' is using a non-existing appearance ''." \ No newline at end of file +warning.config.block.state.variant.invalid_appearance: "Issue found in file - The block '' has an error that the variant '' is using a non-existing appearance ''." +warning.config.block.state.invalid_state: "Issue found in file - The block '' is using an invalid vanilla block state ''." +warning.config.block.state.unavailable_state: "Issue found in file - The block '' is using an unavailable vanilla block state ''." +warning.config.block.state.invalid_vanilla_state_id: "Issue found in file - The block '' is using a vanilla block state '' that exceeds the available slot range '0~'." +warning.config.block.state.conflict: "Issue found in file - The block '' is using a vanilla block state '' that has been occupied by ''." +warning.config.block.bind_real_state: "Issue found in file - The block '' failed to bind real block state for '' as the state has been occupied by ''." +warning.config.block.state.invalid_property_structure: "Issue found in file - The block '' has an invalid property structure ''." +warning.config.block.state.invalid_property: "Issue found in file - Failed to create property '' for block '': ." +warning.config.block.state.no_model_set: "Issue found in file - The block '' is missing the required 'model' or 'models' argument." +warning.config.block.state.invalid_real_state_id: "Issue found in file - The block '' is using a real block state '' that exceeds the available slot range '0~'. Consider adding more real states in 'additional-real-blocks.yml' if the slots are used up." \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 9e458de6c..0cab6ac5d 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -82,7 +82,7 @@ warning.config.item.custom_model_data_conflict: "在文件 中 warning.config.item.lack_model_id: "在文件 中发现问题 - 物品 '' 缺少必要的 'custom-model-data' 或 'item-model' 模型标识参数" warning.config.block.duplicated: "在文件 中发现问题 - 方块 '' 重复定义" warning.config.block.lack_state: "在文件 中发现问题 - 方块 '' 缺少必要的 'state' 状态参数" -warning.config.block.lack_real_id: "在文件 中发现问题 - 方块 '' 的 'state' 配置缺少必要的 'id' 标识参数" +warning.config.block.state.lack_real_id: "在文件 中发现问题 - 方块 '' 的 'state' 配置缺少必要的 'id' 标识参数" warning.config.block.state.lack_state: "在文件 中发现问题 - 方块 '' 的 'state' 配置缺少必要的 'state' 状态参数" warning.config.block.state.lack_properties: "在文件 中发现问题 - 方块 '' 的 'states' 配置缺少必要的 'properties' 属性配置" warning.config.block.state.lack_appearances: "在文件 中发现问题 - 方块 '' 的 'states' 配置缺少必要的 'appearances' 外观配置" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index 61d50a512..b7bbe8e5a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -37,7 +37,7 @@ public final class CraftEngineBlocks { */ @Nullable public static CustomBlock byId(@NotNull Key id) { - return BukkitBlockManager.instance().getBlock(id).orElse(null); + return BukkitBlockManager.instance().blockById(id).orElse(null); } /** diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 95bfdcf33..c62766b00 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -36,7 +36,6 @@ import org.bukkit.NamespacedKey; import org.bukkit.block.data.BlockData; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; -import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; @@ -59,11 +58,7 @@ public class BukkitBlockManager extends AbstractBlockManager { // The total amount of blocks registered private int customBlockCount; - - // CraftEngine objects - private final Map byId = new HashMap<>(); - private final ImmutableBlockState[] stateId2ImmutableBlockStates; - + protected final ImmutableBlockState[] stateId2ImmutableBlockStates; // Minecraft objects // Cached new blocks $ holders private ImmutableMap internalId2StateId; @@ -87,14 +82,9 @@ public class BukkitBlockManager extends AbstractBlockManager { private final Map> blockStateOverrides = new HashMap<>(); // for mod, real block id -> state models private final Map modBlockStates = new HashMap<>(); - // Cached command suggestions - private final List cachedSuggestions = new ArrayList<>(); - // Cached Namespace - private final Set namespacesInUse = new HashSet<>(); // Event listeners private final BlockEventListener blockEventListener; private final FallingBlockRemoveListener fallingBlockRemoveListener; - private WorldEditCommandHelper weCommandHelper; public BukkitBlockManager(BukkitCraftEngine plugin) { @@ -106,7 +96,7 @@ public class BukkitBlockManager extends AbstractBlockManager { if (plugin.hasMod() && plugin.requiresRestart()) { blockEventListener = null; fallingBlockRemoveListener = null; - stateId2ImmutableBlockStates = null; + stateId2ImmutableBlockStates = new ImmutableBlockState[]{}; return; } this.registerBlocks(); @@ -152,11 +142,9 @@ public class BukkitBlockManager extends AbstractBlockManager { @Override public void unload() { - super.clearModelsToGenerate(); + super.unload(); this.clearCache(); this.appearanceToRealState.clear(); - this.byId.clear(); - this.cachedSuggestions.clear(); this.blockStateOverrides.clear(); this.modBlockStates.clear(); if (EmptyBlock.INSTANCE != null) @@ -236,41 +224,6 @@ public class BukkitBlockManager extends AbstractBlockManager { return Collections.unmodifiableMap(this.blockStateOverrides); } - @Override - public Map blocks() { - return Collections.unmodifiableMap(this.byId); - } - - @Override - public Optional getBlock(Key key) { - return Optional.ofNullable(this.byId.get(key)); - } - - @Override - public Collection cachedSuggestions() { - return Collections.unmodifiableCollection(this.cachedSuggestions); - } - - private void initSuggestions() { - this.cachedSuggestions.clear(); - this.namespacesInUse.clear(); - Set states = new HashSet<>(); - for (CustomBlock block : this.byId.values()) { - states.add(block.id().toString()); - this.namespacesInUse.add(block.id().namespace()); - for (ImmutableBlockState state : block.variantProvider().states()) { - states.add(state.toString()); - } - } - for (String state : states) { - this.cachedSuggestions.add(Suggestion.suggestion(state)); - } - } - - public Set namespacesInUse() { - return Collections.unmodifiableSet(this.namespacesInUse); - } - public ImmutableMap> blockAppearanceArranger() { return blockAppearanceArranger; } @@ -392,11 +345,11 @@ public class BukkitBlockManager extends AbstractBlockManager { @Override public void parseSection(Pack pack, Path path, Key id, Map section) { + // check duplicated config if (byId.containsKey(id)) { TranslationManager.instance().log("warning.config.block.duplicated", path.toString(), id.toString()); return; } - // read block settings BlockSettings settings = BlockSettings.fromMap(MiscUtils.castToMap(section.getOrDefault("settings", Map.of()), false)); // read loot table @@ -410,38 +363,46 @@ public class BukkitBlockManager extends AbstractBlockManager { properties = Map.of(); int internalId = MiscUtils.getAsInt(stateSection.getOrDefault("id", -1)); if (internalId < 0) { - TranslationManager.instance().log("warning.config.block.lack_real_id", path.toString(), id.toString()); + TranslationManager.instance().log("warning.config.block.state.lack_real_id", path.toString(), id.toString()); return; } + Pair pair = parseAppearanceSection(path, id, stateSection); if (pair == null) return; + appearances = Map.of("default", pair.right()); Key internalBlockId = Key.of(CraftEngine.NAMESPACE, pair.left().value() + "_" + internalId); int internalBlockRegistryId = MiscUtils.getAsInt(internalId2StateId.getOrDefault(internalBlockId, -1)); if (internalBlockRegistryId == -1) { - plugin.logger().warn(path, "Failed to register " + id + " because id " + internalId + " is not a value between 0~" + (MiscUtils.getAsInt(registeredRealBlockSlots.get(pair.left()))-1) + - ". Consider editing additional-real-blocks.yml if the number of real block IDs is insufficient while there are still available appearances"); + TranslationManager.instance().log("warning.config.block.state.invalid_real_state_id", + path.toString(), + id.toString(), + pair.left().value() + "_" + internalId, + String.valueOf(MiscUtils.getAsInt(registeredRealBlockSlots.get(pair.left()))-1) + ); return; } variants = Map.of("", new VariantState("default", settings, internalBlockRegistryId)); } else { + // states Map statesSection = MiscUtils.castToMap(section.get("states"), true); if (statesSection == null) { TranslationManager.instance().log("warning.config.block.lack_state", path.toString(), id.toString()); return; } + // properties Map propertySection = MiscUtils.castToMap(statesSection.get("properties"), true); if (propertySection == null) { TranslationManager.instance().log("warning.config.block.state.lack_properties", path.toString(), id.toString()); return; } - properties = parseProperties(path, propertySection); + properties = parseProperties(path, id, propertySection); + // appearance Map appearancesSection = MiscUtils.castToMap(statesSection.get("appearances"), true); if (appearancesSection == null) { TranslationManager.instance().log("warning.config.block.state.lack_appearances", path.toString(), id.toString()); return; } - appearances = new HashMap<>(); Map tempTypeMap = new HashMap<>(); for (Map.Entry appearanceEntry : appearancesSection.entrySet()) { @@ -452,13 +413,12 @@ public class BukkitBlockManager extends AbstractBlockManager { tempTypeMap.put(appearanceEntry.getKey(), pair.left()); } } - + // variants Map variantsSection = MiscUtils.castToMap(statesSection.get("variants"), true); if (variantsSection == null) { TranslationManager.instance().log("warning.config.block.state.lack_variants", path.toString(), id.toString()); return; } - variants = new HashMap<>(); for (Map.Entry variantEntry : variantsSection.entrySet()) { if (variantEntry.getValue() instanceof Map variantSection0) { @@ -478,8 +438,12 @@ public class BukkitBlockManager extends AbstractBlockManager { Key internalBlockId = Key.of(CraftEngine.NAMESPACE, baseBlock.value() + "_" + internalId); int internalBlockRegistryId = MiscUtils.getAsInt(internalId2StateId.getOrDefault(internalBlockId, -1)); if (internalBlockRegistryId == -1) { - plugin.logger().warn(path, "Failed to register " + id + " because id " + internalId + " is not a value between 0~" + (MiscUtils.getAsInt(registeredRealBlockSlots.getOrDefault(baseBlock, 1))-1) + - ". Consider editing additional-real-blocks.yml if the number of real block IDs is insufficient while there are still available appearances"); + TranslationManager.instance().log("warning.config.block.state.invalid_real_state_id", + path.toString(), + id.toString(), + internalBlockId.toString(), + String.valueOf(MiscUtils.getAsInt(registeredRealBlockSlots.getOrDefault(baseBlock, 1)) - 1) + ); return; } Map anotherSetting = MiscUtils.castToMap(variantSection.get("settings"), true); @@ -487,18 +451,27 @@ public class BukkitBlockManager extends AbstractBlockManager { } } } + // create or get block holder Holder.Reference holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() -> ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id))); // create block Map behaviorSection = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); - BukkitCustomBlock block = new BukkitCustomBlock(id, holder, properties, appearances, variants, settings, behaviorSection, lootTable); - // bind appearance - bindAppearance(block); - byId.put(id, block); + // bind appearance and real state + for (ImmutableBlockState state : block.variantProvider().states()) { + ImmutableBlockState previous = stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()]; + if (previous != null && !previous.isEmpty()) { + TranslationManager.instance().log("warning.config.block.bind_real_state", path.toString(), id.toString(), state.toString(), previous.toString()); + continue; + } + stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()] = state; + tempBlockAppearanceConvertor.put(state.customBlockState().registryId(), state.vanillaBlockState().registryId()); + appearanceToRealState.computeIfAbsent(state.vanillaBlockState().registryId(), k -> new ArrayList<>()).add(state.customBlockState().registryId()); + } + byId.put(id, block); // generate mod assets if (Config.generateModAssets()) { for (ImmutableBlockState state : block.variantProvider().states()) { @@ -509,27 +482,18 @@ public class BukkitBlockManager extends AbstractBlockManager { } } - private void bindAppearance(CustomBlock block) { - for (ImmutableBlockState state : block.variantProvider().states()) { - ImmutableBlockState previous = this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()]; - if (previous != null && !previous.isEmpty()) { - this.plugin.logger().severe("[Fatal] Failed to bind real block state for " + state + ": the state is already occupied by " + previous); - continue; - } - this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()] = state; - this.tempBlockAppearanceConvertor.put(state.customBlockState().registryId(), state.vanillaBlockState().registryId()); - this.appearanceToRealState.computeIfAbsent(state.vanillaBlockState().registryId(), k -> new ArrayList<>()).add(state.customBlockState().registryId()); - } - } - - private Map> parseProperties(Path path, Map propertiesSection) { + private Map> parseProperties(Path path, Key id, Map propertiesSection) { Map> properties = new HashMap<>(); for (Map.Entry entry : propertiesSection.entrySet()) { if (entry.getValue() instanceof Map params) { - Property property = Properties.fromMap(entry.getKey(), MiscUtils.castToMap(params, false)); - properties.put(entry.getKey(), property); + try { + Property property = Properties.fromMap(entry.getKey(), MiscUtils.castToMap(params, false)); + properties.put(entry.getKey(), property); + } catch (Exception e) { + TranslationManager.instance().log("warning.config.block.state.invalid_property", path.toString(), id.toString(), entry.getKey(), e.getMessage()); + } } else { - this.plugin.logger().warn(path, "Invalid property format: " + entry.getKey()); + TranslationManager.instance().log("warning.config.block.state.invalid_property_structure", path.toString(), id.toString(), entry.getKey()); } } return properties; @@ -537,25 +501,41 @@ public class BukkitBlockManager extends AbstractBlockManager { @Nullable private Pair parseAppearanceSection(Path path, Key id, Map section) { + // require state non null String vanillaStateString = (String) section.get("state"); if (vanillaStateString == null) { TranslationManager.instance().log("warning.config.block.state.lack_state", path.toString(), id.toString()); return null; } + // get its registry id int vanillaStateRegistryId; - try { - vanillaStateRegistryId = parseVanillaStateRegistryId(vanillaStateString); - } catch (BlockStateArrangeException e) { - this.plugin.logger().warn(path, "Failed to load " + id + " - " + e.getMessage(), e); + VanillaStateParseResult parseResult = parseVanillaStateRegistryId(vanillaStateString); + if (parseResult.success()) { + vanillaStateRegistryId = parseResult.result; + } else { + String[] args = new String[parseResult.args.length + 2]; + args[0] = path.toString(); + args[1] = id.toString(); + System.arraycopy(parseResult.args, 0, args, 2, parseResult.args.length); + TranslationManager.instance().log(parseResult.reason(), args); return null; } + + // check conflict Key ifAny = this.tempRegistryIdConflictMap.get(vanillaStateRegistryId); if (ifAny != null && !ifAny.equals(id)) { - this.plugin.logger().warn(path, "Can't use " + BlockStateUtils.idToBlockState(vanillaStateRegistryId) + " as the base block for " + id + " because the state has already been used by " + ifAny); + TranslationManager.instance().log("warning.config.block.state.conflict", path.toString(), id.toString(), BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(vanillaStateRegistryId)).getAsString(), ifAny.toString()); return null; } + + // require models not to be null Object models = section.getOrDefault("models", section.get("model")); + if (models == null) { + TranslationManager.instance().log("warning.config.block.state.no_model_set", path.toString(), id.toString()); + return null; + } + List variants = new ArrayList<>(); if (models instanceof Map singleModelSection) { loadVariantModel(variants, MiscUtils.castToMap(singleModelSection, false)); @@ -565,11 +545,9 @@ public class BukkitBlockManager extends AbstractBlockManager { loadVariantModel(variants, MiscUtils.castToMap(singleModelMap, false)); } } - } else { - this.plugin.logger().warn(path, "No model set for " + id); - return null; } if (variants.isEmpty()) return null; + this.tempRegistryIdConflictMap.put(vanillaStateRegistryId, id); String blockState = BlockStateUtils.idToBlockState(vanillaStateRegistryId).toString(); Key block = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}'))); @@ -604,46 +582,50 @@ public class BukkitBlockManager extends AbstractBlockManager { variants.add(json); } - private int parseVanillaStateRegistryId(String blockState) throws BlockStateArrangeException { + private VanillaStateParseResult parseVanillaStateRegistryId(String blockState) { String[] split = blockState.split(":", 3); - PreConditions.runIfTrue(split.length >= 4, () -> { - throw new BlockStateArrangeException("Invalid vanilla block state: " + blockState); - }); + if (split.length >= 4) { + return VanillaStateParseResult.failure("warning.config.block.state.invalid_state", new String[]{blockState}); + } int registryId; - // minecraft:xxx:0 - // xxx:0 String stateOrId = split[split.length - 1]; boolean isId = !stateOrId.contains("[") && !stateOrId.contains("]"); if (isId) { - if (split.length == 1) { - throw new BlockStateArrangeException("Invalid vanilla block state: " + blockState); - } + if (split.length == 1) return VanillaStateParseResult.failure("warning.config.block.state.invalid_state", new String[]{blockState}); Key block = split.length == 2 ? Key.of(split[0]) : Key.of(split[0], split[1]); try { int id = split.length == 2 ? Integer.parseInt(split[1]) : Integer.parseInt(split[2]); - PreConditions.runIfTrue(id < 0, () -> { - throw new BlockStateArrangeException("Invalid block state: " + blockState); - }); + if (id < 0) return VanillaStateParseResult.failure("warning.config.block.state.invalid_state", new String[]{blockState}); List arranger = this.blockAppearanceArranger.get(block); - if (arranger == null) { - throw new BlockStateArrangeException("No freed block state is available for block " + block); - } - if (id >= arranger.size()) { - throw new BlockStateArrangeException(blockState + " is not a valid block state because " + id + " is outside of the range (0~" + (arranger.size() - 1) + ")"); - } + if (arranger == null) return VanillaStateParseResult.failure("warning.config.block.state.unavailable_state", new String[]{blockState}); + if (id >= arranger.size()) return VanillaStateParseResult.failure("warning.config.block.state.invalid_vanilla_state_id", new String[]{blockState, String.valueOf(arranger.size() - 1)}); registryId = arranger.get(id); } catch (NumberFormatException e) { - throw new BlockStateArrangeException("Invalid block state: " + blockState); + return VanillaStateParseResult.failure("warning.config.block.state.invalid_state", new String[]{blockState}); } } else { try { BlockData blockData = Bukkit.createBlockData(blockState); registryId = BlockStateUtils.blockDataToId(blockData); + if (!this.blockAppearanceMapper.containsKey(registryId)) { + return VanillaStateParseResult.failure("warning.config.block.state.unavailable_state", new String[]{blockState}); + } } catch (IllegalArgumentException e) { - throw new BlockStateArrangeException("Invalid block state: " + blockState); + return VanillaStateParseResult.failure("warning.config.block.state.invalid_state", new String[]{blockState}); } } - return registryId; + return VanillaStateParseResult.success(registryId); + } + + public record VanillaStateParseResult(boolean success, int result, String reason, String[] args) { + + public static VanillaStateParseResult success(int result) { + return new VanillaStateParseResult(true, result, null, null); + } + + public static VanillaStateParseResult failure(String reason, String[] args) { + return new VanillaStateParseResult(false, -1, reason, args); + } } private void loadMappingsAndAdditionalBlocks() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java index 2f79abc20..451c60f5e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java @@ -48,7 +48,7 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior { if (this.defaultBlockState != null) { return this.defaultBlockState; } - Optional optionalCustomBlock = BukkitBlockManager.instance().getBlock(this.targetBlock); + Optional optionalCustomBlock = BukkitBlockManager.instance().blockById(this.targetBlock); if (optionalCustomBlock.isPresent()) { CustomBlock customBlock = optionalCustomBlock.get(); this.defaultBlockState = customBlock.defaultState().customBlockState().handle(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java index 01ee866e1..c19b855ed 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java @@ -60,7 +60,7 @@ public class AxeItemBehavior extends ItemBehavior { return InteractionResult.PASS; } - Optional optionalNewCustomBlock = BukkitBlockManager.instance().getBlock(blockBehavior.stripped()); + Optional optionalNewCustomBlock = BukkitBlockManager.instance().blockById(blockBehavior.stripped()); if (optionalNewCustomBlock.isEmpty()) { CraftEngine.instance().logger().warn("stripped block " + blockBehavior.stripped() + " does not exist"); return InteractionResult.FAIL; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index 40b96fe9d..563a4cfb7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -61,7 +61,7 @@ public class BlockItemBehavior extends ItemBehavior { if (!context.canPlace()) { return InteractionResult.FAIL; } - Optional optionalBlock = BukkitBlockManager.instance().getBlock(this.blockId); + Optional optionalBlock = BukkitBlockManager.instance().blockById(this.blockId); if (optionalBlock.isEmpty()) { CraftEngine.instance().logger().warn("Failed to place unknown block " + this.blockId); return InteractionResult.FAIL; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java index 52b298618..f50b12081 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java @@ -39,7 +39,7 @@ public class BlockStateUtils { } else { String blockTypeString = blockState.substring(0, index); Key block = Key.of(blockTypeString); - Optional optionalCustomBlock = BukkitBlockManager.instance().getBlock(block); + Optional optionalCustomBlock = BukkitBlockManager.instance().blockById(block); if (optionalCustomBlock.isPresent()) { ImmutableBlockState state = BlockStateParser.deserialize(blockState); if (state == null) { @@ -55,7 +55,7 @@ public class BlockStateUtils { } public static List getAllBlockStates(Key block) { - Optional optionalCustomBlock = BukkitBlockManager.instance().getBlock(block); + Optional optionalCustomBlock = BukkitBlockManager.instance().blockById(block); return optionalCustomBlock.map(customBlock -> customBlock.variantProvider().states().stream().map(it -> it.customBlockState().handle()).toList()) .orElseGet(() -> getAllVanillaBlockStates(block)); } @@ -80,7 +80,7 @@ public class BlockStateUtils { } public static BlockData fromBlockData(Object blockState) { - return (BlockData) FastNMS.INSTANCE.method$CraftBlockData$fromData(blockState); + return FastNMS.INSTANCE.method$CraftBlockData$fromData(blockState); } public static int blockDataToId(BlockData blockData) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index a1046b6e7..ba3e03d8f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -2,10 +2,62 @@ package net.momirealms.craftengine.core.block; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Key; +import org.incendo.cloud.suggestion.Suggestion; + +import java.util.*; public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager { + // CraftEngine objects + protected final Map byId = new HashMap<>(); + // Cached command suggestions + protected final List cachedSuggestions = new ArrayList<>(); + // Cached Namespace + protected final Set namespacesInUse = new HashSet<>(); public AbstractBlockManager(CraftEngine plugin) { super(plugin); } + + @Override + public Map blocks() { + return Collections.unmodifiableMap(this.byId); + } + + @Override + public Optional blockById(Key id) { + return Optional.ofNullable(this.byId.get(id)); + } + + @Override + public void unload() { + super.clearModelsToGenerate(); + this.cachedSuggestions.clear(); + this.byId.clear(); + } + + @Override + public Collection cachedSuggestions() { + return Collections.unmodifiableCollection(this.cachedSuggestions); + } + + public Set namespacesInUse() { + return Collections.unmodifiableSet(this.namespacesInUse); + } + + protected void initSuggestions() { + this.cachedSuggestions.clear(); + this.namespacesInUse.clear(); + Set states = new HashSet<>(); + for (CustomBlock block : this.byId.values()) { + states.add(block.id().toString()); + this.namespacesInUse.add(block.id().namespace()); + for (ImmutableBlockState state : block.variantProvider().states()) { + states.add(state.toString()); + } + } + for (String state : states) { + this.cachedSuggestions.add(Suggestion.suggestion(state)); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java index d21392cea..125f42018 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java @@ -24,7 +24,7 @@ public interface BlockManager extends Manageable, ModelGenerator { Map blocks(); - Optional getBlock(Key key); + Optional blockById(Key key); Collection cachedSuggestions(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java index ad31c10fb..ac84cf0d5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java @@ -36,7 +36,7 @@ public class Properties { public static Property fromMap(String name, Map map) { String type = (String) map.getOrDefault("type", "empty"); if (type == null) { - throw new NullPointerException("behavior type cannot be null"); + throw new NullPointerException("Property type cannot be null"); } Key key = Key.withDefaultNamespace(type, "craftengine"); PropertyFactory factory = BuiltInRegistries.PROPERTY_FACTORY.getValue(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 4c2a241a7..73a442ee8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -444,10 +444,8 @@ public abstract class AbstractPackManager implements PackManager { int hashIndex = key.indexOf('#'); String configType = hashIndex != -1 ? key.substring(0, hashIndex) : key; Optional.ofNullable(this.sectionParsers.get(configType)) - .ifPresent(parser -> { - this.cachedConfigs.computeIfAbsent(parser, k -> new ArrayList<>()) - .add(new CachedConfig(castToMap(typeSections0, false), path, pack)); - }); + .ifPresent(parser -> this.cachedConfigs.computeIfAbsent(parser, k -> new ArrayList<>()) + .add(new CachedConfig(castToMap(typeSections0, false), path, pack))); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java b/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java index 5885168b9..471e5ead5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/ResourceLocation.java @@ -19,7 +19,7 @@ public class ResourceLocation { return character == '_' || character == '-' || character >= 'a' && character <= 'z' || character >= '0' && character <= '9' || character == '.'; } - private static boolean isValidNamespace(String namespace) { + public static boolean isValidNamespace(String namespace) { for(int i = 0; i < namespace.length(); ++i) { if (!validNamespaceChar(namespace.charAt(i))) { return false; @@ -28,7 +28,7 @@ public class ResourceLocation { return true; } - private static boolean isValidPath(String path) { + public static boolean isValidPath(String path) { for(int i = 0; i < path.length(); ++i) { if (!validPathChar(path.charAt(i))) { return false; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java index e2702a7da..7184da0b1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java @@ -22,7 +22,7 @@ public class I18NData { return List.of("block." + stateToRealBlockId(parsed)); } else { Key blockId = Key.of(id); - Optional blockOptional = CraftEngine.instance().blockManager().getBlock(blockId); + Optional blockOptional = CraftEngine.instance().blockManager().blockById(blockId); if (blockOptional.isPresent()) { List states = blockOptional.get().variantProvider().states(); if (states.size() == 1) { From 73e43f4d161680e06e7cad3a4e8eb1e18e346f66 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 22:01:54 +0800 Subject: [PATCH 28/37] add warnings --- .../src/main/resources/translations/en.yml | 10 +++++--- .../bukkit/block/BukkitBlockManager.java | 25 +++++++++++++------ .../bukkit/item/BukkitItemManager.java | 4 +-- .../generation/AbstractModelGenerator.java | 19 +++++++++----- .../pack/model/generation/ModelGenerator.java | 2 -- 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 760faf424..92771ab58 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -63,7 +63,7 @@ warning.config.image.invalid_font_name: "Issue found in file - T warning.config.image.lack_char: "Issue found in file - The image '' is missing the required 'char' argument." warning.config.image.codepoint_in_use: "Issue found in file - The image '' is using a character[()] in font that has been used by another image ''." warning.config.image.invalid_codepoint_grid: "Issue found in file - Image '' has an invalid 'chars' codepoint grind." -warning.config.image.file_not_exist: "Issue found in file - PNG file not found for image ''." +warning.config.image.file_not_exist: "Issue found in file - PNG file '' not found for image ''." warning.config.recipe.duplicated: "Issue found in file - Duplicated recipe ''." warning.config.i18n.unknown_locale: "Issue found in file - Unknown locale ''." warning.config.template.duplicated: "Issue found in file - Duplicated template ''." @@ -93,8 +93,12 @@ warning.config.block.state.invalid_state: "Issue found in file - warning.config.block.state.unavailable_state: "Issue found in file - The block '' is using an unavailable vanilla block state ''." warning.config.block.state.invalid_vanilla_state_id: "Issue found in file - The block '' is using a vanilla block state '' that exceeds the available slot range '0~'." warning.config.block.state.conflict: "Issue found in file - The block '' is using a vanilla block state '' that has been occupied by ''." -warning.config.block.bind_real_state: "Issue found in file - The block '' failed to bind real block state for '' as the state has been occupied by ''." +warning.config.block.state.bind_real_state: "Issue found in file - The block '' failed to bind real block state for '' as the state has been occupied by ''." warning.config.block.state.invalid_property_structure: "Issue found in file - The block '' has an invalid property structure ''." warning.config.block.state.invalid_property: "Issue found in file - Failed to create property '' for block '': ." warning.config.block.state.no_model_set: "Issue found in file - The block '' is missing the required 'model' or 'models' argument." -warning.config.block.state.invalid_real_state_id: "Issue found in file - The block '' is using a real block state '' that exceeds the available slot range '0~'. Consider adding more real states in 'additional-real-blocks.yml' if the slots are used up." \ No newline at end of file +warning.config.block.state.invalid_real_state_id: "Issue found in file - The block '' is using a real block state '' that exceeds the available slot range '0~'. Consider adding more real states in 'additional-real-blocks.yml' if the slots are used up." +warning.config.block.state.model.lack_path: "Issue found in file - The block '' is missing the required 'path' option for 'model'." +warning.config.block.state.model.invalid_resource_location: "Issue found in file - The block '' has a 'path' argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" +warning.config.model.generation.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''" +warning.config.model.generation.texture.invalid_resource_location: "Issue found in file - The config '' has a '' texture argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index c62766b00..a326b0678 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -21,6 +21,7 @@ import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; @@ -367,7 +368,7 @@ public class BukkitBlockManager extends AbstractBlockManager { return; } - Pair pair = parseAppearanceSection(path, id, stateSection); + Pair pair = parseAppearanceSection(pack, path, id, stateSection); if (pair == null) return; appearances = Map.of("default", pair.right()); @@ -407,7 +408,7 @@ public class BukkitBlockManager extends AbstractBlockManager { Map tempTypeMap = new HashMap<>(); for (Map.Entry appearanceEntry : appearancesSection.entrySet()) { if (appearanceEntry.getValue() instanceof Map appearanceSection) { - Pair pair = parseAppearanceSection(path, id, MiscUtils.castToMap(appearanceSection, false)); + Pair pair = parseAppearanceSection(pack, path, id, MiscUtils.castToMap(appearanceSection, false)); if (pair == null) return; appearances.put(appearanceEntry.getKey(), pair.right()); tempTypeMap.put(appearanceEntry.getKey(), pair.left()); @@ -463,7 +464,7 @@ public class BukkitBlockManager extends AbstractBlockManager { for (ImmutableBlockState state : block.variantProvider().states()) { ImmutableBlockState previous = stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()]; if (previous != null && !previous.isEmpty()) { - TranslationManager.instance().log("warning.config.block.bind_real_state", path.toString(), id.toString(), state.toString(), previous.toString()); + TranslationManager.instance().log("warning.config.block.state.bind_real_state", path.toString(), id.toString(), state.toString(), previous.toString()); continue; } stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()] = state; @@ -500,7 +501,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } @Nullable - private Pair parseAppearanceSection(Path path, Key id, Map section) { + private Pair parseAppearanceSection(Pack pack, Path path, Key id, Map section) { // require state non null String vanillaStateString = (String) section.get("state"); if (vanillaStateString == null) { @@ -538,11 +539,11 @@ public class BukkitBlockManager extends AbstractBlockManager { List variants = new ArrayList<>(); if (models instanceof Map singleModelSection) { - loadVariantModel(variants, MiscUtils.castToMap(singleModelSection, false)); + loadVariantModel(pack, path, id, variants, MiscUtils.castToMap(singleModelSection, false)); } else if (models instanceof List modelList) { for (Object model : modelList) { if (model instanceof Map singleModelMap) { - loadVariantModel(variants, MiscUtils.castToMap(singleModelMap, false)); + loadVariantModel(pack, path, id, variants, MiscUtils.castToMap(singleModelMap, false)); } } } @@ -567,9 +568,17 @@ public class BukkitBlockManager extends AbstractBlockManager { return Pair.of(block, vanillaStateRegistryId); } - private void loadVariantModel(List variants, Map singleModelMap) { + private void loadVariantModel(Pack pack, Path path, Key id, List variants, Map singleModelMap) { JsonObject json = new JsonObject(); String modelPath = (String) singleModelMap.get("path"); + if (modelPath == null) { + TranslationManager.instance().log("warning.config.block.state.model.lack_path", path.toString(), id.toString()); + return; + } + if (!ResourceLocation.isValid(modelPath)) { + TranslationManager.instance().log("warning.config.block.state.model.invalid_resource_location", path.toString(), id.toString(), modelPath); + return; + } json.addProperty("model", modelPath); if (singleModelMap.containsKey("x")) json.addProperty("x", MiscUtils.getAsInt(singleModelMap.get("x"))); if (singleModelMap.containsKey("y")) json.addProperty("y", MiscUtils.getAsInt(singleModelMap.get("y"))); @@ -577,7 +586,7 @@ public class BukkitBlockManager extends AbstractBlockManager { if (singleModelMap.containsKey("weight")) json.addProperty("weight", MiscUtils.getAsInt(singleModelMap.get("weight"))); Map generationMap = MiscUtils.castToMap(singleModelMap.get("generation"), true); if (generationMap != null) { - prepareModelGeneration(new ModelGeneration(Key.of(modelPath), generationMap)); + prepareModelGeneration(path, id, new ModelGeneration(Key.of(modelPath), generationMap)); } variants.add(json); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index ee8bdb884..2e8905231 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -349,7 +349,7 @@ public class BukkitItemManager extends AbstractItemManager { // Parse models ItemModel model = ItemModels.fromMap(modelSection); for (ModelGeneration generation : model.modelsToGenerate()) { - prepareModelGeneration(generation); + prepareModelGeneration(path, id, generation); } if (Config.packMaxVersion() > 21.39f) { @@ -369,7 +369,7 @@ public class BukkitItemManager extends AbstractItemManager { // use components ItemModel model = ItemModels.fromMap(modelSection); for (ModelGeneration generation : model.modelsToGenerate()) { - prepareModelGeneration(generation); + prepareModelGeneration(path, id, generation); } if (Config.packMaxVersion() > 21.39f) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java index d4c5dd264..8a5a435f7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java @@ -1,8 +1,11 @@ package net.momirealms.craftengine.core.pack.model.generation; +import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.Key; +import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -25,16 +28,20 @@ public abstract class AbstractModelGenerator implements ModelGenerator { this.modelsToGenerate.clear(); } - @Override - public void prepareModelGeneration(ModelGeneration model) { - ModelGeneration generation = this.modelsToGenerate.get(model.path()); - if (generation != null) { - if (generation.equals(model)) { + public void prepareModelGeneration(Path path, Key id, ModelGeneration model) { + ModelGeneration conflict = this.modelsToGenerate.get(model.path()); + if (conflict != null) { + if (conflict.equals(model)) { return; } - this.plugin.logger().severe("Two or more configurations attempt to generate different json models with the same path: " + model.path()); + TranslationManager.instance().log("warning.config.model.generation.conflict", path.toString(), id.toString(), model.path().toString()); return; } + for (Map.Entry texture : model.texturesOverride().entrySet()) { + if (!ResourceLocation.isValid(texture.getValue())) { + TranslationManager.instance().log("warning.config.model.generation.texture.invalid_resource_location", path.toString(), id.toString(), texture.getKey(), texture.getValue()); + } + } this.modelsToGenerate.put(model.path(), model); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGenerator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGenerator.java index fd6383595..2b57fd304 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGenerator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGenerator.java @@ -6,6 +6,4 @@ public interface ModelGenerator { Collection modelsToGenerate(); void clearModelsToGenerate(); - - void prepareModelGeneration(ModelGeneration model); } From 77686ab323303cd5cc18e580d64a4b08b20351e4 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 22:04:40 +0800 Subject: [PATCH 29/37] move totem --- bukkit/loader/src/main/resources/commands.yml | 8 +++---- .../plugin/command/feature/TotemCommand.java | 2 +- .../craftengine/core/util/PreConditions.java | 22 ------------------- 3 files changed, 5 insertions(+), 27 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/PreConditions.java diff --git a/bukkit/loader/src/main/resources/commands.yml b/bukkit/loader/src/main/resources/commands.yml index 1e959b731..125d3e971 100644 --- a/bukkit/loader/src/main/resources/commands.yml +++ b/bukkit/loader/src/main/resources/commands.yml @@ -69,12 +69,12 @@ search_recipe_admin: - /craftengine item search-recipe - /ce item search-recipe -totem: +totem_animation: enable: true - permission: ce.command.admin.totem + permission: ce.command.admin.totem_animation usage: - - /craftengine totem - - /ce totem + - /craftengine feature totem-animation + - /ce feature totem-animation # Debug commands debug_set_block: diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java index 72e8a64db..ec6bcea28 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java @@ -68,6 +68,6 @@ public class TotemCommand extends BukkitCommandFeature { @Override public String getFeatureID() { - return "totem"; + return "totem_animation"; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/PreConditions.java b/core/src/main/java/net/momirealms/craftengine/core/util/PreConditions.java deleted file mode 100644 index 6ed7f921d..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/PreConditions.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.momirealms.craftengine.core.util; - -import org.jetbrains.annotations.NotNull; - -public class PreConditions { - - private PreConditions() {} - - public static boolean runIfTrue(boolean value, @NotNull Runnable runnable) { - if (value) { - runnable.run(); - } - return value; - } - - public static boolean isNull(Object value, @NotNull Runnable runnable) { - if (value == null) { - runnable.run(); - } - return value == null; - } -} From 995ab5cbbeae210a63bc180aa29a9a3e9668723a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 22:11:27 +0800 Subject: [PATCH 30/37] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=BE=E8=85=BE?= =?UTF-8?q?=E8=AF=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/translations/en.yml | 2 +- bukkit/loader/src/main/resources/translations/es.yml | 2 +- .../loader/src/main/resources/translations/zh_cn.yml | 2 +- .../loader/src/main/resources/translations/zh_tw.yml | 2 +- .../bukkit/plugin/command/BukkitCommandManager.java | 2 +- .../{TotemCommand.java => TotemAnimationCommand.java} | 11 +++-------- .../core/plugin/locale/MessageConstants.java | 2 +- gradle.properties | 2 +- 8 files changed, 10 insertions(+), 15 deletions(-) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/{TotemCommand.java => TotemAnimationCommand.java} (86%) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 92771ab58..a20e022d2 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -53,7 +53,7 @@ command.search_recipe.not_found: "No recipe found for this item" command.search_usage.not_found: "No usage found for this item" command.search_recipe.no_item: "Please hold an item before running this command" command.search_usage.no_item: "Please hold an item before running this command" -command.totem.not_totem: "'' is not type of totem_of_undying" +command.totem_animation.failure.not_totem: "Item '' is not minecraft:totem_of_undying" warning.config.image.duplicated: "Issue found in file - Duplicated image ''." warning.config.image.lack_height: "Issue found in file - The image '' is missing the required 'height' argument." warning.config.image.height_smaller_than_ascent: "Issue found in file - The image '' violates the bitmap image rule: 'height' should be no lower than 'ascent'." diff --git a/bukkit/loader/src/main/resources/translations/es.yml b/bukkit/loader/src/main/resources/translations/es.yml index f04f051a0..eda313eaf 100644 --- a/bukkit/loader/src/main/resources/translations/es.yml +++ b/bukkit/loader/src/main/resources/translations/es.yml @@ -53,4 +53,4 @@ command.search_recipe.not_found: "No se encontró ninguna receta para este command.search_usage.not_found: "No se encontró ningún uso para este objeto" command.search_recipe.no_item: "Por favor, sostén un objeto antes de ejecutar este comando" command.search_usage.no_item: "Por favor, sostén un objeto antes de ejecutar este comando" -command.totem.not_totem: "'' no es del tipo totem_of_undying" \ No newline at end of file +command.totem_animation.failure.not_totem: "'' no es del tipo totem_of_undying" \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 0cab6ac5d..815451987 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -53,7 +53,7 @@ command.search_recipe.not_found: "找不到此物品的配方" command.search_usage.not_found: "找不到此物品的用途" command.search_recipe.no_item: "请手持物品后再执行此命令" command.search_usage.no_item: "请手持物品后再执行此命令" -command.totem.not_totem: "'' 不是 totem_of_undying 类型" +command.totem_animation.failure.not_totem: "'' 不是 totem_of_undying 类型" warning.config.image.duplicated: "在文件 中发现问题 - 图片 '' 重复定义" warning.config.image.lack_height: "在文件 中发现问题 - 图片 '' 缺少必要的 'height' 高度参数" warning.config.image.height_smaller_than_ascent: "在文件 中发现问题 - 图片 '' 违反位图规则:'height' 高度值不应小于 'ascent' 基准线高度" diff --git a/bukkit/loader/src/main/resources/translations/zh_tw.yml b/bukkit/loader/src/main/resources/translations/zh_tw.yml index b0d1da410..dfff5088e 100644 --- a/bukkit/loader/src/main/resources/translations/zh_tw.yml +++ b/bukkit/loader/src/main/resources/translations/zh_tw.yml @@ -53,4 +53,4 @@ command.search_recipe.not_found: "找不到此物品的配方" command.search_usage.not_found: "找不到此物品的用途" command.search_recipe.no_item: "執行此命令前請手持物品" command.search_usage.no_item: "執行此命令前請手持物品" -command.totem.not_totem: "'' 不是 totem_of_undying 類型" \ No newline at end of file +command.totem_animation.failure.not_totem: "'' 不是 totem_of_undying 類型" \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java index f83af185c..515ac12ec 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java @@ -46,7 +46,7 @@ public class BukkitCommandManager extends AbstractCommandManager new DebugSetBlockCommand(this, plugin), new DebugSpawnFurnitureCommand(this, plugin), new DebugTargetBlockCommand(this, plugin), - new TotemCommand(this, plugin) + new TotemAnimationCommand(this, plugin) )); final LegacyPaperCommandManager manager = (LegacyPaperCommandManager) getCommandManager(); manager.settings().set(ManagerSetting.ALLOW_UNSAFE_REGISTRATION, true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java similarity index 86% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java index ec6bcea28..1f21b667e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java @@ -28,9 +28,9 @@ import org.incendo.cloud.suggestion.SuggestionProvider; import java.util.concurrent.CompletableFuture; -public class TotemCommand extends BukkitCommandFeature { +public class TotemAnimationCommand extends BukkitCommandFeature { - public TotemCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + public TotemAnimationCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { super(commandManager, plugin); } @@ -49,15 +49,10 @@ public class TotemCommand extends BukkitCommandFeature { NamespacedKey namespacedKey = context.get("id"); Key key = Key.of(namespacedKey.namespace(), namespacedKey.value()); CustomItem item = plugin().itemManager().getCustomItem(key).orElse(null); - if (item == null) { - handleFeedback(context, MessageConstants.COMMAND_ITEM_GET_FAILURE_NOT_EXIST, Component.text(key.toString())); - return; - } - if (MaterialUtils.getMaterial(item.material()) != Material.TOTEM_OF_UNDYING) { + if (item == null || MaterialUtils.getMaterial(item.material()) != Material.TOTEM_OF_UNDYING) { handleFeedback(context, MessageConstants.COMMAND_TOTEM_NOT_TOTEM, Component.text(key.toString())); return; } - ItemStack totem = item.buildItemStack(); MultiplePlayerSelector selector = context.get("players"); for (Player player : selector.values()) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java index bef7dd276..1151d1fe2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java @@ -20,5 +20,5 @@ public interface MessageConstants { TranslatableComponent.Builder COMMAND_SEARCH_RECIPE_NO_ITEM = Component.translatable().key("command.search_recipe.no_item"); TranslatableComponent.Builder COMMAND_SEARCH_USAGE_NOT_FOUND = Component.translatable().key("command.search_usage.not_found"); TranslatableComponent.Builder COMMAND_SEARCH_USAGE_NO_ITEM = Component.translatable().key("command.search_usage.no_item"); - TranslatableComponent.Builder COMMAND_TOTEM_NOT_TOTEM = Component.translatable().key("command.totem.not_totem"); + TranslatableComponent.Builder COMMAND_TOTEM_NOT_TOTEM = Component.translatable().key("command.totem_animation.failure.not_totem"); } diff --git a/gradle.properties b/gradle.properties index 065750cb4..6a652c28d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G # Rule: [major update].[feature update].[bug fix] project_version=0.0.43 config_version=19 -lang_version=3 +lang_version=4 project_group=net.momirealms latest_minecraft_version=1.21.4 From 419b19afb0d170f0a5ff78e782f2c86690496d36 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 23:07:40 +0800 Subject: [PATCH 31/37] Update zh_cn.yml --- .../src/main/resources/translations/zh_cn.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 815451987..6a8b20846 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -88,4 +88,17 @@ warning.config.block.state.lack_properties: "在文件 中发现 warning.config.block.state.lack_appearances: "在文件 中发现问题 - 方块 '' 的 'states' 配置缺少必要的 'appearances' 外观配置" warning.config.block.state.lack_variants: "在文件 中发现问题 - 方块 '' 的 'states' 配置缺少必要的 'variants' 变体配置" warning.config.block.state.variant.lack_appearance: "在文件 中发现问题 - 方块 '' 的 '' 变体配置缺少必要的 'appearance' 外观参数" -warning.config.block.state.variant.invalid_appearance: "在文件 中发现问题 - 方块 '' 的 '' 变体引用了不存在的外观配置 ''" \ No newline at end of file +warning.config.block.state.variant.invalid_appearance: "在文件 中发现问题 - 方块 '' 的 '' 变体引用了不存在的外观配置 ''" +warning.config.block.state.invalid_state: "在文件 中发现问题 - 方块 '' 使用了无效的原版方块状态 ''" +warning.config.block.state.unavailable_state: "在文件 中发现问题 - 方块 '' 使用了不可用的原版方块状态 ''" +warning.config.block.state.invalid_vanilla_state_id: "在文件 中发现问题 - 方块 '' 使用的原版方块状态 '' 超出可用槽位范围 '0~'" +warning.config.block.state.conflict: "在文件 中发现问题 - 方块 '' 使用的原版方块状态 '' 已被 '' 占用" +warning.config.block.state.bind_real_state: "在文件 中发现问题 - 方块 '' 未能绑定真实方块状态 '',该状态已被 '' 占用" +warning.config.block.state.invalid_property_structure: "在文件 中发现问题 - 方块 '' 的属性结构 '' 配置无效" +warning.config.block.state.invalid_property: "在文件 中发现问题 - 无法为方块 '' 创建属性 '':" +warning.config.block.state.no_model_set: "在文件 中发现问题 - 方块 '' 缺少必要的 'model' 或 'models' 模型参数" +warning.config.block.state.invalid_real_state_id: "在文件 中发现问题 - 方块 '' 使用的真实方块状态 '' 超出可用槽位范围 '0~'。若槽位已用尽,请考虑在 additional-real-blocks.yml 中添加更多真实状态" +warning.config.block.state.model.lack_path: "在文件 中发现问题 - 方块 '' 的 'model' 配置缺少必要的 'path' 路径参数" +warning.config.block.state.model.invalid_resource_location: "在文件 中发现问题 - 方块 '' 的 'path' 路径参数 [] 包含非法字符,请参考资源路径规范:https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" +warning.config.model.generation.conflict: "在文件 中发现问题 - 无法为 '' 生成模型,多个配置尝试用相同路径 '' 生成不同的JSON模型" +warning.config.model.generation.texture.invalid_resource_location: "在文件 中发现问题 - 配置项 '' 的 '' 纹理参数 [] 包含非法字符,请参考资源路径规范:https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" \ No newline at end of file From b91cb6b018df2a620c3153e5d17667d9520669a9 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 23:10:26 +0800 Subject: [PATCH 32/37] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/translations/en.yml | 3 ++- bukkit/loader/src/main/resources/translations/zh_cn.yml | 3 ++- .../core/pack/model/generation/AbstractModelGenerator.java | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index a20e022d2..d2c95dfb1 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -101,4 +101,5 @@ warning.config.block.state.invalid_real_state_id: "Issue found in file < warning.config.block.state.model.lack_path: "Issue found in file - The block '' is missing the required 'path' option for 'model'." warning.config.block.state.model.invalid_resource_location: "Issue found in file - The block '' has a 'path' argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" warning.config.model.generation.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''" -warning.config.model.generation.texture.invalid_resource_location: "Issue found in file - The config '' has a '' texture argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" \ No newline at end of file +warning.config.model.generation.texture.invalid_resource_location: "Issue found in file - The config '' has a '' texture argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" +warning.config.model.generation.parent.invalid_resource_location: "Issue found in file - The config '' has a parent argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 6a8b20846..822f32e54 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -101,4 +101,5 @@ warning.config.block.state.invalid_real_state_id: "在文件 中 warning.config.block.state.model.lack_path: "在文件 中发现问题 - 方块 '' 的 'model' 配置缺少必要的 'path' 路径参数" warning.config.block.state.model.invalid_resource_location: "在文件 中发现问题 - 方块 '' 的 'path' 路径参数 [] 包含非法字符,请参考资源路径规范:https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" warning.config.model.generation.conflict: "在文件 中发现问题 - 无法为 '' 生成模型,多个配置尝试用相同路径 '' 生成不同的JSON模型" -warning.config.model.generation.texture.invalid_resource_location: "在文件 中发现问题 - 配置项 '' 的 '' 纹理参数 [] 包含非法字符,请参考资源路径规范:https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" \ No newline at end of file +warning.config.model.generation.texture.invalid_resource_location: "在文件 中发现问题 - 配置项 '' 的 '' 纹理参数 [] 包含非法字符,请参考资源路径规范:https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" +warning.config.model.generation.parent.invalid_resource_location: "在文件 中发现问题 - 配置项 '' 的父模型参数 [] 包含非法字符,请参考资源路径规范:https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java index 8a5a435f7..db58ad265 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java @@ -37,6 +37,10 @@ public abstract class AbstractModelGenerator implements ModelGenerator { TranslationManager.instance().log("warning.config.model.generation.conflict", path.toString(), id.toString(), model.path().toString()); return; } + if (!ResourceLocation.isValid(model.parentModelPath())) { + TranslationManager.instance().log("warning.config.model.generation.parent.invalid_resource_location", path.toString(), id.toString(), model.parentModelPath()); + } + for (Map.Entry texture : model.texturesOverride().entrySet()) { if (!ResourceLocation.isValid(texture.getValue())) { TranslationManager.instance().log("warning.config.model.generation.texture.invalid_resource_location", path.toString(), id.toString(), texture.getKey(), texture.getValue()); From 7ad97e77c353367b555f428cc87f8a378b2fb824 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 23:52:52 +0800 Subject: [PATCH 33/37] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=A6=81=E7=94=A8?= =?UTF-8?q?=E5=8E=9F=E7=89=88=E9=85=8D=E6=96=B9=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 7 +++++++ .../item/recipe/BukkitRecipeManager.java | 18 ++++++++++++++++-- .../generation/AbstractModelGenerator.java | 1 - .../craftengine/core/plugin/config/Config.java | 15 +++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 5624e7bd8..9fededa9d 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -152,7 +152,14 @@ image: sign: true recipe: + # Enable the plugin's recipe system enable: true + # Disable vanilla recipes + disable-vanilla-recipes: + # Disable all vanilla recipes + all: false + # Disable the recipes in list + list: [] gui: browser: diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index a026bee0f..c047c60cd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -297,6 +297,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { @Override public void unload() { + if (!Config.enableRecipeSystem()) return; super.unload(); try { if (VersionHelper.isVersionNewerThan1_21_2()) { @@ -310,6 +311,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { @Override public void delayedLoad() { + if (!Config.enableRecipeSystem()) return; this.injectDataPackRecipes(); } @@ -368,12 +370,23 @@ public class BukkitRecipeManager extends AbstractRecipeManager { for (Object pack : selected) { packResources.add(Reflections.method$Pack$open.invoke(pack)); } + + boolean hasDisabledAny = !Config.disabledVanillaRecipes().isEmpty(); try (AutoCloseable resourceManager = (AutoCloseable) Reflections.constructor$MultiPackResourceManager.newInstance(Reflections.instance$PackType$SERVER_DATA, packResources)) { Map scannedResources = (Map) Reflections.method$FileToIdConverter$listMatchingResources.invoke(fileToIdConverter, resourceManager); for (Map.Entry entry : scannedResources.entrySet()) { Key id = extractKeyFromResourceLocation(entry.getKey().toString()); - // Maybe it's unregistered by other plugins - if (Bukkit.getRecipe(new NamespacedKey(id.namespace(), id.value())) == null) { + // now CraftEngine takes over everything +// // Maybe it's unregistered by other plugins +// if (Bukkit.getRecipe(new NamespacedKey(id.namespace(), id.value())) == null) { +// continue; +// } + if (Config.disableAllVanillaRecipes()) { + this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id)); + continue; + } + if (hasDisabledAny && Config.disabledVanillaRecipes().contains(id)) { + this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id)); continue; } markAsDataPackRecipe(id); @@ -423,6 +436,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { @Override public void runDelayedSyncTasks() { + if (!Config.enableRecipeSystem()) return; try { // run delayed tasks for (Runnable r : this.delayedTasksOnMainThread) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java index db58ad265..90ce13fca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/AbstractModelGenerator.java @@ -40,7 +40,6 @@ public abstract class AbstractModelGenerator implements ModelGenerator { if (!ResourceLocation.isValid(model.parentModelPath())) { TranslationManager.instance().log("warning.config.model.generation.parent.invalid_resource_location", path.toString(), id.toString(), model.parentModelPath()); } - for (Map.Entry texture : model.texturesOverride().entrySet()) { if (!ResourceLocation.isValid(texture.getValue())) { TranslationManager.instance().log("warning.config.model.generation.texture.invalid_resource_location", path.toString(), id.toString(), texture.getKey(), texture.getValue()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index e0bb910ba..41469ac5f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -17,6 +17,7 @@ import net.momirealms.craftengine.core.plugin.PluginProperties; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.plugin.logger.filter.DisconnectLogFilter; import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; @@ -30,6 +31,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; +import java.util.stream.Collectors; public class Config { private static Config instance; @@ -105,7 +107,10 @@ public class Config { protected boolean furniture$hide_base_entity; protected boolean block$sound_system$enable; + protected boolean recipe$enable; + protected boolean recipe$disable_vanilla_recipes$all; + protected Set recipe$disable_vanilla_recipes$list; protected boolean item$non_italic_tag; @@ -259,6 +264,8 @@ public class Config { // recipe recipe$enable = config.getBoolean("recipe.enable", true); + recipe$disable_vanilla_recipes$all = config.getBoolean("recipe.disable-vanilla-recipes.all", false); + recipe$disable_vanilla_recipes$list = config.getStringList("recipe.disable-vanilla-recipes.list").stream().map(Key::of).collect(Collectors.toSet()); // image image$illegal_characters_filter$anvil = config.getBoolean("image.illegal-characters-filter.anvil", true); @@ -350,6 +357,14 @@ public class Config { return instance.recipe$enable; } + public static boolean disableAllVanillaRecipes() { + return instance.recipe$disable_vanilla_recipes$all; + } + + public static Set disabledVanillaRecipes() { + return instance.recipe$disable_vanilla_recipes$list; + } + public static boolean nonItalic() { return instance.item$non_italic_tag; } From 92d208ac49230e2031c45d4cf2de3546a49c0fbf Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 5 Apr 2025 00:41:54 +0800 Subject: [PATCH 34/37] improve break speed --- .../bukkit/plugin/user/BukkitServerPlayer.java | 16 ++++++++++++++-- .../craftengine/core/block/BlockSettings.java | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index e362f2fc5..bb6dd519e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.plugin.user; import com.google.common.collect.Lists; import io.netty.channel.Channel; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -13,6 +14,7 @@ import net.momirealms.craftengine.core.block.PackedBlockState; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.util.Direction; @@ -437,16 +439,26 @@ public class BukkitServerPlayer extends Player { return; } } - this.miningProgress = (float) Reflections.method$BlockStateBase$getDestroyProgress.invoke(this.destroyedState, serverPlayer, Reflections.method$Entity$level.invoke(serverPlayer), blockPos) + miningProgress; + + float progressToAdd = (float) Reflections.method$BlockStateBase$getDestroyProgress.invoke(this.destroyedState, serverPlayer, Reflections.method$Entity$level.invoke(serverPlayer), blockPos); + int id = BlockStateUtils.blockStateToId(this.destroyedState); + ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(id); + if (customState != null && !customState.isEmpty() + && !customState.settings().isCorrectTool(item == null ? ItemKeys.AIR : item.id())) { + progressToAdd *= customState.settings().incorrectToolSpeed(); + } + + this.miningProgress = progressToAdd + miningProgress; int packetStage = (int) (this.miningProgress * 10.0F); if (packetStage != this.lastSentState) { this.lastSentState = packetStage; broadcastDestroyProgress(player, hitPos, blockPos, packetStage); } + if (this.miningProgress >= 1f) { //Reflections.method$ServerLevel$levelEvent.invoke(Reflections.field$CraftWorld$ServerLevel.get(player.getWorld()), null, 2001, blockPos, BlockStateUtils.blockStateToId(this.destroyedState)); Reflections.method$ServerPlayerGameMode$destroyBlock.invoke(gameMode, blockPos); - Object levelEventPacket = Reflections.constructor$ClientboundLevelEventPacket.newInstance(2001, blockPos, BlockStateUtils.blockStateToId(this.destroyedState), false); + Object levelEventPacket = Reflections.constructor$ClientboundLevelEventPacket.newInstance(2001, blockPos, id, false); sendPacket(levelEventPacket, false); this.stopMiningBlock(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java index a75d84b1b..75711f4e9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java @@ -28,6 +28,7 @@ public class BlockSettings { @Nullable Key itemId; Set tags = Set.of(); + float incorrectToolSpeed = 0.3f; Set correctTools = Set.of(); String name; @@ -81,6 +82,7 @@ public class BlockSettings { newSettings.fluidState = settings.fluidState; newSettings.blockLight = settings.blockLight; newSettings.name = settings.name; + newSettings.incorrectToolSpeed = settings.incorrectToolSpeed; return newSettings; } @@ -124,6 +126,10 @@ public class BlockSettings { return canOcclude; } + public float incorrectToolSpeed() { + return incorrectToolSpeed; + } + public String name() { return name; } @@ -243,6 +249,11 @@ public class BlockSettings { return this; } + public BlockSettings incorrectToolSpeed(float incorrectToolSpeed) { + this.incorrectToolSpeed = incorrectToolSpeed; + return this; + } + public BlockSettings isRandomlyTicking(boolean isRandomlyTicking) { this.isRandomlyTicking = isRandomlyTicking; return this; @@ -381,6 +392,10 @@ public class BlockSettings { List tools = MiscUtils.getAsStringList(value); return settings -> settings.correctTools(tools.stream().map(Key::of).collect(Collectors.toSet())); })); + registerFactory("incorrect-tool-dig-speed", (value -> { + float floatValue = MiscUtils.getAsFloat(value); + return settings -> settings.incorrectToolSpeed(floatValue); + })); registerFactory("name", (value -> { String name = value.toString(); return settings -> settings.name(name); From 14d958eee91b55d7834a5ca9e738d34a2f11feba Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 5 Apr 2025 01:21:18 +0800 Subject: [PATCH 35/37] =?UTF-8?q?refactor(network):=20=E4=BD=BF=E7=94=A81.?= =?UTF-8?q?21+=E7=9A=84=E5=86=85=E7=BD=AE=E6=96=B9=E6=B3=95=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=8E=B7=E5=8F=96=E5=8C=85id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 6 ++-- ...acketIds1_21_5.java => PacketIds1_21.java} | 12 +++---- .../plugin/network/impl/PacketIds1_21_2.java | 1 + .../plugin/network/impl/PacketIdsFind.java | 33 +++++++++++++++++++ .../craftengine/bukkit/util/Reflections.java | 17 ++++++++++ 5 files changed, 59 insertions(+), 10 deletions(-) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/{PacketIds1_21_5.java => PacketIds1_21.java} (52%) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIdsFind.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index db3caf172..e12f30a0a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -116,10 +116,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } private PacketIds setupPacketIds() { - if (VersionHelper.isVersionNewerThan1_21_5()) { - return new PacketIds1_21_5(); - } else if (VersionHelper.isVersionNewerThan1_21_2()) { - return new PacketIds1_21_2(); + if (VersionHelper.isVersionNewerThan1_21()) { + return new PacketIds1_21(); } else if (VersionHelper.isVersionNewerThan1_20_5()) { return new PacketIds1_20_5(); } else if (VersionHelper.isVersionNewerThan1_20_3()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21.java similarity index 52% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_5.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21.java index f54faf5cb..ad45cec30 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21.java @@ -2,30 +2,30 @@ package net.momirealms.craftengine.bukkit.plugin.network.impl; import net.momirealms.craftengine.bukkit.plugin.network.PacketIds; -public class PacketIds1_21_5 implements PacketIds { +public class PacketIds1_21 implements PacketIds { @Override public int clientboundBlockUpdatePacket() { - return 8; + return PacketIdsFind.getClientboundPackets("minecraft:block_update"); } @Override public int clientboundSectionBlocksUpdatePacket() { - return 72; + return PacketIdsFind.getClientboundPackets("minecraft:section_blocks_update"); } @Override public int clientboundLevelParticlesPacket() { - return 40; + return PacketIdsFind.getClientboundPackets("minecraft:level_particles"); } @Override public int clientboundLevelEventPacket() { - return 39; + return PacketIdsFind.getClientboundPackets("minecraft:level_event"); } @Override public int clientboundAddEntityPacket() { - return 1; + return PacketIdsFind.getClientboundPackets("minecraft:add_entity"); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_2.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_2.java index 0d387b007..8e86b6914 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_2.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_2.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.network.impl; import net.momirealms.craftengine.bukkit.plugin.network.PacketIds; +@Deprecated public class PacketIds1_21_2 implements PacketIds { @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIdsFind.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIdsFind.java new file mode 100644 index 000000000..fbd54f56f --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIdsFind.java @@ -0,0 +1,33 @@ +package net.momirealms.craftengine.bukkit.plugin.network.impl; + +import com.google.gson.JsonElement; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.plugin.CraftEngine; + +import java.util.HashMap; +import java.util.Map; + +public class PacketIdsFind { + private static final Map> gamePacketIds = new HashMap<>(); + + static { + try { + Object packetReport = Reflections.constructor$PacketReport.newInstance((Object) null); + JsonElement jsonElement = (JsonElement) Reflections.method$PacketReport$serializePackets.invoke(packetReport); + var play = jsonElement.getAsJsonObject().get("play"); + for (var entry : play.getAsJsonObject().entrySet()) { + Map ids = new HashMap<>(); + gamePacketIds.put(entry.getKey(), ids); + for (var entry2 : entry.getValue().getAsJsonObject().entrySet()) { + ids.put(entry2.getKey(), entry2.getValue().getAsJsonObject().get("protocol_id").getAsInt()); + } + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to get packets", e); + } + } + + public static int getClientboundPackets(String packetName) { + return gamePacketIds.get("clientbound").get(packetName); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 04f752199..ae1dc204a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.util; import com.google.common.collect.ImmutableList; +import com.google.gson.JsonElement; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -6123,4 +6124,20 @@ public class Reflections { clazz$EntityLookup, clazz$Entity, int.class ) ); + + // 1.21+ + public static final Class clazz$PacketReport = + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("data.info.PacketReport") + ); + + // 1.21+ + public static final Constructor constructor$PacketReport = Optional.ofNullable(clazz$PacketReport) + .map(it -> ReflectionUtils.getConstructor(it, 0)) + .orElse(null); + + // 1.21+ + public static final Method method$PacketReport$serializePackets = Optional.ofNullable(clazz$PacketReport) + .map(it -> ReflectionUtils.getDeclaredMethod(it, JsonElement.class)) + .orElse(null); } From b8081176d0afdf58e8e7c435343466157649e332 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 5 Apr 2025 02:45:21 +0800 Subject: [PATCH 36/37] fix 1.21.5 --- .../craftengine/core/util/FriendlyByteBuf.java | 14 ++++++++++++++ .../core/world/chunk/PalettedContainer.java | 13 ++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java b/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java index 7b298a6cd..e9b1c7de8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java @@ -217,6 +217,20 @@ public class FriendlyByteBuf extends ByteBuf { return this; } + public FriendlyByteBuf writeFixedSizeLongArray(long[] array) { + for (long value : array) { + this.writeLong(value); + } + return this; + } + + public long[] readFixedSizeLongArray(long[] output) { + for(int i = 0; i < output.length; ++i) { + output[i] = this.readLong(); + } + return output; + } + public long[] readLongArray() { return this.readLongArray(null); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java index bc41daeec..da44b67e9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.IndexedIterable; import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.VersionHelper; import org.jetbrains.annotations.Nullable; import java.util.Arrays; @@ -15,12 +16,14 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; -import java.util.function.IntUnaryOperator; -import java.util.function.Predicate; +import java.util.function.*; import java.util.stream.LongStream; public class PalettedContainer implements PaletteResizeListener, ReadableContainer { + private static final BiConsumer RAW_DATA_WRITER = VersionHelper.isVersionNewerThan1_21_5() ? + (FriendlyByteBuf::writeFixedSizeLongArray) : (FriendlyByteBuf::writeLongArray); + private static final BiConsumer RAW_DATA_READER = VersionHelper.isVersionNewerThan1_21_5() ? + (FriendlyByteBuf::readFixedSizeLongArray) : (FriendlyByteBuf::readLongArray); private final PaletteResizeListener dummyListener = (newSize, added) -> 0; private final IndexedIterable idList; private Data data; @@ -78,7 +81,7 @@ public class PalettedContainer implements PaletteResizeListener, ReadableC int i = buf.readByte(); Data data = this.getCompatibleData(this.data, i); data.palette.readPacket(buf); - buf.readLongArray(data.storage.getData()); + RAW_DATA_READER.accept(buf, data.storage.getData()); this.data = data; } finally { this.unlock(); @@ -303,7 +306,7 @@ public class PalettedContainer implements PaletteResizeListener, ReadableC public void writePacket(FriendlyByteBuf buf) { buf.writeByte(this.storage.getElementBits()); this.palette.writePacket(buf); - buf.writeLongArray(this.storage.getData()); + RAW_DATA_WRITER.accept(buf, this.storage.getData()); } } From 97c6682249fc98040ecc2dfc2979561949f30ea8 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 5 Apr 2025 02:53:05 +0800 Subject: [PATCH 37/37] rename methods --- .../impl/{PacketIdsFind.java => PacketIdFinder.java} | 4 ++-- .../bukkit/plugin/network/impl/PacketIds1_21.java | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/{PacketIdsFind.java => PacketIdFinder.java} (93%) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIdsFind.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIdFinder.java similarity index 93% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIdsFind.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIdFinder.java index fbd54f56f..d7db35e57 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIdsFind.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIdFinder.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import java.util.HashMap; import java.util.Map; -public class PacketIdsFind { +public class PacketIdFinder { private static final Map> gamePacketIds = new HashMap<>(); static { @@ -27,7 +27,7 @@ public class PacketIdsFind { } } - public static int getClientboundPackets(String packetName) { + public static int clientboundByName(String packetName) { return gamePacketIds.get("clientbound").get(packetName); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21.java index ad45cec30..7bce73690 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21.java @@ -6,26 +6,26 @@ public class PacketIds1_21 implements PacketIds { @Override public int clientboundBlockUpdatePacket() { - return PacketIdsFind.getClientboundPackets("minecraft:block_update"); + return PacketIdFinder.clientboundByName("minecraft:block_update"); } @Override public int clientboundSectionBlocksUpdatePacket() { - return PacketIdsFind.getClientboundPackets("minecraft:section_blocks_update"); + return PacketIdFinder.clientboundByName("minecraft:section_blocks_update"); } @Override public int clientboundLevelParticlesPacket() { - return PacketIdsFind.getClientboundPackets("minecraft:level_particles"); + return PacketIdFinder.clientboundByName("minecraft:level_particles"); } @Override public int clientboundLevelEventPacket() { - return PacketIdsFind.getClientboundPackets("minecraft:level_event"); + return PacketIdFinder.clientboundByName("minecraft:level_event"); } @Override public int clientboundAddEntityPacket() { - return PacketIdsFind.getClientboundPackets("minecraft:add_entity"); + return PacketIdFinder.clientboundByName("minecraft:add_entity"); } }