From 7616520cbd7c39956cb85d9b6be83fc0e33c875c Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 17 May 2025 19:32:50 +0800 Subject: [PATCH 01/89] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 499c2cd36..1a37ebf3d 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 @@ -334,7 +334,7 @@ public class BukkitCraftEngine extends CraftEngine { if (this.antiGrief == null) { this.antiGrief = AntiGriefLib.builder(this.bootstrap) .ignoreOP(true) - .silentLogs(true) + .silentLogs(false) .build(); } return this.antiGrief; diff --git a/gradle.properties b/gradle.properties index d97675755..d7a88e90f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ mojang_brigadier_version=1.0.18 byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 -anti_grief_version=0.15 +anti_grief_version=0.16 nms_helper_version=0.65.24 evalex_version=3.5.0 reactive_streams_version=1.0.4 From ee10b560902c69ff4db5603f4f3f9d1a94a7e7fc Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 17 May 2025 21:07:48 +0800 Subject: [PATCH 02/89] =?UTF-8?q?=E5=B0=8F=E5=B9=85=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=8A=A0=E8=BD=BD=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 4 +- .../bukkit/plugin/BukkitCraftEngine.java | 3 +- .../core/font/AbstractFontManager.java | 24 +++++--- .../core/pack/AbstractPackManager.java | 61 ++++++++++--------- .../conflict/matcher/PathMatcherContains.java | 3 +- .../conflict/matcher/PathMatcherExact.java | 3 +- .../matcher/PathMatcherParentPrefix.java | 3 +- .../matcher/PathMatcherParentSuffix.java | 3 +- .../conflict/matcher/PathPatternMatcher.java | 4 +- .../craftengine/core/util/CharacterUtils.java | 34 +++++++++++ .../craftengine/core/util/FileUtils.java | 59 ++++-------------- .../momirealms/craftengine/core/util/Key.java | 10 +-- gradle.properties | 2 +- 13 files changed, 117 insertions(+), 96 deletions(-) diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index e42bbb4be..22eebce60 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -85,8 +85,8 @@ resource-pack: deny-non-minecraft-request: true one-time-token: true rate-limit: - max-requests: 3 - reset-interval: 20 + max-requests: 10 + reset-interval: 30 # Upload the resource pack automatically on generation # When disabled, you must manually trigger uploads using the /ce upload command auto-upload: true 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 1a37ebf3d..6d5f8f262 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 @@ -37,6 +37,7 @@ import net.momirealms.craftengine.core.plugin.gui.category.ItemBrowserManagerImp import net.momirealms.craftengine.core.plugin.logger.JavaPluginLogger; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; +import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bstats.bukkit.Metrics; @@ -205,7 +206,7 @@ public class BukkitCraftEngine extends CraftEngine { @Override public InputStream resourceStream(String filePath) { - return bootstrap.getResource(filePath.replace("\\", "/")); + return bootstrap.getResource(CharacterUtils.replaceBackslashWithSlash(filePath)); } @Override 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 6cd120eb1..495890b3f 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 @@ -47,6 +47,7 @@ public abstract class AbstractFontManager implements FontManager { protected List emojiList; protected List allEmojiSuggestions; + protected Set existingImagePaths = new HashSet<>(); public AbstractFontManager(CraftEngine plugin) { this.plugin = plugin; @@ -67,6 +68,7 @@ public abstract class AbstractFontManager implements FontManager { this.images.clear(); this.illegalChars.clear(); this.emojis.clear(); + this.existingImagePaths.clear(); } @Override @@ -424,12 +426,12 @@ public abstract class AbstractFontManager implements FontManager { throw new LocalizedResourceConfigException("warning.config.image.missing_file", path, id); } - String resourceLocation = file.toString().replace("\\", "/"); + String resourceLocation = CharacterUtils.replaceBackslashWithSlash(file.toString()); if (!ResourceLocation.isValid(resourceLocation)) { throw new LocalizedResourceConfigException("warning.config.image.invalid_file_chars", path, id, resourceLocation); } - String fontName = (String) section.getOrDefault("font", "minecraft:default"); + String fontName = section.getOrDefault("font", "minecraft:default").toString(); if (!ResourceLocation.isValid(fontName)) { throw new LocalizedResourceConfigException("warning.config.image.invalid_font_chars", path, id, fontName); } @@ -437,10 +439,7 @@ public abstract class AbstractFontManager implements FontManager { Key fontKey = Key.withDefaultNamespace(fontName, id.namespace()); Font font = getOrCreateFont(fontKey); List chars; - Object charsObj = section.get("chars"); - if (charsObj == null) { - charsObj = section.get("char"); - } + Object charsObj = ResourceConfigUtils.get(section, "chars", "char"); if (charsObj == null) { throw new LocalizedResourceConfigException("warning.config.image.missing_char", path, id); } @@ -516,7 +515,7 @@ public abstract class AbstractFontManager implements FontManager { .resolve("textures") .resolve(namespacedPath.value()); - if (!Files.exists(targetImagePath)) { + if (!doesImageFileExist(targetImagePath)) { TranslationManager.instance().log("warning.config.image.file_not_found", path.toString(), id.toString(), targetImagePath.toString()); // DO NOT RETURN, JUST GIVE WARNINGS } else if (heightObj == null) { @@ -548,5 +547,16 @@ public abstract class AbstractFontManager implements FontManager { images.put(id, bitmapImage); } + + private boolean doesImageFileExist(Path path) { + if (existingImagePaths.contains(path)) { + return true; + } + boolean exist = Files.exists(path); + if (exist) { + existingImagePaths.add(path); + } + return exist; + } } } 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 caf68d43b..473f1086f 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 @@ -5,6 +5,7 @@ import com.google.common.jimfs.Jimfs; import com.google.gson.*; import dev.dejvokep.boostedyaml.YamlDocument; import dev.dejvokep.boostedyaml.block.implementation.Section; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.momirealms.craftengine.core.font.BitmapImage; import net.momirealms.craftengine.core.font.Font; import net.momirealms.craftengine.core.item.EquipmentData; @@ -421,31 +422,35 @@ public abstract class AbstractPackManager implements PackManager { private void updateCachedConfigFiles() { Map previousFiles = this.cachedConfigFiles; - this.cachedConfigFiles = new HashMap<>(); + this.cachedConfigFiles = new Object2ObjectOpenHashMap<>(32); + Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); for (Pack pack : loadedPacks()) { if (!pack.enabled()) continue; - List files = FileUtils.getYmlConfigsDeeply(pack.configurationFolder()); - for (Path path : files) { - CachedConfigFile cachedFile = previousFiles.get(path); - try { - long lastModifiedTime = Files.getLastModifiedTime(path).toMillis(); - long size = Files.size(path); - if (cachedFile != null && cachedFile.lastModified() == lastModifiedTime && cachedFile.size() == size) { - this.cachedConfigFiles.put(path, cachedFile); - continue; + try { + Files.walkFileTree(pack.configurationFolder(), new SimpleFileVisitor<>() { + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path path, @NotNull BasicFileAttributes attrs) { + if (Files.isRegularFile(path) && path.getFileName().toString().endsWith(".yml")) { + CachedConfigFile cachedFile = previousFiles.get(path); + long lastModifiedTime = attrs.lastModifiedTime().toMillis(); + long size = attrs.size(); + if (cachedFile != null && cachedFile.lastModified() == lastModifiedTime && cachedFile.size() == size) { + AbstractPackManager.this.cachedConfigFiles.put(path, cachedFile); + return FileVisitResult.CONTINUE; + } + try (InputStreamReader inputStream = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { + Map data = yaml.load(inputStream); + if (data == null) return FileVisitResult.CONTINUE; + AbstractPackManager.this.cachedConfigFiles.put(path, new CachedConfigFile(data, pack, lastModifiedTime, size)); + } catch (IOException e) { + AbstractPackManager.this.plugin.logger().severe("Error while reading config file: " + path, e); + } + } + return FileVisitResult.CONTINUE; } - try (InputStreamReader inputStream = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { - Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); - Map data = yaml.load(inputStream); - if (data == null) continue; - - this.cachedConfigFiles.put(path, new CachedConfigFile(data, pack, lastModifiedTime, size)); - } catch (Exception e) { - this.plugin.logger().warn(path, "Error loading config file", e); - } - } catch (IOException e) { - this.plugin.logger().warn(path, "Error reading last modified time", e); - } + }); + } catch (IOException e) { + this.plugin.logger().severe("Error while reading config file", e); } } } @@ -546,9 +551,9 @@ public abstract class AbstractPackManager implements PackManager { private List>> updateCachedAssets(@Nullable FileSystem fs) throws IOException { List folders = new ArrayList<>(); - Map> conflictChecker = new HashMap<>(Math.max(128, this.cachedAssetFiles.size())); + Map> conflictChecker = new Object2ObjectOpenHashMap<>(Math.max(128, this.cachedAssetFiles.size())); Map previousFiles = this.cachedAssetFiles; - this.cachedAssetFiles = new HashMap<>(Math.max(128, this.cachedAssetFiles.size())); + this.cachedAssetFiles = new Object2ObjectOpenHashMap<>(Math.max(128, this.cachedAssetFiles.size())); folders.addAll(loadedPacks().stream().filter(Pack::enabled).map(Pack::resourcePackFolder).toList()); folders.addAll(Config.foldersToMerge().stream().map(it -> plugin.dataFolderPath().getParent().resolve(it)).filter(Files::exists).toList()); for (Path sourceFolder : folders) { @@ -557,8 +562,8 @@ public abstract class AbstractPackManager implements PackManager { @Override public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { CachedAssetFile cachedAsset = previousFiles.get(file); - long lastModified = Files.getLastModifiedTime(file).toMillis(); - long size = Files.size(file); + long lastModified = attrs.lastModifiedTime().toMillis(); + long size = attrs.size(); if (cachedAsset != null && cachedAsset.lastModified() == lastModified && cachedAsset.size() == size) { AbstractPackManager.this.cachedAssetFiles.put(file, cachedAsset); } else { @@ -567,7 +572,7 @@ public abstract class AbstractPackManager implements PackManager { } if (fs == null) return FileVisitResult.CONTINUE; Path relative = sourceFolder.relativize(file); - Path targetPath = fs.getPath("resource_pack/" + relative.toString().replace("\\", "/")); + Path targetPath = fs.getPath("resource_pack/" + CharacterUtils.replaceBackslashWithSlash(relative.toString())); List conflicts = conflictChecker.get(relative); if (conflicts == null) { Files.createDirectories(targetPath.getParent()); @@ -1224,7 +1229,7 @@ public abstract class AbstractPackManager implements PackManager { } try { - Files.writeString(fontPath, fontJson.toString().replace("\\\\u", "\\u")); + Files.writeString(fontPath, CharacterUtils.replaceDoubleBackslashU(fontJson.toString())); } catch (IOException e) { this.plugin.logger().severe("Error writing font to " + fontPath.toAbsolutePath(), e); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherContains.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherContains.java index 3c17607ca..6c9cb8076 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherContains.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherContains.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -18,7 +19,7 @@ public class PathMatcherContains implements Condition { @Override public boolean test(PathContext path) { - String pathStr = path.path().toString().replace("\\", "/"); + String pathStr = CharacterUtils.replaceBackslashWithSlash(path.path().toString()); return pathStr.contains(this.path); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherExact.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherExact.java index bebd9c61a..b2f1e800f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherExact.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherExact.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -18,7 +19,7 @@ public class PathMatcherExact implements Condition { @Override public boolean test(PathContext path) { - String pathStr = path.path().toString().replace("\\", "/"); + String pathStr = CharacterUtils.replaceBackslashWithSlash(path.path().toString()); return pathStr.equals(this.path); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentPrefix.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentPrefix.java index 212ff4c39..940e8cbe3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentPrefix.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentPrefix.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -21,7 +22,7 @@ public class PathMatcherParentPrefix implements Condition { public boolean test(PathContext path) { Path parent = path.path().getParent(); if (parent == null) return false; - String pathStr = parent.toString().replace("\\", "/"); + String pathStr = CharacterUtils.replaceBackslashWithSlash(parent.toString()); return pathStr.startsWith(this.prefix); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentSuffix.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentSuffix.java index 77c061228..8110dbcf0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentSuffix.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatcherParentSuffix.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -21,7 +22,7 @@ public class PathMatcherParentSuffix implements Condition { public boolean test(PathContext path) { Path parent = path.path().getParent(); if (parent == null) return false; - String pathStr = parent.toString().replace("\\", "/"); + String pathStr = CharacterUtils.replaceBackslashWithSlash(parent.toString()); return pathStr.endsWith(suffix); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java index 6826a42aa..43c24a864 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java @@ -2,8 +2,10 @@ package net.momirealms.craftengine.core.pack.conflict.matcher; import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.ContextKey; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -23,7 +25,7 @@ public class PathPatternMatcher implements Condition { @Override public boolean test(PathContext path) { - String pathStr = path.path().toString().replace("\\", "/"); + String pathStr = CharacterUtils.replaceBackslashWithSlash(path.path().toString()); return this.pattern.matcher(pathStr).matches(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java index 7e5e154da..208625927 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java @@ -97,4 +97,38 @@ public class CharacterUtils { } return false; } + + public static String replaceBackslashWithSlash(String input) { + if (input == null || input.isEmpty()) { + return input; + } + StringBuilder sb = new StringBuilder(input.length()); + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + sb.append(c == '\\' ? '/' : c); + } + return sb.toString(); + } + + public static String replaceDoubleBackslashU(String input) { + if (input == null || input.isEmpty()) { + return input; + } + int length = input.length(); + StringBuilder sb = new StringBuilder(length); + int i = 0; + while (i < length) { + if (i + 2 < length + && input.charAt(i) == '\\' + && input.charAt(i + 1) == '\\' + && input.charAt(i + 2) == 'u') { + sb.append("\\u"); + i += 3; + } else { + sb.append(input.charAt(i)); + i++; + } + } + return sb.toString(); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java index a4aec22f6..208adef5e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java @@ -8,6 +8,8 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class FileUtils { @@ -23,55 +25,16 @@ public class FileUtils { } public static List getYmlConfigsDeeply(Path configFolder) { - if (!Files.exists(configFolder)) return List.of(); - List validYaml = new ArrayList<>(); - Deque pathDeque = new ArrayDeque<>(); - pathDeque.push(configFolder); - while (!pathDeque.isEmpty()) { - Path path = pathDeque.pop(); - try (DirectoryStream stream = Files.newDirectoryStream(path)) { - for (Path subPath : stream) { - if (Files.isDirectory(subPath)) { - pathDeque.push(subPath); - } else if (Files.isRegularFile(subPath)) { - String pathString = subPath.toString(); - if (pathString.endsWith(".yml")) { - validYaml.add(subPath); - } - } - } - } catch (IOException e) { - throw new RuntimeException(e); - } + if (!Files.exists(configFolder)) { + return List.of(); } - return validYaml; - } - - public static Pair, List> getConfigsDeeply(Path configFolder) { - if (!Files.exists(configFolder)) return Pair.of(List.of(), List.of()); - List validYaml = new ArrayList<>(); - List validJson = new ArrayList<>(); - Deque pathDeque = new ArrayDeque<>(); - pathDeque.push(configFolder); - while (!pathDeque.isEmpty()) { - Path path = pathDeque.pop(); - try (DirectoryStream stream = Files.newDirectoryStream(path)) { - for (Path subPath : stream) { - if (Files.isDirectory(subPath)) { - pathDeque.push(subPath); - } else if (Files.isRegularFile(subPath)) { - String pathString = subPath.toString(); - if (pathString.endsWith(".yml")) { - validYaml.add(subPath); - } else if (pathString.endsWith(".json")) { - validJson.add(subPath); - } - } - } - } catch (IOException e) { - throw new RuntimeException(e); - } + try (Stream stream = Files.walk(configFolder)) { + return stream.parallel() + .filter(Files::isRegularFile) + .filter(path -> path.toString().endsWith(".yml")) + .toList(); + } catch (IOException e) { + throw new RuntimeException("Failed to traverse directory: " + configFolder, e); } - return Pair.of(validYaml, validJson); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Key.java b/core/src/main/java/net/momirealms/craftengine/core/util/Key.java index 994cf4b6c..6ec44fbc6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Key.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Key.java @@ -34,12 +34,14 @@ public record Key(String namespace, String value) { } public String[] decompose() { - return new String[] { namespace, value }; + return new String[] { this.namespace, this.value }; } @Override public int hashCode() { - return toString().hashCode(); + int result = this.namespace.hashCode(); + result = 31 * result + this.value.hashCode(); + return result; } @Override @@ -54,11 +56,11 @@ public record Key(String namespace, String value) { @Override public @NotNull String toString() { - return namespace + ":" + value; + return this.namespace + ":" + this.value; } public String asString() { - return namespace + ":" + value; + return this.namespace + ":" + this.value; } private static String[] decompose(String id, String namespace) { diff --git a/gradle.properties b/gradle.properties index d7a88e90f..e2b6917ae 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ mojang_brigadier_version=1.0.18 byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 -anti_grief_version=0.16 +anti_grief_version=0.17 nms_helper_version=0.65.24 evalex_version=3.5.0 reactive_streams_version=1.0.4 From df86e822dbededc648e5c6c44a4c6ec1898f6cc5 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 18 May 2025 00:18:22 +0800 Subject: [PATCH 03/89] =?UTF-8?q?feat(bukkit):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=99=90=E5=88=B6=E5=8F=AF=E8=A7=86=E5=AE=B6=E5=85=B7=E6=95=B0?= =?UTF-8?q?=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/feature/TestCommand.java | 32 ++-- .../plugin/network/PacketConsumers.java | 27 ++- .../plugin/user/BukkitServerPlayer.java | 29 ++++ .../core/plugin/network/NetWorkUser.java | 3 + .../core/util/DynamicPriorityTracker.java | 161 ++++++++++++++++++ 5 files changed, 238 insertions(+), 14 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index ab1b59966..33a9ac417 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,6 +1,9 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; +import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import org.bukkit.Material; @@ -38,19 +41,26 @@ public class TestCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) - .required("reset", BooleanParser.booleanParser()) - .required("setTag", NamespacedKeyParser.namespacedKeyParser()) - .required("targetBlock", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { - @Override - public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(TARGET_BLOCK_SUGGESTIONS); - } - })) + // .required("reset", BooleanParser.booleanParser()) + // .required("setTag", NamespacedKeyParser.namespacedKeyParser()) + // .required("targetBlock", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { + // @Override + // public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + // return CompletableFuture.completedFuture(TARGET_BLOCK_SUGGESTIONS); + // } + // })) .handler(context -> { Player player = context.sender(); - player.sendMessage("开始测试"); - NamespacedKey key = context.get("setTag"); - player.sendMessage("结束测试"); + BukkitServerPlayer cePlayer = plugin().adapt(player); + player.sendMessage("visualFurnitureView1: " + cePlayer.visualFurnitureView().getTotalMembers()); + cePlayer.visualFurnitureView().getAllElements().forEach(element -> { + LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); + if (furniture == null || !player.canSee(furniture.baseEntity())) { + cePlayer.visualFurnitureView().removeByEntityId(element.entityId()); + player.sendMessage("remove: " + element.entityId()); + } + }); + player.sendMessage("visualFurnitureView2: " + cePlayer.visualFurnitureView().getTotalMembers()); }); } 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 abd76f731..37948856d 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 @@ -1598,8 +1598,28 @@ public class PacketConsumers { // Furniture LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); if (furniture != null) { - user.entityPacketHandlers().computeIfAbsent(entityId, k -> new FurniturePacketHandler(furniture.fakeEntityIds())); - user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); + Player player = (Player) user.platformPlayer(); + List fakeEntityIds = furniture.fakeEntityIds(); + user.entityPacketHandlers().computeIfAbsent(entityId, k -> new FurniturePacketHandler(fakeEntityIds)); + if (user.visualFurnitureView().getTotalMembers() <= 100) { + user.sendPacket(furniture.spawnPacket(player), false); + } + int[] entityIdsArray = new int[fakeEntityIds.size() + 1]; + entityIdsArray[0] = entityId; + for (int i = 0; i < fakeEntityIds.size(); i++) { + entityIdsArray[i + 1] = fakeEntityIds.get(i); + } + double distance = player.getLocation().distance(furniture.location()); + Object removePacket = Reflections.constructor$ClientboundRemoveEntitiesPacket.newInstance(entityIdsArray); + DynamicPriorityTracker.UpdateResult result = user.visualFurnitureView().addOrUpdateElement(new DynamicPriorityTracker.Element(entityId, distance, removePacket)); + for (DynamicPriorityTracker.Element element : result.getEntered()) { + LoadedFurniture updateFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); + if (updateFurniture == null || !updateFurniture.isValid()) continue; + user.sendPacket(updateFurniture.spawnPacket(player), false); + } + for (DynamicPriorityTracker.Element element : result.getExited()) { + user.sendPacket(element.removePacket(), false); + } if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { event.setCancelled(true); } @@ -1645,6 +1665,7 @@ public class PacketConsumers { int entityId = intList.getInt(i); EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); if (handler != null && handler.handleEntitiesRemove(intList)) { + // user.visualFurnitureView().removeByEntityId(entityId); isChange = true; } } @@ -1726,7 +1747,7 @@ public class PacketConsumers { .withParameter(DirectContextParameters.FURNITURE, furniture) .withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position())) ); - furniture.config().execute(context, EventTrigger.RIGHT_CLICK);; + furniture.config().execute(context, EventTrigger.RIGHT_CLICK); if (player.isSneaking()) { // try placing another furniture above it 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 5e045570f..97d23c5e2 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 @@ -4,6 +4,8 @@ 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.entity.furniture.BukkitFurnitureManager; +import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -23,6 +25,7 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.DynamicPriorityTracker; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; @@ -97,6 +100,7 @@ public class BukkitServerPlayer extends Player { private double cachedInteractionRange; private final Map entityTypeView = new ConcurrentHashMap<>(); + private final DynamicPriorityTracker visualFurnitureView = new DynamicPriorityTracker(100); public BukkitServerPlayer(BukkitCraftEngine plugin, Channel channel) { this.channel = channel; @@ -344,6 +348,7 @@ public class BukkitServerPlayer extends Player { } if (this.gameTicks % 30 == 0) { this.updateGUI(); + this.updateVisualFurnitureView(); } if (this.isDestroyingBlock) { this.tickBlockDestroy(); @@ -368,6 +373,25 @@ public class BukkitServerPlayer extends Player { } } + private void updateVisualFurnitureView() { + if (visualFurnitureView().getTotalMembers() <= 100) return; + for (DynamicPriorityTracker.Element element : visualFurnitureView().getAllElements()) { + LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); + if (furniture == null || !furniture.isValid()) continue; + double distance = platformPlayer().getLocation().distance(furniture.location()); + DynamicPriorityTracker.Element newElement = new DynamicPriorityTracker.Element(element.entityId(), distance, element.removePacket()); + DynamicPriorityTracker.UpdateResult result = visualFurnitureView().addOrUpdateElement(newElement); + for (DynamicPriorityTracker.Element resultElement : result.getEntered()) { + LoadedFurniture updateFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(resultElement.entityId()); + if (updateFurniture == null || !updateFurniture.isValid()) continue; + sendPacket(updateFurniture.spawnPacket(platformPlayer()), false); + } + for (DynamicPriorityTracker.Element resultElement : result.getExited()) { + sendPacket(resultElement.removePacket(), false); + } + } + } + @Override public float getDestroyProgress(Object blockState, BlockPos pos) { return FastNMS.INSTANCE.method$BlockStateBase$getDestroyProgress(blockState, serverPlayer(), FastNMS.INSTANCE.field$CraftWorld$ServerLevel(platformPlayer().getWorld()), LocationUtils.toBlockPos(pos)); @@ -738,6 +762,11 @@ public class BukkitServerPlayer extends Player { return this.entityTypeView; } + @Override + public DynamicPriorityTracker visualFurnitureView() { + return this.visualFurnitureView; + } + public void setResendSound() { resentSoundTick = gameTicks(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index cf9442fee..d442edb97 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.plugin.network; import io.netty.channel.Channel; import net.momirealms.craftengine.core.plugin.Plugin; +import net.momirealms.craftengine.core.util.DynamicPriorityTracker; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.ApiStatus; @@ -43,6 +44,8 @@ public interface NetWorkUser { Map entityPacketHandlers(); + DynamicPriorityTracker visualFurnitureView(); + boolean clientModEnabled(); void setClientModState(boolean enable); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java b/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java new file mode 100644 index 000000000..02e7f7a67 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java @@ -0,0 +1,161 @@ +package net.momirealms.craftengine.core.util; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +public class DynamicPriorityTracker { + + public static class Element { + private final int entityId; + private volatile double distance; + private final Object removePacket; + + public Element(int entityId, double distance, Object removePacket) { + this.entityId = entityId; + this.distance = distance; + this.removePacket = removePacket; + } + + public int entityId() { + return entityId; + } + public double distance() { + return distance; + } + public void setDistance(double distance) { + this.distance = distance; + } + public Object removePacket() { + return removePacket; + } + } + + public static class UpdateResult { + private final List entered = new ArrayList<>(); + private final List exited = new ArrayList<>(); + + public List getEntered() { + return entered; + } + public List getExited() { + return exited; + } + + void addEntered(Element e) { + entered.add(e); + } + void addExited(Element e) { + exited.add(e); + } + } + + private final int capacity; + private final PriorityQueue maxHeap; + private final Map elementMap = new ConcurrentHashMap<>(); + private final Set inHeapSet = ConcurrentHashMap.newKeySet(); + private final ReentrantLock heapLock = new ReentrantLock(); + + public DynamicPriorityTracker(int capacity) { + this.capacity = capacity; + this.maxHeap = new PriorityQueue<>((a, b) -> Double.compare(b.distance, a.distance)); + } + + public UpdateResult addOrUpdateElement(Element newElement) { + UpdateResult result = new UpdateResult(); + heapLock.lock(); + try { + Element existing = elementMap.get(newElement.entityId); + + if (existing != null) { + return handleExistingElement(existing, newElement, result); + } else { + return handleNewElement(newElement, result); + } + } finally { + heapLock.unlock(); + } + } + + private UpdateResult handleNewElement(Element newElement, UpdateResult result) { + elementMap.put(newElement.entityId, newElement); + + if (maxHeap.size() < capacity) { + maxHeap.offer(newElement); + inHeapSet.add(newElement.entityId); + result.addEntered(newElement); + } else if (maxHeap.peek() != null && newElement.distance < maxHeap.peek().distance) { + Element removed = maxHeap.poll(); + inHeapSet.remove(removed.entityId); + result.addExited(removed); + + maxHeap.offer(newElement); + inHeapSet.add(newElement.entityId); + result.addEntered(newElement); + } + return result; + } + + private UpdateResult handleExistingElement(Element existing, Element newElement, UpdateResult result) { + existing.setDistance(newElement.distance); + + boolean wasInHeap = inHeapSet.contains(existing.entityId); + boolean nowInHeap = checkIfShouldBeInHeap(existing.distance); + + if (wasInHeap) { + maxHeap.remove(existing); + maxHeap.offer(existing); + } else if (nowInHeap) { + if (maxHeap.size() < capacity) { + maxHeap.offer(existing); + inHeapSet.add(existing.entityId); + result.addEntered(existing); + } else if (maxHeap.peek() != null && existing.distance < maxHeap.peek().distance) { + Element removed = maxHeap.poll(); + inHeapSet.remove(removed.entityId); + result.addExited(removed); + + maxHeap.offer(existing); + inHeapSet.add(existing.entityId); + result.addEntered(existing); + } + } + return result; + } + + private boolean checkIfShouldBeInHeap(double distance) { + if (maxHeap.size() < capacity) return true; + return maxHeap.peek() != null && distance < maxHeap.peek().distance; + } + + public int getTotalMembers() { + heapLock.lock(); + try { + return elementMap.size(); + } finally { + heapLock.unlock(); + } + } + + public List getAllElements() { + heapLock.lock(); + try { + return List.copyOf(elementMap.values()); + } finally { + heapLock.unlock(); + } + } + + public Element removeByEntityId(int entityId) { + heapLock.lock(); + try { + Element removed = elementMap.remove(entityId); + if (removed != null) { + maxHeap.remove(removed); + } + return removed; + } finally { + heapLock.unlock(); + } + } +} From 3a7276c30962b9a91abd496c9cb2e059aeae2dba Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 18 May 2025 00:52:15 +0800 Subject: [PATCH 04/89] =?UTF-8?q?feat(bukkit):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=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/config.yml | 4 ++ .../plugin/network/PacketConsumers.java | 38 ++++++++++--------- .../plugin/user/BukkitServerPlayer.java | 5 ++- .../core/plugin/config/Config.java | 12 ++++++ .../core/util/DynamicPriorityTracker.java | 12 +++--- gradle.properties | 2 +- 6 files changed, 47 insertions(+), 26 deletions(-) diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 22eebce60..095aed474 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -183,6 +183,10 @@ furniture: # interaction (best performance) # boat (better compatibility with some anti-cheat plugin) collision-entity-type: interaction + # Limit the maximum amount of furniture that players can see by default + max-visible-furniture: + enable: false + amount: 100 emoji: chat: true 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 37948856d..65cb5f409 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 @@ -1601,25 +1601,29 @@ public class PacketConsumers { Player player = (Player) user.platformPlayer(); List fakeEntityIds = furniture.fakeEntityIds(); user.entityPacketHandlers().computeIfAbsent(entityId, k -> new FurniturePacketHandler(fakeEntityIds)); - if (user.visualFurnitureView().getTotalMembers() <= 100) { + if (Config.enableMaxVisibleFurniture()) { + if (user.visualFurnitureView().getTotalMembers() <= Config.maxVisibleFurniture()) { + user.sendPacket(furniture.spawnPacket(player), false); + } + int[] entityIdsArray = new int[fakeEntityIds.size() + 1]; + entityIdsArray[0] = entityId; + for (int i = 0; i < fakeEntityIds.size(); i++) { + entityIdsArray[i + 1] = fakeEntityIds.get(i); + } + double distance = player.getLocation().distance(furniture.location()); + Object removePacket = Reflections.constructor$ClientboundRemoveEntitiesPacket.newInstance(entityIdsArray); + DynamicPriorityTracker.UpdateResult result = user.visualFurnitureView().addOrUpdateElement(new DynamicPriorityTracker.Element(entityId, distance, removePacket)); + for (DynamicPriorityTracker.Element element : result.getEntered()) { + LoadedFurniture updateFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); + if (updateFurniture == null || !updateFurniture.isValid()) continue; + user.sendPacket(updateFurniture.spawnPacket(player), false); + } + for (DynamicPriorityTracker.Element element : result.getExited()) { + user.sendPacket(element.removePacket(), false); + } + } else { user.sendPacket(furniture.spawnPacket(player), false); } - int[] entityIdsArray = new int[fakeEntityIds.size() + 1]; - entityIdsArray[0] = entityId; - for (int i = 0; i < fakeEntityIds.size(); i++) { - entityIdsArray[i + 1] = fakeEntityIds.get(i); - } - double distance = player.getLocation().distance(furniture.location()); - Object removePacket = Reflections.constructor$ClientboundRemoveEntitiesPacket.newInstance(entityIdsArray); - DynamicPriorityTracker.UpdateResult result = user.visualFurnitureView().addOrUpdateElement(new DynamicPriorityTracker.Element(entityId, distance, removePacket)); - for (DynamicPriorityTracker.Element element : result.getEntered()) { - LoadedFurniture updateFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); - if (updateFurniture == null || !updateFurniture.isValid()) continue; - user.sendPacket(updateFurniture.spawnPacket(player), false); - } - for (DynamicPriorityTracker.Element element : result.getExited()) { - user.sendPacket(element.removePacket(), false); - } if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { event.setCancelled(true); } 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 97d23c5e2..8e30e0dca 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 @@ -100,7 +100,7 @@ public class BukkitServerPlayer extends Player { private double cachedInteractionRange; private final Map entityTypeView = new ConcurrentHashMap<>(); - private final DynamicPriorityTracker visualFurnitureView = new DynamicPriorityTracker(100); + private final DynamicPriorityTracker visualFurnitureView = new DynamicPriorityTracker(); public BukkitServerPlayer(BukkitCraftEngine plugin, Channel channel) { this.channel = channel; @@ -374,7 +374,8 @@ public class BukkitServerPlayer extends Player { } private void updateVisualFurnitureView() { - if (visualFurnitureView().getTotalMembers() <= 100) return; + if (!Config.enableMaxVisibleFurniture()) return; + if (visualFurnitureView().getTotalMembers() <= Config.maxVisibleFurniture()) return; for (DynamicPriorityTracker.Element element : visualFurnitureView().getAllElements()) { LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); if (furniture == null || !furniture.isValid()) continue; 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 d6faf0675..d8eb431f2 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 @@ -110,6 +110,8 @@ public class Config { protected Map furniture$handle_invalid_furniture_on_chunk_load$mapping; protected boolean furniture$hide_base_entity; protected ColliderType furniture$collision_entity_type; + protected boolean furniture$max_visible_furniture_enable; + protected int furniture$max_visible_furniture_amount; protected boolean block$sound_system$enable; protected boolean block$simplify_adventure_break_check; @@ -300,6 +302,8 @@ public class Config { furniture$handle_invalid_furniture_on_chunk_load$mapping = builder.build(); furniture$hide_base_entity = config.getBoolean("furniture.hide-base-entity", true); furniture$collision_entity_type = ColliderType.valueOf(config.getString("furniture.collision-entity-type", "interaction").toUpperCase(Locale.ENGLISH)); + furniture$max_visible_furniture_enable = config.getBoolean("furniture.max-visible-furniture.enable", false); + furniture$max_visible_furniture_amount = config.getInt("furniture.max-visible-furniture.amount", 100); // block block$sound_system$enable = config.getBoolean("block.sound-system.enable", true); @@ -417,6 +421,14 @@ public class Config { return instance.resource_pack$supported_version$min; } + public static boolean enableMaxVisibleFurniture() { + return instance.furniture$max_visible_furniture_enable; + } + + public static int maxVisibleFurniture() { + return instance.furniture$max_visible_furniture_amount; + } + public static float packMaxVersion() { return instance.resource_pack$supported_version$max; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java b/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java index 02e7f7a67..50ebee72d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.core.util; +import net.momirealms.craftengine.core.plugin.config.Config; + import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; @@ -50,14 +52,12 @@ public class DynamicPriorityTracker { } } - private final int capacity; private final PriorityQueue maxHeap; private final Map elementMap = new ConcurrentHashMap<>(); private final Set inHeapSet = ConcurrentHashMap.newKeySet(); private final ReentrantLock heapLock = new ReentrantLock(); - public DynamicPriorityTracker(int capacity) { - this.capacity = capacity; + public DynamicPriorityTracker() { this.maxHeap = new PriorityQueue<>((a, b) -> Double.compare(b.distance, a.distance)); } @@ -80,7 +80,7 @@ public class DynamicPriorityTracker { private UpdateResult handleNewElement(Element newElement, UpdateResult result) { elementMap.put(newElement.entityId, newElement); - if (maxHeap.size() < capacity) { + if (maxHeap.size() < Config.maxVisibleFurniture()) { maxHeap.offer(newElement); inHeapSet.add(newElement.entityId); result.addEntered(newElement); @@ -106,7 +106,7 @@ public class DynamicPriorityTracker { maxHeap.remove(existing); maxHeap.offer(existing); } else if (nowInHeap) { - if (maxHeap.size() < capacity) { + if (maxHeap.size() < Config.maxVisibleFurniture()) { maxHeap.offer(existing); inHeapSet.add(existing.entityId); result.addEntered(existing); @@ -124,7 +124,7 @@ public class DynamicPriorityTracker { } private boolean checkIfShouldBeInHeap(double distance) { - if (maxHeap.size() < capacity) return true; + if (maxHeap.size() < Config.maxVisibleFurniture()) return true; return maxHeap.peek() != null && distance < maxHeap.peek().distance; } diff --git a/gradle.properties b/gradle.properties index e2b6917ae..cc8e14db4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] project_version=0.0.54 -config_version=32 +config_version=33 lang_version=12 project_group=net.momirealms latest_supported_version=1.21.5 From ca9ab2ca12014a69f6b367268683c6277f6b8614 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 18 May 2025 03:24:47 +0800 Subject: [PATCH 05/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0zip=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 3 +- .../core/pack/AbstractPackManager.java | 222 +++++++++++------- .../core/plugin/config/Config.java | 4 + gradle.properties | 2 +- 4 files changed, 146 insertions(+), 85 deletions(-) diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 22eebce60..778670b6e 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -62,11 +62,10 @@ resource-pack: remove-tinted-leaves-particle: true merge-external-folders: - ModelEngine/resource pack - - CustomNameplates/ResourcePack - BetterModel/build - BetterHud/build merge-external-zip-files: - - CraftEngine/external_packs/example.zip + - CustomNameplates/resourcepack.zip delivery: # Send the resource pack on joining the server send-on-join: true 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 473f1086f..e5809d59f 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 @@ -420,7 +420,8 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png.mcmeta"); } - private void updateCachedConfigFiles() { + private TreeMap> updateCachedConfigFiles() { + TreeMap> cachedConfigs = new TreeMap<>(); Map previousFiles = this.cachedConfigFiles; this.cachedConfigFiles = new Object2ObjectOpenHashMap<>(32); Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); @@ -436,14 +437,20 @@ public abstract class AbstractPackManager implements PackManager { long size = attrs.size(); if (cachedFile != null && cachedFile.lastModified() == lastModifiedTime && cachedFile.size() == size) { AbstractPackManager.this.cachedConfigFiles.put(path, cachedFile); - return FileVisitResult.CONTINUE; + } else { + try (InputStreamReader inputStream = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { + Map data = yaml.load(inputStream); + if (data == null) return FileVisitResult.CONTINUE; + cachedFile = new CachedConfigFile(data, pack, lastModifiedTime, size); + AbstractPackManager.this.cachedConfigFiles.put(path, cachedFile); + } catch (IOException e) { + AbstractPackManager.this.plugin.logger().severe("Error while reading config file: " + path, e); + return FileVisitResult.CONTINUE; + } } - try (InputStreamReader inputStream = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { - Map data = yaml.load(inputStream); - if (data == null) return FileVisitResult.CONTINUE; - AbstractPackManager.this.cachedConfigFiles.put(path, new CachedConfigFile(data, pack, lastModifiedTime, size)); - } catch (IOException e) { - AbstractPackManager.this.plugin.logger().severe("Error while reading config file: " + path, e); + for (Map.Entry entry : cachedFile.config().entrySet()) { + processConfigEntry(entry, path, cachedFile.pack(), (p, c) -> + cachedConfigs.computeIfAbsent(p, k -> new ArrayList<>()).add(c)); } } return FileVisitResult.CONTINUE; @@ -453,19 +460,12 @@ public abstract class AbstractPackManager implements PackManager { this.plugin.logger().severe("Error while reading config file", e); } } + return cachedConfigs; } private void loadResourceConfigs(Predicate predicate) { - TreeMap> cachedConfigs = new TreeMap<>(); long o1 = System.nanoTime(); - this.updateCachedConfigFiles(); - for (Map.Entry fileEntry : this.cachedConfigFiles.entrySet()) { - CachedConfigFile cachedFile = fileEntry.getValue(); - for (Map.Entry entry : cachedFile.config().entrySet()) { - processConfigEntry(entry, fileEntry.getKey(), cachedFile.pack(), (p, c) -> - cachedConfigs.computeIfAbsent(p, k -> new ArrayList<>()).add(c)); - } - } + TreeMap> cachedConfigs = this.updateCachedConfigFiles(); long o2 = System.nanoTime(); this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); for (Map.Entry> entry : cachedConfigs.entrySet()) { @@ -549,69 +549,6 @@ public abstract class AbstractPackManager implements PackManager { // } // } - private List>> updateCachedAssets(@Nullable FileSystem fs) throws IOException { - List folders = new ArrayList<>(); - Map> conflictChecker = new Object2ObjectOpenHashMap<>(Math.max(128, this.cachedAssetFiles.size())); - Map previousFiles = this.cachedAssetFiles; - this.cachedAssetFiles = new Object2ObjectOpenHashMap<>(Math.max(128, this.cachedAssetFiles.size())); - folders.addAll(loadedPacks().stream().filter(Pack::enabled).map(Pack::resourcePackFolder).toList()); - folders.addAll(Config.foldersToMerge().stream().map(it -> plugin.dataFolderPath().getParent().resolve(it)).filter(Files::exists).toList()); - for (Path sourceFolder : folders) { - if (Files.exists(sourceFolder)) { - Files.walkFileTree(sourceFolder, new SimpleFileVisitor<>() { - @Override - public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { - CachedAssetFile cachedAsset = previousFiles.get(file); - long lastModified = attrs.lastModifiedTime().toMillis(); - long size = attrs.size(); - if (cachedAsset != null && cachedAsset.lastModified() == lastModified && cachedAsset.size() == size) { - AbstractPackManager.this.cachedAssetFiles.put(file, cachedAsset); - } else { - cachedAsset = new CachedAssetFile(Files.readAllBytes(file), lastModified, size); - AbstractPackManager.this.cachedAssetFiles.put(file, cachedAsset); - } - if (fs == null) return FileVisitResult.CONTINUE; - Path relative = sourceFolder.relativize(file); - Path targetPath = fs.getPath("resource_pack/" + CharacterUtils.replaceBackslashWithSlash(relative.toString())); - List conflicts = conflictChecker.get(relative); - if (conflicts == null) { - Files.createDirectories(targetPath.getParent()); - Files.write(targetPath, cachedAsset.data()); - conflictChecker.put(relative, List.of(file)); - } else { - PathContext relativeCTX = PathContext.of(relative); - PathContext targetCTX = PathContext.of(targetPath); - PathContext fileCTX = PathContext.of(file); - for (ResolutionConditional resolution : Config.resolutions()) { - if (resolution.matcher().test(relativeCTX)) { - resolution.resolution().run(targetCTX, fileCTX); - return FileVisitResult.CONTINUE; - } - } - switch (conflicts.size()) { - case 1 -> conflictChecker.put(relative, List.of(conflicts.get(0), file)); - case 2 -> conflictChecker.put(relative, List.of(conflicts.get(0), conflicts.get(1), file)); - case 3 -> conflictChecker.put(relative, List.of(conflicts.get(0), conflicts.get(1), conflicts.get(2), file)); - case 4 -> conflictChecker.put(relative, List.of(conflicts.get(0), conflicts.get(1), conflicts.get(2), conflicts.get(3), file)); - default -> { - // just ignore it if it has many conflict files - } - } - } - return FileVisitResult.CONTINUE; - } - }); - } - } - List>> conflicts = new ArrayList<>(); - for (Map.Entry> entry : conflictChecker.entrySet()) { - if (entry.getValue().size() > 1) { - conflicts.add(Pair.of(entry.getKey(), entry.getValue())); - } - } - return conflicts; - } - @Override public void generateResourcePack() throws IOException { this.plugin.logger().info("Generating resource pack..."); @@ -621,11 +558,11 @@ public abstract class AbstractPackManager implements PackManager { try (FileSystem fs = Jimfs.newFileSystem(Configuration.forCurrentPlatform())) { // firstly merge existing folders Path generatedPackPath = fs.getPath("resource_pack"); - List>> duplicated = this.updateCachedAssets(fs); + List>> duplicated = this.updateCachedAssets(fs); if (!duplicated.isEmpty()) { plugin.logger().severe(AdventureHelper.miniMessage().stripTags(TranslationManager.instance().miniMessageTranslation("warning.config.pack.duplicated_files"))); int x = 1; - for (Pair> path : duplicated) { + for (Pair> path : duplicated) { this.plugin.logger().warn("[ " + (x++) + " ] " + path.left()); for (int i = 0, size = path.right().size(); i < size; i++) { if (i == size - 1) { @@ -1253,4 +1190,125 @@ public abstract class AbstractPackManager implements PackManager { } } } + + private List>> updateCachedAssets(@Nullable FileSystem fs) throws IOException { + Map> conflictChecker = new Object2ObjectOpenHashMap<>(Math.max(128, this.cachedAssetFiles.size())); + Map previousFiles = this.cachedAssetFiles; + this.cachedAssetFiles = new Object2ObjectOpenHashMap<>(Math.max(128, this.cachedAssetFiles.size())); + + List folders = new ArrayList<>(); + folders.addAll(loadedPacks().stream() + .filter(Pack::enabled) + .map(Pack::resourcePackFolder) + .toList()); + folders.addAll(Config.foldersToMerge().stream() + .map(it -> plugin.dataFolderPath().getParent().resolve(it)) + .filter(Files::exists) + .toList()); + for (Path sourceFolder : folders) { + if (Files.exists(sourceFolder)) { + Files.walkFileTree(sourceFolder, new SimpleFileVisitor<>() { + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { + processRegularFile(file, attrs, sourceFolder, fs, conflictChecker, previousFiles); + return FileVisitResult.CONTINUE; + } + }); + } + } + List externalZips = Config.zipsToMerge().stream() + .map(it -> plugin.dataFolderPath().getParent().resolve(it)) + .filter(Files::exists) + .filter(Files::isRegularFile) + .filter(file -> file.getFileName().toString().endsWith(".zip")) + .toList(); + for (Path zip : externalZips) { + processZipFile(zip, zip.getParent(), fs, conflictChecker, previousFiles); + } + + List>> conflicts = new ArrayList<>(); + for (Map.Entry> entry : conflictChecker.entrySet()) { + if (entry.getValue().size() > 1) { + conflicts.add(Pair.of(entry.getKey(), entry.getValue())); + } + } + return conflicts; + } + + private void processRegularFile(Path file, BasicFileAttributes attrs, Path sourceFolder, @Nullable FileSystem fs, + Map> conflictChecker, Map previousFiles) throws IOException { + CachedAssetFile cachedAsset = previousFiles.get(file); + long lastModified = attrs.lastModifiedTime().toMillis(); + long size = attrs.size(); + if (cachedAsset != null && cachedAsset.lastModified() == lastModified && cachedAsset.size() == size) { + cachedAssetFiles.put(file, cachedAsset); + } else { + cachedAsset = new CachedAssetFile(Files.readAllBytes(file), lastModified, size); + cachedAssetFiles.put(file, cachedAsset); + } + if (fs == null) return; + Path relative = sourceFolder.relativize(file); + updateConflictChecker(fs, conflictChecker, file, file, relative, cachedAsset.data()); + } + + private void processZipFile(Path zipFile, Path sourceFolder, @Nullable FileSystem fs, + Map> conflictChecker, Map previousFiles) throws IOException { + try (FileSystem zipFs = FileSystems.newFileSystem(zipFile)) { + long zipLastModified = Files.getLastModifiedTime(zipFile).toMillis(); + long zipSize = Files.size(zipFile); + Path zipRoot = zipFs.getPath("/"); + Files.walkFileTree(zipRoot, new SimpleFileVisitor<>() { + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path entry, @NotNull BasicFileAttributes entryAttrs) throws IOException { + if (entryAttrs.isDirectory()) { + return FileVisitResult.CONTINUE; + } + Path entryPathInZip = zipRoot.relativize(entry); + Path sourcePath = Path.of(zipFile + "!" + entryPathInZip); + CachedAssetFile cachedAsset = previousFiles.get(sourcePath); + if (cachedAsset != null && cachedAsset.lastModified() == zipLastModified && cachedAsset.size() == zipSize) { + cachedAssetFiles.put(sourcePath, cachedAsset); + } else { + byte[] data = Files.readAllBytes(entry); + cachedAsset = new CachedAssetFile(data, zipLastModified, zipSize); + cachedAssetFiles.put(sourcePath, cachedAsset); + } + if (fs != null) { + updateConflictChecker(fs, conflictChecker, entry, sourcePath, entryPathInZip, cachedAsset.data()); + } + return FileVisitResult.CONTINUE; + } + }); + } + } + + private void updateConflictChecker(FileSystem fs, Map> conflictChecker, Path sourcePath, Path namedSourcePath, Path relative, byte[] data) throws IOException { + String relativePath = CharacterUtils.replaceBackslashWithSlash(relative.toString()); + Path targetPath = fs.getPath("resource_pack/" + relativePath); + List conflicts = conflictChecker.get(relativePath); + if (conflicts == null) { + Files.createDirectories(targetPath.getParent()); + Files.write(targetPath, data); + conflictChecker.put(relativePath, List.of(namedSourcePath)); + } else { + PathContext relativeCTX = PathContext.of(relative); + PathContext targetCTX = PathContext.of(targetPath); + PathContext sourceCTX = PathContext.of(sourcePath); + for (ResolutionConditional resolution : Config.resolutions()) { + if (resolution.matcher().test(relativeCTX)) { + resolution.resolution().run(targetCTX, sourceCTX); + return; + } + } + switch (conflicts.size()) { + case 1 -> conflictChecker.put(relativePath, List.of(conflicts.get(0), namedSourcePath)); + case 2 -> conflictChecker.put(relativePath, List.of(conflicts.get(0), conflicts.get(1), namedSourcePath)); + case 3 -> conflictChecker.put(relativePath, List.of(conflicts.get(0), conflicts.get(1), conflicts.get(2), namedSourcePath)); + case 4 -> conflictChecker.put(relativePath, List.of(conflicts.get(0), conflicts.get(1), conflicts.get(2), conflicts.get(3), namedSourcePath)); + default -> { + // just ignore it if it has many conflict files + } + } + } + } } 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 d6faf0675..be96fe1ed 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 @@ -465,6 +465,10 @@ public class Config { return instance.resource_pack$merge_external_folders; } + public static List zipsToMerge() { + return instance.resource_pack$merge_external_zips; + } + public static boolean kickOnDeclined() { return instance.resource_pack$delivery$kick_if_declined; } diff --git a/gradle.properties b/gradle.properties index e2b6917ae..1fabb99a5 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.54 +project_version=0.0.54.1 config_version=32 lang_version=12 project_group=net.momirealms From eba3188c823e8f2f8dc661f47b8683288eee45bc Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 18 May 2025 05:23:59 +0800 Subject: [PATCH 06/89] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=89=A9=E5=93=81?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitCustomItem.java | 36 +- .../bukkit/item/BukkitItemManager.java | 452 +----------------- .../core/item/AbstractItemManager.java | 444 ++++++++++++++++- .../craftengine/core/item/CustomItem.java | 5 +- .../craftengine/core/item/ItemKeys.java | 1 + .../craftengine/core/item/ItemManager.java | 6 +- .../core/item/behavior/ItemBehaviors.java | 22 + .../core/pack/AbstractPackManager.java | 5 +- .../conflict/matcher/PathPatternMatcher.java | 1 - .../HasComponentConditionProperty.java | 8 + .../craftengine/core/util/FileUtils.java | 5 - 11 files changed, 503 insertions(+), 482 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index f3ac95c70..7e2559198 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -2,13 +2,14 @@ package net.momirealms.craftengine.bukkit.item; import com.google.common.collect.ImmutableMap; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.util.MaterialUtils; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -17,7 +18,7 @@ import org.jetbrains.annotations.NotNull; import java.util.*; public class BukkitCustomItem implements CustomItem { - private final Key id; + private final Holder id; private final Key materialKey; private final Material material; private final ItemDataModifier[] modifiers; @@ -30,7 +31,7 @@ public class BukkitCustomItem implements CustomItem { private final EnumMap>> events; @SuppressWarnings("unchecked") - public BukkitCustomItem(Key id, + public BukkitCustomItem(Holder id, Key materialKey, Material material, List> modifiers, @@ -78,6 +79,11 @@ public class BukkitCustomItem implements CustomItem { @Override public Key id() { + return this.id.value(); + } + + @Override + public Holder idHolder() { return this.id; } @@ -147,22 +153,27 @@ public class BukkitCustomItem implements CustomItem { return this.behaviors; } - public static Builder builder() { - return new BuilderImpl(); + public static Builder builder(Material material) { + return new BuilderImpl(material); } public static class BuilderImpl implements Builder { - private Key id; - private Material material; + private Holder id; private Key materialKey; - private ItemSettings settings; - private EnumMap>> events = new EnumMap<>(EventTrigger.class); + private final Material material; + private final EnumMap>> events = new EnumMap<>(EventTrigger.class); private final List behaviors = new ArrayList<>(); private final List> modifiers = new ArrayList<>(); private final List> clientBoundModifiers = new ArrayList<>(); + private ItemSettings settings; + + public BuilderImpl(Material material) { + this.material = material; + this.materialKey = KeyUtils.namespacedKey2Key(material.getKey()); + } @Override - public Builder id(Key id) { + public Builder id(Holder id) { this.id = id; return this; } @@ -170,7 +181,6 @@ public class BukkitCustomItem implements CustomItem { @Override public Builder material(Key material) { this.materialKey = material; - this.material = MaterialUtils.getMaterial(material.value()); return this; } @@ -218,14 +228,14 @@ public class BukkitCustomItem implements CustomItem { @Override public Builder events(EnumMap>> events) { - this.events = events; + this.events.putAll(events); return this; } @Override public CustomItem build() { this.modifiers.addAll(this.settings.modifiers()); - return new BukkitCustomItem(this.id, this.materialKey, this.material, this.modifiers, this.clientBoundModifiers, this.behaviors, this.settings, this.events); + return new BukkitCustomItem(this.id, this.materialKey, this.material, List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), List.copyOf(this.behaviors), this.settings, this.events); } } } 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 5210f9e4a..d7fb27b85 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 @@ -13,45 +13,32 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; -import net.momirealms.craftengine.bukkit.util.MaterialUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.*; -import net.momirealms.craftengine.core.item.behavior.ItemBehavior; -import net.momirealms.craftengine.core.item.behavior.ItemBehaviors; -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.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.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ReflectionUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; -import org.incendo.cloud.suggestion.Suggestion; -import org.incendo.cloud.type.Either; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; -import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.Function; public class BukkitItemManager extends AbstractItemManager { @@ -68,7 +55,7 @@ public class BukkitItemManager extends AbstractItemManager { private final ItemEventListener itemEventListener; private final DebugStickListener debugStickListener; private final ArmorEventListener armorEventListener; - private final ItemParser itemParser; + public BukkitItemManager(BukkitCraftEngine plugin) { super(plugin); @@ -78,7 +65,6 @@ public class BukkitItemManager extends AbstractItemManager { this.itemEventListener = new ItemEventListener(plugin); this.debugStickListener = new DebugStickListener(plugin); this.armorEventListener = new ArmorEventListener(); - this.itemParser = new ItemParser(); this.registerAllVanillaItems(); if (plugin.hasMod()) { Class clazz$CustomStreamCodec = ReflectionUtils.getClazz("net.momirealms.craftengine.mod.item.CustomStreamCodec"); @@ -177,11 +163,6 @@ public class BukkitItemManager extends AbstractItemManager { return this.factory.wrap(ItemTagStream.INSTANCE.fromBytes(bytes)); } - @Override - public ConfigParser 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); @@ -238,417 +219,10 @@ public class BukkitItemManager extends AbstractItemManager { return wrapped.id(); } - public class ItemParser implements ConfigParser { - public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; - - @Override - public String[] sectionId() { - return CONFIG_SECTION_NAME; - } - - @Override - public int loadingSequence() { - return LoadingSequence.ITEM; - } - - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - if (customItems.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.item.duplicate"); - } - - // 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)); - - boolean isVanillaItem = id.namespace().equals("minecraft") && Registry.MATERIAL.get(new NamespacedKey(id.namespace(), id.value())) != null; - String materialStringId; - if (isVanillaItem) { - materialStringId = id.value(); - } else { - materialStringId = ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("material"), "warning.config.item.missing_material"); - } - - Material material = MaterialUtils.getMaterial(materialStringId); - if (material == null) { - throw new LocalizedResourceConfigException("warning.config.item.invalid_material", materialStringId); - } - - Key materialId = Key.of(material.getKey().namespace(), material.getKey().value()); - int customModelData = ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data"); - Key itemModelKey = null; - - CustomItem.Builder itemBuilder = BukkitCustomItem.builder().id(id).material(materialId); - boolean hasItemModelSection = section.containsKey("item-model"); - - // To get at least one model provider - // Sets some basic model info - if (customModelData != 0) { - itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); - } - // Requires the item to have model before apply item-model - else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isOrAbove1_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.dataModifier(new ItemModelModifier<>(itemModelKey)); - } else { - itemModelKey = null; - } - } - - if (hasItemModelSection) { - itemModelKey = Key.from(section.get("item-model").toString()); - itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); - } - - // 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.behaviors(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.dataModifier(function.apply(dataEntry.getValue())); - } catch (IllegalArgumentException e) { - plugin.logger().warn("Invalid data format", e); - } - }); - } - } - - // Add it here to make sure that ce id is always applied - if (!isVanillaItem) - itemBuilder.dataModifier(new IdModifier<>(id)); - - // Get item data - Map clientSideDataSection = MiscUtils.castToMap(section.get("client-bound-data"), true); - if (clientSideDataSection != null) { - for (Map.Entry dataEntry : clientSideDataSection.entrySet()) { - Optional.ofNullable(dataFunctions.get(dataEntry.getKey())).ifPresent(function -> { - try { - itemBuilder.clientBoundDataModifier(function.apply(dataEntry.getValue())); - } catch (IllegalArgumentException e) { - plugin.logger().warn("Invalid client bound data format", e); - } - }); - } - } - - ItemSettings itemSettings = ItemSettings.fromMap(MiscUtils.castToMap(section.get("settings"), true)); - if (isVanillaItem) { - itemSettings.canPlaceRelatedVanillaBlock(true); - } - itemBuilder.settings(itemSettings); - itemBuilder.events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))); - - CustomItem customItem = itemBuilder.build(); - customItems.put(id, customItem); - - // cache command suggestions - cachedSuggestions.add(Suggestion.suggestion(id.toString())); - - // TODO Deprecated 理论支持任意物品类型 - 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; - } - - ItemModel model = ItemModels.fromMap(modelSection); - 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)) { - throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(customModelData), conflict.get(customModelData).toString()); - } - - if (customModelData > 16_777_216) { - throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); - } - - conflict.put(customModelData, id); - - // Parse models - for (ModelGeneration generation : model.modelsToGenerate()) { - prepareModelGeneration(generation); - } - - if (Config.packMaxVersion() > 21.39f) { - TreeMap map = modernOverrides.computeIfAbsent(materialId, k -> new TreeMap<>()); - map.put(customModelData, model); - } - - if (Config.packMinVersion() < 21.39f) { - // TODO 手动指定旧版格式 - 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; - for (ModelGeneration generation : model.modelsToGenerate()) { - prepareModelGeneration(generation); - } - - if (Config.packMaxVersion() > 21.39f) { - modernItemModels1_21_4.put(itemModelKey, model); - } - - if (Config.packMaxVersion() > 21.19f && Config.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) { - throw new LocalizedResourceConfigException("warning.config.item.missing_model_id"); - } - } - } - - private void processModelRecursively( - ItemModel currentModel, - Map accumulatedPredicates, - List resultList, - Key materialId, - int customModelData - ) { - if (currentModel instanceof ConditionItemModel conditionModel) { - handleConditionModel(conditionModel, accumulatedPredicates, resultList, materialId, customModelData); - } else if (currentModel instanceof RangeDispatchItemModel rangeModel) { - handleRangeModel(rangeModel, accumulatedPredicates, resultList, materialId, customModelData); - } else if (currentModel instanceof SelectItemModel selectModel) { - handleSelectModel(selectModel, accumulatedPredicates, resultList, materialId, customModelData); - } else if (currentModel instanceof BaseItemModel baseModel) { - resultList.add(new LegacyOverridesModel( - new LinkedHashMap<>(accumulatedPredicates), - baseModel.path(), - customModelData - )); - } else if (currentModel instanceof SpecialItemModel specialModel) { - resultList.add(new LegacyOverridesModel( - new LinkedHashMap<>(accumulatedPredicates), - specialModel.base(), - customModelData - )); - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void handleConditionModel( - ConditionItemModel model, - Map parentPredicates, - List resultList, - Key materialId, - int customModelData - ) { - if (model.property() instanceof LegacyModelPredicate predicate) { - String predicateId = predicate.legacyPredicateId(materialId); - Map truePredicates = mergePredicates( - parentPredicates, - predicateId, - predicate.toLegacyValue(true) - ); - processModelRecursively( - model.onTrue(), - truePredicates, - resultList, - materialId, - customModelData - ); - Map falsePredicates = mergePredicates( - parentPredicates, - predicateId, - predicate.toLegacyValue(false) - ); - processModelRecursively( - model.onFalse(), - falsePredicates, - resultList, - materialId, - customModelData - ); - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void handleRangeModel( - RangeDispatchItemModel model, - Map parentPredicates, - List resultList, - Key materialId, - int customModelData - ) { - if (model.property() instanceof LegacyModelPredicate predicate) { - String predicateId = predicate.legacyPredicateId(materialId); - for (Map.Entry entry : model.entries().entrySet()) { - Map merged = mergePredicates( - parentPredicates, - predicateId, - predicate.toLegacyValue(entry.getKey()) - ); - processModelRecursively( - entry.getValue(), - merged, - resultList, - materialId, - customModelData - ); - } - if (model.fallBack() != null) { - Map merged = mergePredicates( - parentPredicates, - predicateId, - predicate.toLegacyValue(0f) - ); - processModelRecursively( - model.fallBack(), - merged, - resultList, - materialId, - customModelData - ); - } - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void handleSelectModel( - SelectItemModel model, - Map parentPredicates, - List resultList, - Key materialId, - int customModelData - ) { - if (model.property() instanceof LegacyModelPredicate predicate) { - String predicateId = predicate.legacyPredicateId(materialId); - for (Map.Entry>, ItemModel> entry : model.whenMap().entrySet()) { - List cases = entry.getKey().fallbackOrMapPrimary(List::of); - for (String caseValue : cases) { - Number legacyValue = predicate.toLegacyValue(caseValue); - if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { - if (legacyValue.floatValue() > 1f) { - continue; - } - } - Map merged = mergePredicates( - parentPredicates, - predicateId, - legacyValue - ); - // Additional check for crossbow - if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { - merged = mergePredicates( - merged, - "charged", - 1 - ); - } - processModelRecursively( - entry.getValue(), - merged, - resultList, - materialId, - customModelData - ); - } - } - // Additional check for crossbow - if (model.fallBack() != null) { - if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { - processModelRecursively( - model.fallBack(), - mergePredicates( - parentPredicates, - "charged", - 0 - ), - resultList, - materialId, - customModelData - ); - } else if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { - processModelRecursively( - model.fallBack(), - mergePredicates( - parentPredicates, - "trim_type", - 0f - ), - resultList, - materialId, - customModelData - ); - } - } - } - } - - private Map mergePredicates( - Map existing, - String newKey, - Number newValue - ) { - Map merged = new LinkedHashMap<>(existing); - if (newKey == null) return merged; - merged.put(newKey, newValue); - return merged; + @Override + protected CustomItem.Builder createPlatformItemBuilder(Key materialId) { + Material material = ResourceConfigUtils.requireNonNullOrThrow(Registry.MATERIAL.get(KeyUtils.toNamespacedKey(materialId)), () -> new LocalizedResourceConfigException("warning.config.item.invalid_material", materialId.toString())); + return BukkitCustomItem.builder(material); } @SuppressWarnings("unchecked") 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 4548fadab..8719601b8 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 @@ -1,35 +1,48 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.behavior.ItemBehaviors; import net.momirealms.craftengine.core.item.modifier.*; +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.ItemModel; -import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel; +import net.momirealms.craftengine.core.pack.model.*; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; +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.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.TypeUtils; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.type.Either; +import java.nio.file.Path; import java.util.*; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; public abstract class AbstractItemManager extends AbstractModelGenerator implements ItemManager { protected static final Map> VANILLA_ITEM_EXTRA_BEHAVIORS = new HashMap<>(); - protected static final List VANILLA_ITEMS = new ArrayList<>(); + protected static final Set VANILLA_ITEMS = new HashSet<>(1024); protected static final Map>> VANILLA_ITEM_TAGS = new HashMap<>(); + private final ItemParser itemParser; protected final Map> externalItemProviders = new HashMap<>(); protected final Map>> dataFunctions = new HashMap<>(); protected final Map> customItems = new HashMap<>(); protected final Map>> customItemTags; protected final Map> cmdConflictChecker; protected final Map modernItemModels1_21_4; - protected final Map> modernItemModels1_21_2; + protected final Map> modernItemModels1_21_2; protected final Map> legacyOverrides; protected final Map> modernOverrides; protected final Set equipmentsToGenerate; @@ -37,6 +50,19 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected final List cachedSuggestions = new ArrayList<>(); protected final List cachedTotemSuggestions = new ArrayList<>(); + protected AbstractItemManager(CraftEngine plugin) { + super(plugin); + this.itemParser = new ItemParser(); + this.registerFunctions(); + this.legacyOverrides = new HashMap<>(); + this.modernOverrides = new HashMap<>(); + this.customItemTags = new HashMap<>(); + this.cmdConflictChecker = new HashMap<>(); + this.modernItemModels1_21_4 = new HashMap<>(); + this.modernItemModels1_21_2 = new HashMap<>(); + this.equipmentsToGenerate = new HashSet<>(); + } + protected void registerDataFunction(Function> function, String... alias) { for (String a : alias) { dataFunctions.put(a, function); @@ -49,6 +75,25 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } + protected void applyDataFunctions(Map dataSection, Consumer> consumer) { + if (dataSection != null) { + for (Map.Entry dataEntry : dataSection.entrySet()) { + Optional.ofNullable(dataFunctions.get(dataEntry.getKey())).ifPresent(function -> { + try { + consumer.accept(function.apply(dataEntry.getValue())); + } catch (IllegalArgumentException e) { + plugin.logger().warn("Invalid data format", e); + } + }); + } + } + } + + @Override + public ConfigParser parser() { + return this.itemParser; + } + @Override public ExternalItemProvider getExternalItemProvider(String name) { return this.externalItemProviders.get(name); @@ -81,16 +126,35 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return Optional.ofNullable(this.customItems.get(key)); } - public AbstractItemManager(CraftEngine plugin) { - super(plugin); - this.registerFunctions(); - this.legacyOverrides = new HashMap<>(); - this.modernOverrides = new HashMap<>(); - this.customItemTags = new HashMap<>(); - this.cmdConflictChecker = new HashMap<>(); - this.modernItemModels1_21_4 = new HashMap<>(); - this.modernItemModels1_21_2 = new HashMap<>(); - this.equipmentsToGenerate = new HashSet<>(); + @Override + public boolean addCustomItem(CustomItem customItem) { + Key id = customItem.id(); + if (this.customItems.containsKey(id)) return false; + this.customItems.put(id, customItem); + // cache command suggestions + this.cachedSuggestions.add(Suggestion.suggestion(id.toString())); + // totem animations + if (VersionHelper.isOrAbove1_21_2()) { + this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); + } else if (customItem.material().equals(ItemKeys.TOTEM_OF_UNDYING)) { + this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); + } + // tags + Set tags = customItem.settings().tags(); + for (Key tag : tags) { + this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(customItem.idHolder()); + } + // equipment generation + 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 + } + return true; } @Override @@ -100,7 +164,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl if (holders != null) { items.addAll(holders); } - List> customItems = customItemTags.get(tag); + List> customItems = this.customItemTags.get(tag); if (customItems != null) { items.addAll(customItems); } @@ -160,7 +224,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } @Override - public Map> modernItemModels1_21_2() { + public Map> modernItemModels1_21_2() { return Collections.unmodifiableMap(this.modernItemModels1_21_2); } @@ -184,6 +248,157 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return Collections.unmodifiableCollection(this.equipmentsToGenerate); } + @Override + public boolean isVanillaItem(Key item) { + return VANILLA_ITEMS.contains(item); + } + + protected abstract CustomItem.Builder createPlatformItemBuilder(Key material); + + public class ItemParser implements ConfigParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public int loadingSequence() { + return LoadingSequence.ITEM; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + if (customItems.containsKey(id)) { + throw new LocalizedResourceConfigException("warning.config.item.duplicate"); + } + + // 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)); + + boolean isVanillaItem = isVanillaItem(id); + Key material = Key.from(isVanillaItem ? id.value() : ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("material"), "warning.config.item.missing_material")); + int customModelData = ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data"); + // TODO give warnings if negative + + Key itemModelKey = null; + + CustomItem.Builder itemBuilder = createPlatformItemBuilder(material).id(holder); + boolean hasItemModelSection = section.containsKey("item-model"); + + // To get at least one model provider + // Sets some basic model info + if (customModelData > 0) { + itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); + } + // Requires the item to have model before apply item-model + else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isOrAbove1_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.dataModifier(new ItemModelModifier<>(itemModelKey)); + } else { + itemModelKey = null; + } + } + + if (hasItemModelSection) { + itemModelKey = Key.from(section.get("item-model").toString()); + itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); + } + + // Get item data + applyDataFunctions(MiscUtils.castToMap(section.get("data"), true), itemBuilder::dataModifier); + applyDataFunctions(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); + + // Add custom it here to make sure that id is always applied + if (!isVanillaItem) + itemBuilder.dataModifier(new IdModifier<>(id)); + + CustomItem customItem = itemBuilder + .behaviors(ItemBehaviors.fromObj(pack, path, id, ResourceConfigUtils.get(section, "behavior", "behaviors"))) + .settings(Optional.ofNullable(ResourceConfigUtils.get(section, "settings")) + .map(map -> ItemSettings.fromMap(MiscUtils.castToMap(map, true))) + .map(it -> isVanillaItem ? it.canPlaceRelatedVanillaBlock(true) : it) + .orElse(ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem))) + .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) + .build(); + + addCustomItem(customItem); + + // 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; + } + if (customModelData <= 0 && itemModelKey == null) { + throw new LocalizedResourceConfigException("warning.config.item.missing_model_id"); + } + + ItemModel model = ItemModels.fromMap(modelSection); + for (ModelGeneration generation : model.modelsToGenerate()) { + prepareModelGeneration(generation); + } + + TreeSet legacyOverridesModels = null; + if (Config.packMinVersion() < 21.4f) { + legacyOverridesModels = new TreeSet<>(); + if (section.containsKey("legacy-model")) { + + } else { + processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, material, customModelData); + if (legacyOverridesModels.isEmpty()) { + // TODO give warnings + plugin.debug(() -> "Can't convert " + id + "'s model to legacy format."); + } + } + } + + // use custom model data + if (customModelData != 0) { + // use custom model data + // check conflict + Map conflict = cmdConflictChecker.computeIfAbsent(material, k -> new HashMap<>()); + if (conflict.containsKey(customModelData)) { + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(customModelData), conflict.get(customModelData).toString()); + } + if (customModelData > 16_777_216) { + throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); + } + conflict.put(customModelData, id); + // Parse models + if (Config.packMaxVersion() >= 21.4f) { + TreeMap map = modernOverrides.computeIfAbsent(material, k -> new TreeMap<>()); + map.put(customModelData, model); + } + if (Config.packMinVersion() < 21.4f) { + TreeSet lom = legacyOverrides.computeIfAbsent(material, k -> new TreeSet<>()); + lom.addAll(legacyOverridesModels); + } + } + + // use item model + if (itemModelKey != null) { + if (Config.packMaxVersion() >= 21.4f) { + modernItemModels1_21_4.put(itemModelKey, model); + } + if (Config.packMaxVersion() >= 21.2f && Config.packMinVersion() < 21.4f) { + modernItemModels1_21_2.put(itemModelKey, legacyOverridesModels); + } + } + } + } + private void registerFunctions() { registerDataFunction((obj) -> { Map data = MiscUtils.castToMap(obj, false); @@ -258,4 +473,193 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl }, "equippable"); } } + + protected void processModelRecursively( + ItemModel currentModel, + Map accumulatedPredicates, + Collection resultList, + Key materialId, + int customModelData + ) { + if (currentModel instanceof ConditionItemModel conditionModel) { + handleConditionModel(conditionModel, accumulatedPredicates, resultList, materialId, customModelData); + } else if (currentModel instanceof RangeDispatchItemModel rangeModel) { + handleRangeModel(rangeModel, accumulatedPredicates, resultList, materialId, customModelData); + } else if (currentModel instanceof SelectItemModel selectModel) { + handleSelectModel(selectModel, accumulatedPredicates, resultList, materialId, customModelData); + } else if (currentModel instanceof BaseItemModel baseModel) { + resultList.add(new LegacyOverridesModel( + new LinkedHashMap<>(accumulatedPredicates), + baseModel.path(), + customModelData + )); + } else if (currentModel instanceof SpecialItemModel specialModel) { + resultList.add(new LegacyOverridesModel( + new LinkedHashMap<>(accumulatedPredicates), + specialModel.base(), + customModelData + )); + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void handleConditionModel( + ConditionItemModel model, + Map parentPredicates, + Collection resultList, + Key materialId, + int customModelData + ) { + if (model.property() instanceof LegacyModelPredicate predicate) { + String predicateId = predicate.legacyPredicateId(materialId); + Map truePredicates = mergePredicates( + parentPredicates, + predicateId, + predicate.toLegacyValue(true) + ); + processModelRecursively( + model.onTrue(), + truePredicates, + resultList, + materialId, + customModelData + ); + Map falsePredicates = mergePredicates( + parentPredicates, + predicateId, + predicate.toLegacyValue(false) + ); + processModelRecursively( + model.onFalse(), + falsePredicates, + resultList, + materialId, + customModelData + ); + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void handleRangeModel( + RangeDispatchItemModel model, + Map parentPredicates, + Collection resultList, + Key materialId, + int customModelData + ) { + if (model.property() instanceof LegacyModelPredicate predicate) { + String predicateId = predicate.legacyPredicateId(materialId); + for (Map.Entry entry : model.entries().entrySet()) { + Map merged = mergePredicates( + parentPredicates, + predicateId, + predicate.toLegacyValue(entry.getKey()) + ); + processModelRecursively( + entry.getValue(), + merged, + resultList, + materialId, + customModelData + ); + } + if (model.fallBack() != null) { + Map merged = mergePredicates( + parentPredicates, + predicateId, + predicate.toLegacyValue(0f) + ); + processModelRecursively( + model.fallBack(), + merged, + resultList, + materialId, + customModelData + ); + } + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void handleSelectModel( + SelectItemModel model, + Map parentPredicates, + Collection resultList, + Key materialId, + int customModelData + ) { + if (model.property() instanceof LegacyModelPredicate predicate) { + String predicateId = predicate.legacyPredicateId(materialId); + for (Map.Entry>, ItemModel> entry : model.whenMap().entrySet()) { + List cases = entry.getKey().fallbackOrMapPrimary(List::of); + for (String caseValue : cases) { + Number legacyValue = predicate.toLegacyValue(caseValue); + if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { + if (legacyValue.floatValue() > 1f) { + continue; + } + } + Map merged = mergePredicates( + parentPredicates, + predicateId, + legacyValue + ); + // Additional check for crossbow + if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { + merged = mergePredicates( + merged, + "charged", + 1 + ); + } + processModelRecursively( + entry.getValue(), + merged, + resultList, + materialId, + customModelData + ); + } + } + // Additional check for crossbow + if (model.fallBack() != null) { + if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { + processModelRecursively( + model.fallBack(), + mergePredicates( + parentPredicates, + "charged", + 0 + ), + resultList, + materialId, + customModelData + ); + } else if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { + processModelRecursively( + model.fallBack(), + mergePredicates( + parentPredicates, + "trim_type", + 0f + ), + resultList, + materialId, + customModelData + ); + } + } + } + } + + private Map mergePredicates( + Map existing, + String newKey, + Number newValue + ) { + Map merged = new LinkedHashMap<>(existing); + if (newKey == null) return merged; + merged.put(newKey, newValue); + return merged; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index 8f92db2d7..783506671 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; @@ -17,6 +18,8 @@ public interface CustomItem extends BuildableItem { Key id(); + Holder idHolder(); + Key material(); NetworkItemDataProcessor[] networkItemDataProcessors(); @@ -49,7 +52,7 @@ public interface CustomItem extends BuildableItem { List behaviors(); interface Builder { - Builder id(Key id); + Builder id(Holder id); Builder material(Key material); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index 05c1c2f78..de7c072ac 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -28,6 +28,7 @@ public class ItemKeys { public static final Key BUCKET = Key.of("minecraft:bucket"); public static final Key BONE_MEAL = Key.of("minecraft:bone_meal"); public static final Key ENCHANTED_BOOK = Key.of("minecraft:enchanted_book"); + public static final Key TOTEM_OF_UNDYING = Key.of("minecraft:totem_of_undying"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE 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 a5320e710..655270533 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 @@ -27,7 +27,7 @@ public interface ItemManager extends Manageable, ModelGenerator { Map modernItemModels1_21_4(); - Map> modernItemModels1_21_2(); + Map> modernItemModels1_21_2(); Collection vanillaItems(); @@ -67,6 +67,8 @@ public interface ItemManager extends Manageable, ModelGenerator { return getVanillaItem(key); } + boolean addCustomItem(CustomItem customItem); + List> tagToItems(Key tag); List> tagToVanillaItems(Key tag); @@ -80,4 +82,6 @@ public interface ItemManager extends Manageable, ModelGenerator { Collection cachedSuggestions(); Collection cachedTotemSuggestions(); + + boolean isVanillaItem(Key item); } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java index 09d5eadc1..28c122108 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java @@ -7,10 +7,13 @@ import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; import java.util.Map; public class ItemBehaviors { @@ -32,4 +35,23 @@ public class ItemBehaviors { } return factory.create(pack, path, id, map); } + + public static List fromList(Pack pack, Path path, Key id, List> list) { + List behaviors = new ArrayList<>(list.size()); + for (Map map : list) { + behaviors.add(fromMap(pack, path, id, map)); + } + return behaviors; + } + + @SuppressWarnings("unchecked") + public static List fromObj(Pack pack, Path path, Key id, Object behaviorObj) { + if (behaviorObj instanceof Map) { + return List.of(fromMap(pack, path, id, MiscUtils.castToMap(behaviorObj, false))); + } else if (behaviorObj instanceof List) { + return fromList(pack, path, id, (List>) behaviorObj); + } else { + return List.of(); + } + } } \ 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 e5809d59f..4cd03a29b 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 @@ -43,6 +43,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.nio.file.*; +import java.nio.file.FileSystem; import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.function.BiConsumer; @@ -918,9 +919,9 @@ public abstract class AbstractPackManager implements PackManager { if (Config.packMinVersion() > 21.39f) return; // 此段代码生成1.21.2专用的item model文件,情况非常复杂! - for (Map.Entry> entry : this.plugin.itemManager().modernItemModels1_21_2().entrySet()) { + for (Map.Entry> entry : this.plugin.itemManager().modernItemModels1_21_2().entrySet()) { Key itemModelPath = entry.getKey(); - List legacyOverridesModels = entry.getValue(); + TreeSet legacyOverridesModels = entry.getValue(); // 检测item model合法性 if (PRESET_MODERN_MODELS_ITEM.containsKey(itemModelPath) || PRESET_LEGACY_MODELS_ITEM.containsKey(itemModelPath)) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java index 43c24a864..cf8c72a11 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathPatternMatcher.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.pack.conflict.matcher; import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.ContextKey; import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.util.CharacterUtils; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/HasComponentConditionProperty.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/HasComponentConditionProperty.java index 7da522b40..660d7a264 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/HasComponentConditionProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/HasComponentConditionProperty.java @@ -16,6 +16,14 @@ public class HasComponentConditionProperty implements ConditionProperty { this.ignoreDefault = ignoreDefault; } + public String component() { + return component; + } + + public boolean ignoreDefault() { + return ignoreDefault; + } + @Override public Key type() { return ConditionProperties.HAS_COMPONENT; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java index 208adef5e..0de7bd17f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java @@ -1,14 +1,9 @@ package net.momirealms.craftengine.core.util; import java.io.IOException; -import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; public class FileUtils { From 11ab46bc8e9a8d1925b0cc969029d0f2ea937a5b Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 18 May 2025 18:00:15 +0800 Subject: [PATCH 07/89] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 4 + .../src/main/resources/translations/zh_cn.yml | 1 + .../bukkit/item/BukkitItemManager.java | 3 +- .../core/item/AbstractItemManager.java | 88 ++++++++++++++----- .../core/pack/model/LegacyItemModel.java | 43 +++++++++ 5 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 2a6d99bac..c33a67965 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -145,14 +145,18 @@ warning.config.item.duplicate: "Issue found in file - Duplicated warning.config.item.settings.unknown: "Issue found in file - The item '' is using an unknown setting type ''." warning.config.item.missing_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.invalid_custom_model_data: "Issue found in file - The item '' is using a negative custom model data '' which is invalid." warning.config.item.bad_custom_model_data: "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.missing_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." +warning.config.item.missing_model: "Issue found in file - The item '' is missing the required 'model' section for 1.21.4+ resource pack support." warning.config.item.behavior.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for its item behavior." warning.config.item.behavior.invalid_type: "Issue found in file - The item '' is using an invalid item behavior type ''." warning.config.item.behavior.block.missing_block: "Issue found in file - The item '' is missing the required 'block' argument for 'block_item' behavior." warning.config.item.behavior.furniture.missing_furniture: "Issue found in file - The item '' is missing the required 'furniture' argument for 'furniture_item' behavior." warning.config.item.behavior.liquid_collision.missing_block: "Issue found in file - The item '' is missing the required 'block' argument for 'liquid_collision_block_item' behavior." +warning.config.item.legacy_model.missing_path: "Issue found in file - The item '' is missing the require 'path' argument for legacy-model." +warning.config.item.legacy_model.cannot_convert: "Issue found in file - Cannot convert 1.21.4+ items to legacy format for item ''. Please manually create 'legacy-model' section for this item." warning.config.item.model.invalid_type: "Issue found in file - The item '' is using an invalid model type ''." warning.config.item.model.tint.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for tint." warning.config.item.model.tint.invalid_type: "Issue found in file - The item '' is using an invalid tint type ''." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index f0f71519f..ea6b6e9b8 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -143,6 +143,7 @@ warning.config.item.duplicate: "在文件 发现问题 - 重复 warning.config.item.settings.unknown: "在文件 发现问题 - 物品 '' 使用了未知的设置类型 ''" warning.config.item.missing_material: "在文件 发现问题 - 物品 '' 缺少必需的 'material' 参数" warning.config.item.invalid_material: "在文件 发现问题 - 物品 '' 使用了无效的材料类型 ''" +warning.config.item.invalid_custom_model_data: "在文件 发现问题 - 物品 '' 使用了无效的负数模型值 ''." warning.config.item.bad_custom_model_data: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 数值过大 建议使用小于 16,777,216 的值" warning.config.item.custom_model_data_conflict: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 已被物品 '' 占用" warning.config.item.missing_model_id: "在文件 发现问题 - 物品 '' 缺少必需的 'custom-model-data' 或 'item-model' 参数" 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 d7fb27b85..175a35013 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 @@ -56,7 +56,6 @@ public class BukkitItemManager extends AbstractItemManager { private final DebugStickListener debugStickListener; private final ArmorEventListener armorEventListener; - public BukkitItemManager(BukkitCraftEngine plugin) { super(plugin); instance = this; @@ -131,7 +130,7 @@ public class BukkitItemManager extends AbstractItemManager { @Override public Optional> getVanillaItem(Key key) { - Material material = Registry.MATERIAL.get(Objects.requireNonNull(NamespacedKey.fromString(key.toString()))); + Material material = Registry.MATERIAL.get(KeyUtils.toNamespacedKey(key)); if (material == null) { return Optional.empty(); } 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 8719601b8..d0dd2f51c 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 @@ -17,6 +17,7 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +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; @@ -270,7 +271,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl @Override public void parseSection(Pack pack, Path path, Key id, Map section) { - if (customItems.containsKey(id)) { + if (AbstractItemManager.this.customItems.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.item.duplicate"); } @@ -282,7 +283,12 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl boolean isVanillaItem = isVanillaItem(id); Key material = Key.from(isVanillaItem ? id.value() : ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("material"), "warning.config.item.missing_material")); int customModelData = ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data"); - // TODO give warnings if negative + if (customModelData < 0) { + throw new LocalizedResourceConfigException("warning.config.item.invalid_custom_model_data", String.valueOf(customModelData)); + } + if (customModelData > 16_777_216) { + throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); + } Key itemModelKey = null; @@ -306,7 +312,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } - if (hasItemModelSection) { + if (hasItemModelSection && VersionHelper.isOrAbove1_21_2()) { itemModelKey = Key.from(section.get("item-model").toString()); itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); } @@ -338,28 +344,67 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // 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) { + Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); + if (modelSection == null && legacyModelSection == null) { return; } - if (customModelData <= 0 && itemModelKey == null) { + // 如果设置了model,但是没有模型值? + if (customModelData == 0 && itemModelKey == null) { throw new LocalizedResourceConfigException("warning.config.item.missing_model_id"); } - - ItemModel model = ItemModels.fromMap(modelSection); - for (ModelGeneration generation : model.modelsToGenerate()) { - prepareModelGeneration(generation); + // 1.21.4+必须要配置model区域 + if (Config.packMaxVersion() >= 21.4f && modelSection == null) { + throw new LocalizedResourceConfigException("warning.config.item.missing_model"); } + // 新版格式 + ItemModel modernModel = null; + // 旧版格式 TreeSet legacyOverridesModels = null; - if (Config.packMinVersion() < 21.4f) { - legacyOverridesModels = new TreeSet<>(); - if (section.containsKey("legacy-model")) { + if (Config.packMaxVersion() >= 21.4f) { + modernModel = ItemModels.fromMap(modelSection); + for (ModelGeneration generation : modernModel.modelsToGenerate()) { + prepareModelGeneration(generation); + } + // 如果最低支持版本低于1.21.4,则需要准备旧版overrides模型 + if (Config.packMinVersion() < 21.4f) { + // 如果有旧版格式,就用旧版 + if (legacyModelSection != null) { + LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection); + for (ModelGeneration generation : legacyItemModel.modelsToGenerate()) { + prepareModelGeneration(generation); + } + legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides()); + } else { + // 否则把新版格式并转换为旧版 + legacyOverridesModels = new TreeSet<>(); + processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, material, customModelData); + if (legacyOverridesModels.isEmpty()) { + TranslationManager.instance().log("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString()); + } + } + } + } + // 最高支持版本不超过1.21.4,所以新版model格式为非必需 + else { + // 如果有旧版格式,就用旧版 + if (legacyModelSection != null) { + LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection); + for (ModelGeneration generation : legacyItemModel.modelsToGenerate()) { + prepareModelGeneration(generation); + } + legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides()); } else { + // 否则读新版格式并转换为旧版 + ItemModel model = ItemModels.fromMap(modelSection); + for (ModelGeneration generation : model.modelsToGenerate()) { + prepareModelGeneration(generation); + } + legacyOverridesModels = new TreeSet<>(); processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, material, customModelData); if (legacyOverridesModels.isEmpty()) { - // TODO give warnings - plugin.debug(() -> "Can't convert " + id + "'s model to legacy format."); + TranslationManager.instance().log("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString()); } } } @@ -372,16 +417,13 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl if (conflict.containsKey(customModelData)) { throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(customModelData), conflict.get(customModelData).toString()); } - if (customModelData > 16_777_216) { - throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); - } conflict.put(customModelData, id); // Parse models - if (Config.packMaxVersion() >= 21.4f) { + if (Config.packMaxVersion() >= 21.4f && modernModel != null) { TreeMap map = modernOverrides.computeIfAbsent(material, k -> new TreeMap<>()); - map.put(customModelData, model); + map.put(customModelData, modernModel); } - if (Config.packMinVersion() < 21.4f) { + if (Config.packMinVersion() < 21.4f && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { TreeSet lom = legacyOverrides.computeIfAbsent(material, k -> new TreeSet<>()); lom.addAll(legacyOverridesModels); } @@ -389,10 +431,10 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // use item model if (itemModelKey != null) { - if (Config.packMaxVersion() >= 21.4f) { - modernItemModels1_21_4.put(itemModelKey, model); + if (Config.packMaxVersion() >= 21.4f && modernModel != null) { + modernItemModels1_21_4.put(itemModelKey, modernModel); } - if (Config.packMaxVersion() >= 21.2f && Config.packMinVersion() < 21.4f) { + if (Config.packMaxVersion() >= 21.2f && Config.packMinVersion() < 21.4f && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { modernItemModels1_21_2.put(itemModelKey, legacyOverridesModels); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java new file mode 100644 index 000000000..81db56d2e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java @@ -0,0 +1,43 @@ +package net.momirealms.craftengine.core.pack.model; + +import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; + +public class LegacyItemModel { + private final List modelsToGenerate; + private final String path; + private final List overrides; + + public LegacyItemModel(String path, List overrides, List modelsToGenerate) { + this.modelsToGenerate = modelsToGenerate; + this.path = path; + this.overrides = overrides; + } + + public List modelsToGenerate() { + return modelsToGenerate; + } + + public List overrides() { + return overrides; + } + + public String path() { + return path; + } + + public static LegacyItemModel fromMap(Map legacyModel) { + String legacyModelPath = ResourceConfigUtils.requireNonEmptyStringOrThrow(legacyModel.get("path"), "warning.config.item.legacy_model.missing_path"); + Map generation = MiscUtils.castToMap(legacyModel.get("generation"), true); + ModelGeneration modelGeneration = null; + if (generation != null) { + modelGeneration = ModelGeneration.of(Key.of(legacyModelPath), generation); + } + LegacyOverridesModel legacyOverridesModel = new LegacyOverridesModel(); + } +} From 753ce7e05ae2be411c416f2614868b583fa38e67 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 18 May 2025 19:44:58 +0800 Subject: [PATCH 08/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=89=8B=E5=8A=A8?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E6=97=A7=E7=89=88=E6=A8=A1=E5=9E=8B=E8=A6=86?= =?UTF-8?q?=E5=86=99=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 2 + .../src/main/resources/translations/zh_cn.yml | 29 ++++++-- .../bukkit/block/BukkitBlockManager.java | 30 +++++---- .../bukkit/item/BukkitItemManager.java | 1 - .../core/item/AbstractItemManager.java | 66 ++++++++----------- .../core/pack/AbstractPackManager.java | 4 +- .../core/pack/model/LegacyItemModel.java | 36 ++++++++-- .../core/pack/model/LegacyOverridesModel.java | 6 +- .../core/util/IntIdentityList.java | 4 +- gradle.properties | 6 +- 10 files changed, 111 insertions(+), 73 deletions(-) diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index c33a67965..ba193d14e 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -156,6 +156,8 @@ warning.config.item.behavior.block.missing_block: "Issue found in file < warning.config.item.behavior.furniture.missing_furniture: "Issue found in file - The item '' is missing the required 'furniture' argument for 'furniture_item' behavior." warning.config.item.behavior.liquid_collision.missing_block: "Issue found in file - The item '' is missing the required 'block' argument for 'liquid_collision_block_item' behavior." warning.config.item.legacy_model.missing_path: "Issue found in file - The item '' is missing the require 'path' argument for legacy-model." +warning.config.item.legacy_model.overrides.missing_path: "Issue found in file - The item '' is missing the require 'path' argument for legacy-model overrides." +warning.config.item.legacy_model.overrides.missing_predicate: "Issue found in file - The item '' is missing the require 'predicate' argument for legacy-model overrides." warning.config.item.legacy_model.cannot_convert: "Issue found in file - Cannot convert 1.21.4+ items to legacy format for item ''. Please manually create 'legacy-model' section for this item." warning.config.item.model.invalid_type: "Issue found in file - The item '' is using an invalid model type ''." warning.config.item.model.tint.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for tint." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index ea6b6e9b8..9b35e58a3 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -90,8 +90,10 @@ warning.config.condition.match_block_property.missing_properties: "在 warning.config.condition.match_item.missing_id: "在文件 发现问题 - 配置项 '' 缺少 'match_item' 条件所需的 'id' 参数" warning.config.condition.table_bonus.missing_enchantment: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'enchantment' 参数" warning.config.condition.table_bonus.missing_chances: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'chances' 参数" - - +warning.config.condition.permission.missing_permission: "在文件 中发现问题 - 配置项 '' 缺少 'permission' 条件必需的 'permission' 参数" +warning.config.condition.equals.missing_value1: "在文件 中发现问题 - 配置项 '' 缺少 'equals' 条件必需的 'value1' 参数" +warning.config.condition.equals.missing_value2: "在文件 中发现问题 - 配置项 '' 缺少 'equals' 条件必需的 'value2' 参数" +warning.config.condition.expression.missing_expression: "在文件 中发现问题 - 配置项 '' 缺少 'expression' 条件必需的 'expression' 参数" warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" warning.config.image.duplicate: "在文件 发现问题 - 重复的图片配置 '' 请检查其他文件中是否存在相同配置" warning.config.image.missing_height: "在文件 发现问题 - 图片 '' 缺少必需的 'height' 参数" @@ -147,11 +149,16 @@ warning.config.item.invalid_custom_model_data: "在文件 发现 warning.config.item.bad_custom_model_data: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 数值过大 建议使用小于 16,777,216 的值" warning.config.item.custom_model_data_conflict: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 已被物品 '' 占用" warning.config.item.missing_model_id: "在文件 发现问题 - 物品 '' 缺少必需的 'custom-model-data' 或 'item-model' 参数" +warning.config.item.missing_model: "在文件 中发现问题 - 物品 '' 缺少支持 1.21.4+ 资源包必需的 'model' 配置项" warning.config.item.behavior.missing_type: "在文件 发现问题 - 物品 '' 的行为配置缺少必需的 'type' 参数" warning.config.item.behavior.invalid_type: "在文件 发现问题 - 物品 '' 使用了无效的行为类型 ''" warning.config.item.behavior.block.missing_block: "在文件 发现问题 - 物品 '' 的 'block_item' 行为缺少必需的 'block' 参数" warning.config.item.behavior.furniture.missing_furniture: "在文件 发现问题 - 物品 '' 的 'furniture_item' 行为缺少必需的 'furniture' 参数" warning.config.item.behavior.liquid_collision.missing_block: "在文件 发现问题 - 物品 '' 的 'liquid_collision_block_item' 行为缺少必需的 'block' 参数" +warning.config.item.legacy_model.missing_path: "在文件 中发现问题 - 物品 '' 的旧版模型(legacy-model)缺少必需的 'path' 参数" +warning.config.item.legacy_model.overrides.missing_path: "在文件 中发现问题 - 物品 '' 的旧版模型覆写规则(overrides)缺少必需的 'path' 参数" +warning.config.item.legacy_model.overrides.missing_predicate: "在文件 中发现问题 - 物品 '' 的旧版模型覆写规则(overrides)缺少必需的 'predicate' 参数" +warning.config.item.legacy_model.cannot_convert: "在文件 中发现问题 - 无法将物品 '' 自动转换为旧版格式,请手动为此物品创建 'legacy-model' 配置项" warning.config.item.model.invalid_type: "在文件 发现问题 - 物品 '' 使用了无效的模型类型 ''" warning.config.item.model.tint.missing_type: "在文件 发现问题 - 物品 '' 的染色配置缺少必需的 'type' 参数" warning.config.item.model.tint.invalid_type: "在文件 发现问题 - 物品 '' 使用了无效的染色类型 ''" @@ -298,10 +305,18 @@ warning.config.conflict_matcher.all_of.missing_terms: "在 config.yml warning.config.conflict_matcher.any_of.missing_terms: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 任一匹配器缺少必需的 'terms' 参数" warning.config.conflict_resolution.missing_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案缺少必需的 'type' 参数" warning.config.conflict_resolution.invalid_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案使用了无效类型 ''" -warning.config.event.missing_trigger: "Issue found in file - The config '' is missing the required 'on' argument for event triggers." -warning.config.event.invalid_trigger: "Issue found in file - The config '' is using an invalid event trigger ''." +warning.config.event.missing_trigger: "在文件 中发现问题 - 配置项 '' 缺少事件触发器必需的 'on' 参数" +warning.config.event.invalid_trigger: "在文件 中发现问题 - 配置项 '' 使用了无效的事件触发器 ''" warning.config.event.condition.missing_type: "在文件 - 配置项 '' 的事件条件缺少 'type' 参数" warning.config.event.condition.invalid_type: "在文件 - 配置项 '' 使用了无效的事件条件类型 ''" -warning.config.function.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for function." -warning.config.function.invalid_type: "Issue found in file - The config '' is using an invalid function type ''." -warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." \ No newline at end of file +warning.config.function.missing_type: "在文件 中发现问题 - 配置项 '' 缺少函数必需的 'type' 参数" +warning.config.function.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的函数类型 ''" +warning.config.function.command.missing_command: "在文件 中发现问题 - 配置项 '' 缺少 'command' 函数必需的 'command' 参数" +warning.config.function.actionbar.missing_actionbar: "在文件 中发现问题 - 配置项 '' 缺少 'actionbar' 函数必需的 'actionbar' 参数" +warning.config.function.message.missing_message: "在文件 中发现问题 - 配置项 '' 缺少 'message' 函数必需的 'message' 参数" +warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" +warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" +warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" +warning.config.resource_pack.item_model.conflict.vanilla: "无法为 '' 生成物品模型,因为该物品模型已被原版物品占用" +warning.config.resource_pack.item_model.already_exist: "无法为 '' 生成物品模型,因为文件 '' 已存在" +warning.config.resource_pack.model.generation.already_exist: "无法生成模型,因为模型文件 '' 已存在" \ 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 7d77e45fe..7a039f9b2 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 @@ -7,6 +7,10 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import dev.dejvokep.boostedyaml.YamlDocument; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; @@ -55,11 +59,11 @@ public class BukkitBlockManager extends AbstractBlockManager { 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<>(); + private final Map tempRegistryIdConflictMap = new Int2ObjectOpenHashMap<>(); // A temporary map that converts the custom block registered on the server to the vanilla block ID. - private final Map tempBlockAppearanceConvertor = new HashMap<>(); + private final Map tempBlockAppearanceConvertor = new Int2IntOpenHashMap(); // A temporary map that stores the model path of a certain vanilla block state - private final Map tempVanillaBlockStateModels = new HashMap<>(); + private final Map tempVanillaBlockStateModels = new Int2ObjectOpenHashMap<>(); // The total amount of blocks registered private int customBlockCount; @@ -79,10 +83,10 @@ public class BukkitBlockManager extends AbstractBlockManager { private ImmutableSet affectedSoundBlocks; private ImmutableMap soundMapper; // A list to record the order of registration - private List blockRegisterOrder = new ArrayList<>(); + private List blockRegisterOrder = new ObjectArrayList<>(); // a reverted mapper - private final Map> appearanceToRealState = new HashMap<>(); + private final Map> appearanceToRealState = new Int2ObjectOpenHashMap<>(); // Used to store override information of json files private final Map> blockStateOverrides = new HashMap<>(); // for mod, real block id -> state models @@ -232,11 +236,11 @@ public class BukkitBlockManager extends AbstractBlockManager { } public ImmutableMap> blockAppearanceArranger() { - return blockAppearanceArranger; + return this.blockAppearanceArranger; } public ImmutableMap> realBlockArranger() { - return realBlockArranger; + return this.realBlockArranger; } @Nullable @@ -275,7 +279,7 @@ public class BukkitBlockManager extends AbstractBlockManager { try { Class modClass = ReflectionUtils.getClazz(CraftEngine.MOD_CLASS); Field amountField = ReflectionUtils.getDeclaredField(modClass, "vanillaRegistrySize"); - vanillaStateCount = (int) amountField.get(null); + vanillaStateCount = amountField.getInt(null); } catch (Exception e) { vanillaStateCount = RegistryUtils.currentBlockRegistrySize(); plugin.logger().severe("Fatal error", e); @@ -481,7 +485,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } 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()); + appearanceToRealState.computeIfAbsent(state.vanillaBlockState().registryId(), k -> new IntArrayList()).add(state.customBlockState().registryId()); } BukkitBlockManager.this.byId.put(id, block); @@ -649,9 +653,9 @@ public class BukkitBlockManager extends AbstractBlockManager { YamlDocument mappings = Config.instance().loadOrCreateYamlData("mappings.yml"); Map blockStateMappings = loadBlockStateMappings(mappings); this.validateBlockStateMappings(mappingFile, blockStateMappings); - Map stateMap = new HashMap<>(); + Map stateMap = new Int2ObjectOpenHashMap<>(); Map blockTypeCounter = new LinkedHashMap<>(); - Map appearanceMapper = new HashMap<>(); + Map appearanceMapper = new Int2IntOpenHashMap(); Map> appearanceArranger = new HashMap<>(); for (Map.Entry entry : blockStateMappings.entrySet()) { this.processBlockStateMapping(mappingFile, entry, stateMap, blockTypeCounter, appearanceMapper, appearanceArranger); @@ -727,7 +731,7 @@ public class BukkitBlockManager extends AbstractBlockManager { counter.compute(key, (k, count) -> count == null ? 1 : count + 1); stateMap.put(beforeId, entry.getKey()); stateMap.put(afterId, entry.getValue()); - arranger.computeIfAbsent(key, (k) -> new ArrayList<>()).add(beforeId); + arranger.computeIfAbsent(key, (k) -> new IntArrayList()).add(beforeId); } else { String previousState = stateMap.get(previous); plugin.logger().warn(mappingFile, "Duplicate entry: '" + previousState + "' equals '" + entry.getKey() + "'"); @@ -776,7 +780,7 @@ public class BukkitBlockManager extends AbstractBlockManager { Object clientSideBlock = getBlockFromRegistry(createResourceLocation(clientSideBlockType)); int amount = blockWithCount.getValue(); - List stateIds = new ArrayList<>(); + List stateIds = new IntArrayList(); for (int i = 0; i < amount; i++) { Key realBlockKey = createRealBlockKey(clientSideBlockType, i); 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 175a35013..b961ac758 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 @@ -36,7 +36,6 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; 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 d0dd2f51c..ce2e61986 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 @@ -258,6 +258,16 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl public class ItemParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; + private static final float VERSION_1_21_2 = 21.2f; + private static final float VERSION_1_21_4 = 21.4f; + + private boolean isModernFormatRequired() { + return Config.packMaxVersion() >= VERSION_1_21_4; + } + + private boolean needsLegacyCompatibility() { + return Config.packMinVersion() < VERSION_1_21_4; + } @Override public String[] sectionId() { @@ -338,7 +348,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // add it to category if (section.containsKey("category")) { - plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); + AbstractItemManager.this.plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); } // model part, can be null @@ -353,7 +363,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl throw new LocalizedResourceConfigException("warning.config.item.missing_model_id"); } // 1.21.4+必须要配置model区域 - if (Config.packMaxVersion() >= 21.4f && modelSection == null) { + if (isModernFormatRequired() && modelSection == null) { throw new LocalizedResourceConfigException("warning.config.item.missing_model"); } @@ -362,47 +372,22 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // 旧版格式 TreeSet legacyOverridesModels = null; - if (Config.packMaxVersion() >= 21.4f) { + if (isModernFormatRequired() || (needsLegacyCompatibility() && legacyModelSection == null)) { modernModel = ItemModels.fromMap(modelSection); for (ModelGeneration generation : modernModel.modelsToGenerate()) { prepareModelGeneration(generation); } - // 如果最低支持版本低于1.21.4,则需要准备旧版overrides模型 - if (Config.packMinVersion() < 21.4f) { - // 如果有旧版格式,就用旧版 - if (legacyModelSection != null) { - LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection); - for (ModelGeneration generation : legacyItemModel.modelsToGenerate()) { - prepareModelGeneration(generation); - } - legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides()); - } else { - // 否则把新版格式并转换为旧版 - legacyOverridesModels = new TreeSet<>(); - processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, material, customModelData); - if (legacyOverridesModels.isEmpty()) { - TranslationManager.instance().log("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString()); - } - } - } } - // 最高支持版本不超过1.21.4,所以新版model格式为非必需 - else { - // 如果有旧版格式,就用旧版 + if (needsLegacyCompatibility()) { if (legacyModelSection != null) { - LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection); + LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection, customModelData); for (ModelGeneration generation : legacyItemModel.modelsToGenerate()) { prepareModelGeneration(generation); } legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides()); } else { - // 否则读新版格式并转换为旧版 - ItemModel model = ItemModels.fromMap(modelSection); - for (ModelGeneration generation : model.modelsToGenerate()) { - prepareModelGeneration(generation); - } legacyOverridesModels = new TreeSet<>(); - processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, material, customModelData); + processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, material, customModelData); if (legacyOverridesModels.isEmpty()) { TranslationManager.instance().log("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString()); } @@ -413,29 +398,30 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl if (customModelData != 0) { // use custom model data // check conflict - Map conflict = cmdConflictChecker.computeIfAbsent(material, k -> new HashMap<>()); + Map conflict = AbstractItemManager.this.cmdConflictChecker.computeIfAbsent(material, k -> new HashMap<>()); if (conflict.containsKey(customModelData)) { throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(customModelData), conflict.get(customModelData).toString()); } conflict.put(customModelData, id); // Parse models - if (Config.packMaxVersion() >= 21.4f && modernModel != null) { - TreeMap map = modernOverrides.computeIfAbsent(material, k -> new TreeMap<>()); + if (isModernFormatRequired() && modernModel != null) { + TreeMap map = AbstractItemManager.this.modernOverrides.computeIfAbsent(material, k -> new TreeMap<>()); map.put(customModelData, modernModel); } - if (Config.packMinVersion() < 21.4f && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { - TreeSet lom = legacyOverrides.computeIfAbsent(material, k -> new TreeSet<>()); + if (needsLegacyCompatibility() && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { + TreeSet lom = AbstractItemManager.this.legacyOverrides.computeIfAbsent(material, k -> new TreeSet<>()); lom.addAll(legacyOverridesModels); } } // use item model if (itemModelKey != null) { - if (Config.packMaxVersion() >= 21.4f && modernModel != null) { - modernItemModels1_21_4.put(itemModelKey, modernModel); + if (isModernFormatRequired() && modernModel != null) { + AbstractItemManager.this.modernItemModels1_21_4.put(itemModelKey, modernModel); } - if (Config.packMaxVersion() >= 21.2f && Config.packMinVersion() < 21.4f && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { - modernItemModels1_21_2.put(itemModelKey, legacyOverridesModels); + if (Config.packMaxVersion() >= VERSION_1_21_2 && needsLegacyCompatibility() && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { + TreeSet lom = AbstractItemManager.this.modernItemModels1_21_2.computeIfAbsent(itemModelKey, k -> new TreeSet<>()); + lom.addAll(legacyOverridesModels); } } } 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 4cd03a29b..a91f3b95d 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 @@ -428,8 +428,10 @@ public abstract class AbstractPackManager implements PackManager { Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); for (Pack pack : loadedPacks()) { if (!pack.enabled()) continue; + Path configurationFolderPath = pack.configurationFolder(); + if (!Files.isDirectory(configurationFolderPath)) continue; try { - Files.walkFileTree(pack.configurationFolder(), new SimpleFileVisitor<>() { + Files.walkFileTree(configurationFolderPath, new SimpleFileVisitor<>() { @Override public @NotNull FileVisitResult visitFile(@NotNull Path path, @NotNull BasicFileAttributes attrs) { if (Files.isRegularFile(path) && path.getFileName().toString().endsWith(".yml")) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java index 81db56d2e..925b2bb87 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java @@ -1,10 +1,13 @@ package net.momirealms.craftengine.core.pack.model; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,13 +34,38 @@ public class LegacyItemModel { return path; } - public static LegacyItemModel fromMap(Map legacyModel) { + @SuppressWarnings("unchecked") + public static LegacyItemModel fromMap(Map legacyModel, int customModelData) { String legacyModelPath = ResourceConfigUtils.requireNonEmptyStringOrThrow(legacyModel.get("path"), "warning.config.item.legacy_model.missing_path"); Map generation = MiscUtils.castToMap(legacyModel.get("generation"), true); - ModelGeneration modelGeneration = null; + ModelGeneration baseModelGeneration = null; if (generation != null) { - modelGeneration = ModelGeneration.of(Key.of(legacyModelPath), generation); + baseModelGeneration = ModelGeneration.of(Key.of(legacyModelPath), generation); + } + List> overrides = (List>) legacyModel.get("overrides"); + if (overrides != null) { + List modelGenerations = new ArrayList<>(); + List legacyOverridesModels = new ArrayList<>(); + if (baseModelGeneration != null) modelGenerations.add(baseModelGeneration); + legacyOverridesModels.add(new LegacyOverridesModel(new HashMap<>(), legacyModelPath, customModelData)); + for (Map override : overrides) { + String overrideModelPath = ResourceConfigUtils.requireNonEmptyStringOrThrow(override.get("path"), () -> new LocalizedResourceConfigException("warning.config.item.legacy_model.overrides.missing_path")); + Map predicate = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(override.get("predicate"), "warning.config.item.legacy_model.overrides.missing_predicate"), false); + if (predicate.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.item.legacy_model.overrides.missing_predicate"); + } + Map overrideGeneration = MiscUtils.castToMap(override.get("generation"), true); + if (overrideGeneration != null) { + modelGenerations.add(ModelGeneration.of(Key.of(overrideModelPath), overrideGeneration)); + } + legacyOverridesModels.add(new LegacyOverridesModel(predicate, overrideModelPath, customModelData)); + } + return new LegacyItemModel(legacyModelPath, legacyOverridesModels, modelGenerations); + } else { + return new LegacyItemModel(legacyModelPath, + List.of(new LegacyOverridesModel(new HashMap<>(), legacyModelPath, customModelData)), + baseModelGeneration == null ? List.of() : List.of(baseModelGeneration) + ); } - LegacyOverridesModel legacyOverridesModel = new LegacyOverridesModel(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyOverridesModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyOverridesModel.java index 07d6d1e7f..6d63b08f2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyOverridesModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyOverridesModel.java @@ -2,7 +2,9 @@ package net.momirealms.craftengine.core.pack.model; import com.google.gson.JsonObject; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -11,8 +13,8 @@ public class LegacyOverridesModel implements Comparable { private final String model; private final int customModelData; - public LegacyOverridesModel(Map predicate, String model, int customModelData) { - this.predicate = predicate; + public LegacyOverridesModel(@Nullable Map predicate, @NotNull String model, int customModelData) { + this.predicate = predicate == null ? new HashMap<>() : predicate; this.model = model; this.customModelData = customModelData; if (customModelData > 0) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java b/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java index c6f539f05..a60be053e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java @@ -1,9 +1,9 @@ package net.momirealms.craftengine.core.util; +import it.unimi.dsi.fastutil.ints.IntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -13,7 +13,7 @@ public class IntIdentityList implements IndexedIterable { public IntIdentityList(int size) { this.size = size; - list = new ArrayList<>(size); + list = new IntArrayList(size); for (int i = 0; i < size; i++) { list.add(i); } diff --git a/gradle.properties b/gradle.properties index 1fabb99a5..a350543e3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.54.1 -config_version=32 -lang_version=12 +project_version=0.0.54.2 +config_version=33 +lang_version=13 project_group=net.momirealms latest_supported_version=1.21.5 From e08f65271a572953e8a32cd8a7227f730ace64bb Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 18 May 2025 20:26:53 +0800 Subject: [PATCH 09/89] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E4=B8=8D=E6=AD=BB?= =?UTF-8?q?=E5=9B=BE=E8=85=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 1 + .../bukkit/item/BukkitItemManager.java | 1 + .../bukkit/item/ComponentTypes.java | 1 + .../feature/TotemAnimationCommand.java | 36 ++++++++++++++++--- .../craftengine/core/item/ComponentKeys.java | 1 + .../core/pack/model/LegacyItemModel.java | 6 ++-- .../core/util/IntIdentityList.java | 1 + 7 files changed, 38 insertions(+), 9 deletions(-) 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 7a039f9b2..6f0b2a94d 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 @@ -8,6 +8,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import dev.dejvokep.boostedyaml.YamlDocument; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList; 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 b961ac758..175a35013 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 @@ -36,6 +36,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentTypes.java index d755ab11b..ae037f19f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentTypes.java @@ -26,6 +26,7 @@ public class ComponentTypes { public static final Object CUSTOM_DATA = getComponentType(ComponentKeys.CUSTOM_DATA); public static final Object PROFILE = getComponentType(ComponentKeys.PROFILE); public static final Object DYED_COLOR = getComponentType(ComponentKeys.DYED_COLOR); + public static final Object DEATH_PROTECTION = getComponentType(ComponentKeys.DEATH_PROTECTION); private ComponentTypes() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java index 1f21b667e..e0381d921 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java @@ -1,15 +1,17 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.item.ComponentTypes; 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.item.*; 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 net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.command.CommandSender; @@ -23,9 +25,13 @@ 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.parser.flag.CommandFlag; +import org.incendo.cloud.parser.standard.StringParser; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; +import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; public class TotemAnimationCommand extends BukkitCommandFeature { @@ -45,18 +51,38 @@ public class TotemAnimationCommand extends BukkitCommandFeature { return CompletableFuture.completedFuture(plugin().itemManager().cachedTotemSuggestions()); } })) + .flag(CommandFlag.builder("sound_event").withComponent(NamespacedKeyParser.namespacedKeyParser()).build()) + .flag(CommandFlag.builder("sound_location").withComponent(NamespacedKeyParser.namespacedKeyParser()).build()) .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 || MaterialUtils.getMaterial(item.material()) != Material.TOTEM_OF_UNDYING) { + CustomItem customItem = plugin().itemManager().getCustomItem(key).orElse(null); + if (customItem == null || (!VersionHelper.isOrAbove1_21_2() && customItem.material().equals(ItemKeys.TOTEM_OF_UNDYING))) { handleFeedback(context, MessageConstants.COMMAND_TOTEM_NOT_TOTEM, Component.text(key.toString())); return; } - ItemStack totem = item.buildItemStack(); + Item item = customItem.buildItem(ItemBuildContext.EMPTY); + if (VersionHelper.isOrAbove1_21_2()) { + if (context.flags().contains("sound_location")) { + String soundResourceLocation = context.flags().getValue("sound_location").get().toString(); + if (soundResourceLocation != null) { + item.setComponent(ComponentTypes.DEATH_PROTECTION, Map.of("death_effects", List.of(Map.of("type", "play_sound", "sound", Map.of( + "sound_id", soundResourceLocation + ))))); + } + } else if (context.flags().contains("sound_event")) { + String soundEvent = context.flags().getValue("sound_event").get().toString(); + if (soundEvent != null) { + item.setComponent(ComponentTypes.DEATH_PROTECTION, Map.of("death_effects", List.of(Map.of("type", "play_sound", "sound", soundEvent)))); + } + } else { + item.setComponent(ComponentTypes.DEATH_PROTECTION, Map.of()); + } + } + ItemStack totemItem = item.load(); MultiplePlayerSelector selector = context.get("players"); for (Player player : selector.values()) { - PlayerUtils.sendTotemAnimation(player, totem); + PlayerUtils.sendTotemAnimation(player, totemItem); } }); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java index 597639121..bc64868d0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java @@ -23,4 +23,5 @@ public class ComponentKeys { public static final Key CUSTOM_DATA = Key.of("minecraft", "custom_data"); public static final Key PROFILE = Key.of("minecraft", "profile"); public static final Key DYED_COLOR = Key.of("minecraft", "dyed_color"); + public static final Key DEATH_PROTECTION = Key.of("minecraft", "death_protection"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java index 925b2bb87..aa1cdf921 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java @@ -5,11 +5,9 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import software.amazon.awssdk.services.s3.endpoints.internal.Value; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class LegacyItemModel { private final List modelsToGenerate; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java b/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java index a60be053e..fcceb235b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java @@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; From af5c63e94006457ec33d70600bcaab468b667aac Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 18 May 2025 20:39:51 +0800 Subject: [PATCH 10/89] Update AbstractItemManager.java --- .../momirealms/craftengine/core/item/AbstractItemManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ce2e61986..ab3693dda 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 @@ -291,7 +291,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl .register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), id), id)); boolean isVanillaItem = isVanillaItem(id); - Key material = Key.from(isVanillaItem ? id.value() : ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("material"), "warning.config.item.missing_material")); + Key material = Key.from(isVanillaItem ? id.value() : ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("material"), "warning.config.item.missing_material").toLowerCase(Locale.ENGLISH)); int customModelData = ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data"); if (customModelData < 0) { throw new LocalizedResourceConfigException("warning.config.item.invalid_custom_model_data", String.valueOf(customModelData)); From 15475b05383a99ffebff8b17fadece0a9164df4a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 19 May 2025 04:22:01 +0800 Subject: [PATCH 11/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/util/LegacyInventoryUtils.java | 28 ++++ bukkit/loader/src/main/resources/config.yml | 1 - bukkit/loader/src/main/resources/mappings.yml | 128 +++++++++--------- .../default/configuration/blocks.yml | 11 ++ .../src/main/resources/translations/en.yml | 3 + .../src/main/resources/translations/zh_cn.yml | 3 + .../bukkit/plugin/gui/BukkitGuiManager.java | 53 +++++++- .../bukkit/plugin/gui/BukkitInventory.java | 2 +- .../context/condition/EqualsCondition.java | 2 +- .../function/AbstractConditionalFunction.java | 2 +- .../context/function/CommonFunctions.java | 3 +- .../context/function/OpenWindowFunction.java | 77 +++++++++++ .../plugin/context/function/RunFunction.java | 79 +++++++++++ .../core/plugin/event/EventFunctions.java | 2 + .../core/plugin/gui/GuiManager.java | 6 + .../craftengine/core/plugin/gui/GuiType.java | 11 ++ .../core/plugin/scheduler/RegionExecutor.java | 4 + 17 files changed, 342 insertions(+), 73 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiType.java diff --git a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java index c2249eced..f009e3583 100644 --- a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java +++ b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java @@ -37,4 +37,32 @@ public class LegacyInventoryUtils { public static InventoryView getView(PrepareAnvilEvent event) { return event.getView(); } + + public static void openAnvil(Player player) { + player.openAnvil(null, true); + } + + public static void openCartographyTable(Player player) { + player.openCartographyTable(null, true); + } + + public static void openEnchanting(Player player) { + player.openEnchanting(null, true); + } + + public static void openGrindstone(Player player) { + player.openGrindstone(null, true); + } + + public static void openLoom(Player player) { + player.openLoom(null, true); + } + + public static void openSmithingTable(Player player) { + player.openSmithingTable(null, true); + } + + public static void openWorkbench(Player player) { + player.openWorkbench(null, true); + } } diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 778670b6e..18053ebc2 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -63,7 +63,6 @@ resource-pack: merge-external-folders: - ModelEngine/resource pack - BetterModel/build - - BetterHud/build merge-external-zip-files: - CustomNameplates/resourcepack.zip delivery: diff --git a/bukkit/loader/src/main/resources/mappings.yml b/bukkit/loader/src/main/resources/mappings.yml index 5038f1f8f..94fa679ec 100644 --- a/bukkit/loader/src/main/resources/mappings.yml +++ b/bukkit/loader/src/main/resources/mappings.yml @@ -1328,70 +1328,70 @@ minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=true, ######################################################################################################################################################################################################################## # Can make transparent blocks, but the collision shape is relatively random. Not as useful as leaves. # Chorus Plant -#minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true]# -minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +##minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true]# +#minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] +#minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] ######################################################################################################################################################################################################################## # Ideal block for making 1x1x1 interactive blocks. Best substitute when other blocks are insufficient in appearance. # Note Block diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml index 02ea65f95..4baf0dd0b 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml @@ -61,6 +61,17 @@ items#misc: type: falling_block hurt-amount: 4 max-hurt: 80 + events: + - on: right_click + functions: + - type: run + functions: + - type: open_window + gui-type: anvil + - type: cancel_event + conditions: + - type: expression + expression: "!" settings: template: - default:pickaxe_power/level_4 diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index ba193d14e..39ec93ddc 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -314,6 +314,9 @@ warning.config.function.invalid_type: "Issue found in file - The warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." warning.config.function.actionbar.missing_actionbar: "Issue found in file - The config '' is missing the required 'actionbar' argument for 'actionbar' function." warning.config.function.message.missing_message: "Issue found in file - The config '' is missing the required 'message' argument for 'message' function." +warning.config.function.open_window.missing_gui_type: "Issue found in file - The config '' is missing the required 'gui-type' argument for 'open_window' function." +warning.config.function.open_window.invalid_gui_type: "Issue found in file - The config '' is using an invalid gui type for 'open_window' function. Allowed types: []." +warning.config.function.run.missing_functions: "Issue found in file - The config '' is missing the required 'functions' argument for 'run' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 9b35e58a3..a1d692f6e 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -314,6 +314,9 @@ warning.config.function.invalid_type: "在文件 中发现问题 warning.config.function.command.missing_command: "在文件 中发现问题 - 配置项 '' 缺少 'command' 函数必需的 'command' 参数" warning.config.function.actionbar.missing_actionbar: "在文件 中发现问题 - 配置项 '' 缺少 'actionbar' 函数必需的 'actionbar' 参数" warning.config.function.message.missing_message: "在文件 中发现问题 - 配置项 '' 缺少 'message' 函数必需的 'message' 参数" +warning.config.function.open_window.missing_gui_type: "在文件 中发现问题 - 配置项 '' 缺少 'open_window' 函数必需的 'gui-type' 参数" +warning.config.function.open_window.invalid_gui_type: "在文件 中发现问题 - 配置项 '' 为 'open_window' 函数使用了无效的 GUI 类型 . 允许的类型: []。" +warning.config.function.run.missing_functions: "在文件 中发现问题 - 配置项 '' 缺少 'run' 函数必需的 'functions' 参数" warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java index 79b1528a5..9062dc5b6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java @@ -1,10 +1,13 @@ package net.momirealms.craftengine.bukkit.plugin.gui; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.core.plugin.gui.AbstractGui; -import net.momirealms.craftengine.core.plugin.gui.Gui; -import net.momirealms.craftengine.core.plugin.gui.GuiManager; -import net.momirealms.craftengine.core.plugin.gui.Inventory; +import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.gui.*; +import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -13,6 +16,7 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.inventory.MenuType; public class BukkitGuiManager implements GuiManager, Listener { private final BukkitCraftEngine plugin; @@ -31,6 +35,47 @@ public class BukkitGuiManager implements GuiManager, Listener { HandlerList.unregisterAll(this); } + @SuppressWarnings("UnstableApiUsage") + @Override + public void openInventory(net.momirealms.craftengine.core.entity.player.Player player, GuiType guiType) { + Player bukkitPlayer = (Player) player.platformPlayer(); + if (VersionHelper.isOrAbove1_21_4()) { + switch (guiType) { + case ANVIL -> MenuType.ANVIL.create(bukkitPlayer).open(); + case LOOM -> MenuType.LOOM.create(bukkitPlayer).open(); + case ENCHANTMENT -> MenuType.ENCHANTMENT.create(bukkitPlayer).open(); + case CRAFTING -> MenuType.CRAFTING.create(bukkitPlayer).open(); + case CARTOGRAPHY -> MenuType.CARTOGRAPHY_TABLE.create(bukkitPlayer).open(); + case SMITHING -> MenuType.SMITHING.create(bukkitPlayer).open(); + case GRINDSTONE -> MenuType.GRINDSTONE.create(bukkitPlayer).open(); + } + } else { + switch (guiType) { + case ANVIL -> LegacyInventoryUtils.openAnvil(bukkitPlayer); + case LOOM -> LegacyInventoryUtils.openLoom(bukkitPlayer); + case GRINDSTONE -> LegacyInventoryUtils.openGrindstone(bukkitPlayer); + case SMITHING -> LegacyInventoryUtils.openSmithingTable(bukkitPlayer); + case CRAFTING -> LegacyInventoryUtils.openWorkbench(bukkitPlayer); + case ENCHANTMENT -> LegacyInventoryUtils.openEnchanting(bukkitPlayer); + case CARTOGRAPHY -> LegacyInventoryUtils.openCartographyTable(bukkitPlayer); + } + } + } + + @Override + public void updateInventoryTitle(net.momirealms.craftengine.core.entity.player.Player player, Component component) { + Object nmsPlayer = player.serverPlayer(); + try { + Object containerMenu = Reflections.field$Player$containerMenu.get(nmsPlayer); + int containerId = Reflections.field$AbstractContainerMenu$containerId.getInt(containerMenu); + Object menuType = Reflections.field$AbstractContainerMenu$menuType.get(containerMenu); + Object packet = Reflections.constructor$ClientboundOpenScreenPacket.newInstance(containerId, menuType, ComponentUtils.adventureToMinecraft(component)); + player.sendPacket(packet, false); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to update inventory title", e); + } + } + @Override public Inventory createInventory(Gui gui, int size) { CraftEngineInventoryHolder holder = new CraftEngineInventoryHolder(gui); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitInventory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitInventory.java index d7bb0b932..13464fc7b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitInventory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitInventory.java @@ -31,7 +31,7 @@ public class BukkitInventory implements Inventory { Reflections.field$Player$containerMenu.set(nmsPlayer, menu); Reflections.method$ServerPlayer$initMenu.invoke(nmsPlayer, menu); } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to update inventory title", e); + CraftEngine.instance().logger().warn("Failed to create bukkit inventory", e); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java index bc48c0a1a..68a84533c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java @@ -33,7 +33,7 @@ public class EqualsCondition implements Condition { @Override public Condition create(Map arguments) { String value1 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value1"), "warning.config.condition.equals.missing_value1"); - String value2 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value1"), "warning.config.condition.equals.missing_value2"); + String value2 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value2"), "warning.config.condition.equals.missing_value2"); return new EqualsCondition<>(TextProviders.fromString(value1), TextProviders.fromString(value2)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java index 394552424..44d22ba1a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java @@ -51,7 +51,7 @@ public abstract class AbstractConditionalFunction implement } else if (predicates instanceof Map map) { return List.of(factory.apply(MiscUtils.castToMap(map, false))); } - throw new IllegalArgumentException("Unsupported condition type: " + predicates.getClass().getSimpleName()); + throw new UnsupportedOperationException("Unsupported conditions argument class type: " + predicates.getClass().getSimpleName()); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index ed0bd1e32..f0df7a51c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -5,11 +5,12 @@ import net.momirealms.craftengine.core.util.Key; public final class CommonFunctions { private CommonFunctions() {} - public static final Key RUN_ALL = Key.of("craftengine:run_all"); + public static final Key RUN = Key.of("craftengine:run"); public static final Key COMMAND = Key.of("craftengine:command"); public static final Key MESSAGE = Key.of("craftengine:message"); public static final Key ACTIONBAR = Key.of("craftengine:actionbar"); public static final Key TITLE = Key.of("craftengine:title"); + public static final Key OPEN_WINDOW = Key.of("craftengine:open_window"); public static final Key PARTICLE = Key.of("craftengine:particle"); public static final Key SOUND = Key.of("craftengine:sound"); public static final Key POTION_EFFECT = Key.of("craftengine:potion_effect"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java new file mode 100644 index 000000000..242149a45 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java @@ -0,0 +1,77 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.*; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.plugin.gui.GuiType; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.*; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +public class OpenWindowFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; + private final GuiType guiType; + private final TextProvider optionalTitle; + + public OpenWindowFunction(List> predicates, @Nullable PlayerSelector selector, GuiType guiType, TextProvider optionalTitle) { + super(predicates); + this.selector = selector; + this.guiType = guiType; + this.optionalTitle = optionalTitle; + } + + @Override + public void runInternal(CTX ctx) { + Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + if (this.selector == null) { + owner.ifPresent(it -> { + CraftEngine.instance().guiManager().openInventory(it, this.guiType); + if (this.optionalTitle != null) { + CraftEngine.instance().guiManager().updateInventoryTitle(it, AdventureHelper.miniMessage().deserialize(this.optionalTitle.get(ctx), ctx.tagResolvers())); + } + }); + } else { + for (Player viewer : this.selector.get(ctx)) { + CraftEngine.instance().guiManager().openInventory(viewer, this.guiType); + if (this.optionalTitle != null) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer, ContextHolder.EMPTY)); + CraftEngine.instance().guiManager().updateInventoryTitle(viewer, AdventureHelper.miniMessage().deserialize(this.optionalTitle.get(relationalContext), relationalContext.tagResolvers())); + } + } + } + } + + @Override + public Key type() { + return CommonFunctions.OPEN_WINDOW; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + TextProvider title = Optional.ofNullable(arguments.get("title")).map(String::valueOf).map(TextProviders::fromString).orElse(null); + String rawType = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("gui-type"), "warning.config.function.open_window.missing_gui_type"); + try { + GuiType type = GuiType.valueOf(rawType.toUpperCase(Locale.ENGLISH)); + return new OpenWindowFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), type, title); + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.function.open_window.invalid_gui_type", e, rawType, EnumUtils.toString(GuiType.values())); + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java new file mode 100644 index 000000000..1cc08eb6c --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java @@ -0,0 +1,79 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.event.EventFunctions; +import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.world.WorldPosition; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class RunFunction extends AbstractConditionalFunction { + private final List> functions; + private final NumberProvider delay; + + public RunFunction(List> functions, NumberProvider delay, List> predicates) { + super(predicates); + this.functions = functions; + this.delay = delay; + } + + @Override + public void runInternal(CTX ctx) { + int delay = this.delay.getInt(ctx); + if (delay <= 0) { + for (Function function : functions) { + function.run(ctx); + } + } else { + Optional position = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (!VersionHelper.isFolia() || position.isEmpty()) { + CraftEngine.instance().scheduler().sync().runLater(() -> { + for (Function function : functions) { + function.run(ctx); + } + }, delay); + } else { + WorldPosition pos = position.get(); + CraftEngine.instance().scheduler().sync().runLater(() -> { + for (Function function : functions) { + function.run(ctx); + } + }, delay, pos.world().platformWorld(), MCUtils.fastFloor(pos.x()) >> 4, MCUtils.fastFloor(pos.z()) >> 4); + } + } + } + + @Override + public Key type() { + return CommonFunctions.RUN; + } + + public static class FactoryImpl extends AbstractFactory { + private final java.util.function.Function, Function> functionFactory; + + public FactoryImpl(java.util.function.Function, Function> functionFactory, java.util.function.Function, Condition> conditionFactory) { + super(conditionFactory); + this.functionFactory = functionFactory; + } + + @Override + public Function create(Map arguments) { + NumberProvider delay = NumberProviders.fromObject(arguments.getOrDefault("delay", 0)); + @SuppressWarnings("unchecked") + List> functions = (List>) ResourceConfigUtils.requireNonNullOrThrow(arguments.get("functions"), "warning.config.function.run.missing_functions"); + List> fun = new ArrayList<>(); + for (Map function : functions) { + fun.add(this.functionFactory.apply(function)); + } + return new RunFunction<>(fun, delay, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java index 91d28760f..001d58f81 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java @@ -24,7 +24,9 @@ public class EventFunctions { register(CommonFunctions.MESSAGE, new MessageFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.ACTIONBAR, new ActionBarFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.TITLE, new TitleFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.OPEN_WINDOW, new OpenWindowFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.CANCEL_EVENT, new CancelEventFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.RUN, new RunFunction.FactoryImpl<>(EventFunctions::fromMap, EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { 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 8c4e25cb1..c23e6f7e8 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,14 @@ package net.momirealms.craftengine.core.plugin.gui; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.Manageable; public interface GuiManager extends Manageable { + void openInventory(Player player, GuiType guiType); + + void updateInventoryTitle(Player player, Component component); + Inventory createInventory(Gui gui, int size); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiType.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiType.java new file mode 100644 index 000000000..f004bfa2e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiType.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.core.plugin.gui; + +public enum GuiType { + ANVIL, + CARTOGRAPHY, + ENCHANTMENT, + GRINDSTONE, + LOOM, + SMITHING, + CRAFTING +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/scheduler/RegionExecutor.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/scheduler/RegionExecutor.java index cbe7c938a..c77bbb0e1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/scheduler/RegionExecutor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/scheduler/RegionExecutor.java @@ -20,6 +20,10 @@ public interface RegionExecutor extends Executor { SchedulerTask runAsyncLater(Runnable runnable, long delay); + default SchedulerTask runLater(Runnable runnable, long delay) { + return runLater(runnable, delay, null, 0 ,0); + } + SchedulerTask runLater(Runnable runnable, long delay, W world, int x, int z); SchedulerTask runRepeating(Runnable runnable, long delay, long period, W world, int x, int z); From 924a992921daf1f222282e99fc2910f32eb605cb Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 19 May 2025 13:01:50 +0800 Subject: [PATCH 12/89] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/commands.yml | 7 +++ .../plugin/command/BukkitCommandManager.java | 3 +- .../SetMaxVisibleFurnitureCommand.java | 36 ++++++++++++++++ .../plugin/command/feature/TestCommand.java | 19 ++++---- .../plugin/network/PacketConsumers.java | 29 +++++++++---- .../plugin/user/BukkitServerPlayer.java | 27 +++++++++--- .../craftengine/core/plugin/CraftEngine.java | 4 ++ .../core/plugin/network/NetWorkUser.java | 2 + .../core/util/DynamicPriorityTracker.java | 43 ++++++++++++++++--- gradle.properties | 2 +- 10 files changed, 142 insertions(+), 30 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java diff --git a/bukkit/loader/src/main/resources/commands.yml b/bukkit/loader/src/main/resources/commands.yml index fdf4e1613..7dbe7a78a 100644 --- a/bukkit/loader/src/main/resources/commands.yml +++ b/bukkit/loader/src/main/resources/commands.yml @@ -111,6 +111,13 @@ list_resource: - /craftengine resource list - /ce resource list +set_max_visible_furniture: + enable: true + permission: ce.command.player.set_max_visible_furniture + usage: + - /craftengine feature set-max-visible-furniture + - /ce feature set-max-visible-furniture + # Debug commands debug_set_block: enable: true 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 c1f1c3f39..40cbc68ee 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 @@ -52,7 +52,8 @@ public class BukkitCommandManager extends AbstractCommandManager new DisableResourceCommand(this, plugin), new ListResourceCommand(this, plugin), new UploadPackCommand(this, plugin), - new SendResourcePackCommand(this, plugin) + new SendResourcePackCommand(this, plugin), + new SetMaxVisibleFurnitureCommand(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/SetMaxVisibleFurnitureCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java new file mode 100644 index 000000000..e07630d36 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java @@ -0,0 +1,36 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.parser.standard.IntegerParser; + +public class SetMaxVisibleFurnitureCommand extends BukkitCommandFeature { + + public SetMaxVisibleFurnitureCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .senderType(Player.class) + .required("max", IntegerParser.integerParser(1)) + .handler(context -> { + // 需要找一个更好的存储方案 + BukkitServerPlayer cePlayer = plugin().adapt(context.sender()); + Integer max = context.get("max"); + cePlayer.setMaxVisibleFurniture(max, true); + }); + } + + @Override + public String getFeatureID() { + return "set_max_visible_furniture"; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 33a9ac417..8ce4d7495 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -52,15 +52,16 @@ public class TestCommand extends BukkitCommandFeature { .handler(context -> { Player player = context.sender(); BukkitServerPlayer cePlayer = plugin().adapt(player); - player.sendMessage("visualFurnitureView1: " + cePlayer.visualFurnitureView().getTotalMembers()); - cePlayer.visualFurnitureView().getAllElements().forEach(element -> { - LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); - if (furniture == null || !player.canSee(furniture.baseEntity())) { - cePlayer.visualFurnitureView().removeByEntityId(element.entityId()); - player.sendMessage("remove: " + element.entityId()); - } - }); - player.sendMessage("visualFurnitureView2: " + cePlayer.visualFurnitureView().getTotalMembers()); + player.sendMessage("visualFurnitureView: " + cePlayer.visualFurnitureView().getTotalMembers()); + player.sendMessage(cePlayer.visualFurnitureView() + "\n==============================="); + // cePlayer.visualFurnitureView().getAllElements().forEach(element -> { + // LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); + // if (furniture == null || !player.canSee(furniture.baseEntity())) { + // cePlayer.visualFurnitureView().removeByEntityId(element.entityId()); + // player.sendMessage("remove: " + element.entityId()); + // } + // }); + // player.sendMessage("visualFurnitureView2: " + cePlayer.visualFurnitureView().getTotalMembers()); }); } 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 65cb5f409..301b54540 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 @@ -1605,12 +1605,13 @@ public class PacketConsumers { if (user.visualFurnitureView().getTotalMembers() <= Config.maxVisibleFurniture()) { user.sendPacket(furniture.spawnPacket(player), false); } - int[] entityIdsArray = new int[fakeEntityIds.size() + 1]; - entityIdsArray[0] = entityId; + int[] entityIdsArray = new int[fakeEntityIds.size() + 2]; + entityIdsArray[0] = -114514; + entityIdsArray[1] = entityId; for (int i = 0; i < fakeEntityIds.size(); i++) { - entityIdsArray[i + 1] = fakeEntityIds.get(i); + entityIdsArray[i + 2] = fakeEntityIds.get(i); } - double distance = player.getLocation().distance(furniture.location()); + double distance = furniture.location().distanceSquared(player.getLocation()); Object removePacket = Reflections.constructor$ClientboundRemoveEntitiesPacket.newInstance(entityIdsArray); DynamicPriorityTracker.UpdateResult result = user.visualFurnitureView().addOrUpdateElement(new DynamicPriorityTracker.Element(entityId, distance, removePacket)); for (DynamicPriorityTracker.Element element : result.getEntered()) { @@ -1665,12 +1666,24 @@ public class PacketConsumers { FriendlyByteBuf buf = event.getBuffer(); boolean isChange = false; IntList intList = buf.readIntIdList(); + int first = intList.getFirst(); for (int i = 0, size = intList.size(); i < size; i++) { int entityId = intList.getInt(i); - EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); - if (handler != null && handler.handleEntitiesRemove(intList)) { - // user.visualFurnitureView().removeByEntityId(entityId); - isChange = true; + if (first != -114514) { + EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); + if (handler != null && handler.handleEntitiesRemove(intList)) { + user.visualFurnitureView().removeByEntityId(entityId); + isChange = true; + } + } else { + if (entityId == first) { + intList.removeFirst(); + isChange = true; + } + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null && handler.handleEntitiesRemove(intList)) { + isChange = true; + } } } if (isChange) { 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 8e30e0dca..090cfbb82 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 @@ -31,16 +31,14 @@ import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; -import org.bukkit.FluidCollisionMode; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.SoundCategory; +import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.Block; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.persistence.PersistentDataType; import org.bukkit.util.RayTraceResult; import org.jetbrains.annotations.Nullable; @@ -50,6 +48,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class BukkitServerPlayer extends Player { + public static final NamespacedKey MAX_VISIBLE_FURNITURE_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:max_visible_furniture")); private final BukkitCraftEngine plugin; // handshake private ProtocolVersion protocolVersion = ProtocolVersion.UNKNOWN; @@ -98,6 +97,7 @@ public class BukkitServerPlayer extends Player { // cache interaction range here private int lastUpdateInteractionRangeTick; private double cachedInteractionRange; + private Integer maxVisibleFurniture = -1; private final Map entityTypeView = new ConcurrentHashMap<>(); private final DynamicPriorityTracker visualFurnitureView = new DynamicPriorityTracker(); @@ -112,6 +112,9 @@ public class BukkitServerPlayer extends Player { this.serverPlayerRef = new WeakReference<>(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)); this.uuid = player.getUniqueId(); this.name = player.getName(); + this.maxVisibleFurniture = player.getPersistentDataContainer() + .getOrDefault(MAX_VISIBLE_FURNITURE_KEY, PersistentDataType.INTEGER, -1); + this.visualFurnitureView.setMaxVisibleFurniture(this.maxVisibleFurniture); } @Override @@ -348,11 +351,11 @@ public class BukkitServerPlayer extends Player { } if (this.gameTicks % 30 == 0) { this.updateGUI(); - this.updateVisualFurnitureView(); } if (this.isDestroyingBlock) { this.tickBlockDestroy(); } + this.updateVisualFurnitureView(); if (Config.predictBreaking() && !this.isDestroyingCustomBlock) { // if it's not destroying blocks, we do predict if ((gameTicks() + entityID()) % Config.predictBreakingInterval() == 0) { @@ -379,7 +382,7 @@ public class BukkitServerPlayer extends Player { for (DynamicPriorityTracker.Element element : visualFurnitureView().getAllElements()) { LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); if (furniture == null || !furniture.isValid()) continue; - double distance = platformPlayer().getLocation().distance(furniture.location()); + double distance = furniture.location().distanceSquared(platformPlayer().getLocation()); DynamicPriorityTracker.Element newElement = new DynamicPriorityTracker.Element(element.entityId(), distance, element.removePacket()); DynamicPriorityTracker.UpdateResult result = visualFurnitureView().addOrUpdateElement(newElement); for (DynamicPriorityTracker.Element resultElement : result.getEntered()) { @@ -768,6 +771,18 @@ public class BukkitServerPlayer extends Player { return this.visualFurnitureView; } + @Override + public void setMaxVisibleFurniture(int maxVisibleFurniture, boolean fromCommand) { + if (fromCommand) { + platformPlayer().getPersistentDataContainer() + .set(MAX_VISIBLE_FURNITURE_KEY, PersistentDataType.INTEGER, maxVisibleFurniture); + this.maxVisibleFurniture = maxVisibleFurniture; + } + this.visualFurnitureView.setMaxVisibleFurniture( + this.maxVisibleFurniture == -1 ? maxVisibleFurniture : this.maxVisibleFurniture + ); + } + public void setResendSound() { resentSoundTick = gameTicks(); } 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 53f8b5da5..f04069413 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.plugin; import net.momirealms.craftengine.core.advancement.AdvancementManager; 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.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.item.ItemManager; @@ -131,6 +132,9 @@ public abstract class CraftEngine implements Plugin { long time1 = System.currentTimeMillis(); // firstly reload main config this.config.load(); + for (Player player : this.networkManager().onlineUsers()) { + player.setMaxVisibleFurniture(Config.maxVisibleFurniture(), false); + } // reset debugger this.debugger = Config.debug() ? (s) -> logger.info("[Debug] " + s.get()) : (s) -> {}; // now we reload the translations diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index d442edb97..a0283efab 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -46,6 +46,8 @@ public interface NetWorkUser { DynamicPriorityTracker visualFurnitureView(); + void setMaxVisibleFurniture(int maxVisibleFurniture, boolean fromCommand); + boolean clientModEnabled(); void setClientModState(boolean enable); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java b/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java index 50ebee72d..f538a6269 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java @@ -31,6 +31,15 @@ public class DynamicPriorityTracker { public Object removePacket() { return removePacket; } + + @Override + public String toString() { + return "Element{" + + "entityId=" + entityId + + ", distance=" + distance + + ", removePacket=" + removePacket + + '}'; + } } public static class UpdateResult { @@ -50,17 +59,31 @@ public class DynamicPriorityTracker { void addExited(Element e) { exited.add(e); } + + @Override + public String toString() { + return "UpdateResult{" + + "entered=" + entered + + ", exited=" + exited + + '}'; + } } + private Integer maxVisibleFurniture; private final PriorityQueue maxHeap; private final Map elementMap = new ConcurrentHashMap<>(); private final Set inHeapSet = ConcurrentHashMap.newKeySet(); private final ReentrantLock heapLock = new ReentrantLock(); public DynamicPriorityTracker() { + this.maxVisibleFurniture = Config.maxVisibleFurniture(); this.maxHeap = new PriorityQueue<>((a, b) -> Double.compare(b.distance, a.distance)); } + public void setMaxVisibleFurniture(int maxVisibleFurniture) { + this.maxVisibleFurniture = maxVisibleFurniture; + } + public UpdateResult addOrUpdateElement(Element newElement) { UpdateResult result = new UpdateResult(); heapLock.lock(); @@ -80,7 +103,7 @@ public class DynamicPriorityTracker { private UpdateResult handleNewElement(Element newElement, UpdateResult result) { elementMap.put(newElement.entityId, newElement); - if (maxHeap.size() < Config.maxVisibleFurniture()) { + if (maxHeap.size() < maxVisibleFurniture) { maxHeap.offer(newElement); inHeapSet.add(newElement.entityId); result.addEntered(newElement); @@ -106,7 +129,7 @@ public class DynamicPriorityTracker { maxHeap.remove(existing); maxHeap.offer(existing); } else if (nowInHeap) { - if (maxHeap.size() < Config.maxVisibleFurniture()) { + if (maxHeap.size() < maxVisibleFurniture) { maxHeap.offer(existing); inHeapSet.add(existing.entityId); result.addEntered(existing); @@ -124,7 +147,7 @@ public class DynamicPriorityTracker { } private boolean checkIfShouldBeInHeap(double distance) { - if (maxHeap.size() < Config.maxVisibleFurniture()) return true; + if (maxHeap.size() < maxVisibleFurniture) return true; return maxHeap.peek() != null && distance < maxHeap.peek().distance; } @@ -146,16 +169,26 @@ public class DynamicPriorityTracker { } } - public Element removeByEntityId(int entityId) { + public void removeByEntityId(int entityId) { heapLock.lock(); try { Element removed = elementMap.remove(entityId); if (removed != null) { maxHeap.remove(removed); + inHeapSet.remove(entityId); } - return removed; } finally { heapLock.unlock(); } } + + @Override + public String toString() { + return "DynamicPriorityTracker{" + + "maxHeap=" + maxHeap + + ", elementMap=" + elementMap + + ", inHeapSet=" + inHeapSet + + ", heapLock=" + heapLock + + '}'; + } } diff --git a/gradle.properties b/gradle.properties index a350543e3..a493a2f38 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] project_version=0.0.54.2 -config_version=33 +config_version=34 lang_version=13 project_group=net.momirealms latest_supported_version=1.21.5 From 32e720d6b2683d902f015edf9947917f7b106134 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 19 May 2025 13:03:05 +0800 Subject: [PATCH 13/89] =?UTF-8?q?fix(bukkit):=20=E5=85=88=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E4=B8=8D=E5=90=AF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/commands.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bukkit/loader/src/main/resources/commands.yml b/bukkit/loader/src/main/resources/commands.yml index 7dbe7a78a..313d117b4 100644 --- a/bukkit/loader/src/main/resources/commands.yml +++ b/bukkit/loader/src/main/resources/commands.yml @@ -112,7 +112,7 @@ list_resource: - /ce resource list set_max_visible_furniture: - enable: true + enable: false permission: ce.command.player.set_max_visible_furniture usage: - /craftengine feature set-max-visible-furniture From d827140547d3caac6ebc18a28dc3b322a28cab95 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 19 May 2025 13:05:13 +0800 Subject: [PATCH 14/89] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=80=A7=E8=83=BD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/command/feature/SetMaxVisibleFurnitureCommand.java | 2 +- .../craftengine/bukkit/plugin/user/BukkitServerPlayer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java index e07630d36..e71b6f43d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java @@ -22,7 +22,7 @@ public class SetMaxVisibleFurnitureCommand extends BukkitCommandFeature { - // 需要找一个更好的存储方案 + // 需要找一个更好的存储方案去兼容跨服和在初始化的时候加载 BukkitServerPlayer cePlayer = plugin().adapt(context.sender()); Integer max = context.get("max"); cePlayer.setMaxVisibleFurniture(max, true); 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 090cfbb82..d1f37059a 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 @@ -351,11 +351,11 @@ public class BukkitServerPlayer extends Player { } if (this.gameTicks % 30 == 0) { this.updateGUI(); + this.updateVisualFurnitureView(); } if (this.isDestroyingBlock) { this.tickBlockDestroy(); } - this.updateVisualFurnitureView(); if (Config.predictBreaking() && !this.isDestroyingCustomBlock) { // if it's not destroying blocks, we do predict if ((gameTicks() + entityID()) % Config.predictBreakingInterval() == 0) { From 70f0d5d9b4bafc816ddb6c45fb1be546bf33a439 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 19 May 2025 13:12:35 +0800 Subject: [PATCH 15/89] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 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 301b54540..63392db00 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 @@ -1667,22 +1667,23 @@ public class PacketConsumers { boolean isChange = false; IntList intList = buf.readIntIdList(); int first = intList.getFirst(); - for (int i = 0, size = intList.size(); i < size; i++) { - int entityId = intList.getInt(i); - if (first != -114514) { + if (first != -114514) { + for (int i = 0, size = intList.size(); i < size; i++) { + int entityId = intList.getInt(i); EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); if (handler != null && handler.handleEntitiesRemove(intList)) { user.visualFurnitureView().removeByEntityId(entityId); isChange = true; } - } else { - if (entityId == first) { - intList.removeFirst(); - isChange = true; - } + } + } else { + intList.removeFirst(); + isChange = true; + for (int i = 0, size = intList.size(); i < size; i++) { + int entityId = intList.getInt(i); EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); - if (handler != null && handler.handleEntitiesRemove(intList)) { - isChange = true; + if (handler != null) { + handler.handleEntitiesRemove(intList); } } } From e60a818331ccfa45862b8b8c7aa87c93f2b26ebd Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 19 May 2025 16:52:58 +0800 Subject: [PATCH 16/89] =?UTF-8?q?=E6=9E=84=E9=80=A0=E6=8A=BD=E8=B1=A1?= =?UTF-8?q?=E7=9A=84=E8=87=AA=E5=AE=9A=E4=B9=89=E7=89=A9=E5=93=81=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitCustomItem.java | 122 ++--------------- .../bukkit/item/BukkitItemManager.java | 6 +- .../core/item/AbstractCustomItem.java | 128 ++++++++++++++++++ .../core/item/AbstractItemManager.java | 4 +- .../craftengine/core/loot/LootTable.java | 1 - .../parameter/DirectContextParameters.java | 1 + .../parameter/ItemParameterProvider.java | 1 + 7 files changed, 144 insertions(+), 119 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index 7e2559198..a0438f38c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.bukkit.item; -import com.google.common.collect.ImmutableMap; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.*; @@ -13,113 +12,19 @@ import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; import java.util.*; -public class BukkitCustomItem implements CustomItem { - private final Holder id; - private final Key materialKey; +public class BukkitCustomItem extends AbstractCustomItem { private final Material material; - private final ItemDataModifier[] modifiers; - private final Map> modifierMap; - private final ItemDataModifier[] clientBoundModifiers; - private final Map> clientBoundModifierMap; - private final NetworkItemDataProcessor[] networkItemDataProcessors; - private final List behaviors; - private final ItemSettings settings; - private final EnumMap>> events; - @SuppressWarnings("unchecked") - public BukkitCustomItem(Holder id, - Key materialKey, - Material material, - List> modifiers, - List> clientBoundModifiers, + public BukkitCustomItem(Holder id, Key materialKey, Material material, List behaviors, + List> modifiers, List> clientBoundModifiers, ItemSettings settings, EnumMap>> events) { - this.id = id; + super(id, materialKey, behaviors, modifiers, clientBoundModifiers, settings, events); this.material = material; - this.materialKey = materialKey; - this.events = events; - // unchecked cast - this.modifiers = modifiers.toArray(new ItemDataModifier[0]); - // unchecked cast - this.clientBoundModifiers = clientBoundModifiers.toArray(new ItemDataModifier[0]); - this.behaviors = List.copyOf(behaviors); - this.settings = settings; - ImmutableMap.Builder> modifierMapBuilder = ImmutableMap.builder(); - for (ItemDataModifier modifier : modifiers) { - modifierMapBuilder.put(modifier.name(), modifier); - } - this.modifierMap = modifierMapBuilder.build(); - ImmutableMap.Builder> clientSideModifierMapBuilder = ImmutableMap.builder(); - List> networkItemDataProcessors = new ArrayList<>(); - for (ItemDataModifier modifier : clientBoundModifiers) { - String name = modifier.name(); - clientSideModifierMapBuilder.put(name, modifier); - if (this.modifierMap.containsKey(name)) { - networkItemDataProcessors.add(NetworkItemDataProcessor.both(this.modifierMap.get(name), modifier)); - } else { - networkItemDataProcessors.add(NetworkItemDataProcessor.clientOnly(modifier)); - } - } - this.clientBoundModifierMap = clientSideModifierMapBuilder.build(); - // unchecked cast - this.networkItemDataProcessors = networkItemDataProcessors.toArray(new NetworkItemDataProcessor[0]); - } - - @Override - public void execute(PlayerOptionalContext context, EventTrigger trigger) { - for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { - function.run(context); - } - } - - @Override - public Key id() { - return this.id.value(); - } - - @Override - public Holder idHolder() { - return this.id; - } - - @Override - public Key material() { - return this.materialKey; - } - - @Override - public NetworkItemDataProcessor[] networkItemDataProcessors() { - return this.networkItemDataProcessors; - } - - @Override - public ItemDataModifier[] dataModifiers() { - return this.modifiers; - } - - @Override - public Map> dataModifierMap() { - return this.modifierMap; - } - - @Override - public boolean hasClientBoundDataModifier() { - return this.clientBoundModifiers.length != 0; - } - - @Override - public ItemDataModifier[] clientBoundDataModifiers() { - return this.clientBoundModifiers; - } - - @Override - public Map> clientBoundDataModifierMap() { - return this.clientBoundModifierMap; } @Override @@ -133,11 +38,6 @@ public class BukkitCustomItem implements CustomItem { return wrapped.load(); } - @Override - public ItemSettings settings() { - return this.settings; - } - @Override public Item buildItem(ItemBuildContext context) { ItemStack item = new ItemStack(this.material); @@ -148,11 +48,6 @@ public class BukkitCustomItem implements CustomItem { return BukkitCraftEngine.instance().itemManager().wrap(wrapped.load()); } - @Override - public @NotNull List behaviors() { - return this.behaviors; - } - public static Builder builder(Material material) { return new BuilderImpl(material); } @@ -162,9 +57,9 @@ public class BukkitCustomItem implements CustomItem { private Key materialKey; private final Material material; private final EnumMap>> events = new EnumMap<>(EventTrigger.class); - private final List behaviors = new ArrayList<>(); - private final List> modifiers = new ArrayList<>(); - private final List> clientBoundModifiers = new ArrayList<>(); + private final List behaviors = new ArrayList<>(4); + private final List> modifiers = new ArrayList<>(4); + private final List> clientBoundModifiers = new ArrayList<>(4); private ItemSettings settings; public BuilderImpl(Material material) { @@ -235,7 +130,8 @@ public class BukkitCustomItem implements CustomItem { @Override public CustomItem build() { this.modifiers.addAll(this.settings.modifiers()); - return new BukkitCustomItem(this.id, this.materialKey, this.material, List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), List.copyOf(this.behaviors), this.settings, this.events); + return new BukkitCustomItem(this.id, this.materialKey, this.material, List.copyOf(this.behaviors), + List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), this.settings, this.events); } } } 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 175a35013..57fa33974 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 @@ -193,7 +193,7 @@ public class BukkitItemManager extends AbstractItemManager { @Override public Item createWrappedItem(Key id, @Nullable Player player) { - return Optional.ofNullable(customItems.get(id)).map(it -> it.buildItem(player)).orElseGet(() -> { + return Optional.ofNullable(this.customItems.get(id)).map(it -> it.buildItem(player)).orElseGet(() -> { ItemStack itemStack = createVanillaItemStack(id); return wrap(itemStack); }); @@ -219,9 +219,9 @@ public class BukkitItemManager extends AbstractItemManager { } @Override - protected CustomItem.Builder createPlatformItemBuilder(Key materialId) { + protected CustomItem.Builder createPlatformItemBuilder(Holder id, Key materialId) { Material material = ResourceConfigUtils.requireNonNullOrThrow(Registry.MATERIAL.get(KeyUtils.toNamespacedKey(materialId)), () -> new LocalizedResourceConfigException("warning.config.item.invalid_material", materialId.toString())); - return BukkitCustomItem.builder(material); + return BukkitCustomItem.builder(material).material(materialId).id(id); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java new file mode 100644 index 000000000..7d88df3ad --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java @@ -0,0 +1,128 @@ +package net.momirealms.craftengine.core.item; + +import com.google.common.collect.ImmutableMap; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public abstract class AbstractCustomItem implements CustomItem { + protected final Holder id; + protected final Key material; + protected final ItemDataModifier[] modifiers; + protected final Map> modifierMap; + protected final ItemDataModifier[] clientBoundModifiers; + protected final Map> clientBoundModifierMap; + protected final NetworkItemDataProcessor[] networkItemDataProcessors; + protected final List behaviors; + protected final ItemSettings settings; + protected final EnumMap>> events; + protected final Item base; + + @SuppressWarnings("unchecked") + public AbstractCustomItem(Holder id, Key material, + List behaviors, + List> modifiers, + List> clientBoundModifiers, + ItemSettings settings, + EnumMap>> events) { + this.id = id; + this.material = material; + this.events = events; + // unchecked cast + this.modifiers = modifiers.toArray(new ItemDataModifier[0]); + // unchecked cast + this.clientBoundModifiers = clientBoundModifiers.toArray(new ItemDataModifier[0]); + this.behaviors = List.copyOf(behaviors); + this.settings = settings; + ImmutableMap.Builder> modifierMapBuilder = ImmutableMap.builder(); + for (ItemDataModifier modifier : modifiers) { + modifierMapBuilder.put(modifier.name(), modifier); + } + this.modifierMap = modifierMapBuilder.build(); + ImmutableMap.Builder> clientSideModifierMapBuilder = ImmutableMap.builder(); + List> networkItemDataProcessors = new ArrayList<>(); + for (ItemDataModifier modifier : clientBoundModifiers) { + String name = modifier.name(); + clientSideModifierMapBuilder.put(name, modifier); + if (this.modifierMap.containsKey(name)) { + networkItemDataProcessors.add(NetworkItemDataProcessor.both(this.modifierMap.get(name), modifier)); + } else { + networkItemDataProcessors.add(NetworkItemDataProcessor.clientOnly(modifier)); + } + } + this.clientBoundModifierMap = clientSideModifierMapBuilder.build(); + // unchecked cast + this.networkItemDataProcessors = networkItemDataProcessors.toArray(new NetworkItemDataProcessor[0]); + this.base = (Item) CraftEngine.instance().itemManager().wrap(CraftEngine.instance().itemManager().getVanillaItem(material).get().buildItemStack()); + } + + @Override + public void execute(PlayerOptionalContext context, EventTrigger trigger) { + for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { + function.run(context); + } + } + + @Override + public Key id() { + return this.id.value(); + } + + @Override + public Holder idHolder() { + return this.id; + } + + @Override + public Key material() { + return this.material; + } + + @Override + public NetworkItemDataProcessor[] networkItemDataProcessors() { + return this.networkItemDataProcessors; + } + + @Override + public ItemDataModifier[] dataModifiers() { + return this.modifiers; + } + + @Override + public Map> dataModifierMap() { + return this.modifierMap; + } + + @Override + public boolean hasClientBoundDataModifier() { + return this.clientBoundModifiers.length != 0; + } + + @Override + public ItemDataModifier[] clientBoundDataModifiers() { + return this.clientBoundModifiers; + } + + @Override + public Map> clientBoundDataModifierMap() { + return this.clientBoundModifierMap; + } + + @Override + public ItemSettings settings() { + return this.settings; + } + + @Override + public @NotNull List behaviors() { + return this.behaviors; + } +} 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 ab3693dda..2d746bd2b 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 @@ -254,7 +254,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return VANILLA_ITEMS.contains(item); } - protected abstract CustomItem.Builder createPlatformItemBuilder(Key material); + protected abstract CustomItem.Builder createPlatformItemBuilder(Holder id, Key material); public class ItemParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; @@ -302,7 +302,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl Key itemModelKey = null; - CustomItem.Builder itemBuilder = createPlatformItemBuilder(material).id(holder); + CustomItem.Builder itemBuilder = createPlatformItemBuilder(holder, material); boolean hasItemModelSection = section.containsKey("item-model"); // To get at least one model provider diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java index 3ea626c53..32d744ba0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java @@ -127,7 +127,6 @@ public class LootTable { } } - // TODO https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/loot-system/flat-format public static LootPool readFlatFormatLootPool(String pool) { return null; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java index 151b69866..798c8e53d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java @@ -57,5 +57,6 @@ public final class DirectContextParameters { public static final ContextKey IS_FLYING = ContextKey.direct("is_flying"); public static final ContextKey IS_SNEAKING = ContextKey.direct("is_sneaking"); public static final ContextKey IS_CUSTOM = ContextKey.direct("is_custom"); + public static final ContextKey IS_BLOCK_ITEM = ContextKey.direct("is_block_item"); public static final ContextKey GAMEMODE = ContextKey.direct("gamemode"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java index a4709072f..f9d4617f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java @@ -15,6 +15,7 @@ public class ItemParameterProvider implements ChainParameterProvider> { CONTEXT_FUNCTIONS.put(DirectContextParameters.ID, Item::id); CONTEXT_FUNCTIONS.put(DirectContextParameters.CUSTOM_MODEL_DATA, i -> i.customModelData().orElse(null)); CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_CUSTOM, Item::isCustomItem); + CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_BLOCK_ITEM, Item::isBlockItem); } @SuppressWarnings("unchecked") From eaf8d3663b15419507146389f354375871849d81 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 20 May 2025 04:10:35 +0800 Subject: [PATCH 17/89] =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=96=B9=E5=9D=97?= =?UTF-8?q?=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 338 ++++++------------ .../bukkit/block/BukkitCustomBlock.java | 62 +++- .../bukkit/item/BukkitCustomItem.java | 4 +- .../bukkit/item/BukkitItemManager.java | 1 - .../DebugAppearanceStateUsageCommand.java | 2 +- .../feature/TotemAnimationCommand.java | 8 +- .../bukkit/util/BlockStateUtils.java | 4 +- .../bukkit/util/InteractUtils.java | 2 +- .../core/block/AbstractBlockManager.java | 77 +++- .../core/block/AbstractCustomBlock.java | 195 ++++++++++ .../craftengine/core/block/BlockManager.java | 14 + .../craftengine/core/block/BlockSettings.java | 1 + .../core/block/BlockStateMatcher.java | 2 +- .../craftengine/core/block/CustomBlock.java | 240 ++----------- .../craftengine/core/block/EmptyBlock.java | 6 +- .../core/block/ImmutableBlockState.java | 14 +- .../core/block/InactiveCustomBlock.java | 6 +- .../core/block/UnsafeBlockStateMatcher.java | 2 +- .../craftengine/core/block/VanillaBlock.java | 6 + .../core/block/behavior/BlockBehaviors.java | 2 +- .../core/pack/model/LegacyItemModel.java | 6 +- .../context/function/OpenWindowFunction.java | 5 +- .../plugin/context/function/RunFunction.java | 6 +- .../craftengine/core/util/GsonHelper.java | 13 + .../core/util/IntIdentityList.java | 1 - .../craftengine/core/util/ListUtils.java | 16 + .../core/util/ResourceConfigUtils.java | 49 +++ 27 files changed, 598 insertions(+), 484 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlock.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/ListUtils.java 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 6f0b2a94d..5308d06ee 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 @@ -3,12 +3,10 @@ package net.momirealms.craftengine.bukkit.block; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import dev.dejvokep.boostedyaml.YamlDocument; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -28,12 +26,8 @@ import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; -import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.event.EventFunctions; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -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,7 +39,6 @@ import org.bukkit.Registry; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; -import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; @@ -58,50 +51,34 @@ 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 Int2ObjectOpenHashMap<>(); - // A temporary map that converts the custom block registered on the server to the vanilla block ID. - private final Map tempBlockAppearanceConvertor = new Int2IntOpenHashMap(); - // A temporary map that stores the model path of a certain vanilla block state - private final Map tempVanillaBlockStateModels = new Int2ObjectOpenHashMap<>(); - // The total amount of blocks registered private int customBlockCount; protected final ImmutableBlockState[] stateId2ImmutableBlockStates; // Minecraft objects // Cached new blocks $ holders - private ImmutableMap internalId2StateId; - private ImmutableMap stateId2BlockHolder; + private Map internalId2StateId; + private Map stateId2BlockHolder; // This map is used to change the block states that are not necessarily needed into a certain block state - private ImmutableMap blockAppearanceMapper; + private Map blockAppearanceMapper; // Used to automatically arrange block states for strings such as minecraft:note_block:0 - private ImmutableMap> blockAppearanceArranger; - private ImmutableMap> realBlockArranger; + private Map> blockAppearanceArranger; + private Map> realBlockArranger; // Record the amount of real blocks by block type - private LinkedHashMap registeredRealBlockSlots; + private Map registeredRealBlockSlots; // A set of blocks that sounds have been removed - private ImmutableSet affectedSoundBlocks; - private ImmutableMap soundMapper; + private Set affectedSoundBlocks; + private Map soundMapper; // A list to record the order of registration private List blockRegisterOrder = new ObjectArrayList<>(); - - // a reverted mapper - private final Map> appearanceToRealState = new Int2ObjectOpenHashMap<>(); - // Used to store override information of json files - private final Map> blockStateOverrides = new HashMap<>(); - // for mod, real block id -> state models - private final Map modBlockStates = new HashMap<>(); // Event listeners private final BlockEventListener blockEventListener; private final FallingBlockRemoveListener fallingBlockRemoveListener; - - private Map> clientBoundTags = Map.of(); - private Map> previousTags = Map.of(); + // cached tag packet protected Object cachedUpdateTagsPacket; public BukkitBlockManager(BukkitCraftEngine plugin) { super(plugin); + instance = this; this.plugin = plugin; this.blockParser = new BlockParser(); this.initVanillaRegistry(); @@ -120,42 +97,33 @@ public class BukkitBlockManager extends AbstractBlockManager { if (enableNoteBlocks) { this.recordVanillaNoteBlocks(); } - if (VersionHelper.isOrAbove1_20_3()) { - this.fallingBlockRemoveListener = new FallingBlockRemoveListener(); - } else this.fallingBlockRemoveListener = null; - this.stateId2ImmutableBlockStates = new ImmutableBlockState[customBlockCount]; + this.fallingBlockRemoveListener = VersionHelper.isOrAbove1_20_3() ? new FallingBlockRemoveListener() : null; + this.stateId2ImmutableBlockStates = new ImmutableBlockState[this.customBlockCount]; Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.INSTANCE.defaultState()); - instance = this; this.resetPacketConsumers(); } - public List blockRegisterOrder() { - return Collections.unmodifiableList(this.blockRegisterOrder); - } - public static BukkitBlockManager instance() { return instance; } + public List blockRegisterOrder() { + return Collections.unmodifiableList(this.blockRegisterOrder); + } + @Override public void delayedInit() { - Bukkit.getPluginManager().registerEvents(this.blockEventListener, plugin.bootstrap()); + Bukkit.getPluginManager().registerEvents(this.blockEventListener, this.plugin.bootstrap()); if (this.fallingBlockRemoveListener != null) { - Bukkit.getPluginManager().registerEvents(this.fallingBlockRemoveListener, plugin.bootstrap()); + Bukkit.getPluginManager().registerEvents(this.fallingBlockRemoveListener, this.plugin.bootstrap()); } } @Override public void unload() { super.unload(); - this.clearCache(); - this.appearanceToRealState.clear(); - this.blockStateOverrides.clear(); - this.modBlockStates.clear(); if (EmptyBlock.STATE != null) Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.STATE); - this.previousTags = this.clientBoundTags; - this.clientBoundTags = new HashMap<>(); } @Override @@ -172,15 +140,14 @@ public class BukkitBlockManager extends AbstractBlockManager { @Override public void delayedLoad() { - initSuggestions(); - resetPacketConsumers(); - clearCache(); - resendTags(); + this.resetPacketConsumers(); + super.delayedLoad(); } - private void resendTags() { + @Override + protected void resendTags() { // if there's no change - if (this.clientBoundTags.equals(this.previousTags)) return; + if (this.clientBoundTags.equals(this.previousClientBoundTags)) return; List list = new ArrayList<>(); for (Map.Entry> entry : this.clientBoundTags.entrySet()) { list.add(new TagUtils.TagEntry(entry.getKey(), entry.getValue())); @@ -197,23 +164,19 @@ public class BukkitBlockManager extends AbstractBlockManager { } } - private void clearCache() { - this.tempRegistryIdConflictMap.clear(); - this.tempBlockAppearanceConvertor.clear(); - this.tempVanillaBlockStateModels.clear(); - } - @Nullable public Object getMinecraftBlockHolder(int stateId) { return stateId2BlockHolder.get(stateId); } @NotNull + @Override public ImmutableBlockState getImmutableBlockStateUnsafe(int stateId) { return this.stateId2ImmutableBlockStates[stateId - BlockStateUtils.vanillaStateSize()]; } @Nullable + @Override public ImmutableBlockState getImmutableBlockState(int stateId) { if (!BlockStateUtils.isVanillaBlock(stateId)) { return this.stateId2ImmutableBlockStates[stateId - BlockStateUtils.vanillaStateSize()]; @@ -221,34 +184,46 @@ public class BukkitBlockManager extends AbstractBlockManager { return null; } - @Override - public Map modBlockStates() { - return Collections.unmodifiableMap(this.modBlockStates); - } - @Override public ConfigParser parser() { return this.blockParser; } @Override - public Map> blockOverrides() { - return Collections.unmodifiableMap(this.blockStateOverrides); + public void addBlock(Key id, CustomBlock customBlock) { + // bind appearance and real state + for (ImmutableBlockState state : customBlock.variantProvider().states()) { + ImmutableBlockState previous = this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()]; + if (previous != null && !previous.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.block.state.bind_failed", state.toString(), previous.toString()); + } + 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 IntArrayList()).add(state.customBlockState().registryId()); + } + super.addBlock(id, customBlock); } - public ImmutableMap> blockAppearanceArranger() { + @Override + public Key getBlockOwnerId(PackedBlockState state) { + return BlockStateUtils.getBlockOwnerIdFromState(state.handle()); + } + + @Override + public int availableAppearances(Key blockType) { + return Optional.ofNullable(this.registeredRealBlockSlots.get(blockType)).orElse(0); + } + + @NotNull + public Map> blockAppearanceArranger() { return this.blockAppearanceArranger; } - public ImmutableMap> realBlockArranger() { + @NotNull + public Map> realBlockArranger() { return this.realBlockArranger; } - @Nullable - public List appearanceToRealStates(int appearanceStateId) { - return this.appearanceToRealState.get(appearanceStateId); - } - private void initMirrorRegistry() { int size = RegistryUtils.currentBlockRegistrySize(); PackedBlockState[] states = new PackedBlockState[size]; @@ -276,25 +251,25 @@ public class BukkitBlockManager extends AbstractBlockManager { private void initVanillaRegistry() { int vanillaStateCount; - if (plugin.hasMod()) { + if (this.plugin.hasMod()) { try { Class modClass = ReflectionUtils.getClazz(CraftEngine.MOD_CLASS); Field amountField = ReflectionUtils.getDeclaredField(modClass, "vanillaRegistrySize"); vanillaStateCount = amountField.getInt(null); } catch (Exception e) { vanillaStateCount = RegistryUtils.currentBlockRegistrySize(); - plugin.logger().severe("Fatal error", e); + this.plugin.logger().severe("Fatal error", e); } } else { vanillaStateCount = RegistryUtils.currentBlockRegistrySize(); } - plugin.logger().info("Vanilla block count: " + vanillaStateCount); + this.plugin.logger().info("Vanilla block count: " + vanillaStateCount); BlockStateUtils.init(vanillaStateCount); } @SuppressWarnings("unchecked") private void registerBlocks() { - plugin.logger().info("Registering blocks. Please wait..."); + this.plugin.logger().info("Registering blocks. Please wait..."); try { ImmutableMap.Builder builder1 = ImmutableMap.builder(); ImmutableMap.Builder builder2 = ImmutableMap.builder(); @@ -367,7 +342,7 @@ public class BukkitBlockManager extends AbstractBlockManager { parseVanillaBlock(pack, path, id, section); } else { // check duplicated config - if (byId.containsKey(id)) { + if (BukkitBlockManager.this.byId.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.block.duplicate"); } parseCustomBlock(pack, path, id, section); @@ -376,128 +351,73 @@ public class BukkitBlockManager extends AbstractBlockManager { private void parseCustomBlock(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)); - + BlockSettings settings = BlockSettings.fromMap(MiscUtils.castToMap(section.get("settings"), true)); // read states Map> properties; Map appearances; Map variants; - Object stateObj = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state"); - Map stateSection = MiscUtils.castToMap(stateObj, true); + Map stateSection = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state"), true); + boolean singleState = !stateSection.containsKey("properties"); // single state - if (!stateSection.containsKey("properties")) { + if (singleState) { properties = Map.of(); - int internalId = ResourceConfigUtils.getAsInt(stateSection.getOrDefault("id", -1), "id"); - if (internalId < 0) { - throw new LocalizedResourceConfigException("warning.config.block.state.missing_real_id"); - } - - Pair pair = parseAppearanceSection(id, stateSection); - if (pair == null) return; - - appearances = Map.of("default", pair.right()); - String internalBlock = pair.left().value() + "_" + internalId; - Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, internalBlock); + int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id"); + VanillaBlock vanillaBlock = getVanillaBlock(id, stateSection); + appearances = Map.of("", vanillaBlock.registryId()); + Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, vanillaBlock.type().value() + "_" + internalId); int internalBlockRegistryId = Optional.ofNullable(internalId2StateId.get(internalBlockId)).orElse(-1); if (internalBlockRegistryId == -1) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", - internalBlock, - String.valueOf(registeredRealBlockSlots.get(pair.left()) - 1)); + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(vanillaBlock.type()) - 1)); } - variants = Map.of("", new VariantState("default", settings, internalBlockRegistryId)); + variants = Map.of("", new VariantState("", settings, internalBlockRegistryId)); } else { // properties - Map propertySection = MiscUtils.castToMap(stateSection.get("properties"), true); - if (propertySection == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.missing_properties"); - } - properties = parseProperties(propertySection); + properties = getProperties(MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), true)); // appearance - Map appearancesSection = MiscUtils.castToMap(stateSection.get("appearances"), true); - if (appearancesSection == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.missing_appearances"); - } appearances = new HashMap<>(); - Map tempTypeMap = new HashMap<>(); - for (Map.Entry appearanceEntry : appearancesSection.entrySet()) { - if (appearanceEntry.getValue() instanceof Map appearanceSection) { - Pair pair = parseAppearanceSection(id, MiscUtils.castToMap(appearanceSection, false)); - if (pair == null) return; - appearances.put(appearanceEntry.getKey(), pair.right()); - tempTypeMap.put(appearanceEntry.getKey(), pair.left()); + Map appearance2BlockType = new HashMap<>(); + for (Map.Entry appearanceEntry : MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), false).entrySet()) { + if (appearanceEntry.getValue() instanceof Map) { + VanillaBlock vanillaBlock = getVanillaBlock(id, MiscUtils.castToMap(appearanceEntry.getValue(), false)); + appearances.put(appearanceEntry.getKey(), vanillaBlock.registryId()); + appearance2BlockType.put(appearanceEntry.getKey(), vanillaBlock.type()); } } // variants - Map variantsSection = MiscUtils.castToMap(stateSection.get("variants"), true); - if (variantsSection == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.missing_variants"); - } 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) { - throw new LocalizedResourceConfigException("warning.config.block.state.variant.missing_appearance", variantName); - } + for (Map.Entry variantEntry : MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), false).entrySet()) { + if (variantEntry.getValue() instanceof Map) { + Map variantSection = MiscUtils.castToMap(variantEntry.getValue(), false); + String variantNBT = variantEntry.getKey(); + String appearance = ResourceConfigUtils.requireNonEmptyStringOrThrow(variantSection.get("appearance"), "warning.config.block.state.variant.missing_appearance"); if (!appearances.containsKey(appearance)) { - throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantName, appearance); + throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearance); } - int internalId = ResourceConfigUtils.getAsInt(variantSection.getOrDefault("id", -1), "id"); - Key baseBlock = tempTypeMap.get(appearance); + int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(variantSection.get("id"), "warning.config.block.state.missing_real_id"), "id"); + Key baseBlock = appearance2BlockType.get(appearance); Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, baseBlock.value() + "_" + internalId); int internalBlockRegistryId = Optional.ofNullable(internalId2StateId.get(internalBlockId)).orElse(-1); if (internalBlockRegistryId == -1) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", - internalBlockId.toString(), - String.valueOf(registeredRealBlockSlots.getOrDefault(baseBlock, 1) - 1)); + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(baseBlock) - 1)); } Map anotherSetting = MiscUtils.castToMap(variantSection.get("settings"), true); - variants.put(variantName, new VariantState(appearance, anotherSetting == null ? settings : BlockSettings.ofFullCopy(settings, anotherSetting), internalBlockRegistryId)); + variants.put(variantNBT, new VariantState(appearance, anotherSetting == null ? settings : BlockSettings.ofFullCopy(settings, anotherSetting), internalBlockRegistryId)); } } } - Object eventsObj = ResourceConfigUtils.get(section, "events", "event"); - EnumMap>> events = EventFunctions.parseEvents(eventsObj); - - Map behaviors = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); CustomBlock block = BukkitCustomBlock.builder(id) .appearances(appearances) .variantMapper(variants) - .lootTable(lootTable) .properties(properties) .settings(settings) - .behavior(behaviors) - .events(events) + .lootTable(LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), true))) + .behavior(MiscUtils.castToMap(section.get("behavior"), true)) + .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) .build(); - // 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.state.bind_failed", 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 IntArrayList()).add(state.customBlockState().registryId()); - } - - BukkitBlockManager.this.byId.put(id, block); - - // generate mod assets - if (Config.generateModAssets()) { - for (ImmutableBlockState state : block.variantProvider().states()) { - Key realBlockId = BlockStateUtils.getBlockOwnerIdFromState(state.customBlockState()); - modBlockStates.put(realBlockId, tempVanillaBlockStateModels.get(state.vanillaBlockState().registryId())); - } - } + addBlock(id, block); } private void parseVanillaBlock(Pack pack, Path path, Key id, Map section) { @@ -518,7 +438,8 @@ public class BukkitBlockManager extends AbstractBlockManager { } } - private Map> parseProperties(Map propertiesSection) { + @NotNull + private Map> getProperties(Map propertiesSection) { Map> properties = new HashMap<>(); for (Map.Entry entry : propertiesSection.entrySet()) { Property property = Properties.fromMap(entry.getKey(), MiscUtils.castToMap(entry.getValue(), false)); @@ -527,69 +448,40 @@ public class BukkitBlockManager extends AbstractBlockManager { return properties; } - @Nullable - private Pair parseAppearanceSection(Key id, Map section) { + @NotNull + private VanillaBlock getVanillaBlock(Key id, Map section) { // require state non null - Object vanillaStateString = section.get("state"); - if (vanillaStateString == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.missing_state"); - } - + String vanillaBlockStateTag = ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("state"), "warning.config.block.state.missing_state"); // get its registry id - int vanillaStateRegistryId = parseVanillaStateRegistryId(vanillaStateString.toString()); - - // check conflict - Key ifAny = this.tempRegistryIdConflictMap.get(vanillaStateRegistryId); + int vanillaBlockStateRegistryId = getVanillaBlockStateRegistryId(vanillaBlockStateTag); + // check if another block has occupied the appearance + // TODO blocks share the same look + Key ifAny = this.tempRegistryIdConflictMap.get(vanillaBlockStateRegistryId); if (ifAny != null && !ifAny.equals(id)) { - throw new LocalizedResourceConfigException("warning.config.block.state.conflict", BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(vanillaStateRegistryId)).getAsString(), ifAny.toString()); + throw new LocalizedResourceConfigException("warning.config.block.state.conflict", BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(vanillaBlockStateRegistryId)).getAsString(), ifAny.toString()); } - // require models not to be null - Object models = section.get("models"); - if (models == null) { - models = section.get("model"); - } - if (models == null) { + Object models = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "models", "model"), "warning.config.block.state.missing_model"); + List variants = ResourceConfigUtils.parseConfigAsList(models, this::getVariantModel); + if (variants.isEmpty()) { throw new LocalizedResourceConfigException("warning.config.block.state.missing_model"); } - - List variants = new ArrayList<>(); - if (models instanceof Map singleModelSection) { - loadVariantModel(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)); - } - } - } - 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('}'))); - String propertyData = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']')); - Map paths = this.blockStateOverrides.computeIfAbsent(block, k -> new HashMap<>()); - if (variants.size() == 1) { - paths.put(propertyData, variants.get(0)); - this.tempVanillaBlockStateModels.put(vanillaStateRegistryId, variants.get(0)); - } else { - JsonArray array = new JsonArray(); - for (JsonObject object : variants) { - array.add(object); - } - paths.put(propertyData, array); - this.tempVanillaBlockStateModels.put(vanillaStateRegistryId, array); - } - return Pair.of(block, vanillaStateRegistryId); + // TODO blocks share the same look + this.tempRegistryIdConflictMap.put(vanillaBlockStateRegistryId, id); + // gets the full block state + String blockState = BlockStateUtils.idToBlockState(vanillaBlockStateRegistryId).toString(); + Key blockId = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}'))); + String propertyNBT = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']')); + // for generating assets + JsonElement combinedVariant = GsonHelper.combine(variants); + this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()).put(propertyNBT, combinedVariant); + this.tempVanillaBlockStateModels.put(vanillaBlockStateRegistryId, combinedVariant); + return new VanillaBlock(blockId, propertyNBT, vanillaBlockStateRegistryId); } - private void loadVariantModel(List variants, Map singleModelMap) { + private JsonObject getVariantModel(Map singleModelMap) { JsonObject json = new JsonObject(); - String modelPath = (String) singleModelMap.get("path"); - if (modelPath == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.model.missing_path"); - } + String modelPath = ResourceConfigUtils.requireNonEmptyStringOrThrow(singleModelMap.get("path"), "warning.config.block.state.model.missing_path"); if (!ResourceLocation.isValid(modelPath)) { throw new LocalizedResourceConfigException("warning.config.block.state.model.invalid_path", modelPath); } @@ -602,10 +494,10 @@ public class BukkitBlockManager extends AbstractBlockManager { if (generationMap != null) { prepareModelGeneration(ModelGeneration.of(Key.of(modelPath), generationMap)); } - variants.add(json); + return json; } - private int parseVanillaStateRegistryId(String blockState) { + private int getVanillaBlockStateRegistryId(String blockState) { String[] split = blockState.split(":", 3); if (split.length >= 4) { throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index 17891cded..c9897a727 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -28,7 +28,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; import java.util.*; -public class BukkitCustomBlock extends CustomBlock { +public class BukkitCustomBlock extends AbstractCustomBlock { protected BukkitCustomBlock( Key id, @@ -147,17 +147,67 @@ public class BukkitCustomBlock extends CustomBlock { } public static Builder builder(Key id) { - return new Builder(id); + return new BuilderImpl(id); } - public static class Builder extends CustomBlock.Builder { + public static class BuilderImpl implements Builder { + protected final Key id; + protected Map> properties; + protected Map appearances; + protected Map variantMapper; + protected BlockSettings settings; + protected Map behavior; + protected LootTable lootTable; + protected EnumMap>> events; - protected Builder(Key id) { - super(id); + public BuilderImpl(Key id) { + this.id = id; } @Override - public CustomBlock build() { + public Builder events(EnumMap>> events) { + this.events = events; + return this; + } + + @Override + public Builder appearances(Map appearances) { + this.appearances = appearances; + return this; + } + + @Override + public Builder behavior(Map behavior) { + this.behavior = behavior; + return this; + } + + @Override + public Builder lootTable(LootTable lootTable) { + this.lootTable = lootTable; + return this; + } + + @Override + public Builder properties(Map> properties) { + this.properties = properties; + return this; + } + + @Override + public Builder settings(BlockSettings settings) { + this.settings = settings; + return this; + } + + @Override + public Builder variantMapper(Map variantMapper) { + this.variantMapper = variantMapper; + return this; + } + + @Override + public @NotNull CustomBlock build() { // create or get block holder Holder.Reference holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() -> ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id))); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index a0438f38c..fd7c32143 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -13,7 +13,9 @@ import net.momirealms.craftengine.core.util.Key; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import java.util.*; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; public class BukkitCustomItem extends AbstractCustomItem { private final Material material; 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 57fa33974..f51b4ee82 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 @@ -36,7 +36,6 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java index 2aad44aad..f47eb842e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java @@ -51,7 +51,7 @@ public class DebugAppearanceStateUsageCommand extends BukkitCommandFeature reals = blockManager.appearanceToRealStates(appearance); - if (reals == null) { + if (reals == null || reals.isEmpty()) { Component hover = Component.text(baseBlockId.value() + ":" + i).color(NamedTextColor.GREEN); hover = hover.append(Component.newline()).append(Component.text(BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(appearance)).getAsString()).color(NamedTextColor.GREEN)); text = text.color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java index e0381d921..63f72aaca 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java @@ -3,16 +3,17 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.item.ComponentTypes; 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.*; +import net.momirealms.craftengine.core.item.CustomItem; +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.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 net.momirealms.craftengine.core.util.VersionHelper; -import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -26,7 +27,6 @@ import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; import org.incendo.cloud.parser.flag.CommandFlag; -import org.incendo.cloud.parser.standard.StringParser; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; 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 81163c601..a5d8d4446 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 @@ -101,10 +101,10 @@ public class BlockStateUtils { } public static Key getBlockOwnerId(Block block) { - return getBlockOwnerId(block.getBlockData()); + return getBlockOwnerIdFromData(block.getBlockData()); } - public static Key getBlockOwnerId(BlockData block) { + public static Key getBlockOwnerIdFromData(BlockData block) { Object blockState = blockDataToBlockState(block); return getBlockOwnerIdFromState(blockState); } 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 7152b3f98..fa6c73e44 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 @@ -274,7 +274,7 @@ public class InteractUtils { } public static boolean isInteractable(Player player, BlockData state, BlockHitResult hit, Item item) { - Key blockType = BlockStateUtils.getBlockOwnerId(state); + Key blockType = BlockStateUtils.getBlockOwnerIdFromData(state); if (INTERACTIONS.containsKey(blockType)) { return INTERACTIONS.get(blockType).apply(player, item, state, hit); } else { 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 ba3e03d8f..48bde480b 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 @@ -1,9 +1,14 @@ package net.momirealms.craftengine.core.block; +import com.google.gson.JsonElement; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.Key; import org.incendo.cloud.suggestion.Suggestion; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -14,11 +19,46 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected final List cachedSuggestions = new ArrayList<>(); // Cached Namespace protected final Set namespacesInUse = new HashSet<>(); + // for mod, real block id -> state models + protected final Map modBlockStates = new HashMap<>(); + // A temporary map that stores the model path of a certain vanilla block state + protected final Map tempVanillaBlockStateModels = new Int2ObjectOpenHashMap<>(); + // A temporary map used to detect whether the same block state corresponds to multiple models. + protected final Map tempRegistryIdConflictMap = new Int2ObjectOpenHashMap<>(); + // A temporary map that converts the custom block registered on the server to the vanilla block ID. + protected final Map tempBlockAppearanceConvertor = new Int2IntOpenHashMap(); + // Used to store override information of json files + protected final Map> blockStateOverrides = new HashMap<>(); + // a reverted mapper + protected final Map> appearanceToRealState = new Int2ObjectOpenHashMap<>(); + // client side block tags + protected Map> clientBoundTags = Map.of(); + protected Map> previousClientBoundTags = Map.of(); - public AbstractBlockManager(CraftEngine plugin) { + protected AbstractBlockManager(CraftEngine plugin) { super(plugin); } + @Override + public void unload() { + super.clearModelsToGenerate(); + this.clearCache(); + this.cachedSuggestions.clear(); + this.blockStateOverrides.clear(); + this.modBlockStates.clear(); + this.byId.clear(); + this.previousClientBoundTags = this.clientBoundTags; + this.clientBoundTags = new HashMap<>(); + this.appearanceToRealState.clear(); + } + + @Override + public void delayedLoad() { + this.initSuggestions(); + this.clearCache(); + this.resendTags(); + } + @Override public Map blocks() { return Collections.unmodifiableMap(this.byId); @@ -30,10 +70,24 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } @Override - public void unload() { - super.clearModelsToGenerate(); - this.cachedSuggestions.clear(); - this.byId.clear(); + public void addBlock(Key id, CustomBlock customBlock) { + this.byId.put(id, customBlock); + // generate mod assets + if (Config.generateModAssets()) { + for (ImmutableBlockState state : customBlock.variantProvider().states()) { + this.modBlockStates.put(getBlockOwnerId(state.customBlockState()), this.tempVanillaBlockStateModels.get(state.vanillaBlockState().registryId())); + } + } + } + + @Override + public Map modBlockStates() { + return Collections.unmodifiableMap(this.modBlockStates); + } + + @Override + public Map> blockOverrides() { + return Collections.unmodifiableMap(this.blockStateOverrides); } @Override @@ -45,6 +99,12 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return Collections.unmodifiableSet(this.namespacesInUse); } + protected void clearCache() { + this.tempRegistryIdConflictMap.clear(); + this.tempBlockAppearanceConvertor.clear(); + this.tempVanillaBlockStateModels.clear(); + } + protected void initSuggestions() { this.cachedSuggestions.clear(); this.namespacesInUse.clear(); @@ -60,4 +120,11 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.cachedSuggestions.add(Suggestion.suggestion(state)); } } + + @NotNull + public List appearanceToRealStates(int appearanceStateId) { + return Optional.ofNullable(this.appearanceToRealState.get(appearanceStateId)).orElse(List.of()); + } + + protected abstract void resendTags(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java new file mode 100644 index 000000000..cb3efd929 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java @@ -0,0 +1,195 @@ +package net.momirealms.craftengine.core.block; + +import com.google.common.collect.ImmutableMap; +import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviors; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.item.context.BlockPlaceContext; +import net.momirealms.craftengine.core.loot.LootTable; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.shared.block.BlockBehavior; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.BiFunction; + +public abstract class AbstractCustomBlock implements CustomBlock { + protected final Holder holder; + protected final Key id; + protected final BlockStateVariantProvider variantProvider; + protected final Map> properties; + protected final BlockBehavior behavior; + protected final BiFunction placementFunction; + protected final ImmutableBlockState defaultState; + protected final Map>> events; + @Nullable + protected final LootTable lootTable; + + protected AbstractCustomBlock( + @NotNull Key id, + @NotNull Holder.Reference holder, + @NotNull Map> properties, + @NotNull Map appearances, + @NotNull Map variantMapper, + @NotNull BlockSettings settings, + @NotNull Map>> events, + @Nullable Map behavior, + @Nullable LootTable lootTable + ) { + holder.bindValue(this); + this.holder = holder; + this.id = id; + this.lootTable = lootTable; + this.properties = ImmutableMap.copyOf(properties); + this.events = events; + this.variantProvider = new BlockStateVariantProvider(holder, ImmutableBlockState::new, properties); + this.defaultState = this.variantProvider.getDefaultState(); + this.behavior = BlockBehaviors.fromMap(this, behavior); + List> placements = new ArrayList<>(4); + for (Map.Entry> propertyEntry : this.properties.entrySet()) { + placements.add(Property.createStateForPlacement(propertyEntry.getKey(), propertyEntry.getValue())); + } + this.placementFunction = composite(placements); + for (Map.Entry entry : variantMapper.entrySet()) { + String nbtString = entry.getKey(); + CompoundTag tag = BlockNbtParser.deserialize(this, nbtString); + if (tag == null) { + throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString); + } + VariantState variantState = entry.getValue(); + int vanillaStateRegistryId = appearances.getOrDefault(variantState.appearance(), -1); + // This should never happen + if (vanillaStateRegistryId == -1) { + vanillaStateRegistryId = appearances.values().iterator().next(); + } + // Late init states + for (ImmutableBlockState state : this.getPossibleStates(tag)) { + state.setBehavior(this.behavior); + state.setSettings(variantState.settings()); + state.setVanillaBlockState(BlockRegistryMirror.stateByRegistryId(vanillaStateRegistryId)); + state.setCustomBlockState(BlockRegistryMirror.stateByRegistryId(variantState.internalRegistryId())); + } + } + // double check if there's any invalid state + for (ImmutableBlockState state : this.variantProvider().states()) { + if (state.settings() == null) { + state.setSettings(settings); + } + } + this.applyPlatformSettings(); + } + + private static BiFunction composite(List> placements) { + return switch (placements.size()) { + case 0 -> (c, i) -> i; + case 1 -> placements.get(0); + case 2 -> { + BiFunction f1 = placements.get(0); + BiFunction f2 = placements.get(1); + yield (c, i) -> f2.apply(c, f1.apply(c, i)); + } + default -> (c, i) -> { + for (BiFunction f : placements) { + i = f.apply(c, i); + } + return i; + }; + }; + } + + protected abstract void applyPlatformSettings(); + + @Override + public @Nullable LootTable lootTable() { + return this.lootTable; + } + + @Override + public void execute(PlayerOptionalContext context, EventTrigger trigger) { + for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { + function.run(context); + } + } + + @NotNull + @Override + public BlockStateVariantProvider variantProvider() { + return this.variantProvider; + } + + @NotNull + @Override + public final Key id() { + return this.id; + } + + @Override + public List getPossibleStates(CompoundTag nbt) { + List tempStates = new ArrayList<>(); + tempStates.add(defaultState()); + for (Property property : this.variantProvider.getDefaultState().getProperties()) { + Tag value = nbt.get(property.name()); + if (value != null) { + tempStates.replaceAll(immutableBlockState -> ImmutableBlockState.with(immutableBlockState, property, property.unpack(value))); + } else { + List newStates = new ArrayList<>(); + for (ImmutableBlockState state : tempStates) { + for (Object possibleValue : property.possibleValues()) { + newStates.add(ImmutableBlockState.with(state, property, possibleValue)); + } + } + tempStates = newStates; + } + } + return tempStates; + } + + @Override + public ImmutableBlockState getBlockState(CompoundTag nbt) { + ImmutableBlockState state = defaultState(); + for (Map.Entry entry : nbt.tags.entrySet()) { + Property property = this.variantProvider.getProperty(entry.getKey()); + if (property != null) { + try { + state = ImmutableBlockState.with(state, property, property.unpack(entry.getValue())); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to parse block state: " + entry.getKey(), e); + } + } + } + return state; + } + + @Override + public @Nullable Property getProperty(String name) { + return this.properties.get(name); + } + + @Override + public @NotNull Collection> properties() { + return this.properties.values(); + } + + @Override + public final ImmutableBlockState defaultState() { + return this.defaultState; + } + + @Override + public ImmutableBlockState getStateForPlacement(BlockPlaceContext context) { + ImmutableBlockState state = this.placementFunction.apply(context, defaultState()); + if (this.behavior instanceof AbstractBlockBehavior blockBehavior) { + state = blockBehavior.updateStateForPlacement(context, state); + } + return 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 8cbeb5a5a..208355f1a 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 @@ -7,7 +7,9 @@ import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; import org.incendo.cloud.suggestion.Suggestion; +import org.jetbrains.annotations.NotNull; +import javax.annotation.Nullable; import java.util.Collection; import java.util.Map; import java.util.Optional; @@ -26,7 +28,19 @@ public interface BlockManager extends Manageable, ModelGenerator { Optional blockById(Key key); + void addBlock(Key id, CustomBlock customBlock); + Collection cachedSuggestions(); Map soundMapper(); + + int availableAppearances(Key blockType); + + Key getBlockOwnerId(PackedBlockState state); + + @NotNull + ImmutableBlockState getImmutableBlockStateUnsafe(int stateId); + + @Nullable + ImmutableBlockState getImmutableBlockState(int stateId); } 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 cfcfd042c..79e268a99 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 @@ -42,6 +42,7 @@ public class BlockSettings { } public static BlockSettings fromMap(Map map) { + if (map == null || map.isEmpty()) return BlockSettings.of(); return applyModifiers(BlockSettings.of(), map); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateMatcher.java index 3886220dc..87678487c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateMatcher.java @@ -24,7 +24,7 @@ public class BlockStateMatcher { } public boolean matches(ImmutableBlockState state) { - if (!state.owner().value().id.equals(this.id)) { + if (!state.owner().value().id().equals(this.id)) { return false; } for (Pair, Comparable> pair : this.properties) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java index 73c324414..2e3fb29a7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java @@ -1,251 +1,59 @@ package net.momirealms.craftengine.core.block; -import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.BlockBehaviors; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.loot.LootTable; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.event.EventTrigger; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.shared.block.BlockBehavior; import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; -import java.util.function.BiFunction; +import java.util.Collection; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; -public abstract class CustomBlock { - protected final Holder holder; - protected final Key id; - protected final BlockStateVariantProvider variantProvider; - protected final Map> properties; - protected final BlockBehavior behavior; - protected final List> placements; - protected final ImmutableBlockState defaultState; - protected final EnumMap>> events; - @Nullable - protected final LootTable lootTable; +public interface CustomBlock { - protected CustomBlock( - @NotNull Key id, - @NotNull Holder.Reference holder, - @NotNull Map> properties, - @NotNull Map appearances, - @NotNull Map variantMapper, - @NotNull BlockSettings settings, - @NotNull EnumMap>> events, - @Nullable Map behavior, - @Nullable LootTable lootTable - ) { - holder.bindValue(this); - this.holder = holder; - this.id = id; - this.lootTable = lootTable; - this.properties = properties; - this.placements = new ArrayList<>(); - this.events = events; - this.variantProvider = new BlockStateVariantProvider(holder, ImmutableBlockState::new, properties); - this.defaultState = this.variantProvider.getDefaultState(); - this.behavior = BlockBehaviors.fromMap(this, behavior); - for (Map.Entry entry : variantMapper.entrySet()) { - String nbtString = entry.getKey(); - CompoundTag tag = BlockNbtParser.deserialize(this, nbtString); - if (tag == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString); - } - VariantState variantState = entry.getValue(); - int vanillaStateRegistryId = appearances.getOrDefault(variantState.appearance(), -1); - // This should never happen - if (vanillaStateRegistryId == -1) { - vanillaStateRegistryId = appearances.values().iterator().next(); - } - // Late init states - for (ImmutableBlockState state : this.getPossibleStates(tag)) { - state.setBehavior(this.behavior); - state.setSettings(variantState.settings()); - state.setVanillaBlockState(BlockRegistryMirror.stateByRegistryId(vanillaStateRegistryId)); - state.setCustomBlockState(BlockRegistryMirror.stateByRegistryId(variantState.internalRegistryId())); - } - } - // double check if there's any invalid state - for (ImmutableBlockState state : this.variantProvider().states()) { - if (state.settings() == null) { - state.setSettings(settings); - } - } - this.applyPlatformSettings(); - for (Map.Entry> propertyEntry : this.properties.entrySet()) { - this.placements.add(Property.createStateForPlacement(propertyEntry.getKey(), propertyEntry.getValue())); - } - } + Key id(); - protected abstract void applyPlatformSettings(); + @Nullable LootTable lootTable(); - @Nullable - public LootTable lootTable() { - return lootTable; - } + void execute(PlayerOptionalContext context, EventTrigger trigger); - public void execute(PlayerOptionalContext context, EventTrigger trigger) { - for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { - function.run(context); - } - } + @NotNull BlockStateVariantProvider variantProvider(); - @NotNull - public BlockStateVariantProvider variantProvider() { - return variantProvider; - } + List getPossibleStates(CompoundTag nbt); - @NotNull - public final Key id() { - return id; - } + ImmutableBlockState getBlockState(CompoundTag nbt); - private List getPossibleStates(CompoundTag nbt) { - List tempStates = new ArrayList<>(); - tempStates.add(defaultState()); - for (Property property : variantProvider.getDefaultState().getProperties()) { - Tag value = nbt.get(property.name()); - if (value != null) { - tempStates.replaceAll(immutableBlockState -> ImmutableBlockState.with(immutableBlockState, property, property.unpack(value))); - } else { - List newStates = new ArrayList<>(); - for (ImmutableBlockState state : tempStates) { - for (Object possibleValue : property.possibleValues()) { - newStates.add(ImmutableBlockState.with(state, property, possibleValue)); - } - } - tempStates = newStates; - } - } - return tempStates; - } + @Nullable Property getProperty(String name); - public ImmutableBlockState getBlockState(CompoundTag nbt) { - ImmutableBlockState state = defaultState(); - for (Map.Entry entry : nbt.tags.entrySet()) { - Property property = this.variantProvider.getProperty(entry.getKey()); - if (property != null) { - try { - state = ImmutableBlockState.with(state, property, property.unpack(entry.getValue())); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to parse block state: " + entry.getKey(), e); - } - } - } - return state; - } + @NotNull Collection> properties(); - @Nullable - public Property getProperty(String name) { - return this.properties.get(name); - } + ImmutableBlockState defaultState(); - @NotNull - public Collection> properties() { - return this.properties.values(); - } + ImmutableBlockState getStateForPlacement(BlockPlaceContext context); - public final ImmutableBlockState defaultState() { - return this.defaultState; - } + interface Builder { - public ImmutableBlockState getStateForPlacement(BlockPlaceContext context) { - ImmutableBlockState state = defaultState(); - for (BiFunction placement : this.placements) { - state = placement.apply(context, state); - } - if (this.behavior instanceof AbstractBlockBehavior blockBehavior) { - state = blockBehavior.updateStateForPlacement(context, state); - } - return state; - } + Builder events(EnumMap>> events); - public abstract static class Builder { - protected final Key id; - protected Map> properties; - protected Map appearances; - protected Map variantMapper; - protected BlockSettings settings; - protected Map behavior; - protected LootTable lootTable; - protected EnumMap>> events; + Builder appearances(Map appearances); - protected Builder(Key id) { - this.id = id; - } + Builder behavior(Map behavior); - public Builder events(EnumMap>> events) { - this.events = events; - return this; - } + Builder lootTable(LootTable lootTable); - public Builder appearances(Map appearances) { - this.appearances = appearances; - return this; - } + Builder properties(Map> properties); - public Builder behavior(Map behavior) { - this.behavior = behavior; - return this; - } + Builder settings(BlockSettings settings); - public Builder lootTable(LootTable lootTable) { - this.lootTable = lootTable; - return this; - } + Builder variantMapper(Map variantMapper); - public Builder properties(Map> properties) { - this.properties = properties; - return this; - } - - public Builder settings(BlockSettings settings) { - this.settings = settings; - return this; - } - - public Builder variantMapper(Map variantMapper) { - this.variantMapper = variantMapper; - return this; - } - - public Map appearances() { - return appearances; - } - - public Map behavior() { - return behavior; - } - - public Key id() { - return id; - } - - public LootTable lootTable() { - return lootTable; - } - - public Map> properties() { - return properties; - } - - public BlockSettings settings() { - return settings; - } - - public Map variantMapper() { - return variantMapper; - } - - public abstract CustomBlock build(); + @NotNull CustomBlock build(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java index 4e5cca009..1e24acdc0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java @@ -1,18 +1,16 @@ package net.momirealms.craftengine.core.block; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; -import java.util.EnumMap; import java.util.Map; -public class EmptyBlock extends CustomBlock { +public class EmptyBlock extends AbstractCustomBlock { public static EmptyBlock INSTANCE; public static ImmutableBlockState STATE; public EmptyBlock(Key id, Holder.Reference holder) { - super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), new EnumMap<>(EventTrigger.class), null, null); + super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), null, null); INSTANCE = this; STATE = defaultState(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index 772468379..32c5890a9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -35,7 +35,7 @@ public class ImmutableBlockState extends BlockStateHolder { } public BlockBehavior behavior() { - return behavior; + return this.behavior; } public void setBehavior(BlockBehavior behavior) { @@ -43,7 +43,7 @@ public class ImmutableBlockState extends BlockStateHolder { } public BlockSettings settings() { - return settings; + return this.settings; } public void setSettings(BlockSettings settings) { @@ -116,16 +116,16 @@ public class ImmutableBlockState extends BlockStateHolder { } public CompoundTag getNbtToSave() { - if (tag == null) { - tag = toNbtToSave(propertiesNbt()); + if (this.tag == null) { + this.tag = toNbtToSave(propertiesNbt()); } - return tag; + return this.tag; } public CompoundTag toNbtToSave(CompoundTag properties) { CompoundTag tag = new CompoundTag(); tag.put("properties", properties); - tag.put("id", NBT.createString(owner.value().id().toString())); + tag.put("id", NBT.createString(this.owner.value().id().asString())); return tag; } @@ -140,7 +140,7 @@ public class ImmutableBlockState extends BlockStateHolder { @SuppressWarnings("unchecked") public List> getDrops(@NotNull ContextHolder.Builder builder, @NotNull World world, @Nullable Player player) { - CustomBlock block = owner.value(); + CustomBlock block = this.owner.value(); if (block == null) return List.of(); LootTable lootTable = (LootTable) block.lootTable(); if (lootTable == null) return List.of(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java index a733f2bfd..29ee6e7a0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java @@ -1,20 +1,18 @@ package net.momirealms.craftengine.core.block; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.CompoundTag; -import java.util.EnumMap; import java.util.HashMap; import java.util.Map; -public class InactiveCustomBlock extends CustomBlock { +public class InactiveCustomBlock extends AbstractCustomBlock { private final Map cachedData = new HashMap<>(); public InactiveCustomBlock(Key id, Holder.Reference holder) { - super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), new EnumMap<>(EventTrigger.class), null, null); + super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), null, null); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/UnsafeBlockStateMatcher.java b/core/src/main/java/net/momirealms/craftengine/core/block/UnsafeBlockStateMatcher.java index 00b9d4b49..f0174a4ad 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/UnsafeBlockStateMatcher.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/UnsafeBlockStateMatcher.java @@ -24,7 +24,7 @@ public class UnsafeBlockStateMatcher { } public boolean matches(ImmutableBlockState state) { - if (!state.owner().value().id.equals(this.id)) { + if (!state.owner().value().id().equals(this.id)) { return false; } CustomBlock customBlock = state.owner().value(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlock.java new file mode 100644 index 000000000..1ce3a53ef --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlock.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.block; + +import net.momirealms.craftengine.core.util.Key; + +public record VanillaBlock(Key type, String properties, int registryId) { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java index d75ffc494..610dbb221 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java @@ -30,7 +30,7 @@ public class BlockBehaviors { Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); BlockBehaviorFactory factory = BuiltInRegistries.BLOCK_BEHAVIOR_FACTORY.getValue(key); if (factory == null) { - throw new LocalizedResourceConfigException("warning.config.block.behavior.invalid_type", type.toString()); + throw new LocalizedResourceConfigException("warning.config.block.behavior.invalid_type", type); } return factory.create(block, map); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java index aa1cdf921..925b2bb87 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/LegacyItemModel.java @@ -5,9 +5,11 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import software.amazon.awssdk.services.s3.endpoints.internal.Value; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class LegacyItemModel { private final List modelsToGenerate; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java index 242149a45..010098123 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java @@ -10,7 +10,10 @@ import net.momirealms.craftengine.core.plugin.context.text.TextProvider; import net.momirealms.craftengine.core.plugin.context.text.TextProviders; import net.momirealms.craftengine.core.plugin.gui.GuiType; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.EnumUtils; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import javax.annotation.Nullable; import java.util.List; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java index 1cc08eb6c..801e13667 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java @@ -6,8 +6,10 @@ import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.plugin.event.EventFunctions; -import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldPosition; import java.util.ArrayList; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/GsonHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/GsonHelper.java index 7dcb40ce1..6245e85d6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/GsonHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/GsonHelper.java @@ -8,6 +8,7 @@ import java.io.BufferedWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.Map; public class GsonHelper { @@ -101,4 +102,16 @@ public class GsonHelper { throw new RuntimeException("Invalid JSON response: " + json, e); } } + + public static JsonElement combine(List jo) { + if (jo.size() == 1) { + return jo.get(0); + } else { + JsonArray ja = new JsonArray(); + for (JsonElement je : jo) { + ja.add(je); + } + return ja; + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java b/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java index fcceb235b..a60be053e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java @@ -4,7 +4,6 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ListUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ListUtils.java new file mode 100644 index 000000000..7c8ef0ae0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ListUtils.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.util; + +import java.util.Collections; +import java.util.List; + +public final class ListUtils { + + private ListUtils() {} + + public static List compact(final List list) { + if (list.isEmpty()) return Collections.emptyList(); + if (list.size() == 1) return List.of(list.get(0)); + if (list.size() == 2) return List.of(list.get(0), list.get(1)); + return list; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index b81e56ca0..0c0407385 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -1,9 +1,14 @@ package net.momirealms.craftengine.core.util; +import com.mojang.datafixers.util.Either; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.function.Function; import java.util.function.Supplier; public final class ResourceConfigUtils { @@ -36,6 +41,50 @@ public final class ResourceConfigUtils { return s; } + @SuppressWarnings("unchecked") + public static Either> parseConfigAsEither(Object config, Function, T> converter) { + if (config instanceof Map) { + return Either.left(converter.apply((Map) config)); + } else if (config instanceof List list) { + return switch (list.size()) { + case 0 -> Either.right(Collections.emptyList()); + case 1 -> Either.left(converter.apply((Map) list.get(0))); + case 2 -> Either.right(List.of(converter.apply((Map) list.get(0)), converter.apply((Map) list.get(1)))); + default -> { + List result = new ArrayList<>(list.size()); + for (Object o : list) { + result.add(converter.apply((Map) o)); + } + yield Either.right(result); + } + }; + } else { + return Either.right(Collections.emptyList()); + } + } + + @SuppressWarnings("unchecked") + public static List parseConfigAsList(Object config, Function, T> converter) { + if (config instanceof Map) { + return List.of(converter.apply((Map) config)); + } else if (config instanceof List list) { + return switch (list.size()) { + case 0 -> Collections.emptyList(); + case 1 -> List.of(converter.apply((Map) list.get(0))); + case 2 -> List.of(converter.apply((Map) list.get(0)), converter.apply((Map) list.get(1))); + default -> { + List result = new ArrayList<>(list.size()); + for (Object o : list) { + result.add(converter.apply((Map) o)); + } + yield result; + } + }; + } else { + return Collections.emptyList(); + } + } + public static Object get(Map arguments, String... keys) { for (String key : keys) { Object value = arguments.get(key); From c6a0c0ae5d922903ef3748c73fbe53412b9d0466 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 20 May 2025 04:26:38 +0800 Subject: [PATCH 18/89] =?UTF-8?q?=E6=8F=90=E9=AB=98=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=85=BC=E5=AE=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/blocks.yml | 14 +++--- .../bukkit/block/BlockEventListener.java | 2 +- .../bukkit/block/BukkitBlockManager.java | 2 +- .../bukkit/block/BukkitCustomBlock.java | 20 ++++----- .../furniture/BukkitFurnitureManager.java | 6 +-- .../bukkit/item/BukkitCustomItem.java | 9 ++-- .../item/behavior/BlockItemBehavior.java | 2 +- .../item/behavior/FurnitureItemBehavior.java | 2 +- .../item/listener/ItemEventListener.java | 2 +- .../plugin/network/PacketConsumers.java | 2 +- .../core/block/AbstractCustomBlock.java | 2 +- .../craftengine/core/block/CustomBlock.java | 4 +- .../entity/furniture/CustomFurniture.java | 11 ++--- .../core/item/AbstractCustomItem.java | 6 +-- .../core/item/AbstractItemManager.java | 2 +- .../craftengine/core/item/CustomItem.java | 4 +- .../{ => context}/event/EventConditions.java | 2 +- .../{ => context}/event/EventFunctions.java | 44 ++++--------------- .../{ => context}/event/EventTrigger.java | 2 +- 19 files changed, 54 insertions(+), 84 deletions(-) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => context}/event/EventConditions.java (98%) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => context}/event/EventFunctions.java (64%) rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => context}/event/EventTrigger.java (93%) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml index 4baf0dd0b..b979b00a7 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml @@ -64,14 +64,12 @@ items#misc: events: - on: right_click functions: - - type: run - functions: - - type: open_window - gui-type: anvil - - type: cancel_event - conditions: - - type: expression - expression: "!" + - type: open_window + gui-type: anvil + - type: cancel_event + conditions: + - type: expression + expression: "!" settings: template: - default:pickaxe_power/level_4 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 31b16f093..bc80b371d 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 @@ -18,7 +18,7 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; 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 5308d06ee..542b9b38e 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 @@ -26,7 +26,7 @@ import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; -import net.momirealms.craftengine.core.plugin.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index c9897a727..b6d0d7441 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -11,7 +11,7 @@ import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.WritableRegistry; @@ -31,13 +31,13 @@ import java.util.*; public class BukkitCustomBlock extends AbstractCustomBlock { protected BukkitCustomBlock( - Key id, - Holder.Reference holder, - Map> properties, - Map appearances, - Map variantMapper, - BlockSettings settings, - @NotNull EnumMap>> events, + @NotNull Key id, + @NotNull Holder.Reference holder, + @NotNull Map> properties, + @NotNull Map appearances, + @NotNull Map variantMapper, + @NotNull BlockSettings settings, + @NotNull Map>> events, @Nullable Map behavior, @Nullable LootTable lootTable ) { @@ -158,14 +158,14 @@ public class BukkitCustomBlock extends AbstractCustomBlock { protected BlockSettings settings; protected Map behavior; protected LootTable lootTable; - protected EnumMap>> events; + protected Map>> events; public BuilderImpl(Key id) { this.id = id; } @Override - public Builder events(EnumMap>> events) { + public Builder events(Map>> events) { this.events = events; return this; } 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 5d35be647..621a03733 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 @@ -18,8 +18,8 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.event.EventFunctions; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; @@ -217,7 +217,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { // get loot table LootTable lootTable = lootMap == null ? null : LootTable.fromMap(lootMap); - EnumMap>> events = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); + Map>> events = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); CustomFurniture furniture = new CustomFurniture(id, settings, placements, events, lootTable); byId.put(id, furniture); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index fd7c32143..f117a6990 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.bukkit.Material; @@ -16,6 +16,7 @@ import org.bukkit.inventory.ItemStack; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; +import java.util.Map; public class BukkitCustomItem extends AbstractCustomItem { private final Material material; @@ -24,7 +25,7 @@ public class BukkitCustomItem extends AbstractCustomItem { List behaviors, List> modifiers, List> clientBoundModifiers, ItemSettings settings, - EnumMap>> events) { + Map>> events) { super(id, materialKey, behaviors, modifiers, clientBoundModifiers, settings, events); this.material = material; } @@ -58,7 +59,7 @@ public class BukkitCustomItem extends AbstractCustomItem { private Holder id; private Key materialKey; private final Material material; - private final EnumMap>> events = new EnumMap<>(EventTrigger.class); + private final Map>> events = new EnumMap<>(EventTrigger.class); private final List behaviors = new ArrayList<>(4); private final List> modifiers = new ArrayList<>(4); private final List> clientBoundModifiers = new ArrayList<>(4); @@ -124,7 +125,7 @@ public class BukkitCustomItem extends AbstractCustomItem { } @Override - public Builder events(EnumMap>> events) { + public Builder events(Map>> events) { this.events.putAll(events); return this; } 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 00fbf33cc..05edf3460 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 @@ -26,7 +26,7 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.Direction; 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 20773f4f1..4e8238e2d 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 @@ -24,7 +24,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.Vec3d; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index 183db3a06..f602e34e1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -17,7 +17,7 @@ import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.world.BlockHitResult; 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 abd76f731..cb633c860 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 @@ -36,7 +36,7 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.network.*; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.*; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java index cb3efd929..6c74b4ee9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java index 2e3fb29a7..bbe3d21e7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.CompoundTag; import org.jetbrains.annotations.NotNull; @@ -40,7 +40,7 @@ public interface CustomBlock { interface Builder { - Builder events(EnumMap>> events); + Builder events(Map>> events); Builder appearances(Map appearances); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java index 8d2d93885..e1602fd58 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java @@ -3,30 +3,27 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; -import java.util.Collections; -import java.util.EnumMap; -import java.util.List; -import java.util.Optional; +import java.util.*; public class CustomFurniture { private final Key id; private final FurnitureSettings settings; private final EnumMap placements; private final AnchorType anyType; - private final EnumMap>> events; + private final Map>> events; @Nullable private final LootTable lootTable; public CustomFurniture(@NotNull Key id, @NotNull FurnitureSettings settings, @NotNull EnumMap placements, - @NotNull EnumMap>> events, + @NotNull Map>> events, @Nullable LootTable lootTable) { this.id = id; this.settings = settings; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java index 7d88df3ad..76e5c0d31 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; @@ -23,7 +23,7 @@ public abstract class AbstractCustomItem implements CustomItem { protected final NetworkItemDataProcessor[] networkItemDataProcessors; protected final List behaviors; protected final ItemSettings settings; - protected final EnumMap>> events; + protected final Map>> events; protected final Item base; @SuppressWarnings("unchecked") @@ -32,7 +32,7 @@ public abstract class AbstractCustomItem implements CustomItem { List> modifiers, List> clientBoundModifiers, ItemSettings settings, - EnumMap>> events) { + Map>> events) { this.id = id; this.material = material; this.events = events; 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 2d746bd2b..9b0b5be71 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 @@ -15,7 +15,7 @@ import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectPrope import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; -import net.momirealms.craftengine.core.plugin.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index 783506671..d21ff5693 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; @@ -70,7 +70,7 @@ public interface CustomItem extends BuildableItem { Builder settings(ItemSettings settings); - Builder events(EnumMap>> events); + Builder events(Map>> events); CustomItem build(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java similarity index 98% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java index b1c578046..5b6adc177 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.plugin.event; +package net.momirealms.craftengine.core.plugin.context.event; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java similarity index 64% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index 001d58f81..169593072 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.plugin.event; +package net.momirealms.craftengine.core.plugin.context.event; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.*; @@ -12,10 +12,7 @@ import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class EventFunctions { @@ -45,31 +42,15 @@ public class EventFunctions { return factory.create(map); } - public static EnumMap>> parseEvents(Object eventsObj) { + public static Map>> parseEvents(Object eventsObj) { + if (eventsObj == null) return Map.of(); EnumMap>> events = new EnumMap<>(EventTrigger.class); if (eventsObj instanceof Map eventsSection) { Map eventsSectionMap = MiscUtils.castToMap(eventsSection, false); for (Map.Entry eventEntry : eventsSectionMap.entrySet()) { try { EventTrigger eventTrigger = EventTrigger.byName(eventEntry.getKey()); - if (eventEntry.getValue() instanceof List list) { - if (list.size() == 1) { - events.put(eventTrigger, List.of(EventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)))); - } else if (list.size() == 2) { - events.put(eventTrigger, List.of( - EventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)), - EventFunctions.fromMap(MiscUtils.castToMap(list.get(1), false)) - )); - } else { - List> eventsList = new ArrayList<>(); - for (Object event : list) { - eventsList.add(EventFunctions.fromMap(MiscUtils.castToMap(event, false))); - } - events.put(eventTrigger, eventsList); - } - } else if (eventEntry.getValue() instanceof Map eventSection) { - events.put(eventTrigger, List.of(EventFunctions.fromMap(MiscUtils.castToMap(eventSection, false)))); - } + events.put(eventTrigger, ResourceConfigUtils.parseConfigAsList(eventEntry.getValue(), EventFunctions::fromMap)); } catch (IllegalArgumentException e) { throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", eventEntry.getKey()); } @@ -78,24 +59,17 @@ public class EventFunctions { @SuppressWarnings("unchecked") List> eventsList = (List>) list; for (Map eventSection : eventsList) { - Object onObj = eventSection.get("on"); - if (onObj == null) { - throw new LocalizedResourceConfigException("warning.config.event.missing_trigger"); - } + String on = ResourceConfigUtils.requireNonEmptyStringOrThrow(eventSection.get("on"), "warning.config.event.missing_trigger"); try { - EventTrigger eventTrigger = EventTrigger.byName(onObj.toString()); + EventTrigger eventTrigger = EventTrigger.byName(on); if (eventSection.containsKey("type")) { Function function = EventFunctions.fromMap(eventSection); events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(function); } else if (eventSection.containsKey("functions")) { - @SuppressWarnings("unchecked") - List> functionList = (List>) eventSection.get("functions"); - for (Map function : functionList) { - events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(EventFunctions.fromMap(function)); - } + events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(Objects.requireNonNull(BuiltInRegistries.EVENT_FUNCTION_FACTORY.getValue(CommonFunctions.RUN)).create(eventSection)); } } catch (IllegalArgumentException e) { - throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", onObj.toString()); + throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", on); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventTrigger.java similarity index 93% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventTrigger.java index 8c7060079..7e5f3c882 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventTrigger.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.plugin.event; +package net.momirealms.craftengine.core.plugin.context.event; import java.util.HashMap; import java.util.Map; From fb98450207dca5871f83c1952112c7e3bdddcd39 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 20 May 2025 04:34:30 +0800 Subject: [PATCH 19/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9B=B4=E5=8A=A0?= =?UTF-8?q?=E6=96=B9=E4=BE=BF=E7=9A=84shift=E7=82=B9=E5=87=BB=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E7=89=A9=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/plugin/gui/GuiElement.java | 2 +- .../gui/category/ItemBrowserManagerImpl.java | 27 ++++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java index ae89d0b8e..c48418575 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java @@ -11,7 +11,7 @@ import java.util.function.Function; public interface GuiElement { - static GuiElement EMPTY = GuiElement.constant(null, (e, c) -> c.cancel()); + GuiElement EMPTY = GuiElement.constant(null, (e, c) -> c.cancel()); @Nullable Item item(); 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 024b294df..2e9d1e6d0 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 @@ -24,9 +24,11 @@ import java.util.*; @SuppressWarnings("DuplicatedCode") public class ItemBrowserManagerImpl implements ItemBrowserManager { + private static final String SHIFT_LEFT = "SHIFT_LEFT"; + private static final String SHIFT_RIGHT = "SHIFT_RIGHT"; private static final Set MOVE_TO_OTHER_INV = Set.of("SHIFT_LEFT", "SHIFT_RIGHT"); - private static final Set LEFT_CLICK = Set.of("LEFT", "SHIFT_LEFT"); - private static final Set RIGHT_CLICK = Set.of("RIGHT", "SHIFT_RIGHT"); + private static final Set LEFT_CLICK = Set.of("LEFT", SHIFT_LEFT); + private static final Set RIGHT_CLICK = Set.of("RIGHT", SHIFT_RIGHT); private static final Set MIDDLE_CLICK = Set.of("MIDDLE"); private static final Set DOUBLE_CLICK = Set.of("DOUBLE_CLICK"); private final CraftEngine plugin; @@ -258,11 +260,22 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { if (item == null) return null; return new ItemWithAction(item, (e, c) -> { c.cancel(); - if (MIDDLE_CLICK.contains(c.type()) && player.isCreativeMode() && player.hasPermission(GET_ITEM_PERMISSION) && c.itemOnCursor() == null) { - Item newItem = this.plugin.itemManager().createWrappedItem(e.item().id(), player); - newItem.count(newItem.maxStackSize()); - c.setItemOnCursor(newItem); - return; + if (player.isCreativeMode() && player.hasPermission(GET_ITEM_PERMISSION)) { + if (MIDDLE_CLICK.contains(c.type()) && c.itemOnCursor() == null) { + Item newItem = this.plugin.itemManager().createWrappedItem(e.item().id(), player); + newItem.count(newItem.maxStackSize()); + c.setItemOnCursor(newItem); + return; + } + if (SHIFT_LEFT.equals(c.type())) { + player.giveItem(this.plugin.itemManager().createWrappedItem(e.item().id(), player)); + return; + } else if (SHIFT_RIGHT.equals(c.type())) { + Item newItem = this.plugin.itemManager().createWrappedItem(e.item().id(), player); + newItem.count(newItem.maxStackSize()); + player.giveItem(newItem); + return; + } } if (LEFT_CLICK.contains(c.type())) { List> inRecipes = this.plugin.recipeManager().recipeByResult(itemId); From f8be28c9335650fb44bc9a3479ce1986b94cf9c9 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 20 May 2025 04:51:05 +0800 Subject: [PATCH 20/89] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=B6=E5=85=B7?= =?UTF-8?q?=E7=A1=AC=E7=A2=B0=E6=92=9E=E7=AE=B1=E4=BA=A4=E4=BA=92=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index a350543e3..2ee29d431 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.54.2 +project_version=0.0.54.3 config_version=33 lang_version=13 project_group=net.momirealms @@ -51,7 +51,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.65.24 +nms_helper_version=0.65.25 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 2f215e2140167e6bb278657e9895918179ed1259 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 20 May 2025 05:34:37 +0800 Subject: [PATCH 21/89] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E6=89=93=E5=8C=85?= =?UTF-8?q?=E8=BF=9B=E6=8F=92=E4=BB=B6=E6=9C=AC=E4=BD=93=E7=9A=84adventure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/build.gradle.kts | 1 - .../main/resources/craft-engine.properties | 7 +- .../bukkit/block/BlockEventListener.java | 2 +- .../bukkit/block/BukkitCustomBlock.java | 7 +- .../furniture/BukkitFurnitureManager.java | 2 +- .../bukkit/item/BukkitCustomItem.java | 2 +- .../item/behavior/BlockItemBehavior.java | 2 +- .../item/behavior/FurnitureItemBehavior.java | 2 +- .../item/listener/ItemEventListener.java | 2 +- .../plugin/command/BukkitSenderFactory.java | 20 +-- .../plugin/network/PacketConsumers.java | 2 +- .../bukkit/util/ComponentUtils.java | 4 + core/build.gradle.kts | 3 +- .../core/block/AbstractCustomBlock.java | 2 +- .../craftengine/core/block/CustomBlock.java | 3 +- .../entity/furniture/CustomFurniture.java | 2 +- .../core/item/AbstractCustomItem.java | 2 +- .../craftengine/core/item/CustomItem.java | 3 +- .../craftengine/core/plugin/CraftEngine.java | 5 +- .../plugin/command/sender/SenderFactory.java | 5 +- .../core/plugin/dependency/Dependencies.java | 134 ++++++++++++++++-- 21 files changed, 164 insertions(+), 48 deletions(-) diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index 5085f47dc..f90ee42e0 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -21,7 +21,6 @@ dependencies { implementation(project(":bukkit:compatibility")) implementation(project(":bukkit:compatibility:legacy")) - implementation("net.kyori:adventure-platform-bukkit:${rootProject.properties["adventure_platform_version"]}") implementation("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}") implementation("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}") implementation("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}") diff --git a/bukkit/loader/src/main/resources/craft-engine.properties b/bukkit/loader/src/main/resources/craft-engine.properties index 9e875e126..d8ee70d9f 100644 --- a/bukkit/loader/src/main/resources/craft-engine.properties +++ b/bukkit/loader/src/main/resources/craft-engine.properties @@ -23,10 +23,9 @@ commons-io=${commons_io_version} commons-imaging=${commons_imaging_version} byte-buddy=${byte_buddy_version} 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} -adventure-text-serializer-json-legacy-impl=${adventure_bundle_version} +examination-api=1.3.0 +option=1.1.0 +adventure-api=${adventure_bundle_version} netty-codec-http=${netty_version} ahocorasick=${ahocorasick_version} lz4=${lz4_version} 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 bc80b371d..436a2d9df 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 @@ -17,8 +17,8 @@ import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index b6d0d7441..443c63c44 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -10,8 +10,8 @@ import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.WritableRegistry; @@ -26,7 +26,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; -import java.util.*; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; public class BukkitCustomBlock extends AbstractCustomBlock { 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 621a03733..64ea33f4b 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 @@ -17,9 +17,9 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index f117a6990..241646d22 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -6,8 +6,8 @@ import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.bukkit.Material; 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 05edf3460..4f4f19cf8 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 @@ -25,8 +25,8 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.Direction; 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 4e8238e2d..f42317250 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 @@ -23,8 +23,8 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.Vec3d; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index f602e34e1..3ac9d8823 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -16,8 +16,8 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.world.BlockHitResult; 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 a9a2ba020..4725c79eb 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 @@ -1,8 +1,7 @@ package net.momirealms.craftengine.bukkit.plugin.command; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.ComponentUtils; @@ -18,11 +17,9 @@ import org.bukkit.entity.Player; import java.util.UUID; public class BukkitSenderFactory extends SenderFactory { - private final BukkitAudiences audiences; public BukkitSenderFactory(BukkitCraftEngine plugin) { super(plugin); - this.audiences = BukkitAudiences.create(plugin.bootstrap()); } @Override @@ -41,20 +38,18 @@ public class BukkitSenderFactory extends SenderFactory audience(sender).sendMessage(message)); + String legacy = LegacyComponentSerializer.legacySection().serialize(message); + plugin().scheduler().sync().run(() -> sender.sendMessage(legacy)); } } @@ -93,6 +88,5 @@ public class BukkitSenderFactory extends SenderFactory { protected abstract String name(T sender); - protected abstract Audience audience(T sender); - protected abstract void sendMessage(T sender, Component message); protected abstract Tristate permissionState(T sender, String node); @@ -44,7 +41,7 @@ public abstract class SenderFactory

{ } public Sender console() { - return console; + return this.console; } public Sender wrap(C sender) { 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 2499f83d8..c5c54940d 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 @@ -200,37 +200,155 @@ public class Dependencies { List.of(Relocation.of("snakeyaml", "org{}yaml{}snakeyaml")) ); + public static final Dependency OPTION = new Dependency( + "option", + "net{}kyori", + "option", + "option", + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ); + + public static final Dependency ADVENTURE_API = new Dependency( + "adventure-api", + "net{}kyori", + "adventure-api", + "adventure-api", + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ); + + public static final Dependency ADVENTURE_KEY = new Dependency( + "adventure-key", + "net{}kyori", + "adventure-key", + "adventure-key", + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ) { + @Override + public String getVersion() { + return ADVENTURE_API.getVersion(); + } + }; + + public static final Dependency EXAMINATION_API = new Dependency( + "examination-api", + "net{}kyori", + "examination-api", + "examination-api", + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ); + + public static final Dependency EXAMINATION_STRING = new Dependency( + "examination-string", + "net{}kyori", + "examination-string", + "examination-string", + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ) { + @Override + public String getVersion() { + return EXAMINATION_API.getVersion(); + } + }; + public static final Dependency MINIMESSAGE = new Dependency( "adventure-text-minimessage", "net{}kyori", "adventure-text-minimessage", "adventure-text-minimessage", - List.of(Relocation.of("adventure", "net{}kyori{}adventure")) - ); + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ) { + @Override + public String getVersion() { + return ADVENTURE_API.getVersion(); + } + }; + + public static final Dependency TEXT_SERIALIZER_COMMONS = new Dependency( + "adventure-text-serializer-commons", + "net{}kyori", + "adventure-text-serializer-commons", + "adventure-text-serializer-commons", + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ) { + @Override + public String getVersion() { + return ADVENTURE_API.getVersion(); + } + }; public static final Dependency TEXT_SERIALIZER_GSON = new Dependency( "adventure-text-serializer-gson", "net{}kyori", "adventure-text-serializer-gson", "adventure-text-serializer-gson", - List.of(Relocation.of("adventure", "net{}kyori{}adventure")) - ); + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ) { + @Override + public String getVersion() { + return ADVENTURE_API.getVersion(); + } + }; public static final Dependency TEXT_SERIALIZER_GSON_LEGACY = new Dependency( "adventure-text-serializer-json-legacy-impl", "net{}kyori", "adventure-text-serializer-json-legacy-impl", "adventure-text-serializer-json-legacy-impl", - List.of(Relocation.of("adventure", "net{}kyori{}adventure")) - ); + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ) { + @Override + public String getVersion() { + return ADVENTURE_API.getVersion(); + } + }; + + public static final Dependency TEXT_SERIALIZER_LEGACY = new Dependency( + "adventure-text-serializer-legacy", + "net{}kyori", + "adventure-text-serializer-legacy", + "adventure-text-serializer-legacy", + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ) { + @Override + public String getVersion() { + return ADVENTURE_API.getVersion(); + } + }; public static final Dependency TEXT_SERIALIZER_JSON = new Dependency( "adventure-text-serializer-json", "net{}kyori", "adventure-text-serializer-json", "adventure-text-serializer-json", - List.of(Relocation.of("adventure", "net{}kyori{}adventure")) - ); + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ) { + @Override + public String getVersion() { + return ADVENTURE_API.getVersion(); + } + }; public static final Dependency AHO_CORASICK = new Dependency( "ahocorasick", From c7886892779e3c2aee2e6363a7147ab85663e207 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 21 May 2025 17:08:26 +0800 Subject: [PATCH 22/89] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=AE=B6=E5=85=B7?= =?UTF-8?q?=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skript/effect/EffRemoveFurniture.java | 9 +- .../bukkit/api/BukkitAdaptors.java | 7 + .../bukkit/api/CraftEngineFurniture.java | 82 ++++--- .../bukkit/api/event/FurnitureBreakEvent.java | 9 +- .../api/event/FurnitureInteractEvent.java | 9 +- .../bukkit/api/event/FurniturePlaceEvent.java | 9 +- .../furniture/BukkitCustomFurniture.java | 74 ++++++ ...dedFurniture.java => BukkitFurniture.java} | 39 ++- .../furniture/BukkitFurnitureElement.java | 73 +++++- .../furniture/BukkitFurnitureManager.java | 228 ++++-------------- .../item/behavior/FurnitureItemBehavior.java | 10 +- .../item/listener/ItemEventListener.java | 9 +- .../plugin/network/PacketConsumers.java | 16 +- .../furniture/AbstractCustomFurniture.java | 80 ++++++ .../furniture/AbstractFurnitureElement.java | 8 +- .../furniture/AbstractFurnitureManager.java | 125 ++++++++++ .../entity/furniture/CustomFurniture.java | 93 +++---- .../core/entity/furniture/Furniture.java | 5 +- .../entity/furniture/FurnitureElement.java | 21 ++ .../entity/furniture/FurnitureManager.java | 6 + .../core/util/ResourceConfigUtils.java | 5 + gradle.properties | 12 +- gradle/wrapper/gradle-wrapper.properties | 2 +- server-mod/v1_20_1/build.gradle.kts | 2 +- server-mod/v1_20_5/build.gradle.kts | 2 +- server-mod/v1_21_5/build.gradle.kts | 2 +- 26 files changed, 585 insertions(+), 352 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitCustomFurniture.java rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/{LoadedFurniture.java => BukkitFurniture.java} (93%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractCustomFurniture.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java index 750dd937c..0e5b8885a 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java @@ -6,7 +6,8 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; -import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; +import net.momirealms.craftengine.core.entity.furniture.Furniture; import org.bukkit.entity.Entity; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -23,9 +24,9 @@ public class EffRemoveFurniture extends Effect { protected void execute(Event e) { for (Entity entity : entities.getArray(e)) { if (CraftEngineFurniture.isFurniture(entity)) { - LoadedFurniture loadedFurniture = CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity); - if (loadedFurniture != null) { - loadedFurniture.destroy(); + Furniture bukkitFurniture = CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity); + if (bukkitFurniture != null) { + bukkitFurniture.destroy(); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java index f11ae4be3..3986509cf 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java @@ -3,8 +3,11 @@ package net.momirealms.craftengine.bukkit.api; import net.momirealms.craftengine.bukkit.entity.BukkitEntity; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.bukkit.world.BukkitWorld; +import net.momirealms.craftengine.core.world.WorldPosition; +import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; @@ -29,4 +32,8 @@ public final class BukkitAdaptors { public static BukkitBlockInWorld adapt(final Block block) { return new BukkitBlockInWorld(block); } + + public static Location toLocation(WorldPosition position) { + return LocationUtils.toLocation(position); + } } 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 aa9616867..38fbf9f3a 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 @@ -1,13 +1,14 @@ package net.momirealms.craftengine.bukkit.api; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; -import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; +import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; @@ -48,7 +49,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @Nullable - public static LoadedFurniture place(Location location, Key furnitureId) { + public static Furniture place(Location location, Key furnitureId) { CustomFurniture furniture = byId(furnitureId); if (furniture == null) return null; return place(location, furnitureId, furniture.getAnyPlacement()); @@ -63,7 +64,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @Nullable - public static LoadedFurniture place(Location location, Key furnitureId, AnchorType anchorType) { + public static Furniture place(Location location, Key furnitureId, AnchorType anchorType) { CustomFurniture furniture = byId(furnitureId); if (furniture == null) return null; return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), true); @@ -78,7 +79,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @NotNull - public static LoadedFurniture place(Location location, CustomFurniture furniture, AnchorType anchorType) { + public static Furniture place(Location location, CustomFurniture furniture, AnchorType anchorType) { return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), true); } @@ -92,7 +93,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @Nullable - public static LoadedFurniture place(Location location, Key furnitureId, AnchorType anchorType, boolean playSound) { + public static Furniture place(Location location, Key furnitureId, AnchorType anchorType, boolean playSound) { CustomFurniture furniture = byId(furnitureId); if (furniture == null) return null; return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), playSound); @@ -108,7 +109,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @NotNull - public static LoadedFurniture place(Location location, CustomFurniture furniture, AnchorType anchorType, boolean playSound) { + public static Furniture place(Location location, CustomFurniture furniture, AnchorType anchorType, boolean playSound) { return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), playSound); } @@ -152,7 +153,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @Nullable - public static LoadedFurniture getLoadedFurnitureByBaseEntity(@NotNull Entity baseEntity) { + public static Furniture getLoadedFurnitureByBaseEntity(@NotNull Entity baseEntity) { return BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(baseEntity.getEntityId()); } @@ -163,7 +164,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @Nullable - public static LoadedFurniture getLoadedFurnitureBySeat(@NotNull Entity seat) { + public static Furniture 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().loadedFurnitureByRealEntityId(baseEntityId); @@ -172,107 +173,108 @@ public final class CraftEngineFurniture { /** * Removes furniture * - * @param furniture furniture base entity + * @param entity furniture base entity * @return success or not */ - public static boolean remove(@NotNull Entity furniture) { - if (!isFurniture(furniture)) return false; - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(furniture.getEntityId()); - if (loadedFurniture == null) return false; - loadedFurniture.destroy(); + public static boolean remove(@NotNull Entity entity) { + if (!isFurniture(entity)) return false; + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entity.getEntityId()); + if (furniture == null) return false; + furniture.destroy(); return true; } /** * Removes furniture, with more options * - * @param furniture furniture base entity + * @param entity furniture base entity * @param dropLoot whether to drop loots * @param playSound whether to play break sound * @return success or not */ - public static boolean remove(@NotNull Entity furniture, + public static boolean remove(@NotNull Entity entity, boolean dropLoot, boolean playSound) { - if (!isFurniture(furniture)) return false; - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(furniture.getEntityId()); - if (loadedFurniture == null) return false; - remove(loadedFurniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound); + if (!isFurniture(entity)) return false; + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entity.getEntityId()); + if (furniture == null) return false; + remove(furniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound); return true; } /** * Removes furniture, with more options * - * @param furniture furniture base entity + * @param entity furniture base entity * @param player the player who removes the furniture * @param dropLoot whether to drop loots * @param playSound whether to play break sound * @return success or not */ - public static boolean remove(@NotNull Entity furniture, + public static boolean remove(@NotNull Entity entity, @Nullable Player player, boolean dropLoot, boolean playSound) { - if (!isFurniture(furniture)) return false; - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(furniture.getEntityId()); - if (loadedFurniture == null) return false; - remove(loadedFurniture, player, dropLoot, playSound); + if (!isFurniture(entity)) return false; + Furniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entity.getEntityId()); + if (furniture == null) return false; + remove(furniture, player, dropLoot, playSound); return true; } /** * Removes furniture by providing furniture instance * - * @param loadedFurniture loaded furniture + * @param furniture loaded furniture * @param dropLoot whether to drop loots * @param playSound whether to play break sound */ - public static void remove(@NotNull LoadedFurniture loadedFurniture, + public static void remove(@NotNull Furniture furniture, boolean dropLoot, boolean playSound) { - remove(loadedFurniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound); + remove(furniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound); } /** * Removes furniture by providing furniture instance * - * @param loadedFurniture loaded furniture + * @param furniture loaded furniture * @param player the player who removes the furniture * @param dropLoot whether to drop loots * @param playSound whether to play break sound */ - public static void remove(@NotNull LoadedFurniture loadedFurniture, + public static void remove(@NotNull Furniture furniture, @Nullable Player player, boolean dropLoot, boolean playSound) { - remove(loadedFurniture, player == null ? null : BukkitCraftEngine.instance().adapt(player), dropLoot, playSound); + remove(furniture, player == null ? null : BukkitCraftEngine.instance().adapt(player), dropLoot, playSound); } /** * Removes furniture by providing furniture instance * - * @param loadedFurniture loaded furniture + * @param furniture loaded furniture * @param player the player who removes the furniture * @param dropLoot whether to drop loots * @param playSound whether to play break sound */ @SuppressWarnings("unchecked") - public static void remove(@NotNull LoadedFurniture loadedFurniture, + public static void remove(@NotNull Furniture furniture, @Nullable net.momirealms.craftengine.core.entity.player.Player player, boolean dropLoot, boolean playSound) { - Location location = loadedFurniture.dropLocation(); - loadedFurniture.destroy(); - LootTable lootTable = (LootTable) loadedFurniture.config().lootTable(); + if (!furniture.isValid()) return; + Location location = ((BukkitFurniture) furniture).dropLocation(); + furniture.destroy(); + LootTable lootTable = (LootTable) furniture.config().lootTable(); World world = new BukkitWorld(location.getWorld()); WorldPosition position = new WorldPosition(world, location.getX(), location.getY(), location.getZ()); if (dropLoot && lootTable != null) { ContextHolder.Builder builder = ContextHolder.builder() .withParameter(DirectContextParameters.POSITION, position) - .withParameter(DirectContextParameters.FURNITURE, loadedFurniture) - .withOptionalParameter(DirectContextParameters.FURNITURE_ITEM, loadedFurniture.extraData().item().orElse(null)); + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withOptionalParameter(DirectContextParameters.FURNITURE_ITEM, furniture.extraData().item().orElse(null)); if (player != null) { builder.withParameter(DirectContextParameters.PLAYER, player); } @@ -282,7 +284,7 @@ public final class CraftEngineFurniture { } } if (playSound) { - world.playBlockSound(position, loadedFurniture.config().settings().sounds().breakSound()); + world.playBlockSound(position, furniture.config().settings().sounds().breakSound()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java index 013a25e7a..204a8d8c1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.api.event; -import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; +import net.momirealms.craftengine.core.entity.furniture.Furniture; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; @@ -11,10 +12,10 @@ import org.jetbrains.annotations.NotNull; public class FurnitureBreakEvent extends PlayerEvent implements Cancellable { private static final HandlerList HANDLER_LIST = new HandlerList(); private boolean cancelled; - private final LoadedFurniture furniture; + private final BukkitFurniture furniture; public FurnitureBreakEvent(@NotNull Player player, - @NotNull LoadedFurniture furniture) { + @NotNull BukkitFurniture furniture) { super(player); this.furniture = furniture; } @@ -25,7 +26,7 @@ public class FurnitureBreakEvent extends PlayerEvent implements Cancellable { } @NotNull - public LoadedFurniture furniture() { + public Furniture furniture() { return this.furniture; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java index 053fa45f6..3600e70fd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.api.event; -import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; +import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.player.InteractionHand; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -12,12 +13,12 @@ import org.jetbrains.annotations.NotNull; public class FurnitureInteractEvent extends PlayerEvent implements Cancellable { private static final HandlerList HANDLER_LIST = new HandlerList(); private boolean cancelled; - private final LoadedFurniture furniture; + private final BukkitFurniture furniture; private final InteractionHand hand; private final Location interactionPoint; public FurnitureInteractEvent(@NotNull Player player, - @NotNull LoadedFurniture furniture, + @NotNull BukkitFurniture furniture, @NotNull InteractionHand hand, @NotNull Location interactionPoint) { super(player); @@ -42,7 +43,7 @@ public class FurnitureInteractEvent extends PlayerEvent implements Cancellable { } @NotNull - public LoadedFurniture furniture() { + public Furniture furniture() { return this.furniture; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java index 5c373aa03..35862abb1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.api.event; -import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; +import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.player.InteractionHand; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -12,12 +13,12 @@ import org.jetbrains.annotations.NotNull; public class FurniturePlaceEvent extends PlayerEvent implements Cancellable { private static final HandlerList HANDLER_LIST = new HandlerList(); private final Location location; - private final LoadedFurniture furniture; + private final BukkitFurniture furniture; private final InteractionHand hand; private boolean cancelled; public FurniturePlaceEvent(@NotNull Player player, - @NotNull LoadedFurniture furniture, + @NotNull BukkitFurniture furniture, @NotNull Location location, @NotNull InteractionHand hand) { super(player); @@ -32,7 +33,7 @@ public class FurniturePlaceEvent extends PlayerEvent implements Cancellable { } @NotNull - public LoadedFurniture furniture() { + public Furniture furniture() { return this.furniture; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitCustomFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitCustomFurniture.java new file mode 100644 index 000000000..5f2d30270 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitCustomFurniture.java @@ -0,0 +1,74 @@ +package net.momirealms.craftengine.bukkit.entity.furniture; + +import net.momirealms.craftengine.core.entity.furniture.AbstractCustomFurniture; +import net.momirealms.craftengine.core.entity.furniture.AnchorType; +import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; +import net.momirealms.craftengine.core.entity.furniture.FurnitureSettings; +import net.momirealms.craftengine.core.loot.LootTable; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public class BukkitCustomFurniture extends AbstractCustomFurniture { + + protected BukkitCustomFurniture(@NotNull Key id, + @NotNull FurnitureSettings settings, + @NotNull Map placements, + @NotNull Map>> events, + @Nullable LootTable lootTable) { + super(id, settings, placements, events, lootTable); + } + + public static Builder builder() { + return new BuilderImpl(); + } + + public static class BuilderImpl implements Builder { + private Key id; + private Map placements; + private FurnitureSettings settings; + private Map>> events; + private LootTable lootTable; + + @Override + public CustomFurniture build() { + return new BukkitCustomFurniture(id, settings, placements, events, lootTable); + } + + @Override + public Builder id(Key id) { + this.id = id; + return this; + } + + @Override + public Builder placement(Map placements) { + this.placements = placements; + return this; + } + + @Override + public Builder settings(FurnitureSettings settings) { + this.settings = settings; + return this; + } + + @Override + public Builder lootTable(LootTable lootTable) { + this.lootTable = lootTable; + return this; + } + + @Override + public Builder events(Map>> events) { + this.events = events; + return this; + } + } +} 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/BukkitFurniture.java similarity index 93% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java index daaeddaf6..b26ef3651 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/BukkitFurniture.java @@ -1,9 +1,13 @@ package net.momirealms.craftengine.bukkit.entity.furniture; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; import net.momirealms.craftengine.bukkit.entity.BukkitEntity; 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.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.entity.furniture.*; @@ -29,7 +33,7 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.*; -public class LoadedFurniture implements Furniture { +public class BukkitFurniture implements Furniture { private final Key id; private final CustomFurniture furniture; private final AnchorType anchorType; @@ -44,8 +48,8 @@ public class LoadedFurniture implements Furniture { // cache private final List fakeEntityIds; private final List entityIds; - private final Map hitBoxes = new HashMap<>(); - private final Map aabb = new HashMap<>(); + private final Map hitBoxes = new Int2ObjectArrayMap<>(); + private final Map aabb = new Int2ObjectArrayMap<>(); private final boolean minimized; private final boolean hasExternalModel; // seats @@ -55,7 +59,7 @@ public class LoadedFurniture implements Furniture { private Object cachedSpawnPacket; private Object cachedMinimizedSpawnPacket; - public LoadedFurniture(Entity baseEntity, + public BukkitFurniture(Entity baseEntity, CustomFurniture furniture, FurnitureExtraData extraData) { this.id = furniture.id(); @@ -66,8 +70,8 @@ public class LoadedFurniture implements Furniture { this.baseEntity = new WeakReference<>(baseEntity); this.furniture = furniture; this.minimized = furniture.settings().minimized(); - List fakeEntityIds = new ArrayList<>(); - List mainEntityIds = new ArrayList<>(); + List fakeEntityIds = new IntArrayList(); + List mainEntityIds = new IntArrayList(); mainEntityIds.add(this.baseEntityId); CustomFurniture.Placement placement = furniture.getPlacement(anchorType); @@ -84,19 +88,11 @@ public class LoadedFurniture implements Furniture { this.hasExternalModel = false; } - float yaw = this.location.getYaw(); - Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - yaw), 0).conjugate(); - - double x = location.getX(); - double y = location.getY(); - double z = location.getZ(); - + Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate(); List packets = new ArrayList<>(); List minimizedPackets = new ArrayList<>(); List colliders = new ArrayList<>(); - - World world = world(); - WorldPosition position = new WorldPosition(world, x, y, z, yaw, 0); + WorldPosition position = position(); Integer dyedColor = this.extraData.dyedColor().orElse(null); for (FurnitureElement element : placement.elements()) { int entityId = Reflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); @@ -154,13 +150,8 @@ public class LoadedFurniture implements Furniture { } @Override - public Vec3d position() { - return new Vec3d(location.getX(), location.getY(), location.getZ()); - } - - @Override - public World world() { - return new BukkitWorld(this.location.getWorld()); + public WorldPosition position() { + return LocationUtils.toWorldPosition(this.location); } @NotNull @@ -170,7 +161,7 @@ public class LoadedFurniture implements Furniture { @NotNull public Entity baseEntity() { - Entity entity = baseEntity.get(); + Entity entity = this.baseEntity.get(); if (entity == null) { throw new RuntimeException("Base entity not found. It might be unloaded."); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java index e2d2a29f8..ab6c56129 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java @@ -7,6 +7,7 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement; +import net.momirealms.craftengine.core.entity.furniture.FurnitureElement; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; @@ -30,10 +31,10 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement { ItemDisplayContext transform, Vector3f scale, Vector3f translation, - Vector3f offset, + Vector3f position, Quaternionf rotation, boolean applyDyedColor) { - super(item, billboard, transform, scale, translation, offset, rotation, applyDyedColor); + super(item, billboard, transform, scale, translation, position, rotation, applyDyedColor); this.commonValues = new ArrayList<>(); ItemDisplayEntityData.Scale.addEntityDataIfNotDefaultValue(scale(), this.commonValues); ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(rotation(), this.commonValues); @@ -67,4 +68,72 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement { ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), cachedValues); return cachedValues; } + + public static Builder builder() { + return new BuilderImpl(); + } + + public static class BuilderImpl implements Builder { + private boolean applyDyedColor; + private Key item; + private Billboard billboard; + private ItemDisplayContext transform; + private Vector3f scale; + private Vector3f translation; + private Vector3f position; + private Quaternionf rotation; + + @Override + public Builder applyDyedColor(boolean applyDyedColor) { + this.applyDyedColor = applyDyedColor; + return this; + } + + @Override + public Builder item(Key item) { + this.item = item; + return this; + } + + @Override + public Builder billboard(Billboard billboard) { + this.billboard = billboard; + return this; + } + + @Override + public Builder transform(ItemDisplayContext transform) { + this.transform = transform; + return this; + } + + @Override + public Builder scale(Vector3f scale) { + this.scale = scale; + return this; + } + + @Override + public Builder translation(Vector3f translation) { + this.translation = translation; + return this; + } + + @Override + public Builder position(Vector3f position) { + this.position = position; + return this; + } + + @Override + public Builder rotation(Quaternionf rotation) { + this.rotation = rotation; + return this; + } + + @Override + public FurnitureElement build() { + return new BukkitFurnitureElement(item, billboard, transform, scale, translation, position, rotation, applyDyedColor); + } + } } 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 64ea33f4b..1a70f53c0 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 @@ -6,58 +6,45 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.network.handler.FurniturePacketHandler; import net.momirealms.craftengine.bukkit.util.EntityUtils; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; -import net.momirealms.craftengine.core.entity.Billboard; -import net.momirealms.craftengine.core.entity.ItemDisplayContext; 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.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigParser; -import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; -import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; -import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; 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.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.*; import org.bukkit.entity.*; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; -import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; import javax.annotation.Nullable; import java.io.IOException; -import java.nio.file.Path; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; public class BukkitFurnitureManager extends AbstractFurnitureManager { - public static final NamespacedKey FURNITURE_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:furniture_id")); - // DEPRECATED - // public static final NamespacedKey FURNITURE_ANCHOR_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:anchor_type")); - public static final NamespacedKey FURNITURE_EXTRA_DATA_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:furniture_extra_data")); - 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")); - public static final NamespacedKey FURNITURE_COLLISION = Objects.requireNonNull(NamespacedKey.fromString("craftengine:collision")); + public static final NamespacedKey FURNITURE_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_KEY); + public static final NamespacedKey FURNITURE_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_EXTRA_DATA_KEY); + public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY); + public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY); + public static final NamespacedKey FURNITURE_COLLISION = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_COLLISION); public static Class COLLISION_ENTITY_CLASS = Interaction.class; public static Object NMS_COLLISION_ENTITY_TYPE = Reflections.instance$EntityType$INTERACTION; public static ColliderType COLLISION_ENTITY_TYPE = ColliderType.INTERACTION; private static BukkitFurnitureManager instance; private final BukkitCraftEngine plugin; - private final FurnitureParser furnitureParser; - private final Map furnitureByRealEntityId = new ConcurrentHashMap<>(256, 0.5f); - private final Map furnitureByEntityId = new ConcurrentHashMap<>(512, 0.5f); + 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; @@ -67,9 +54,9 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { } public BukkitFurnitureManager(BukkitCraftEngine plugin) { + super(plugin); instance = this; this.plugin = plugin; - this.furnitureParser = new FurnitureParser(); this.furnitureEventListener = new FurnitureEventListener(this); this.dismountListener = VersionHelper.isOrAbove1_20_3() ? new DismountListener1_20_3(this) : new DismountListener1_20(this::handleDismount); } @@ -79,7 +66,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { return this.place(LocationUtils.toLocation(position), furniture, extraData, playSound); } - public LoadedFurniture place(Location location, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound) { + public BukkitFurniture place(Location location, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound) { Optional optionalAnchorType = extraData.anchorType(); if (optionalAnchorType.isEmpty() || !furniture.isAllowedPlacement(optionalAnchorType.get())) { extraData.anchorType(furniture.getAnyPlacement()); @@ -101,128 +88,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { return loadedFurnitureByRealEntityId(furnitureEntity.getEntityId()); } - @Override - public ConfigParser parser() { - return this.furnitureParser; - } - - public class FurnitureParser implements ConfigParser { - public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; - - @Override - public String[] sectionId() { - return CONFIG_SECTION_NAME; - } - - @Override - public int loadingSequence() { - return LoadingSequence.FURNITURE; - } - - @SuppressWarnings("unchecked") - @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - if (byId.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.furniture.duplicate", path, id); - } - - Map lootMap = MiscUtils.castToMap(section.get("loot"), true); - Map settingsMap = MiscUtils.castToMap(section.get("settings"), true); - Map placementMap = MiscUtils.castToMap(section.get("placement"), true); - if (placementMap == null) { - throw new LocalizedResourceConfigException("warning.config.furniture.missing_placement", path, id); - } - - EnumMap placements = new EnumMap<>(AnchorType.class); - - for (Map.Entry entry : placementMap.entrySet()) { - // anchor type - AnchorType anchorType = AnchorType.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH)); - Map placementArguments = MiscUtils.castToMap(entry.getValue(), true); - - Optional optionalLootSpawnOffset = Optional.ofNullable(placementArguments.get("loot-spawn-offset")).map(it -> MiscUtils.getAsVector3f(it, "loot-spawn-offset")); - - // 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 LocalizedResourceConfigException("warning.config.furniture.element.missing_item", path, 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.getAsVector3f(element.getOrDefault("scale", "1"), "scale"), - MiscUtils.getAsVector3f(element.getOrDefault("translation", "0"), "translation"), - MiscUtils.getAsVector3f(element.getOrDefault("position", "0"), "position"), - MiscUtils.getAsQuaternionf(element.getOrDefault("rotation", "0"), "rotation"), - (boolean) element.getOrDefault("apply-dyed-color", true) - ); - elements.add(furnitureElement); - } - - // external model providers - Optional externalModel; - if (placementArguments.containsKey("model-engine")) { - externalModel = Optional.of(plugin.compatibilityManager().createModelEngineModel(placementArguments.get("model-engine").toString())); - } else if (placementArguments.containsKey("better-model")) { - externalModel = Optional.of(plugin.compatibilityManager().createBetterModelModel(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); - } - 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]), - rotationRule, - alignmentRule, - externalModel, - optionalLootSpawnOffset - )); - } else { - placements.put(anchorType, new CustomFurniture.Placement( - elements.toArray(new FurnitureElement[0]), - hitboxes.toArray(new HitBox[0]), - RotationRule.ANY, - AlignmentRule.CENTER, - externalModel, - optionalLootSpawnOffset - )); - } - } - - // get furniture settings - FurnitureSettings settings = FurnitureSettings.fromMap(settingsMap); - - // get loot table - LootTable lootTable = lootMap == null ? null : LootTable.fromMap(lootMap); - Map>> events = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); - CustomFurniture furniture = new CustomFurniture(id, settings, placements, events, lootTable); - byId.put(id, furniture); - } - } - @Override public void delayedInit() { COLLISION_ENTITY_CLASS = Config.colliderType() == ColliderType.INTERACTION ? Interaction.class : Boat.class; @@ -264,19 +129,29 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { @Nullable @Override - public LoadedFurniture loadedFurnitureByRealEntityId(int entityId) { + public BukkitFurniture loadedFurnitureByRealEntityId(int entityId) { return this.furnitureByRealEntityId.get(entityId); } @Override @Nullable - public LoadedFurniture loadedFurnitureByEntityId(int entityId) { + public BukkitFurniture loadedFurnitureByEntityId(int entityId) { return this.furnitureByEntityId.get(entityId); } + @Override + protected CustomFurniture.Builder furnitureBuilder() { + return BukkitCustomFurniture.builder(); + } + + @Override + protected FurnitureElement.Builder furnitureElementBuilder() { + return BukkitFurnitureElement.builder(); + } + protected void handleBaseEntityUnload(Entity entity) { int id = entity.getEntityId(); - LoadedFurniture furniture = this.furnitureByRealEntityId.remove(id); + BukkitFurniture furniture = this.furnitureByRealEntityId.remove(id); if (furniture != null) { Location location = entity.getLocation(); boolean isPreventing = FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); @@ -305,7 +180,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { if (optionalFurniture.isEmpty()) return; CustomFurniture customFurniture = optionalFurniture.get(); - LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); + BukkitFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); if (previous != null) return; Location location = display.getLocation(); @@ -313,7 +188,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { boolean preventChange = FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); if (above1_20_1) { if (!preventChange) { - LoadedFurniture furniture = addNewFurniture(display, customFurniture); + BukkitFurniture furniture = addNewFurniture(display, customFurniture); furniture.initializeColliders(); for (Player player : display.getTrackedPlayers()) { this.plugin.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); @@ -321,7 +196,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { } } } else { - LoadedFurniture furniture = addNewFurniture(display, customFurniture); + BukkitFurniture furniture = addNewFurniture(display, customFurniture); for (Player player : display.getTrackedPlayers()) { this.plugin.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds())); this.plugin.networkManager().sendPacket(player, furniture.spawnPacket(player)); @@ -383,9 +258,9 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { Optional optionalFurniture = furnitureById(key); if (optionalFurniture.isPresent()) { CustomFurniture customFurniture = optionalFurniture.get(); - LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); + BukkitFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); if (previous != null) return; - LoadedFurniture furniture = addNewFurniture(display, customFurniture); + BukkitFurniture furniture = addNewFurniture(display, customFurniture); furniture.initializeColliders(); // safely do it here } } @@ -412,23 +287,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { return FurnitureExtraData.fromBytes(extraData); } -// private AnchorType getAnchorType(Entity baseEntity, CustomFurniture furniture) { -// String anchorType = baseEntity.getPersistentDataContainer().get(FURNITURE_ANCHOR_KEY, PersistentDataType.STRING); -// if (anchorType != null) { -// try { -// AnchorType unverified = AnchorType.valueOf(anchorType); -// if (furniture.isAllowedPlacement(unverified)) { -// return unverified; -// } -// } catch (IllegalArgumentException ignored) { -// } -// } -// AnchorType anchorTypeEnum = furniture.getAnyPlacement(); -// baseEntity.getPersistentDataContainer().set(FURNITURE_ANCHOR_KEY, PersistentDataType.STRING, anchorTypeEnum.name()); -// return anchorTypeEnum; -// } - - private synchronized LoadedFurniture addNewFurniture(ItemDisplay display, CustomFurniture furniture) { + private synchronized BukkitFurniture addNewFurniture(ItemDisplay display, CustomFurniture furniture) { FurnitureExtraData extraData; try { extraData = getFurnitureExtraData(display); @@ -436,16 +295,21 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { extraData = FurnitureExtraData.builder().build(); plugin.logger().warn("Furniture extra data could not be loaded", e); } - LoadedFurniture loadedFurniture = new LoadedFurniture(display, furniture, extraData); - this.furnitureByRealEntityId.put(loadedFurniture.baseEntityId(), loadedFurniture); - for (int entityId : loadedFurniture.entityIds()) { - this.furnitureByEntityId.put(entityId, loadedFurniture); + BukkitFurniture bukkitFurniture = new BukkitFurniture(display, furniture, extraData); + this.furnitureByRealEntityId.put(bukkitFurniture.baseEntityId(), bukkitFurniture); + for (int entityId : bukkitFurniture.entityIds()) { + this.furnitureByEntityId.put(entityId, bukkitFurniture); } - for (Collider collisionEntity : loadedFurniture.collisionEntities()) { + for (Collider collisionEntity : bukkitFurniture.collisionEntities()) { int collisionEntityId = FastNMS.INSTANCE.method$Entity$getId(collisionEntity.handle()); - this.furnitureByRealEntityId.put(collisionEntityId, loadedFurniture); + this.furnitureByRealEntityId.put(collisionEntityId, bukkitFurniture); } - return loadedFurniture; + return bukkitFurniture; + } + + @Override + protected HitBox defaultHitBox() { + return InteractionHitBox.DEFAULT; } protected void handleDismount(Player player, Entity entity) { @@ -458,7 +322,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { Integer baseFurniture = vehicle.getPersistentDataContainer().get(FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); if (baseFurniture == null) return; vehicle.remove(); - LoadedFurniture furniture = loadedFurnitureByRealEntityId(baseFurniture); + BukkitFurniture furniture = loadedFurnitureByRealEntityId(baseFurniture); if (furniture == null) { return; } 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 f42317250..7ce7603f6 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 @@ -3,7 +3,7 @@ package net.momirealms.craftengine.bukkit.item.behavior; import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptPlaceEvent; import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; -import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.DirectionUtils; @@ -134,7 +134,7 @@ public class FurnitureItemBehavior extends ItemBehavior { Item item = context.getItem(); - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().place( + BukkitFurniture bukkitFurniture = BukkitFurnitureManager.instance().place( furnitureLocation.clone(), customFurniture, FurnitureExtraData.builder() .item(item.copyWithCount(1)) @@ -142,15 +142,15 @@ public class FurnitureItemBehavior extends ItemBehavior { .dyedColor(item.dyedColor().orElse(null)) .build(), false); - FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, loadedFurniture, furnitureLocation, context.getHand()); + FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, bukkitFurniture, furnitureLocation, context.getHand()); if (EventUtils.fireAndCheckCancel(placeEvent)) { - loadedFurniture.destroy(); + bukkitFurniture.destroy(); return InteractionResult.FAIL; } Cancellable dummy = Cancellable.dummy(); PlayerOptionalContext functionContext = PlayerOptionalContext.of(player, ContextHolder.builder() - .withParameter(DirectContextParameters.FURNITURE, loadedFurniture) + .withParameter(DirectContextParameters.FURNITURE, bukkitFurniture) .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(furnitureLocation)) .withParameter(DirectContextParameters.EVENT, dummy) .withParameter(DirectContextParameters.HAND, context.getHand()) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index 3ac9d8823..abaf50b8d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -121,7 +121,14 @@ public class ItemEventListener implements Listener { // interact block with items if (hasItem && action == Action.RIGHT_CLICK_BLOCK) { - Location interactionPoint = Objects.requireNonNull(event.getInteractionPoint(), "interaction point should not be null"); + Location interactionPoint = event.getInteractionPoint(); + // some plugins would trigger this event without interaction point + if (interactionPoint == null) { + if (hasCustomItem) { + event.setCancelled(true); + } + return; + } Direction direction = DirectionUtils.toDirection(event.getBlockFace()); BlockPos pos = LocationUtils.toBlockPos(block.getLocation()); Vec3d vec3d = new Vec3d(interactionPoint.getX(), interactionPoint.getY(), interactionPoint.getZ()); 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 949b9ae16..de40cc956 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 @@ -11,7 +11,7 @@ import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; -import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; @@ -1489,7 +1489,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().loadedFurnitureByEntityId(entityId); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); if (furniture == null) return; Player player = (Player) user.platformPlayer(); if (player == null) return; @@ -1518,7 +1518,7 @@ public class PacketConsumers { } }; - private static void handlePickItemFromEntityOnMainThread(Player player, LoadedFurniture furniture) throws Exception { + private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Exception { Key itemId = furniture.config().settings().itemId(); if (itemId == null) return; pickItem(player, itemId, null, FastNMS.INSTANCE.method$CraftEntity$getHandle(furniture.baseEntity())); @@ -1596,7 +1596,7 @@ public class PacketConsumers { int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet); if (entityType == Reflections.instance$EntityType$ITEM_DISPLAY) { // Furniture - LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); if (furniture != null) { user.entityPacketHandlers().computeIfAbsent(entityId, k -> new FurniturePacketHandler(furniture.fakeEntityIds())); user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); @@ -1606,7 +1606,7 @@ public class PacketConsumers { } } else if (entityType == BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE) { // Cancel collider entity packet - LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); if (furniture != null) { event.setCancelled(true); user.entityPacketHandlers().put(entityId, FurnitureCollisionPacketHandler.INSTANCE); @@ -1670,7 +1670,7 @@ public class PacketConsumers { } else { entityId = FastNMS.INSTANCE.field$ServerboundInteractPacket$entityId(packet); } - LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); if (furniture == null) return; Object action = Reflections.field$ServerboundInteractPacket$action.get(packet); Object actionType = Reflections.method$ServerboundInteractPacket$Action$getType.invoke(action); @@ -1694,7 +1694,7 @@ public class PacketConsumers { // execute functions PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.FURNITURE, furniture) - .withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position())) + .withParameter(DirectContextParameters.POSITION, furniture.position()) ); furniture.config().execute(context, EventTrigger.LEFT_CLICK); furniture.config().execute(context, EventTrigger.BREAK); @@ -1724,7 +1724,7 @@ public class PacketConsumers { // execute functions PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.FURNITURE, furniture) - .withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position())) + .withParameter(DirectContextParameters.POSITION, furniture.position()) ); furniture.config().execute(context, EventTrigger.RIGHT_CLICK);; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractCustomFurniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractCustomFurniture.java new file mode 100644 index 000000000..d617a91ac --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractCustomFurniture.java @@ -0,0 +1,80 @@ +package net.momirealms.craftengine.core.entity.furniture; + +import net.momirealms.craftengine.core.loot.LootTable; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public abstract class AbstractCustomFurniture implements CustomFurniture { + private final Key id; + private final FurnitureSettings settings; + private final Map placements; + private final Map>> events; + @Nullable + private final LootTable lootTable; + + private final AnchorType anyType; + + protected AbstractCustomFurniture(@NotNull Key id, + @NotNull FurnitureSettings settings, + @NotNull Map placements, + @NotNull Map>> events, + @Nullable LootTable lootTable) { + this.id = id; + this.settings = settings; + this.placements = placements; + this.lootTable = lootTable; + this.events = events; + this.anyType = placements.keySet().stream().findFirst().orElse(null); + } + + @Override + public void execute(PlayerOptionalContext context, EventTrigger trigger) { + for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { + function.run(context); + } + } + + @Override + public Key id() { + return this.id; + } + + @Override + public Map placements() { + return this.placements; + } + + @Override + public FurnitureSettings settings() { + return this.settings; + } + + @Override + public @Nullable LootTable lootTable() { + return this.lootTable; + } + + @Override + public AnchorType getAnyPlacement() { + return this.anyType; + } + + @Override + public boolean isAllowedPlacement(AnchorType anchorType) { + return this.placements.containsKey(anchorType); + } + + @Override + public Placement getPlacement(AnchorType anchorType) { + return this.placements.get(anchorType); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java index 18cc2fa80..3b4863b0f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureElement.java @@ -12,7 +12,7 @@ public abstract class AbstractFurnitureElement implements FurnitureElement { private final ItemDisplayContext transform; private final Vector3f scale; private final Vector3f translation; - private final Vector3f offset; + private final Vector3f position; private final Quaternionf rotation; private final boolean applyDyedColor; @@ -21,7 +21,7 @@ public abstract class AbstractFurnitureElement implements FurnitureElement { ItemDisplayContext transform, Vector3f scale, Vector3f translation, - Vector3f offset, + Vector3f position, Quaternionf rotation, boolean applyDyedColor) { this.billboard = billboard; @@ -30,7 +30,7 @@ public abstract class AbstractFurnitureElement implements FurnitureElement { this.translation = translation; this.item = item; this.rotation = rotation; - this.offset = offset; + this.position = position; this.applyDyedColor = applyDyedColor; } @@ -71,6 +71,6 @@ public abstract class AbstractFurnitureElement implements FurnitureElement { @Override public Vector3f position() { - return offset; + return position; } } 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 index c9839cb60..bb5c88cf0 100644 --- 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 @@ -1,15 +1,40 @@ package net.momirealms.craftengine.core.entity.furniture; +import net.momirealms.craftengine.core.entity.Billboard; +import net.momirealms.craftengine.core.entity.ItemDisplayContext; +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.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.incendo.cloud.suggestion.Suggestion; +import org.joml.Vector3f; +import java.nio.file.Path; import java.util.*; public abstract class AbstractFurnitureManager implements FurnitureManager { protected final Map byId = new HashMap<>(); + private final CraftEngine plugin; + private final FurnitureParser furnitureParser; // Cached command suggestions private final List cachedSuggestions = new ArrayList<>(); + public AbstractFurnitureManager(CraftEngine plugin) { + this.plugin = plugin; + this.furnitureParser = new FurnitureParser(); + } + + @Override + public ConfigParser parser() { + return this.furnitureParser; + } + @Override public void delayedLoad() { this.initSuggestions(); @@ -37,4 +62,104 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { public void unload() { this.byId.clear(); } + + protected abstract HitBox defaultHitBox(); + + protected abstract FurnitureElement.Builder furnitureElementBuilder(); + + protected abstract CustomFurniture.Builder furnitureBuilder(); + + public class FurnitureParser implements ConfigParser { + public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public int loadingSequence() { + return LoadingSequence.FURNITURE; + } + + @SuppressWarnings("unchecked") + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + if (byId.containsKey(id)) { + throw new LocalizedResourceConfigException("warning.config.furniture.duplicate", path, id); + } + + EnumMap placements = new EnumMap<>(AnchorType.class); + Map placementMap = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(section.get("placement"), "warning.config.furniture.missing_placement"), false); + for (Map.Entry entry : placementMap.entrySet()) { + // anchor type + AnchorType anchorType = AnchorType.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH)); + Map placementArguments = MiscUtils.castToMap(entry.getValue(), false); + Optional optionalLootSpawnOffset = Optional.ofNullable(placementArguments.get("loot-spawn-offset")).map(it -> MiscUtils.getAsVector3f(it, "loot-spawn-offset")); + // furniture display elements + List elements = new ArrayList<>(); + List> elementConfigs = (List>) placementArguments.getOrDefault("elements", List.of()); + for (Map element : elementConfigs) { + FurnitureElement furnitureElement = furnitureElementBuilder() + .item(Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(element.get("item"), "warning.config.furniture.element.missing_item"))) + .applyDyedColor((boolean) element.getOrDefault("apply-dyed-color", true)) + .billboard(ResourceConfigUtils.getOrDefault(element.get("billboard"), o -> Billboard.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), Billboard.FIXED)) + .transform(ResourceConfigUtils.getOrDefault(element.get("transform"), o -> ItemDisplayContext.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), ItemDisplayContext.NONE)) + .scale(MiscUtils.getAsVector3f(element.getOrDefault("scale", "1"), "scale")) + .position(MiscUtils.getAsVector3f(element.getOrDefault("position", "0"), "position")) + .translation(MiscUtils.getAsVector3f(element.getOrDefault("translation", "0"), "translation")) + .rotation(MiscUtils.getAsQuaternionf(element.getOrDefault("rotation", "0"), "rotation")) + .build(); + elements.add(furnitureElement); + } + + // external model providers + Optional externalModel; + if (placementArguments.containsKey("model-engine")) { + externalModel = Optional.of(plugin.compatibilityManager().createModelEngineModel(placementArguments.get("model-engine").toString())); + } else if (placementArguments.containsKey("better-model")) { + externalModel = Optional.of(plugin.compatibilityManager().createBetterModelModel(placementArguments.get("better-model").toString())); + } else { + externalModel = Optional.empty(); + } + + // add hitboxes + List hitboxes = ResourceConfigUtils.parseConfigAsList(placementArguments.get("hitboxes"), HitBoxTypes::fromMap); + if (hitboxes.isEmpty() && externalModel.isEmpty()) { + hitboxes.add(defaultHitBox()); + } + + // rules + Map ruleSection = MiscUtils.castToMap(placementArguments.get("rules"), true); + if (ruleSection != null) { + placements.put(anchorType, new CustomFurniture.Placement( + elements.toArray(new FurnitureElement[0]), + hitboxes.toArray(new HitBox[0]), + ResourceConfigUtils.getOrDefault(ruleSection.get("rotation"), o -> RotationRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), RotationRule.ANY), + ResourceConfigUtils.getOrDefault(ruleSection.get("alignment"), o -> AlignmentRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), AlignmentRule.CENTER), + externalModel, + optionalLootSpawnOffset + )); + } else { + placements.put(anchorType, new CustomFurniture.Placement( + elements.toArray(new FurnitureElement[0]), + hitboxes.toArray(new HitBox[0]), + RotationRule.ANY, + AlignmentRule.CENTER, + externalModel, + optionalLootSpawnOffset + )); + } + } + + CustomFurniture furniture = furnitureBuilder() + .id(id) + .settings(FurnitureSettings.fromMap(MiscUtils.castToMap(section.get("settings"), true))) + .placement(placements) + .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) + .lootTable(LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), true))) + .build(); + AbstractFurnitureManager.this.byId.put(id, furniture); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java index caf7c4281..5357caabb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java @@ -5,74 +5,53 @@ import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.util.Key; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; -import java.util.*; +import java.util.List; +import java.util.Map; +import java.util.Optional; -public class CustomFurniture { - private final Key id; - private final FurnitureSettings settings; - private final EnumMap placements; - private final AnchorType anyType; - private final Map>> events; - @Nullable - private final LootTable lootTable; +// TODO 家具的设计存在问题。家具也应该存在不同的状态,而不是根据放置规则直接决定状态类型 +public interface CustomFurniture { - public CustomFurniture(@NotNull Key id, - @NotNull FurnitureSettings settings, - @NotNull EnumMap placements, - @NotNull Map>> events, - @Nullable LootTable lootTable) { - this.id = id; - this.settings = settings; - this.placements = placements; - this.lootTable = lootTable; - this.events = events; - this.anyType = placements.keySet().stream().findFirst().orElse(null); - } + void execute(PlayerOptionalContext context, EventTrigger trigger); - public void execute(PlayerOptionalContext context, EventTrigger trigger) { - for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { - function.run(context); - } - } + Key id(); - public Key id() { - return id; - } + Map placements(); - public EnumMap placements() { - return placements; - } - - public FurnitureSettings settings() { - return settings; - } + FurnitureSettings settings(); @Nullable - public LootTable lootTable() { - return lootTable; + LootTable lootTable(); + + AnchorType getAnyPlacement(); + + boolean isAllowedPlacement(AnchorType anchorType); + + Placement getPlacement(AnchorType anchorType); + + interface Builder { + + Builder id(Key id); + + Builder placement(Map placements); + + Builder settings(FurnitureSettings settings); + + Builder lootTable(LootTable lootTable); + + Builder events(Map>> events); + + CustomFurniture build(); } - public AnchorType getAnyPlacement() { - return this.anyType; - } - - public boolean isAllowedPlacement(AnchorType anchorType) { - return placements.containsKey(anchorType); - } - - public Placement getPlacement(AnchorType anchorType) { - return placements.get(anchorType); - } - - public record Placement(FurnitureElement[] elements, - HitBox[] hitBoxes, - RotationRule rotationRule, - AlignmentRule alignmentRule, - Optional externalModel, - Optional dropOffset) { + record Placement(FurnitureElement[] elements, + HitBox[] hitBoxes, + RotationRule rotationRule, + AlignmentRule alignmentRule, + Optional externalModel, + Optional dropOffset) { } } 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 index fea19d1e0..f843c3911 100644 --- 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 @@ -4,6 +4,7 @@ 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 net.momirealms.craftengine.core.world.WorldPosition; import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; @@ -13,9 +14,7 @@ import java.util.UUID; public interface Furniture { void initializeColliders(); - Vec3d position(); - - World world(); + WorldPosition position(); boolean isValid(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java index c730621e8..f997ce0fe 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java @@ -29,4 +29,25 @@ public interface FurnitureElement { Vector3f position(); void initPackets(int entityId, @NotNull WorldPosition position, @NotNull Quaternionf conjugated, @Nullable Integer dyedColor, Consumer packets); + + interface Builder { + + Builder item(Key item); + + Builder billboard(Billboard billboard); + + Builder transform(ItemDisplayContext transform); + + Builder scale(Vector3f scale); + + Builder translation(Vector3f translation); + + Builder position(Vector3f position); + + Builder rotation(Quaternionf rotation); + + Builder applyDyedColor(boolean applyDyedColor); + + FurnitureElement build(); + } } 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 50d4787c1..51c33827e 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 @@ -12,6 +12,12 @@ import java.util.Collection; import java.util.Optional; public interface FurnitureManager extends Manageable { + Key FURNITURE_KEY = Key.of("craftengine:furniture_id"); + Key FURNITURE_EXTRA_DATA_KEY = Key.of("craftengine:furniture_extra_data"); + Key FURNITURE_SEAT_BASE_ENTITY_KEY = Key.of("craftengine:seat_to_base_entity"); + Key FURNITURE_SEAT_VECTOR_3F_KEY = Key.of("craftengine:seat_vector"); + Key FURNITURE_COLLISION = Key.of("craftengine:collision"); + String FURNITURE_ADMIN_NODE = "craftengine.furniture.admin"; ConfigParser parser(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index 0c0407385..338ed70c0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.util; import com.mojang.datafixers.util.Either; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -15,6 +16,10 @@ public final class ResourceConfigUtils { private ResourceConfigUtils() {} + public static T getOrDefault(@Nullable O raw, Function function, T defaultValue) { + return raw != null ? function.apply(raw) : defaultValue; + } + public static T requireNonNullOrThrow(T obj, String node) { if (obj == null) throw new LocalizedResourceConfigException(node); diff --git a/gradle.properties b/gradle.properties index 2ee29d431..70296301e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -71,9 +71,9 @@ modmenu_version=13.0.3 cloth_version=17.0.144 # Proxy settings -#systemProp.socks.proxyHost=127.0.0.1 -#systemProp.socks.proxyPort=7890 -#systemProp.http.proxyHost=127.0.0.1 -#systemProp.http.proxyPort=7890 -#systemProp.https.proxyHost=127.0.0.1 -#systemProp.https.proxyPort=7890 \ No newline at end of file +systemProp.socks.proxyHost=127.0.0.1 +systemProp.socks.proxyPort=7890 +systemProp.http.proxyHost=127.0.0.1 +systemProp.http.proxyPort=7890 +systemProp.https.proxyHost=127.0.0.1 +systemProp.https.proxyPort=7890 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c6f003026..3c44eb1b6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/server-mod/v1_20_1/build.gradle.kts b/server-mod/v1_20_1/build.gradle.kts index 0266dd510..c6e5910ba 100644 --- a/server-mod/v1_20_1/build.gradle.kts +++ b/server-mod/v1_20_1/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("java-library") id("com.gradleup.shadow") version "9.0.0-beta13" - id("io.papermc.paperweight.userdev") version "2.0.0-beta.16" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } repositories { diff --git a/server-mod/v1_20_5/build.gradle.kts b/server-mod/v1_20_5/build.gradle.kts index db31453d2..38964e5ad 100644 --- a/server-mod/v1_20_5/build.gradle.kts +++ b/server-mod/v1_20_5/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("java-library") id("com.gradleup.shadow") version "9.0.0-beta13" - id("io.papermc.paperweight.userdev") version "2.0.0-beta.16" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } repositories { diff --git a/server-mod/v1_21_5/build.gradle.kts b/server-mod/v1_21_5/build.gradle.kts index 617f52ce2..ef78707c3 100644 --- a/server-mod/v1_21_5/build.gradle.kts +++ b/server-mod/v1_21_5/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("java-library") id("com.gradleup.shadow") version "9.0.0-beta13" - id("io.papermc.paperweight.userdev") version "2.0.0-beta.16" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } repositories { From 7bcfbf9cfefdf7cabbd495cfc8959ce3ab83d6e4 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 21 May 2025 21:09:02 +0800 Subject: [PATCH 23/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E7=9A=84?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E7=B1=BB=E5=9E=8B=E5=92=8C=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skript/effect/EffRemoveFurniture.java | 1 - .../src/main/resources/translations/en.yml | 2 + .../src/main/resources/translations/zh_cn.yml | 2 + .../bukkit/api/CraftEngineFurniture.java | 2 +- .../bukkit/block/BukkitBlockManager.java | 33 +++++-- .../entity/furniture/BukkitFurniture.java | 4 - .../furniture/BukkitFurnitureManager.java | 2 +- .../projectile/BukkitProjectileManager.java | 2 +- .../item/behavior/FurnitureItemBehavior.java | 2 +- .../item/listener/DebugStickListener.java | 2 +- .../plugin/network/PacketConsumers.java | 8 +- .../plugin/user/BukkitServerPlayer.java | 9 +- .../bukkit/util/BlockStateUtils.java | 6 ++ .../bukkit/util/MaterialUtils.java | 2 +- .../craftengine/bukkit/world/BukkitWorld.java | 8 ++ .../craftengine/core/block/BlockManager.java | 7 +- .../core/block/BlockRegistryMirror.java | 8 +- .../core/block/BlockStateWrapper.java | 67 ++++++++++++++ .../core/block/ImmutableBlockState.java | 14 +-- .../core/block/PackedBlockState.java | 4 - ...nillaBlock.java => VanillaBlockState.java} | 2 +- .../core/block/properties/Property.java | 2 +- .../core/entity/furniture/Furniture.java | 2 - .../entity/furniture/FurnitureManager.java | 2 +- .../core/entity/player/Player.java | 2 + .../craftengine/core/font/Emoji.java | 3 +- .../craftengine/core/item/ItemManager.java | 2 +- .../core/item/recipe/StackedContents.java | 2 +- .../craftengine/core/loot/LootConditions.java | 1 + .../craftengine/core/loot/LootContext.java | 3 +- .../core/pack/host/impl/AlistHost.java | 2 +- .../core/plugin/context/ContextHolder.java | 2 +- .../context/condition/CommonConditions.java | 1 + .../context/condition/IsNullCondition.java | 38 ++++++++ .../plugin/context/event/EventConditions.java | 1 + .../plugin/context/event/EventFunctions.java | 2 + .../context/function/ActionBarFunction.java | 2 +- .../context/function/BreakBlockFunction.java | 53 +++++++++++ .../context/function/CommandFunction.java | 2 +- .../context/function/CommonFunctions.java | 2 + .../context/function/MessageFunction.java | 2 +- .../context/function/OpenWindowFunction.java | 2 +- .../context/function/PlaceBlockFunction.java | 87 +++++++++++++++++++ .../context/function/TitleFunction.java | 2 +- .../number/ExpressionNumberProvider.java | 12 +++ .../context/number/FixedNumberProvider.java | 13 ++- .../plugin/context/number/NumberProvider.java | 2 + .../context/number/NumberProviders.java | 4 + .../context/number/UniformNumberProvider.java | 5 ++ .../craftengine/core/registry/Holder.java | 2 +- .../core/registry/MappedRegistry.java | 2 +- .../craftengine/core/registry/Registry.java | 2 +- .../craftengine/core/util/MCUtils.java | 2 +- .../craftengine/core/world/World.java | 3 + .../chunk/storage/CompressionMethod.java | 2 +- .../core/world/chunk/storage/RegionFile.java | 2 +- .../core/world/collision/AABB.java | 2 +- gradle.properties | 12 +-- 58 files changed, 393 insertions(+), 76 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/PackedBlockState.java rename core/src/main/java/net/momirealms/craftengine/core/block/{VanillaBlock.java => VanillaBlockState.java} (55%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/IsNullCondition.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java index 0e5b8885a..5996a8ae7 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/effect/EffRemoveFurniture.java @@ -6,7 +6,6 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; -import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.core.entity.furniture.Furniture; import org.bukkit.entity.Entity; import org.bukkit.event.Event; diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 39ec93ddc..985333fdd 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -94,6 +94,7 @@ warning.config.condition.permission.missing_permission: "Issue found in warning.config.condition.equals.missing_value1: "Issue found in file - The config '' is missing the required 'value1' argument for 'equals' condition." warning.config.condition.equals.missing_value2: "Issue found in file - The config '' is missing the required 'value2' argument for 'equals' condition." warning.config.condition.expression.missing_expression: "Issue found in file - The config '' is missing the required 'expression' argument for 'expression' condition." +warning.config.condition.is_null.missing_argument: "Issue found in file - The config '' is missing the required 'argument' argument for 'is_null' condition." warning.config.structure.not_section: "Issue found in file - The config '' is expected to be a config section while it's actually a(n) ''." warning.config.image.duplicate: "Issue found in file - Duplicated image ''. Please check if there is the same configuration in other files." warning.config.image.missing_height: "Issue found in file - The image '' is missing the required 'height' argument." @@ -317,6 +318,7 @@ warning.config.function.message.missing_message: "Issue found in file Issue found in file - The config '' is missing the required 'gui-type' argument for 'open_window' function." warning.config.function.open_window.invalid_gui_type: "Issue found in file - The config '' is using an invalid gui type for 'open_window' function. Allowed types: []." warning.config.function.run.missing_functions: "Issue found in file - The config '' is missing the required 'functions' argument for 'run' function." +warning.config.function.place_block.missing_block_state: "Issue found in file - The config '' is missing the required 'block-state' argument for 'place_block' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index a1d692f6e..ab9ca80ab 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -94,6 +94,7 @@ warning.config.condition.permission.missing_permission: "在文件 在文件 中发现问题 - 配置项 '' 缺少 'equals' 条件必需的 'value1' 参数" warning.config.condition.equals.missing_value2: "在文件 中发现问题 - 配置项 '' 缺少 'equals' 条件必需的 'value2' 参数" warning.config.condition.expression.missing_expression: "在文件 中发现问题 - 配置项 '' 缺少 'expression' 条件必需的 'expression' 参数" +warning.config.condition.is_null.missing_argument: "在文件 发现问题 - 配置项 '' 缺少 'is_null' 条件的必需的 'argument' 参数." warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" warning.config.image.duplicate: "在文件 发现问题 - 重复的图片配置 '' 请检查其他文件中是否存在相同配置" warning.config.image.missing_height: "在文件 发现问题 - 图片 '' 缺少必需的 'height' 参数" @@ -317,6 +318,7 @@ warning.config.function.message.missing_message: "在文件 中 warning.config.function.open_window.missing_gui_type: "在文件 中发现问题 - 配置项 '' 缺少 'open_window' 函数必需的 'gui-type' 参数" warning.config.function.open_window.invalid_gui_type: "在文件 中发现问题 - 配置项 '' 为 'open_window' 函数使用了无效的 GUI 类型 . 允许的类型: []。" warning.config.function.run.missing_functions: "在文件 中发现问题 - 配置项 '' 缺少 'run' 函数必需的 'functions' 参数" +warning.config.function.place_block.missing_block_state: "在文件 中发现问题 - 配置项 '' 缺少 'place_block' 函数必需的 'block-state' 参数." warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" 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 38fbf9f3a..62d1ef3f5 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 @@ -1,7 +1,7 @@ package net.momirealms.craftengine.bukkit.api; -import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; 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 542b9b38e..4f3b93ee7 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 @@ -40,8 +40,8 @@ import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.io.File; import java.lang.reflect.Field; import java.nio.file.Path; @@ -164,6 +164,21 @@ public class BukkitBlockManager extends AbstractBlockManager { } } + @Nullable + @Override + public BlockStateWrapper createPackedBlockState(String blockState) { + ImmutableBlockState state = BlockStateParser.deserialize(blockState); + if (state != null) { + return state.customBlockState(); + } + try { + BlockData blockData = Bukkit.createBlockData(blockState); + return BlockStateUtils.toPackedBlockState(blockData); + } catch (IllegalArgumentException e) { + return null; + } + } + @Nullable public Object getMinecraftBlockHolder(int stateId) { return stateId2BlockHolder.get(stateId); @@ -205,7 +220,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } @Override - public Key getBlockOwnerId(PackedBlockState state) { + public Key getBlockOwnerId(BlockStateWrapper state) { return BlockStateUtils.getBlockOwnerIdFromState(state.handle()); } @@ -226,11 +241,11 @@ public class BukkitBlockManager extends AbstractBlockManager { private void initMirrorRegistry() { int size = RegistryUtils.currentBlockRegistrySize(); - PackedBlockState[] states = new PackedBlockState[size]; + BlockStateWrapper[] states = new BlockStateWrapper[size]; for (int i = 0; i < size; i++) { - states[i] = new PackedBlockState(BlockStateUtils.idToBlockState(i), i); + states[i] = BlockStateWrapper.create(BlockStateUtils.idToBlockState(i), i, BlockStateUtils.isVanillaBlock(i)); } - BlockRegistryMirror.init(states, new PackedBlockState(Reflections.instance$Blocks$STONE$defaultState, BlockStateUtils.blockStateToId(Reflections.instance$Blocks$STONE$defaultState))); + BlockRegistryMirror.init(states, BlockStateWrapper.vanilla(Reflections.instance$Blocks$STONE$defaultState, BlockStateUtils.blockStateToId(Reflections.instance$Blocks$STONE$defaultState))); } private void registerEmptyBlock() { @@ -363,7 +378,7 @@ public class BukkitBlockManager extends AbstractBlockManager { if (singleState) { properties = Map.of(); int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id"); - VanillaBlock vanillaBlock = getVanillaBlock(id, stateSection); + VanillaBlockState vanillaBlock = getVanillaBlock(id, stateSection); appearances = Map.of("", vanillaBlock.registryId()); Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, vanillaBlock.type().value() + "_" + internalId); int internalBlockRegistryId = Optional.ofNullable(internalId2StateId.get(internalBlockId)).orElse(-1); @@ -379,7 +394,7 @@ public class BukkitBlockManager extends AbstractBlockManager { Map appearance2BlockType = new HashMap<>(); for (Map.Entry appearanceEntry : MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), false).entrySet()) { if (appearanceEntry.getValue() instanceof Map) { - VanillaBlock vanillaBlock = getVanillaBlock(id, MiscUtils.castToMap(appearanceEntry.getValue(), false)); + VanillaBlockState vanillaBlock = getVanillaBlock(id, MiscUtils.castToMap(appearanceEntry.getValue(), false)); appearances.put(appearanceEntry.getKey(), vanillaBlock.registryId()); appearance2BlockType.put(appearanceEntry.getKey(), vanillaBlock.type()); } @@ -449,7 +464,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } @NotNull - private VanillaBlock getVanillaBlock(Key id, Map section) { + private VanillaBlockState getVanillaBlock(Key id, Map section) { // require state non null String vanillaBlockStateTag = ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("state"), "warning.config.block.state.missing_state"); // get its registry id @@ -476,7 +491,7 @@ public class BukkitBlockManager extends AbstractBlockManager { JsonElement combinedVariant = GsonHelper.combine(variants); this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()).put(propertyNBT, combinedVariant); this.tempVanillaBlockStateModels.put(vanillaBlockStateRegistryId, combinedVariant); - return new VanillaBlock(blockId, propertyNBT, vanillaBlockStateRegistryId); + return new VanillaBlockState(blockId, propertyNBT, vanillaBlockStateRegistryId); } private JsonObject getVariantModel(Map singleModelMap) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java index b26ef3651..fb5e908b8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.entity.furniture; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import net.momirealms.craftengine.bukkit.entity.BukkitEntity; import net.momirealms.craftengine.bukkit.nms.FastNMS; @@ -9,15 +8,12 @@ import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils; 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.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 net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; import org.bukkit.Location; 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 1a70f53c0..4f8927967 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 @@ -22,9 +22,9 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; -import javax.annotation.Nullable; import java.io.IOException; import java.util.Collection; import java.util.List; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java index 3d3ad8f87..6bef2fecf 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java @@ -25,8 +25,8 @@ import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.event.world.EntitiesLoadEvent; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; 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 7ce7603f6..3c49d8c86 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 @@ -2,8 +2,8 @@ package net.momirealms.craftengine.bukkit.item.behavior; import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptPlaceEvent; import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent; -import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.DirectionUtils; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java index ff87989ed..59ef9e2dd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java @@ -25,8 +25,8 @@ import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Collection; import java.util.HashMap; import java.util.Map; 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 de40cc956..e110d229a 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 @@ -10,8 +10,8 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; @@ -39,7 +39,10 @@ import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.network.*; import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.world.*; +import net.momirealms.craftengine.core.world.BlockHitResult; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.EntityHitResult; +import net.momirealms.craftengine.core.world.WorldEvents; import net.momirealms.craftengine.core.world.chunk.Palette; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; @@ -47,7 +50,6 @@ import net.momirealms.craftengine.core.world.chunk.packet.MCSection; import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.*; -import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; 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 5e045570f..00d219bd8 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 @@ -11,8 +11,8 @@ import net.momirealms.craftengine.bukkit.plugin.gui.CraftEngineInventoryHolder; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.BlockSettings; +import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.block.PackedBlockState; import net.momirealms.craftengine.core.entity.player.GameMode; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; @@ -405,7 +405,7 @@ public class BukkitServerPlayer extends Player { // instant break boolean custom = immutableBlockState != null; if (custom && getDestroyProgress(state, pos) >= 1f) { - PackedBlockState vanillaBlockState = immutableBlockState.vanillaBlockState(); + BlockStateWrapper vanillaBlockState = immutableBlockState.vanillaBlockState(); // if it's not an instant break on client side, we should resend level event if (vanillaBlockState != null && getDestroyProgress(vanillaBlockState.handle(), pos) < 1f) { Object levelEventPacket = FastNMS.INSTANCE.constructor$ClientboundLevelEventPacket( @@ -613,6 +613,11 @@ public class BukkitServerPlayer extends Player { } } + @Override + public void breakBlock(int x, int y, int z) { + platformPlayer().breakBlock(new Location(platformPlayer().getWorld(), x, y, z).getBlock()); + } + private void broadcastDestroyProgress(org.bukkit.entity.Player player, BlockPos hitPos, Object blockPos, int stage) { Object packet = FastNMS.INSTANCE.constructor$ClientboundBlockDestructionPacket(Integer.MAX_VALUE - entityID(), blockPos, stage); for (org.bukkit.entity.Player other : player.getWorld().getPlayers()) { 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 a5d8d4446..6e167553e 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 @@ -33,6 +33,12 @@ public class BlockStateUtils { hasInit = true; } + public static BlockStateWrapper toPackedBlockState(BlockData blockData) { + Object state = blockDataToBlockState(blockData); + int id = blockStateToId(state); + return BlockStateWrapper.create(state, id, isVanillaBlock(id)); + } + public static boolean isCorrectTool(@NotNull ImmutableBlockState state, @Nullable Item itemInHand) { BlockSettings settings = state.settings(); if (settings.requireCorrectTool()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MaterialUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MaterialUtils.java index f6cc84aa0..0ef3c5caf 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MaterialUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MaterialUtils.java @@ -4,8 +4,8 @@ import net.momirealms.craftengine.core.util.Key; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Locale; import java.util.Objects; import java.util.Optional; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index 1554d3d79..4314a2fda 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -95,4 +96,11 @@ public class BukkitWorld implements World { public long time() { return platformWorld().getTime(); } + + @Override + public void setBlockAt(int x, int y, int z, BlockStateWrapper blockState, int flags) { + Object worldServer = serverWorld(); + Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z); + FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState.handle(), flags); + } } 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 208355f1a..0319ecfd9 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 @@ -8,8 +8,8 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Collection; import java.util.Map; import java.util.Optional; @@ -36,11 +36,14 @@ public interface BlockManager extends Manageable, ModelGenerator { int availableAppearances(Key blockType); - Key getBlockOwnerId(PackedBlockState state); + Key getBlockOwnerId(BlockStateWrapper state); @NotNull ImmutableBlockState getImmutableBlockStateUnsafe(int stateId); @Nullable ImmutableBlockState getImmutableBlockState(int stateId); + + @Nullable + BlockStateWrapper createPackedBlockState(String blockState); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java index f93bf3a57..72cb6de1c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java @@ -1,15 +1,15 @@ package net.momirealms.craftengine.core.block; public class BlockRegistryMirror { - private static PackedBlockState[] customBlockStates; - private static PackedBlockState stoneState; + private static BlockStateWrapper[] customBlockStates; + private static BlockStateWrapper stoneState; - public static void init(PackedBlockState[] states, PackedBlockState state) { + public static void init(BlockStateWrapper[] states, BlockStateWrapper state) { customBlockStates = states; stoneState = state; } - public static PackedBlockState stateByRegistryId(int vanillaId) { + public static BlockStateWrapper stateByRegistryId(int vanillaId) { if (vanillaId < 0) return stoneState; return customBlockStates[vanillaId]; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java new file mode 100644 index 000000000..319a105af --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java @@ -0,0 +1,67 @@ +package net.momirealms.craftengine.core.block; + +public interface BlockStateWrapper { + + Object handle(); + + int registryId(); + + boolean isVanillaBlock(); + + static BlockStateWrapper vanilla(Object handle, int registryId) { + return new VanillaBlockState(handle, registryId); + } + + static BlockStateWrapper custom(Object handle, int registryId) { + return new CustomBlockState(handle, registryId); + } + + static BlockStateWrapper create(Object handle, int registryId, boolean isVanillaBlock) { + if (isVanillaBlock) return new VanillaBlockState(handle, registryId); + else return new CustomBlockState(handle, registryId); + } + + abstract class AbstractBlockState implements BlockStateWrapper { + protected final Object handle; + protected final int registryId; + + public AbstractBlockState(Object handle, int registryId) { + this.handle = handle; + this.registryId = registryId; + } + + @Override + public Object handle() { + return this.handle; + } + + @Override + public int registryId() { + return this.registryId; + } + } + + class VanillaBlockState extends AbstractBlockState { + + public VanillaBlockState(Object handle, int registryId) { + super(handle, registryId); + } + + @Override + public boolean isVanillaBlock() { + return true; + } + } + + class CustomBlockState extends AbstractBlockState { + + public CustomBlockState(Object handle, int registryId) { + super(handle, registryId); + } + + @Override + public boolean isVanillaBlock() { + return false; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index 32c5890a9..68747718d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -14,14 +14,14 @@ import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.NBT; import net.momirealms.sparrow.nbt.Tag; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.List; public class ImmutableBlockState extends BlockStateHolder { private CompoundTag tag; - private PackedBlockState customBlockState; - private PackedBlockState vanillaBlockState; + private BlockStateWrapper customBlockState; + private BlockStateWrapper vanillaBlockState; private BlockBehavior behavior; private Integer hashCode; @@ -81,19 +81,19 @@ public class ImmutableBlockState extends BlockStateHolder { return settings.pushReaction; } - public PackedBlockState customBlockState() { + public BlockStateWrapper customBlockState() { return this.customBlockState; } - public PackedBlockState vanillaBlockState() { + public BlockStateWrapper vanillaBlockState() { return this.vanillaBlockState; } - public void setCustomBlockState(@NotNull PackedBlockState customBlockState) { + public void setCustomBlockState(@NotNull BlockStateWrapper customBlockState) { this.customBlockState = customBlockState; } - public void setVanillaBlockState(@NotNull PackedBlockState vanillaBlockState) { + public void setVanillaBlockState(@NotNull BlockStateWrapper vanillaBlockState) { this.vanillaBlockState = vanillaBlockState; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/PackedBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/PackedBlockState.java deleted file mode 100644 index 9abfb6db8..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/block/PackedBlockState.java +++ /dev/null @@ -1,4 +0,0 @@ -package net.momirealms.craftengine.core.block; - -public record PackedBlockState(Object handle, int registryId) { -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlockState.java similarity index 55% rename from core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlock.java rename to core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlockState.java index 1ce3a53ef..9e811011f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlockState.java @@ -2,5 +2,5 @@ package net.momirealms.craftengine.core.block; import net.momirealms.craftengine.core.util.Key; -public record VanillaBlock(Key type, String properties, int registryId) { +public record VanillaBlockState(Key type, String properties, int registryId) { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java index a61d33e00..84bbfda65 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java @@ -5,8 +5,8 @@ import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.HorizontalDirection; import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.HashMap; import java.util.List; import java.util.Map; 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 index f843c3911..691092619 100644 --- 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 @@ -2,8 +2,6 @@ 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 net.momirealms.craftengine.core.world.WorldPosition; import org.jetbrains.annotations.NotNull; import org.joml.Vector3f; 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 51c33827e..2a31d46de 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 @@ -6,8 +6,8 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.WorldPosition; import org.incendo.cloud.suggestion.Suggestion; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Collection; import java.util.Optional; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index bb50aec7d..70e614cd2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -36,6 +36,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract void abortMiningBlock(); + public abstract void breakBlock(int x, int y, int z); + public abstract double getCachedInteractionRange(); public abstract void onSwingHand(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/Emoji.java b/core/src/main/java/net/momirealms/craftengine/core/font/Emoji.java index 81a51429b..8ce6168d8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/Emoji.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/Emoji.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.font; -import javax.annotation.Nullable; +import org.jetbrains.annotations.Nullable; + import java.util.List; public class 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 655270533..8a100cc33 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 @@ -11,8 +11,8 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.incendo.cloud.suggestion.Suggestion; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.*; public interface ItemManager extends Manageable, ModelGenerator { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/StackedContents.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/StackedContents.java index c6a483ac6..15442f74c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/StackedContents.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/StackedContents.java @@ -4,8 +4,8 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.objects.Reference2IntMap; import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.ArrayList; import java.util.BitSet; import java.util.List; diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java index 43ca9b0aa..9ea20df82 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java @@ -33,6 +33,7 @@ public class LootConditions { register(CommonConditions.PERMISSION, new PermissionCondition.FactoryImpl<>()); register(CommonConditions.EQUALS, new EqualsCondition.FactoryImpl<>()); register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>()); + register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>()); } public static void register(Key key, ConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java index 5e3c9092d..8ca3cf5e2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootContext.java @@ -5,8 +5,7 @@ import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.world.World; import org.jetbrains.annotations.NotNull; - -import javax.annotation.Nullable; +import org.jetbrains.annotations.Nullable; public class LootContext extends PlayerOptionalContext { private final World world; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java index 2ae5335c1..26a20125b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java @@ -10,8 +10,8 @@ import net.momirealms.craftengine.core.pack.host.ResourcePackHosts; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.util.*; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java index 037b53e39..5e54f2ea8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ContextHolder.java @@ -1,8 +1,8 @@ package net.momirealms.craftengine.core.plugin.context; import com.google.common.collect.ImmutableMap; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java index 600d204c8..ad64b2ec5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java @@ -20,4 +20,5 @@ public final class CommonConditions { public static final Key PERMISSION = Key.from("craftengine:permission"); public static final Key EQUALS = Key.from("craftengine:equals"); public static final Key EXPRESSION = Key.from("craftengine:expression"); + public static final Key IS_NULL = Key.from("craftengine:is_null"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/IsNullCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/IsNullCondition.java new file mode 100644 index 000000000..7ea6d60cb --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/IsNullCondition.java @@ -0,0 +1,38 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; +import java.util.Optional; + +public class IsNullCondition implements Condition { + private final ContextKey key; + + public IsNullCondition(ContextKey key) { + this.key = key; + } + + @Override + public Key type() { + return CommonConditions.IS_NULL; + } + + @Override + public boolean test(CTX ctx) { + Optional optional = ctx.getOptionalParameter(this.key); + return optional.isPresent(); + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + String argument = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("argument"), "warning.config.condition.is_null.missing_argument"); + return new IsNullCondition<>(ContextKey.chain(argument)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java index 5b6adc177..e7eea8bc8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java @@ -31,6 +31,7 @@ public class EventConditions { register(CommonConditions.PERMISSION, new PermissionCondition.FactoryImpl<>()); register(CommonConditions.EQUALS, new EqualsCondition.FactoryImpl<>()); register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>()); + register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>()); } public static void register(Key key, ConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index 169593072..c056c1c7e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -24,6 +24,8 @@ public class EventFunctions { register(CommonFunctions.OPEN_WINDOW, new OpenWindowFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.CANCEL_EVENT, new CancelEventFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.RUN, new RunFunction.FactoryImpl<>(EventFunctions::fromMap, EventConditions::fromMap)); + register(CommonFunctions.PLACE_BLOCK, new PlaceBlockFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.BREAK_BLOCK, new BreakBlockFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java index 1db327924..4e04272f7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java @@ -10,8 +10,8 @@ import net.momirealms.craftengine.core.plugin.context.text.TextProviders; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.List; import java.util.Map; import java.util.Optional; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java new file mode 100644 index 000000000..97d5fc4b4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java @@ -0,0 +1,53 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MCUtils; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class BreakBlockFunction extends AbstractConditionalFunction { + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + + public BreakBlockFunction(NumberProvider x, NumberProvider y, NumberProvider z, List> predicates) { + super(predicates); + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + optionalPlayer.ifPresent(player -> player.breakBlock(MCUtils.fastFloor(x.getDouble(ctx)), MCUtils.fastFloor(y.getDouble(ctx)), MCUtils.fastFloor(z.getDouble(ctx)))); + } + + @Override + public Key type() { + return CommonFunctions.BREAK_BLOCK; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); + NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); + NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); + return new BreakBlockFunction<>(x, y, z, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java index 0b203a447..61a4137c4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java @@ -12,8 +12,8 @@ import net.momirealms.craftengine.core.plugin.context.text.TextProviders; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.List; import java.util.Map; import java.util.Optional; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index f0df7a51c..4e7b764b4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -16,9 +16,11 @@ public final class CommonFunctions { public static final Key POTION_EFFECT = Key.of("craftengine:potion_effect"); public static final Key BREAK_BLOCK = Key.of("craftengine:break_block"); public static final Key CANCEL_EVENT = Key.of("craftengine:cancel_event"); + public static final Key PLACE_BLOCK = Key.of("craftengine:place_block"); public static final Key FOOD = Key.of("craftengine:food"); public static final Key SATURATION = Key.of("craftengine:saturation"); public static final Key MONEY = Key.of("craftengine:money"); public static final Key OXYGEN = Key.of("craftengine:oxygen"); public static final Key MINE_RADIUS = Key.of("craftengine:mine_radius"); + public static final Key DROP_LOOT = Key.of("craftengine:drop_loot"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java index 1b4f2ddbd..eeee93a4f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java @@ -11,8 +11,8 @@ 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.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.List; import java.util.Map; import java.util.Optional; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java index 010098123..53dd47587 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java @@ -14,8 +14,8 @@ import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.EnumUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.List; import java.util.Locale; import java.util.Map; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java new file mode 100644 index 000000000..2c0daf916 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java @@ -0,0 +1,87 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.block.UpdateOption; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class PlaceBlockFunction extends AbstractConditionalFunction { + private final DelayedInitBlockState delayedInitBlockState; + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final NumberProvider updateFlags; + + public PlaceBlockFunction(DelayedInitBlockState delayedInitBlockState, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider updateFlags, List> predicates) { + super(predicates); + this.delayedInitBlockState = delayedInitBlockState; + this.x = x; + this.y = y; + this.z = z; + this.updateFlags = updateFlags; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isPresent()) { + World world = optionalWorldPosition.get().world(); + world.setBlockAt(MCUtils.fastFloor(this.x.getDouble(ctx)), MCUtils.fastFloor(this.y.getDouble(ctx)), MCUtils.fastFloor(this.z.getDouble(ctx)), this.delayedInitBlockState.getState(), this.updateFlags.getInt(ctx)); + } + } + + @Override + public Key type() { + return CommonFunctions.PLACE_BLOCK; + } + + public static class DelayedInitBlockState { + private final String state; + private BlockStateWrapper packedBlockState; + + public DelayedInitBlockState(String state) { + this.state = state; + } + + public BlockStateWrapper getState() { + if (this.packedBlockState == null) { + this.packedBlockState = CraftEngine.instance().blockManager().createPackedBlockState(state); + if (this.packedBlockState == null) { + CraftEngine.instance().logger().warn("Could not create block state: " + this.state); + } + } + return this.packedBlockState; + } + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + String state = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("block-state"), "warning.config.function.place_block.missing_block_state"); + DelayedInitBlockState delayedInitBlockState = new DelayedInitBlockState(state); + NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); + NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); + NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); + NumberProvider flags = Optional.ofNullable(arguments.get("update-flags")).map(NumberProviders::fromObject).orElse(NumberProviders.direct(UpdateOption.UPDATE_ALL.flags())); + return new PlaceBlockFunction<>(delayedInitBlockState, x, y, z, flags, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java index 6d55589ae..28900c5a1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java @@ -11,8 +11,8 @@ import net.momirealms.craftengine.core.plugin.context.text.TextProvider; import net.momirealms.craftengine.core.plugin.context.text.TextProviders; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.List; import java.util.Map; import java.util.Optional; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java index 6428df308..43bf33fcf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/ExpressionNumberProvider.java @@ -31,6 +31,18 @@ public class ExpressionNumberProvider implements NumberProvider { } } + @Override + public double getDouble(Context context) { + Component resultComponent = AdventureHelper.customMiniMessage().deserialize(this.expr, context.tagResolvers()); + String resultString = AdventureHelper.plainTextContent(resultComponent); + Expression expression = new Expression(resultString); + try { + return expression.evaluate().getNumberValue().doubleValue(); + } catch (EvaluationException | ParseException e) { + throw new RuntimeException("Invalid expression: " + this.expr + " -> " + resultString + " -> Cannot parse", e); + } + } + @Override public Key type() { return NumberProviders.EXPRESSION; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java index 3bbf7729f..b4662a547 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/FixedNumberProvider.java @@ -10,14 +10,19 @@ import java.util.Map; public class FixedNumberProvider implements NumberProvider { public static final FactoryImpl FACTORY = new FactoryImpl(); - private final float value; + private final double value; - public FixedNumberProvider(float value) { + public FixedNumberProvider(double value) { this.value = value; } @Override public float getFloat(Context context) { + return (float) this.value; + } + + @Override + public double getDouble(Context context) { return this.value; } @@ -32,12 +37,12 @@ public class FixedNumberProvider implements NumberProvider { public NumberProvider create(Map arguments) { String plainOrExpression = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value"), "warning.config.number.fixed.missing_value"); try { - float value = Float.parseFloat(plainOrExpression); + double value = Double.parseDouble(plainOrExpression); return new FixedNumberProvider(value); } catch (NumberFormatException e) { Expression expression = new Expression(plainOrExpression); try { - return new FixedNumberProvider(expression.evaluate().getNumberValue().floatValue()); + return new FixedNumberProvider(expression.evaluate().getNumberValue().doubleValue()); } catch (Exception e1) { throw new LocalizedResourceConfigException("warning.config.number.fixed.invalid_value", e1, plainOrExpression); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProvider.java index 93cdd64a0..9ea8a03d1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProvider.java @@ -7,6 +7,8 @@ public interface NumberProvider { float getFloat(Context context); + double getDouble(Context context); + default int getInt(Context context) { return Math.round(this.getFloat(context)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java index 8baef2d0b..2d7fb1591 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java @@ -41,6 +41,10 @@ public class NumberProviders { return functions; } + public static NumberProvider direct(double value) { + return new FixedNumberProvider(value); + } + public static NumberProvider fromMap(Map map) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.number.missing_type"); Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java index 62d7c4ddc..dca387d0e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/UniformNumberProvider.java @@ -30,6 +30,11 @@ public class UniformNumberProvider implements NumberProvider { return RandomUtils.generateRandomInt(this.min.getInt(context), this.max.getInt(context) + 1); } + @Override + public double getDouble(Context context) { + return RandomUtils.generateRandomDouble(this.min.getDouble(context), this.max.getDouble(context)); + } + @Override public float getFloat(Context context) { return RandomUtils.generateRandomFloat(this.min.getFloat(context), this.max.getFloat(context)); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java index 06e1c25f9..d4aae38ea 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java @@ -3,8 +3,8 @@ package net.momirealms.craftengine.core.registry; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Collection; import java.util.Collections; import java.util.Optional; diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/MappedRegistry.java b/core/src/main/java/net/momirealms/craftengine/core/registry/MappedRegistry.java index 2a20fd589..219c1d5b7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/MappedRegistry.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/MappedRegistry.java @@ -3,8 +3,8 @@ package net.momirealms.craftengine.core.registry; import com.google.common.collect.Maps; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.*; public class MappedRegistry implements WritableRegistry { diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registry.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registry.java index 4540d9c19..970d47b15 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registry.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registry.java @@ -2,8 +2,8 @@ package net.momirealms.craftengine.core.registry; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Map; import java.util.Optional; import java.util.Set; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java index 7886f0e0f..95e1621f7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java @@ -1,8 +1,8 @@ package net.momirealms.craftengine.core.util; import com.google.common.collect.Iterators; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Iterator; import java.util.List; import java.util.function.Consumer; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index 565d93067..c48a66415 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.world; +import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; @@ -21,6 +22,8 @@ public interface World { return getBlockAt(pos.x(), pos.y(), pos.z()); } + void setBlockAt(int x, int y, int z, BlockStateWrapper blockState, int flags); + String name(); Path directory(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CompressionMethod.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CompressionMethod.java index bf9f74ecd..cfe5268c0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CompressionMethod.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/CompressionMethod.java @@ -5,8 +5,8 @@ import net.jpountz.lz4.LZ4BlockInputStream; import net.jpountz.lz4.LZ4BlockOutputStream; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.dependency.Dependencies; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java index b2e8ad51b..d1feed960 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/RegionFile.java @@ -5,8 +5,8 @@ import net.momirealms.craftengine.core.plugin.logger.PluginLogger; import net.momirealms.craftengine.core.world.ChunkPos; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.NBT; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.io.*; import java.nio.Buffer; import java.nio.ByteBuffer; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java b/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java index faf6b5bc2..d0a02fd09 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/collision/AABB.java @@ -3,8 +3,8 @@ package net.momirealms.craftengine.core.world.collision; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.world.EntityHitResult; import net.momirealms.craftengine.core.world.Vec3d; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Optional; public class AABB { diff --git a/gradle.properties b/gradle.properties index 70296301e..2ee29d431 100644 --- a/gradle.properties +++ b/gradle.properties @@ -71,9 +71,9 @@ modmenu_version=13.0.3 cloth_version=17.0.144 # Proxy settings -systemProp.socks.proxyHost=127.0.0.1 -systemProp.socks.proxyPort=7890 -systemProp.http.proxyHost=127.0.0.1 -systemProp.http.proxyPort=7890 -systemProp.https.proxyHost=127.0.0.1 -systemProp.https.proxyPort=7890 \ No newline at end of file +#systemProp.socks.proxyHost=127.0.0.1 +#systemProp.socks.proxyPort=7890 +#systemProp.http.proxyHost=127.0.0.1 +#systemProp.http.proxyPort=7890 +#systemProp.https.proxyHost=127.0.0.1 +#systemProp.https.proxyPort=7890 \ No newline at end of file From 454e778378037dafa212d9a3e98d192562ab95bf Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 21 May 2025 23:41:52 +0800 Subject: [PATCH 24/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E7=9A=84?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E5=92=8C=E6=9D=A1=E4=BB=B6=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 5 ++ .../src/main/resources/translations/zh_cn.yml | 5 ++ .../bukkit/entity/BukkitEntity.java | 4 +- .../bukkit/item/ComponentItemWrapper.java | 2 +- .../bukkit/item/LegacyItemWrapper.java | 2 +- .../item/behavior/FurnitureItemBehavior.java | 2 +- .../plugin/user/BukkitServerPlayer.java | 24 +++++- .../craftengine/bukkit/util/SoundUtils.java | 17 +++++ .../craftengine/bukkit/world/BukkitWorld.java | 7 ++ .../core/entity/AbstractEntity.java | 2 +- .../craftengine/core/entity/Entity.java | 6 +- .../core/entity/player/Player.java | 8 ++ .../core/item/context/UseOnContext.java | 2 +- .../craftengine/core/loot/LootConditions.java | 1 + .../craftengine/core/loot/LootTable.java | 6 +- .../context/condition/CommonConditions.java | 1 + .../context/condition/HandCondition.java | 49 +++++++++++++ .../context/condition/IsNullCondition.java | 2 +- .../plugin/context/event/EventConditions.java | 1 + .../plugin/context/event/EventFunctions.java | 7 ++ .../context/function/BreakBlockFunction.java | 6 +- .../context/function/CommonFunctions.java | 12 +-- .../context/function/DropLootFunction.java | 68 +++++++++++++++++ .../context/function/PlaceBlockFunction.java | 6 +- .../context/function/PlaySoundFunction.java | 73 +++++++++++++++++++ .../context/function/SetCountFunction.java | 57 +++++++++++++++ .../context/function/SetFoodFunction.java | 50 +++++++++++++ .../function/SetSaturationFunction.java | 50 +++++++++++++ .../context/function/SwingHandFunction.java | 52 +++++++++++++ .../function/UpdateInteractionFunction.java | 41 +++++++++++ .../parameter/DirectContextParameters.java | 4 + .../parameter/EntityParameterProvider.java | 2 + .../parameter/PlayerParameterProvider.java | 13 ++-- .../parameter/PositionParameterProvider.java | 2 + .../craftengine/core/sound/SoundSource.java | 27 +++++++ .../craftengine/core/util/Direction.java | 4 +- .../craftengine/core/world/World.java | 4 + 37 files changed, 589 insertions(+), 35 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HandCondition.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DropLootFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaySoundFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetCountFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SwingHandFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateInteractionFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/sound/SoundSource.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 985333fdd..26a9afbb3 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -95,6 +95,8 @@ warning.config.condition.equals.missing_value1: "Issue found in file Issue found in file - The config '' is missing the required 'value2' argument for 'equals' condition." warning.config.condition.expression.missing_expression: "Issue found in file - The config '' is missing the required 'expression' argument for 'expression' condition." warning.config.condition.is_null.missing_argument: "Issue found in file - The config '' is missing the required 'argument' argument for 'is_null' condition." +warning.config.condition.hand.missing_hand: "Issue found in file - The config '' is missing the required 'hand' argument for 'hand' condition." +warning.config.condition.hand.invalid_hand: "Issue found in file - The config '' is using an invalid 'hand' argument '' for 'hand' condition. Allowed hand types: []" warning.config.structure.not_section: "Issue found in file - The config '' is expected to be a config section while it's actually a(n) ''." warning.config.image.duplicate: "Issue found in file - Duplicated image ''. Please check if there is the same configuration in other files." warning.config.image.missing_height: "Issue found in file - The image '' is missing the required 'height' argument." @@ -319,6 +321,9 @@ warning.config.function.open_window.missing_gui_type: "Issue found in fi warning.config.function.open_window.invalid_gui_type: "Issue found in file - The config '' is using an invalid gui type for 'open_window' function. Allowed types: []." warning.config.function.run.missing_functions: "Issue found in file - The config '' is missing the required 'functions' argument for 'run' function." warning.config.function.place_block.missing_block_state: "Issue found in file - The config '' is missing the required 'block-state' argument for 'place_block' function." +warning.config.function.set_food.missing_food: "Issue found in file - The config '' is missing the required 'food' argument for 'set_food' function." +warning.config.function.set_saturation.missing_saturation: "Issue found in file - The config '' is missing the required 'saturation' argument for 'set_saturation' function." +warning.config.function.play_sound.missing_sound: "Issue found in file - The config '' is missing the required 'sound' argument for 'play_sound' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index ab9ca80ab..983dc9e9c 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -96,6 +96,8 @@ warning.config.condition.equals.missing_value2: "在文件 中 warning.config.condition.expression.missing_expression: "在文件 中发现问题 - 配置项 '' 缺少 'expression' 条件必需的 'expression' 参数" warning.config.condition.is_null.missing_argument: "在文件 发现问题 - 配置项 '' 缺少 'is_null' 条件的必需的 'argument' 参数." warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" +warning.config.condition.hand.missing_hand: "Issue found in file - The config '' is missing the required 'hand' argument for 'hand' condition." +warning.config.condition.hand.invalid_hand: "Issue found in file - The config '' is using an invalid 'hand' argument '' for 'hand' condition. Allowed hand types: []" warning.config.image.duplicate: "在文件 发现问题 - 重复的图片配置 '' 请检查其他文件中是否存在相同配置" warning.config.image.missing_height: "在文件 发现问题 - 图片 '' 缺少必需的 'height' 参数" warning.config.image.height_ascent_conflict: "在文件 发现问题 - 图片 '' 违反位图规则: 'height' 参数 '' 必须不小于 'ascent' 参数 ''" @@ -319,6 +321,9 @@ warning.config.function.open_window.missing_gui_type: "在文件 warning.config.function.open_window.invalid_gui_type: "在文件 中发现问题 - 配置项 '' 为 'open_window' 函数使用了无效的 GUI 类型 . 允许的类型: []。" warning.config.function.run.missing_functions: "在文件 中发现问题 - 配置项 '' 缺少 'run' 函数必需的 'functions' 参数" warning.config.function.place_block.missing_block_state: "在文件 中发现问题 - 配置项 '' 缺少 'place_block' 函数必需的 'block-state' 参数." +warning.config.function.set_food.missing_food: "Issue found in file - The config '' is missing the required 'food' argument for 'set_food' function." +warning.config.function.set_saturation.missing_saturation: "Issue found in file - The config '' is missing the required 'saturation' argument for 'set_saturation' function." +warning.config.function.play_sound.missing_sound: "Issue found in file - The config '' is missing the required 'sound' argument for 'play_sound' function." warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java index ffe08c8fd..2193b86f9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java @@ -42,12 +42,12 @@ public class BukkitEntity extends AbstractEntity { } @Override - public float getXRot() { + public float xRot() { return literalObject().getYaw(); } @Override - public float getYRot() { + public float yRot() { return literalObject().getPitch(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java index b7c1eb500..c4bdbc860 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java @@ -98,6 +98,6 @@ public class ComponentItemWrapper implements ItemWrapper { @Override public void count(int amount) { - this.item.setAmount(amount); + this.item.setAmount(Math.max(amount, 0)); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java index 5e58510c9..154e121e5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java @@ -60,7 +60,7 @@ public class LegacyItemWrapper implements ItemWrapper { @Override public ItemStack load() { ItemStack itemStack = this.rtagItem.load(); - itemStack.setAmount(this.count); + itemStack.setAmount(Math.max(this.count, 0)); return itemStack; } 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 3c49d8c86..b604359e9 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 @@ -105,7 +105,7 @@ public class FurnitureItemBehavior extends ItemBehavior { finalPlacePosition = new Vec3d(xz.left(), xz.right(), clickedPosition.z()); } } else { - furnitureYaw = placement.rotationRule().apply(180 + player.getXRot()); + furnitureYaw = placement.rotationRule().apply(180 + player.xRot()); Pair xz = placement.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.z())); finalPlacePosition = new Vec3d(xz.left(), clickedPosition.y(), xz.right()); } 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 00d219bd8..3dce61b66 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 @@ -675,12 +675,12 @@ public class BukkitServerPlayer extends Player { } @Override - public float getYRot() { + public float yRot() { return platformPlayer().getPitch(); } @Override - public float getXRot() { + public float xRot() { return platformPlayer().getYaw(); } @@ -838,4 +838,24 @@ public class BukkitServerPlayer extends Player { public boolean isFlying() { return platformPlayer().isFlying(); } + + @Override + public int foodLevel() { + return platformPlayer().getFoodLevel(); + } + + @Override + public void setFoodLevel(int foodLevel) { + this.platformPlayer().setFoodLevel(Math.min(Math.max(0, foodLevel), 20)); + } + + @Override + public float saturation() { + return platformPlayer().getSaturation(); + } + + @Override + public void setSaturation(float saturation) { + this.platformPlayer().setSaturation(saturation); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/SoundUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/SoundUtils.java index a733074e5..de80480fa 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/SoundUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/SoundUtils.java @@ -1,7 +1,9 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.core.block.BlockSounds; +import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; +import org.bukkit.SoundCategory; public class SoundUtils { @@ -21,4 +23,19 @@ public class SoundUtils { public static Object getOrRegisterSoundEvent(Key key) throws ReflectiveOperationException { return Reflections.method$SoundEvent$createVariableRangeEvent.invoke(null, KeyUtils.toResourceLocation(key)); } + + public static SoundCategory toBukkit(SoundSource source) { + return switch (source) { + case BLOCK -> SoundCategory.BLOCKS; + case MUSIC -> SoundCategory.MUSIC; + case VOICE -> SoundCategory.VOICE; + case MASTER -> SoundCategory.MASTER; + case PLAYER -> SoundCategory.PLAYERS; + case RECORD -> SoundCategory.RECORDS; + case AMBIENT -> SoundCategory.AMBIENT; + case HOSTILE -> SoundCategory.HOSTILE; + case NEUTRAL -> SoundCategory.NEUTRAL; + case WEATHER -> SoundCategory.WEATHER; + }; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index 4314a2fda..c1b6949a5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -3,8 +3,10 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.SoundUtils; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockInWorld; @@ -87,6 +89,11 @@ public class BukkitWorld implements World { }); } + @Override + public void playSound(Position location, Key sound, float volume, float pitch, SoundSource source) { + platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); + } + @Override public void playBlockSound(Position location, Key sound, float volume, float pitch) { platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundCategory.BLOCKS, volume, pitch); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java b/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java index c9eb5a247..fa9643892 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/AbstractEntity.java @@ -6,6 +6,6 @@ public abstract class AbstractEntity implements Entity { @Override public WorldPosition position() { - return new WorldPosition(world(), x(), y(), z(), getXRot(), getYRot()); + return new WorldPosition(world(), x(), y(), z(), xRot(), yRot()); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java index 15720fa5c..aac181c4b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java @@ -20,12 +20,12 @@ public interface Entity { void tick(); - float getXRot(); + float xRot(); + + float yRot(); int entityID(); - float getYRot(); - World world(); Direction getDirection(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index 70e614cd2..c0132edf8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -116,4 +116,12 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public boolean isAdventureMode() { return gameMode() == GameMode.ADVENTURE; } + + public abstract int foodLevel(); + + public abstract void setFoodLevel(int foodLevel); + + public abstract float saturation(); + + public abstract void setSaturation(float saturation); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java b/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java index 5e6280e02..e07191478 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java @@ -73,6 +73,6 @@ public class UseOnContext { } public float getRotation() { - return this.player == null ? 0.0F : this.player.getYRot(); + return this.player == null ? 0.0F : this.player.yRot(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java index 9ea20df82..26798ceb1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java @@ -34,6 +34,7 @@ public class LootConditions { register(CommonConditions.EQUALS, new EqualsCondition.FactoryImpl<>()); register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>()); register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>()); + register(CommonConditions.HAND, new HandCondition.FactoryImpl<>()); } public static void register(Key key, ConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java index 32d744ba0..662cefcea 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java @@ -78,15 +78,15 @@ public class LootTable { ); } - public ArrayList> getRandomItems(ContextHolder parameters, World world) { + public List> getRandomItems(ContextHolder parameters, World world) { return this.getRandomItems(parameters, world, null); } - public ArrayList> getRandomItems(ContextHolder parameters, World world, @Nullable Player player) { + public List> getRandomItems(ContextHolder parameters, World world, @Nullable Player player) { return this.getRandomItems(new LootContext(world, player, player == null ? 1f : (float) player.luck(), parameters)); } - private ArrayList> getRandomItems(LootContext context) { + private List> getRandomItems(LootContext context) { ArrayList> list = new ArrayList<>(); this.getRandomItems(context, list::add); return list; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java index ad64b2ec5..44a588cb9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java @@ -21,4 +21,5 @@ public final class CommonConditions { public static final Key EQUALS = Key.from("craftengine:equals"); public static final Key EXPRESSION = Key.from("craftengine:expression"); public static final Key IS_NULL = Key.from("craftengine:is_null"); + public static final Key HAND = Key.from("craftengine:hand"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HandCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HandCondition.java new file mode 100644 index 000000000..8cc171076 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HandCondition.java @@ -0,0 +1,49 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +public class HandCondition implements Condition { + private final InteractionHand hand; + + public HandCondition(InteractionHand hand) { + this.hand = hand; + } + + @Override + public Key type() { + return CommonConditions.HAND; + } + + @Override + public boolean test(CTX ctx) { + Optional optional = ctx.getOptionalParameter(DirectContextParameters.HAND); + if (optional.isPresent()) { + InteractionHand hand = optional.get(); + return hand.equals(this.hand); + } + return false; + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + String hand = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("hand"), "warning.config.condition.hand.missing_hand"); + try { + return new HandCondition<>(InteractionHand.valueOf(hand.toUpperCase(Locale.ENGLISH))); + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.condition.hand.invalid_hand", hand); + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/IsNullCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/IsNullCondition.java index 7ea6d60cb..010221218 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/IsNullCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/IsNullCondition.java @@ -24,7 +24,7 @@ public class IsNullCondition implements Condition { @Override public boolean test(CTX ctx) { Optional optional = ctx.getOptionalParameter(this.key); - return optional.isPresent(); + return optional.isEmpty(); } public static class FactoryImpl implements ConditionFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java index e7eea8bc8..3c93dd0e0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java @@ -32,6 +32,7 @@ public class EventConditions { register(CommonConditions.EQUALS, new EqualsCondition.FactoryImpl<>()); register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>()); register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>()); + register(CommonConditions.HAND, new HandCondition.FactoryImpl<>()); } public static void register(Key key, ConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index c056c1c7e..ae0c66bd3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -26,6 +26,13 @@ public class EventFunctions { register(CommonFunctions.RUN, new RunFunction.FactoryImpl<>(EventFunctions::fromMap, EventConditions::fromMap)); register(CommonFunctions.PLACE_BLOCK, new PlaceBlockFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.BREAK_BLOCK, new BreakBlockFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.UPDATE_INTERACTION_TICK, new UpdateInteractionFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.SET_COUNT, new SetCountFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.DROP_LOOT, new DropLootFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.SWING_HAND, new SwingHandFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.SET_FOOD, new SetFoodFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.SET_SATURATION, new SetSaturationFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.PLAY_SOUND, new PlaySoundFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java index 97d5fc4b4..025cda880 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java @@ -44,9 +44,9 @@ public class BreakBlockFunction extends AbstractConditional @Override public Function create(Map arguments) { - NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); - NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); - NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); + NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); + NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); + NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); return new BreakBlockFunction<>(x, y, z, getPredicates(arguments)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index 4e7b764b4..82de72647 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -12,15 +12,15 @@ public final class CommonFunctions { public static final Key TITLE = Key.of("craftengine:title"); public static final Key OPEN_WINDOW = Key.of("craftengine:open_window"); public static final Key PARTICLE = Key.of("craftengine:particle"); - public static final Key SOUND = Key.of("craftengine:sound"); + public static final Key PLAY_SOUND = Key.of("craftengine:play_sound"); public static final Key POTION_EFFECT = Key.of("craftengine:potion_effect"); public static final Key BREAK_BLOCK = Key.of("craftengine:break_block"); public static final Key CANCEL_EVENT = Key.of("craftengine:cancel_event"); + public static final Key UPDATE_INTERACTION_TICK = Key.of("craftengine:update_interaction_tick"); + public static final Key SET_COUNT = Key.of("craftengine:set_count"); public static final Key PLACE_BLOCK = Key.of("craftengine:place_block"); - public static final Key FOOD = Key.of("craftengine:food"); - public static final Key SATURATION = Key.of("craftengine:saturation"); - public static final Key MONEY = Key.of("craftengine:money"); - public static final Key OXYGEN = Key.of("craftengine:oxygen"); - public static final Key MINE_RADIUS = Key.of("craftengine:mine_radius"); + public static final Key SET_FOOD = Key.of("craftengine:food"); + public static final Key SET_SATURATION = Key.of("craftengine:saturation"); public static final Key DROP_LOOT = Key.of("craftengine:drop_loot"); + public static final Key SWING_HAND = Key.of("craftengine:swing_hand"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DropLootFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DropLootFunction.java new file mode 100644 index 000000000..216c1c511 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DropLootFunction.java @@ -0,0 +1,68 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.LootTable; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class DropLootFunction extends AbstractConditionalFunction { + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final LootTable lootTable; + + public DropLootFunction(NumberProvider x, NumberProvider y, NumberProvider z, LootTable lootTable, List> predicates) { + super(predicates); + this.x = x; + this.y = y; + this.z = z; + this.lootTable = lootTable; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isPresent()) { + World world = optionalWorldPosition.get().world(); + WorldPosition position = new WorldPosition(world, x.getDouble(ctx), y.getDouble(ctx), z.getDouble(ctx)); + Player player = ctx.getOptionalParameter(DirectContextParameters.PLAYER).orElse(null); + List> items = lootTable.getRandomItems(ctx.contexts(), world, player); + for (Item item : items) { + world.dropItemNaturally(position, item); + } + } + } + + @Override + public Key type() { + return CommonFunctions.DROP_LOOT; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); + NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); + NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); + LootTable loots = LootTable.fromMap(MiscUtils.castToMap(arguments.get("loot"), true)); + return new DropLootFunction<>(x, y, z, loots, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java index 2c0daf916..c5fbeae29 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java @@ -77,9 +77,9 @@ public class PlaceBlockFunction extends AbstractConditional public Function create(Map arguments) { String state = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("block-state"), "warning.config.function.place_block.missing_block_state"); DelayedInitBlockState delayedInitBlockState = new DelayedInitBlockState(state); - NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); - NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); - NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); + NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); + NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); + NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); NumberProvider flags = Optional.ofNullable(arguments.get("update-flags")).map(NumberProviders::fromObject).orElse(NumberProviders.direct(UpdateOption.UPDATE_ALL.flags())); return new PlaceBlockFunction<>(delayedInitBlockState, x, y, z, flags, getPredicates(arguments)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaySoundFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaySoundFunction.java new file mode 100644 index 000000000..ea5f4c547 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaySoundFunction.java @@ -0,0 +1,73 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.sound.SoundSource; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +public class PlaySoundFunction extends AbstractConditionalFunction { + private final Key soundEvent; + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final NumberProvider volume; + private final NumberProvider pitch; + private final SoundSource source; + + public PlaySoundFunction(Key soundEvent, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider volume, NumberProvider pitch, SoundSource source, List> predicates) { + super(predicates); + this.soundEvent = soundEvent; + this.x = x; + this.y = y; + this.z = z; + this.volume = volume; + this.pitch = pitch; + this.source = source; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isPresent()) { + World world = optionalWorldPosition.get().world(); + world.playSound(new Vec3d(this.x.getDouble(ctx), this.y.getDouble(ctx), this.z.getDouble(ctx)), + this.soundEvent, this.volume.getFloat(ctx), this.pitch.getFloat(ctx), this.source); + } + } + + @Override + public Key type() { + return CommonFunctions.PLAY_SOUND; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Key soundEvent = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("sound"), "warning.config.function.play_sound.missing_sound")); + NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); + NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); + NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); + NumberProvider volume = NumberProviders.fromObject(arguments.getOrDefault("volume", 1)); + NumberProvider pitch = NumberProviders.fromObject(arguments.getOrDefault("pitch", 1)); + SoundSource source = Optional.ofNullable(arguments.get("source")).map(String::valueOf).map(it -> SoundSource.valueOf(it.toUpperCase(Locale.ENGLISH))).orElse(SoundSource.MASTER); + return new PlaySoundFunction<>(soundEvent, x, y, z, volume, pitch, source, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetCountFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetCountFunction.java new file mode 100644 index 000000000..6d9e6b496 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetCountFunction.java @@ -0,0 +1,57 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class SetCountFunction extends AbstractConditionalFunction { + private final NumberProvider count; + private final boolean add; + + public SetCountFunction(NumberProvider count, boolean add, List> predicates) { + super(predicates); + this.count = count; + this.add = add; + } + + @Override + public void runInternal(CTX ctx) { + Optional> optionalItem = ctx.getOptionalParameter(DirectContextParameters.ITEM_IN_HAND); + if (optionalItem.isPresent()) { + Item item = optionalItem.get(); + if (this.add) { + item.count(Math.min(item.count() + (this.count.getInt(ctx)), item.maxStackSize())); + } else { + item.count(Math.min(this.count.getInt(ctx), item.maxStackSize())); + } + } + } + + @Override + public Key type() { + return CommonFunctions.SET_COUNT; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("count"), "warning.config.function.set_count.missing_count"); + boolean add = (boolean) arguments.getOrDefault("add", false); + return new SetCountFunction<>(NumberProviders.fromObject(value), add, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java new file mode 100644 index 000000000..fcd05f71a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java @@ -0,0 +1,50 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class SetFoodFunction extends AbstractConditionalFunction { + private final NumberProvider count; + private final boolean add; + + public SetFoodFunction(NumberProvider count, boolean add, List> predicates) { + super(predicates); + this.count = count; + this.add = add; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + optionalPlayer.ifPresent(player -> player.setFoodLevel(this.add ? player.foodLevel() + this.count.getInt(ctx) : this.count.getInt(ctx))); + } + + @Override + public Key type() { + return CommonFunctions.SET_FOOD; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("food"), "warning.config.function.set_food.missing_food"); + boolean add = (boolean) arguments.getOrDefault("add", false); + return new SetFoodFunction<>(NumberProviders.fromObject(value), add, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java new file mode 100644 index 000000000..86634543f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java @@ -0,0 +1,50 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class SetSaturationFunction extends AbstractConditionalFunction { + private final NumberProvider count; + private final boolean add; + + public SetSaturationFunction(NumberProvider count, boolean add, List> predicates) { + super(predicates); + this.count = count; + this.add = add; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + optionalPlayer.ifPresent(player -> player.setSaturation(this.add ? player.saturation() + this.count.getFloat(ctx) : this.count.getFloat(ctx))); + } + + @Override + public Key type() { + return CommonFunctions.SET_SATURATION; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("saturation"), "warning.config.function.set_saturation.missing_saturation"); + boolean add = (boolean) arguments.getOrDefault("add", false); + return new SetSaturationFunction<>(NumberProviders.fromObject(value), add, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SwingHandFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SwingHandFunction.java new file mode 100644 index 000000000..935fa210e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SwingHandFunction.java @@ -0,0 +1,52 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +public class SwingHandFunction extends AbstractConditionalFunction { + private final Optional hand; + + public SwingHandFunction(Optional hand, List> predicates) { + super(predicates); + this.hand = hand; + } + + @Override + public void runInternal(CTX ctx) { + Optional cancellable = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + cancellable.ifPresent(value -> { + if (this.hand.isPresent()) { + value.swingHand(this.hand.get()); + } else { + value.swingHand(ctx.getOptionalParameter(DirectContextParameters.HAND).orElse(InteractionHand.MAIN_HAND)); + } + }); + } + + @Override + public Key type() { + return CommonFunctions.SWING_HAND; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Optional optionalHand = Optional.ofNullable(arguments.get("hand")).map(it -> InteractionHand.valueOf(it.toString().toUpperCase(Locale.ENGLISH))); + return new SwingHandFunction<>(optionalHand, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateInteractionFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateInteractionFunction.java new file mode 100644 index 000000000..6ef587ad5 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateInteractionFunction.java @@ -0,0 +1,41 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class UpdateInteractionFunction extends AbstractConditionalFunction { + + public UpdateInteractionFunction(List> predicates) { + super(predicates); + } + + @Override + public void runInternal(CTX ctx) { + Optional cancellable = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + cancellable.ifPresent(value -> value.updateLastSuccessfulInteractionTick(value.gameTicks())); + } + + @Override + public Key type() { + return CommonFunctions.UPDATE_INTERACTION_TICK; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + return new UpdateInteractionFunction<>(getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java index 798c8e53d..495739c3b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java @@ -39,9 +39,13 @@ public final class DirectContextParameters { public static final ContextKey X = ContextKey.direct("x"); public static final ContextKey Y = ContextKey.direct("y"); public static final ContextKey Z = ContextKey.direct("z"); + public static final ContextKey YAW = ContextKey.direct("yaw"); + public static final ContextKey PITCH = ContextKey.direct("pitch"); public static final ContextKey BLOCK_X = ContextKey.direct("block_x"); public static final ContextKey BLOCK_Y = ContextKey.direct("block_y"); public static final ContextKey BLOCK_Z = ContextKey.direct("block_z"); + public static final ContextKey FOOD = ContextKey.direct("food"); + public static final ContextKey SATURATION = ContextKey.direct("saturation"); public static final ContextKey UUID = ContextKey.direct("uuid"); public static final ContextKey> MAIN_HAND_ITEM = ContextKey.direct("main_hand_item"); public static final ContextKey> OFF_HAND_ITEM = ContextKey.direct("off_hand_item"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java index b36225670..465b49809 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java @@ -16,6 +16,8 @@ public class EntityParameterProvider implements ChainParameterProvider { CONTEXT_FUNCTIONS.put(DirectContextParameters.X, Entity::x); CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, Entity::y); CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, Entity::z); + CONTEXT_FUNCTIONS.put(DirectContextParameters.YAW, Entity::xRot); + CONTEXT_FUNCTIONS.put(DirectContextParameters.PITCH, Entity::yRot); CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, Entity::position); CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x())); CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java index 4075c6ff8..042b08c05 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.core.plugin.context.parameter; -import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.entity.Entity; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; @@ -16,13 +15,17 @@ import java.util.function.Function; public class PlayerParameterProvider implements ChainParameterProvider { private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); static { - CONTEXT_FUNCTIONS.put(DirectContextParameters.X, AbstractEntity::x); - CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, AbstractEntity::y); - CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, AbstractEntity::z); - CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, AbstractEntity::position); + CONTEXT_FUNCTIONS.put(DirectContextParameters.X, Entity::x); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, Entity::y); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, Entity::z); + CONTEXT_FUNCTIONS.put(DirectContextParameters.YAW, Entity::xRot); + CONTEXT_FUNCTIONS.put(DirectContextParameters.PITCH, Entity::yRot); + CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, Entity::position); CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x())); CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.FOOD, Player::foodLevel); + CONTEXT_FUNCTIONS.put(DirectContextParameters.SATURATION, Player::saturation); CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, Player::name); CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, Player::uuid); CONTEXT_FUNCTIONS.put(DirectContextParameters.WORLD, Entity::world); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java index 710917c19..b7e2b26b6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java @@ -18,6 +18,8 @@ public class PositionParameterProvider implements ChainParameterProvider MCUtils.fastFloor(p.x())); CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundSource.java b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundSource.java new file mode 100644 index 000000000..e48a6c429 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundSource.java @@ -0,0 +1,27 @@ +package net.momirealms.craftengine.core.sound; + +import org.jetbrains.annotations.NotNull; + +public enum SoundSource { + MASTER("master"), + MUSIC("music"), + RECORD("record"), + WEATHER("weather"), + BLOCK("block"), + HOSTILE("hostile"), + NEUTRAL("neutral"), + PLAYER("player"), + AMBIENT("ambient"), + VOICE("voice"); + + private final String id; + + SoundSource(final String id) { + this.id = id; + } + + @NotNull + public String id() { + return this.id; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java b/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java index 87cd8df73..a48bfdc14 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java @@ -94,8 +94,8 @@ public enum Direction { } public static Direction[] orderedByNearest(AbstractEntity entity) { - float xRotation = entity.getXRot() * (float) (Math.PI / 180.0); - float yRotation = -entity.getYRot() * (float) (Math.PI / 180.0); + float xRotation = entity.xRot() * (float) (Math.PI / 180.0); + float yRotation = -entity.yRot() * (float) (Math.PI / 180.0); float sinX = (float) Math.sin(xRotation); float cosX = (float) Math.cos(xRotation); float sinY = (float) Math.sin(yRotation); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index c48a66415..08efec880 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -1,8 +1,10 @@ package net.momirealms.craftengine.core.world; +import net.kyori.adventure.sound.Sound; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.sound.SoundData; +import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import java.nio.file.Path; @@ -34,6 +36,8 @@ public interface World { void dropExp(Position location, int amount); + void playSound(Position location, Key sound, float volume, float pitch, SoundSource source); + void playBlockSound(Position location, Key sound, float volume, float pitch); default void playBlockSound(Position location, SoundData data) { From 29c32054f06b2892c3ca7b5a1c3642522c183acd Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 22 May 2025 16:02:58 +0800 Subject: [PATCH 25/89] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/build.gradle.kts | 1 - .../core/plugin/dependency/Dependencies.java | 69 ------------------- .../core/plugin/dependency/Dependency.java | 18 +++-- .../dependency/DependencyManagerImpl.java | 40 ++++++++++- .../dependency/DependencyRepository.java | 1 + .../craftengine/core/util/FileUtils.java | 15 ++++ .../craftengine/core/world/World.java | 1 - gradle.properties | 3 +- 8 files changed, 62 insertions(+), 86 deletions(-) diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 0b9d4ae93..75e8293ea 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -46,7 +46,6 @@ dependencies { compileOnly("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}") // Adventure compileOnly("net.kyori:adventure-api:${rootProject.properties["adventure_bundle_version"]}") - compileOnly("net.kyori:adventure-platform-bukkit:${rootProject.properties["adventure_platform_version"]}") compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}") compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}") { exclude("com.google.code.gson", "gson") 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 c5c54940d..3342d05b1 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 @@ -11,7 +11,6 @@ public class Dependencies { "asm", "org.ow2.asm", "asm", - "asm", Collections.emptyList() ); @@ -19,7 +18,6 @@ public class Dependencies { "asm-commons", "org.ow2.asm", "asm-commons", - "asm-commons", Collections.emptyList() ); @@ -27,7 +25,6 @@ public class Dependencies { "jar-relocator", "me.lucko", "jar-relocator", - "jar-relocator", Collections.emptyList() ); @@ -35,7 +32,6 @@ public class Dependencies { "geantyref", "io{}leangen{}geantyref", "geantyref", - "geantyref", List.of(Relocation.of("geantyref", "io{}leangen{}geantyref")) ); @@ -43,7 +39,6 @@ public class Dependencies { "cloud-core", "org{}incendo", "cloud-core", - "cloud-core", List.of(Relocation.of("cloud", "org{}incendo{}cloud"), Relocation.of("geantyref", "io{}leangen{}geantyref")) ); @@ -52,7 +47,6 @@ public class Dependencies { "cloud-brigadier", "org{}incendo", "cloud-brigadier", - "cloud-brigadier", List.of(Relocation.of("cloud", "org{}incendo{}cloud"), Relocation.of("geantyref", "io{}leangen{}geantyref")) ); @@ -61,7 +55,6 @@ public class Dependencies { "cloud-services", "org{}incendo", "cloud-services", - "cloud-services", List.of(Relocation.of("cloud", "org{}incendo{}cloud"), Relocation.of("geantyref", "io{}leangen{}geantyref")) ); @@ -70,7 +63,6 @@ public class Dependencies { "cloud-bukkit", "org{}incendo", "cloud-bukkit", - "cloud-bukkit", List.of(Relocation.of("cloud", "org{}incendo{}cloud"), Relocation.of("geantyref", "io{}leangen{}geantyref"), Relocation.of("adventure", "net{}kyori{}adventure"), @@ -82,7 +74,6 @@ public class Dependencies { "cloud-paper", "org{}incendo", "cloud-paper", - "cloud-paper", List.of(Relocation.of("cloud", "org{}incendo{}cloud"), Relocation.of("geantyref", "io{}leangen{}geantyref"), Relocation.of("adventure", "net{}kyori{}adventure"), @@ -94,7 +85,6 @@ public class Dependencies { "cloud-minecraft-extras", "org{}incendo", "cloud-minecraft-extras", - "cloud-minecraft-extras", List.of(Relocation.of("cloud", "org{}incendo{}cloud"), Relocation.of("geantyref", "io{}leangen{}geantyref"), Relocation.of("adventure", "net{}kyori{}adventure"), @@ -106,7 +96,6 @@ public class Dependencies { "boosted-yaml", "dev{}dejvokep", "boosted-yaml", - "boosted-yaml", List.of(Relocation.of("boostedyaml", "dev{}dejvokep{}boostedyaml")) ); @@ -114,7 +103,6 @@ public class Dependencies { "bstats-base", "org{}bstats", "bstats-base", - "bstats-base", List.of(Relocation.of("bstats", "org{}bstats")) ); @@ -122,7 +110,6 @@ public class Dependencies { "bstats-bukkit", "org{}bstats", "bstats-bukkit", - "bstats-bukkit", List.of(Relocation.of("bstats", "org{}bstats")) ) { @Override @@ -135,7 +122,6 @@ public class Dependencies { "gson", "com.google.code.gson", "gson", - "gson", Collections.emptyList() ); @@ -143,7 +129,6 @@ public class Dependencies { "caffeine", "com{}github{}ben-manes{}caffeine", "caffeine", - "caffeine", List.of(Relocation.of("caffeine", "com{}github{}benmanes{}caffeine")) ); @@ -151,7 +136,6 @@ public class Dependencies { "zstd-jni", "com.github.luben", "zstd-jni", - "zstd-jni", Collections.emptyList() ); @@ -159,7 +143,6 @@ public class Dependencies { "slf4j-api", "org.slf4j", "slf4j-api", - "slf4j-api", Collections.emptyList() ); @@ -167,7 +150,6 @@ public class Dependencies { "slf4j-simple", "org.slf4j", "slf4j-simple", - "slf4j-simple", Collections.emptyList() ) { @Override @@ -180,7 +162,6 @@ public class Dependencies { "commons-io", "commons-io", "commons-io", - "commons-io", List.of(Relocation.of("commons", "org{}apache{}commons")) ); @@ -188,7 +169,6 @@ public class Dependencies { "byte-buddy", "net{}bytebuddy", "byte-buddy", - "byte-buddy", List.of(Relocation.of("bytebuddy", "net{}bytebuddy")) ); @@ -196,7 +176,6 @@ public class Dependencies { "snake-yaml", "org{}yaml", "snakeyaml", - "snakeyaml", List.of(Relocation.of("snakeyaml", "org{}yaml{}snakeyaml")) ); @@ -204,7 +183,6 @@ public class Dependencies { "option", "net{}kyori", "option", - "option", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -214,7 +192,6 @@ public class Dependencies { "adventure-api", "net{}kyori", "adventure-api", - "adventure-api", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -224,7 +201,6 @@ public class Dependencies { "adventure-key", "net{}kyori", "adventure-key", - "adventure-key", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -239,7 +215,6 @@ public class Dependencies { "examination-api", "net{}kyori", "examination-api", - "examination-api", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -249,7 +224,6 @@ public class Dependencies { "examination-string", "net{}kyori", "examination-string", - "examination-string", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -264,7 +238,6 @@ public class Dependencies { "adventure-text-minimessage", "net{}kyori", "adventure-text-minimessage", - "adventure-text-minimessage", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -279,7 +252,6 @@ public class Dependencies { "adventure-text-serializer-commons", "net{}kyori", "adventure-text-serializer-commons", - "adventure-text-serializer-commons", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -294,7 +266,6 @@ public class Dependencies { "adventure-text-serializer-gson", "net{}kyori", "adventure-text-serializer-gson", - "adventure-text-serializer-gson", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -309,7 +280,6 @@ public class Dependencies { "adventure-text-serializer-json-legacy-impl", "net{}kyori", "adventure-text-serializer-json-legacy-impl", - "adventure-text-serializer-json-legacy-impl", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -324,7 +294,6 @@ public class Dependencies { "adventure-text-serializer-legacy", "net{}kyori", "adventure-text-serializer-legacy", - "adventure-text-serializer-legacy", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -339,7 +308,6 @@ public class Dependencies { "adventure-text-serializer-json", "net{}kyori", "adventure-text-serializer-json", - "adventure-text-serializer-json", List.of(Relocation.of("option", "net{}kyori{}option"), Relocation.of("examination", "net{}kyori{}examination"), Relocation.of("adventure", "net{}kyori{}adventure")) @@ -354,7 +322,6 @@ public class Dependencies { "ahocorasick", "org{}ahocorasick", "ahocorasick", - "aho-corasick", List.of(Relocation.of("ahocorasick", "org{}ahocorasick")) ); @@ -362,7 +329,6 @@ public class Dependencies { "lz4", "org{}lz4", "lz4-java", - "lz4-java", List.of(Relocation.of("jpountz", "net{}jpountz")) ); @@ -370,7 +336,6 @@ public class Dependencies { "evalex", "com{}ezylang", "EvalEx", - "evalex", List.of(Relocation.of("evalex", "com{}ezylang{}evalex")) ); @@ -378,7 +343,6 @@ public class Dependencies { "netty-codec-http", "io{}netty", "netty-codec-http", - "netty-codec-http", Collections.emptyList() ); @@ -386,7 +350,6 @@ public class Dependencies { "netty-codec-http2", "io{}netty", "netty-codec-http2", - "netty-codec-http2", Collections.emptyList() ); @@ -394,7 +357,6 @@ public class Dependencies { "reactive-streams", "org{}reactivestreams", "reactive-streams", - "reactive-streams", List.of(Relocation.of("reactivestreams", "org{}reactivestreams")) ); @@ -402,7 +364,6 @@ public class Dependencies { "jimfs", "com{}google{}jimfs", "jimfs", - "jimfs", List.of(Relocation.of("jimfs", "com{}google{}common{}jimfs")) ); @@ -410,7 +371,6 @@ public class Dependencies { "commons-imaging", "org{}apache{}commons", "commons-imaging", - "commons-imaging", List.of(Relocation.of("imaging", "org{}apache{}commons{}imaging")) ); @@ -418,7 +378,6 @@ public class Dependencies { "amazon-sdk-s3", "software{}amazon{}awssdk", "s3", - "amazon-s3", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -429,7 +388,6 @@ public class Dependencies { "amazon-sdk-netty-nio-client", "software{}amazon{}awssdk", "netty-nio-client", - "amazon-netty-nio-client", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -445,7 +403,6 @@ public class Dependencies { "amazon-sdk-core", "software{}amazon{}awssdk", "sdk-core", - "amazon-sdk-core", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -461,7 +418,6 @@ public class Dependencies { "amazon-sdk-auth", "software{}amazon{}awssdk", "auth", - "amazon-auth", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -477,7 +433,6 @@ public class Dependencies { "amazon-sdk-regions", "software{}amazon{}awssdk", "regions", - "amazon-regions", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -493,7 +448,6 @@ public class Dependencies { "amazon-sdk-identity-spi", "software{}amazon{}awssdk", "identity-spi", - "amazon-identity-spi", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -509,7 +463,6 @@ public class Dependencies { "amazon-sdk-http-client-spi", "software{}amazon{}awssdk", "http-client-spi", - "amazon-http-client-spi", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -525,7 +478,6 @@ public class Dependencies { "amazon-sdk-protocol-core", "software{}amazon{}awssdk", "protocol-core", - "amazon-protocol-core", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -541,7 +493,6 @@ public class Dependencies { "amazon-sdk-aws-xml-protocol", "software{}amazon{}awssdk", "aws-xml-protocol", - "amazon-aws-xml-protocol", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -557,7 +508,6 @@ public class Dependencies { "amazon-sdk-json-utils", "software{}amazon{}awssdk", "json-utils", - "amazon-json-utils", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -573,7 +523,6 @@ public class Dependencies { "amazon-sdk-aws-core", "software{}amazon{}awssdk", "aws-core", - "amazon-aws-core", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -589,7 +538,6 @@ public class Dependencies { "amazon-sdk-utils", "software{}amazon{}awssdk", "utils", - "amazon-utils", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -605,7 +553,6 @@ public class Dependencies { "amazon-sdk-annotations", "software{}amazon{}awssdk", "annotations", - "amazon-annotations", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -621,7 +568,6 @@ public class Dependencies { "amazon-sdk-crt-core", "software{}amazon{}awssdk", "crt-core", - "amazon-crt-core", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -637,7 +583,6 @@ public class Dependencies { "amazon-sdk-checksums", "software{}amazon{}awssdk", "checksums", - "amazon-checksums", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -653,7 +598,6 @@ public class Dependencies { "amazon-sdk-eventstream", "software{}amazon{}eventstream", "eventstream", - "amazon-eventstream", List.of( Relocation.of("eventstream", "software{}amazon{}eventstream"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -664,7 +608,6 @@ public class Dependencies { "amazon-sdk-profiles", "software{}amazon{}awssdk", "profiles", - "amazon-profiles", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -680,7 +623,6 @@ public class Dependencies { "amazon-sdk-retries", "software{}amazon{}awssdk", "retries", - "amazon-retries", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -696,7 +638,6 @@ public class Dependencies { "amazon-sdk-endpoints-spi", "software{}amazon{}awssdk", "endpoints-spi", - "amazon-endpoints-spi", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -712,7 +653,6 @@ public class Dependencies { "amazon-sdk-arns", "software{}amazon{}awssdk", "arns", - "amazon-arns", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -728,7 +668,6 @@ public class Dependencies { "amazon-sdk-aws-query-protocol", "software{}amazon{}awssdk", "aws-query-protocol", - "amazon-aws-query-protocol", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -744,7 +683,6 @@ public class Dependencies { "amazon-sdk-http-auth-aws", "software{}amazon{}awssdk", "http-auth-aws", - "amazon-http-auth-aws", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -760,7 +698,6 @@ public class Dependencies { "amazon-sdk-http-auth-spi", "software{}amazon{}awssdk", "http-auth-spi", - "amazon-http-auth-spi", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -776,7 +713,6 @@ public class Dependencies { "amazon-sdk-http-auth", "software{}amazon{}awssdk", "http-auth", - "amazon-http-auth", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -792,7 +728,6 @@ public class Dependencies { "amazon-sdk-http-auth-aws-eventstream", "software{}amazon{}awssdk", "http-auth-aws-eventstream", - "amazon-http-auth-aws-eventstream", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -808,7 +743,6 @@ public class Dependencies { "amazon-sdk-checksums-spi", "software{}amazon{}awssdk", "checksums-spi", - "amazon-checksums-spi", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -824,7 +758,6 @@ public class Dependencies { "amazon-sdk-retries-spi", "software{}amazon{}awssdk", "retries-spi", - "amazon-retries-spi", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -840,7 +773,6 @@ public class Dependencies { "amazon-sdk-metrics-spi", "software{}amazon{}awssdk", "metrics-spi", - "amazon-metrics-spi", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") @@ -856,7 +788,6 @@ public class Dependencies { "amazon-sdk-third-party-jackson-core", "software{}amazon{}awssdk", "third-party-jackson-core", - "amazon-third-party-jackson-core", List.of( Relocation.of("awssdk", "software{}amazon{}awssdk"), Relocation.of("reactivestreams", "org{}reactivestreams") 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 6a6c7e4b4..6dd449cb9 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 @@ -11,14 +11,12 @@ public class Dependency { private final String id; private final String groupId; private final String rawArtifactId; - private final String customArtifactID; private final List relocations; - public Dependency(String id, String groupId, String rawArtifactId, String customArtifactID, List relocations) { + public Dependency(String id, String groupId, String artifactId, List relocations) { this.id = id; this.groupId = groupId; - this.rawArtifactId = rawArtifactId; - this.customArtifactID = customArtifactID; + this.rawArtifactId = artifactId; this.relocations = relocations; } @@ -34,14 +32,14 @@ public class Dependency { return rawArtifactId; } - public String customArtifactID() { - return customArtifactID; - } - public List relocations() { return relocations; } + public String toLocalPath() { + return rewriteEscaping(groupId).replace(".", "/") + "/" + this.rawArtifactId + "/" + getVersion(); + } + private static final String MAVEN_FORMAT = "%s/%s/%s/%s-%s.jar"; public String mavenPath() { @@ -55,7 +53,7 @@ public class Dependency { } public String fileName(String classifier) { - String name = customArtifactID.toLowerCase(Locale.ENGLISH).replace('_', '-'); + String name = this.rawArtifactId.toLowerCase(Locale.ENGLISH).replace('_', '-'); String extra = classifier == null || classifier.isEmpty() ? "" : "-" + classifier; @@ -66,7 +64,7 @@ public class Dependency { return PluginProperties.getValue(id); } - private static String rewriteEscaping(String s) { + public static String rewriteEscaping(String s) { return s.replace("{}", "."); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/DependencyManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/DependencyManagerImpl.java index 0f3f15376..a6ecf30a3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/DependencyManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/DependencyManagerImpl.java @@ -5,16 +5,19 @@ import net.momirealms.craftengine.core.plugin.classpath.ClassPathAppender; import net.momirealms.craftengine.core.plugin.dependency.classloader.IsolatedClassLoader; import net.momirealms.craftengine.core.plugin.dependency.relocation.Relocation; import net.momirealms.craftengine.core.plugin.dependency.relocation.RelocationHandler; +import net.momirealms.craftengine.core.util.FileUtils; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.DirectoryStream; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.stream.Stream; public class DependencyManagerImpl implements DependencyManager { private final DependencyRegistry registry; @@ -112,18 +115,38 @@ public class DependencyManagerImpl implements DependencyManager { private Path downloadDependency(Dependency dependency) throws DependencyDownloadException { String fileName = dependency.fileName(null); - Path file = this.cacheDirectory.resolve(fileName); + Path file = this.cacheDirectory.resolve(dependency.toLocalPath()).resolve(fileName); // if the file already exists, don't attempt to re-download it. if (Files.exists(file)) { return file; } + // before downloading a newer version, delete those outdated files + Path versionFolder = file.getParent().getParent(); + if (Files.exists(versionFolder) && Files.isDirectory(versionFolder)) { + String version = dependency.getVersion(); + try (Stream dirStream = Files.list(versionFolder)) { + dirStream.filter(Files::isDirectory) + .filter(it -> !it.getFileName().toString().equals(version)) + .forEach(dir -> { + try { + FileUtils.deleteDirectory(dir); + plugin.logger().info("Cleaned up outdated dependency " + dir); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } catch (IOException e) { + throw new RuntimeException("Failed to clean " + versionFolder, e); + } + } + DependencyDownloadException lastError = null; List repository = DependencyRepository.getByID("maven"); if (!repository.isEmpty()) { int i = 0; while (i < repository.size()) { try { - plugin.logger().info("Downloading dependency(" + fileName + ")[" + repository.get(i).getUrl() + dependency.mavenPath() + "]"); + plugin.logger().info("Downloading dependency " + repository.get(i).getUrl() + dependency.mavenPath()); repository.get(i).download(dependency, file); plugin.logger().info("Successfully downloaded " + fileName); return file; @@ -142,7 +165,7 @@ public class DependencyManagerImpl implements DependencyManager { return normalFile; } - Path remappedFile = this.cacheDirectory.resolve(dependency.fileName(DependencyRegistry.isGsonRelocated() ? "remapped-legacy" : "remapped")); + Path remappedFile = this.cacheDirectory.resolve(dependency.toLocalPath()).resolve(dependency.fileName(DependencyRegistry.isGsonRelocated() ? "remapped-legacy" : "remapped")); // if the remapped source exists already, just use that. if (Files.exists(remappedFile)) { @@ -159,6 +182,7 @@ public class DependencyManagerImpl implements DependencyManager { Path cacheDirectory = plugin.dataFolderPath().resolve("libs"); try { if (Files.exists(cacheDirectory) && (Files.isDirectory(cacheDirectory) || Files.isSymbolicLink(cacheDirectory))) { + cleanDirectoryJars(cacheDirectory); return cacheDirectory; } @@ -174,6 +198,16 @@ public class DependencyManagerImpl implements DependencyManager { return cacheDirectory; } + private static void cleanDirectoryJars(Path directory) throws IOException { + try (DirectoryStream stream = Files.newDirectoryStream(directory)) { + for (Path file : stream) { + if (Files.isRegularFile(file) && file.getFileName().toString().endsWith(".jar")) { + Files.delete(file); + } + } + } + } + @Override public void close() { IOException firstEx = null; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/DependencyRepository.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/DependencyRepository.java index b7f4c0d66..8fe0fa762 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/DependencyRepository.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/dependency/DependencyRepository.java @@ -82,6 +82,7 @@ public enum DependencyRepository { public void download(Dependency dependency, Path file) throws DependencyDownloadException { try { + Files.createDirectories(file.getParent()); Files.write(file, download(dependency)); } catch (IOException e) { throw new DependencyDownloadException(e); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java index 0de7bd17f..ac23e93a2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.util; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Comparator; import java.util.List; import java.util.stream.Stream; @@ -19,6 +20,20 @@ public class FileUtils { Files.createDirectories(Files.exists(path) ? path.toRealPath() : path); } + public static void deleteDirectory(Path folder) throws IOException { + if (!Files.exists(folder)) return; + try (Stream walk = Files.walk(folder)) { + walk.sorted(Comparator.reverseOrder()) + .forEach(path -> { + try { + Files.delete(path); + } catch (IOException ioException) { + throw new RuntimeException(ioException); + } + }); + } + } + public static List getYmlConfigsDeeply(Path configFolder) { if (!Files.exists(configFolder)) { return List.of(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index 08efec880..0dacaa8e4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.core.world; -import net.kyori.adventure.sound.Sound; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.sound.SoundData; diff --git a/gradle.properties b/gradle.properties index 2ee29d431..a3b6ef8c4 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.54.3 +project_version=0.0.54.5 config_version=33 lang_version=13 project_group=net.momirealms @@ -21,7 +21,6 @@ asm_version=9.8 asm_commons_version=9.8 jar_relocator_version=1.7 adventure_bundle_version=4.21.0 -adventure_platform_version=4.4.0 cloud_core_version=2.0.0 cloud_services_version=2.0.0 cloud_brigadier_version=2.0.0-beta.10 From 99a161a308475da309dc480f705623de7a1916e7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 22 May 2025 18:33:32 +0800 Subject: [PATCH 26/89] =?UTF-8?q?=E6=9B=B4=E6=96=B0API=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compatibility/BukkitCompatibilityManager.java | 11 ++++++----- .../bukkit/api/CraftEngineFurniture.java | 14 +++++++------- .../bukkit/api/event/FurnitureBreakEvent.java | 2 +- .../bukkit/api/event/FurnitureInteractEvent.java | 2 +- .../bukkit/api/event/FurniturePlaceEvent.java | 2 +- .../entity/furniture/AbstractFurnitureManager.java | 2 +- .../craftengine/core/plugin/CraftEngine.java | 2 +- .../core/plugin/dependency/Dependencies.java | 14 ++++++++++++++ gradle.properties | 2 +- 9 files changed, 33 insertions(+), 18 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java index c4888be8c..a4a72da12 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java @@ -67,11 +67,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager { // } // } } - } - - @Override - public void onDelayedEnable() { - this.initItemHooks(); // WorldEdit if (this.isPluginEnabled("FastAsyncWorldEdit")) { this.initFastAsyncWorldEditHook(); @@ -80,6 +75,12 @@ public class BukkitCompatibilityManager implements CompatibilityManager { this.initWorldEditHook(); logHook("WorldEdit"); } + } + + @Override + public void onDelayedEnable() { + this.initItemHooks(); + if (this.isPluginEnabled("LuckPerms")) { this.initLuckPermsHook(); logHook("LuckPerms"); 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 62d1ef3f5..e899291a4 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 @@ -49,7 +49,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @Nullable - public static Furniture place(Location location, Key furnitureId) { + public static BukkitFurniture place(Location location, Key furnitureId) { CustomFurniture furniture = byId(furnitureId); if (furniture == null) return null; return place(location, furnitureId, furniture.getAnyPlacement()); @@ -64,7 +64,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @Nullable - public static Furniture place(Location location, Key furnitureId, AnchorType anchorType) { + public static BukkitFurniture place(Location location, Key furnitureId, AnchorType anchorType) { CustomFurniture furniture = byId(furnitureId); if (furniture == null) return null; return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), true); @@ -79,7 +79,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @NotNull - public static Furniture place(Location location, CustomFurniture furniture, AnchorType anchorType) { + public static BukkitFurniture place(Location location, CustomFurniture furniture, AnchorType anchorType) { return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), true); } @@ -93,7 +93,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @Nullable - public static Furniture place(Location location, Key furnitureId, AnchorType anchorType, boolean playSound) { + public static BukkitFurniture place(Location location, Key furnitureId, AnchorType anchorType, boolean playSound) { CustomFurniture furniture = byId(furnitureId); if (furniture == null) return null; return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), playSound); @@ -109,7 +109,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @NotNull - public static Furniture place(Location location, CustomFurniture furniture, AnchorType anchorType, boolean playSound) { + public static BukkitFurniture place(Location location, CustomFurniture furniture, AnchorType anchorType, boolean playSound) { return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), playSound); } @@ -153,7 +153,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @Nullable - public static Furniture getLoadedFurnitureByBaseEntity(@NotNull Entity baseEntity) { + public static BukkitFurniture getLoadedFurnitureByBaseEntity(@NotNull Entity baseEntity) { return BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(baseEntity.getEntityId()); } @@ -164,7 +164,7 @@ public final class CraftEngineFurniture { * @return the loaded furniture */ @Nullable - public static Furniture getLoadedFurnitureBySeat(@NotNull Entity seat) { + public static BukkitFurniture 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().loadedFurnitureByRealEntityId(baseEntityId); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java index 204a8d8c1..db42cb252 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java @@ -26,7 +26,7 @@ public class FurnitureBreakEvent extends PlayerEvent implements Cancellable { } @NotNull - public Furniture furniture() { + public BukkitFurniture furniture() { return this.furniture; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java index 3600e70fd..b89bb7ba3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java @@ -43,7 +43,7 @@ public class FurnitureInteractEvent extends PlayerEvent implements Cancellable { } @NotNull - public Furniture furniture() { + public BukkitFurniture furniture() { return this.furniture; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java index 35862abb1..e6f1405c1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java @@ -33,7 +33,7 @@ public class FurniturePlaceEvent extends PlayerEvent implements Cancellable { } @NotNull - public Furniture furniture() { + public BukkitFurniture furniture() { return this.furniture; } 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 index bb5c88cf0..5e28da9ac 100644 --- 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 @@ -126,7 +126,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { // add hitboxes List hitboxes = ResourceConfigUtils.parseConfigAsList(placementArguments.get("hitboxes"), HitBoxTypes::fromMap); if (hitboxes.isEmpty() && externalModel.isEmpty()) { - hitboxes.add(defaultHitBox()); + hitboxes = List.of(defaultHitBox()); } // rules 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 d42fea25e..df20daeff 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 @@ -308,7 +308,7 @@ public abstract class CraftEngine implements Plugin { Dependencies.BOOSTED_YAML, Dependencies.OPTION, Dependencies.EXAMINATION_API, Dependencies.EXAMINATION_STRING, - Dependencies.ADVENTURE_KEY, Dependencies.ADVENTURE_API, + Dependencies.ADVENTURE_KEY, Dependencies.ADVENTURE_API, Dependencies.ADVENTURE_NBT, Dependencies.MINIMESSAGE, Dependencies.TEXT_SERIALIZER_COMMONS, Dependencies.TEXT_SERIALIZER_LEGACY, Dependencies.TEXT_SERIALIZER_GSON, Dependencies.TEXT_SERIALIZER_GSON_LEGACY, 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 3342d05b1..8102e8e61 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 @@ -197,6 +197,20 @@ public class Dependencies { Relocation.of("adventure", "net{}kyori{}adventure")) ); + public static final Dependency ADVENTURE_NBT = new Dependency( + "adventure-nbt", + "net{}kyori", + "adventure-nbt", + List.of(Relocation.of("option", "net{}kyori{}option"), + Relocation.of("examination", "net{}kyori{}examination"), + Relocation.of("adventure", "net{}kyori{}adventure")) + ) { + @Override + public String getVersion() { + return ADVENTURE_API.getVersion(); + } + }; + public static final Dependency ADVENTURE_KEY = new Dependency( "adventure-key", "net{}kyori", diff --git a/gradle.properties b/gradle.properties index a3b6ef8c4..c17776f19 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.54.5 +project_version=0.0.54.6 config_version=33 lang_version=13 project_group=net.momirealms From f1588e349b0346514cddde64b5617b17e81c7ec9 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 22 May 2025 23:17:51 +0800 Subject: [PATCH 27/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0particle=E5=87=BD?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/plants.yml | 44 ++++++ .../src/main/resources/translations/en.yml | 6 + .../src/main/resources/translations/zh_cn.yml | 6 + .../item/listener/ItemEventListener.java | 2 +- .../craftengine/bukkit/util/ColorUtils.java | 11 ++ .../bukkit/util/ParticleUtils.java | 18 ++- .../craftengine/bukkit/world/BukkitWorld.java | 18 ++- .../core/block/DelayedInitBlockState.java | 22 +++ .../core/item/DelayedInitItem.java | 23 +++ .../pack/host/impl/SelfHostHttpServer.java | 3 + .../AbstractChainParameterContext.java | 1 - .../plugin/context/event/EventFunctions.java | 1 + .../context/function/CommonFunctions.java | 1 + .../context/function/ParticleFunction.java | 135 ++++++++++++++++++ .../context/function/PlaceBlockFunction.java | 20 +-- .../parameter/DirectContextParameters.java | 1 - .../craftengine/core/util/Color.java | 48 +++++++ .../craftengine/core/world/World.java | 6 + .../core/world/particle/BlockStateData.java | 16 +++ .../core/world/particle/ColorData.java | 15 ++ .../core/world/particle/DustData.java | 21 +++ .../world/particle/DustTransitionData.java | 27 ++++ .../core/world/particle/ItemStackData.java | 16 +++ .../core/world/particle/JavaTypeData.java | 13 ++ .../core/world/particle/ParticleData.java | 4 + .../core/world/particle/ParticleTypes.java | 22 +++ .../core/world/particle/TrailData.java | 40 ++++++ .../core/world/particle/VibrationData.java | 33 +++++ 28 files changed, 547 insertions(+), 26 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ColorUtils.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/DelayedInitBlockState.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/DelayedInitItem.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/Color.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/particle/ColorData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/particle/DustData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/particle/DustTransitionData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/particle/JavaTypeData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleTypes.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/particle/TrailData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/particle/VibrationData.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 1b26e33b2..3fde1cb5a 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -203,6 +203,50 @@ blocks: crop_item: minecraft:ender_pearl crop_seed: default:ender_pearl_flower_seeds ripe_age: 2 + events: + - on: break + conditions: + - type: match_block_property + properties: + age: 2 + functions: + - type: particle + x: " + 0.5" + y: " + 0.5" + z: " + 0.5" + particle: "minecraft:end_rod" + count: 15 + offset-x: 0.4 + offset-y: 0.4 + offset-z: 0.4 + - type: play_sound + sound: minecraft:entity.enderman.teleport + x: " + 0.5" + y: " + 0.5" + z: " + 0.5" + - on: right_click + conditions: + - type: match_block_property + properties: + age: 2 + - type: "!is_null" + argument: "item_in_hand" + - type: "equals" + value1: "" + value2: "default:ender_pearl_flower_seeds" + functions: + - type: break_block + x: "" + y: "" + z: "" + - type: place_block + x: "" + y: "" + z: "" + block-state: default:ender_pearl_flower[age=0] + - type: set_count + add: true + count: -1 states: properties: age: diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 26a9afbb3..fdfa1323b 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -324,6 +324,12 @@ warning.config.function.place_block.missing_block_state: "Issue found in warning.config.function.set_food.missing_food: "Issue found in file - The config '' is missing the required 'food' argument for 'set_food' function." warning.config.function.set_saturation.missing_saturation: "Issue found in file - The config '' is missing the required 'saturation' argument for 'set_saturation' function." warning.config.function.play_sound.missing_sound: "Issue found in file - The config '' is missing the required 'sound' argument for 'play_sound' function." +warning.config.function.particle.missing_particle: "Issue found in file - The config '' is missing the required 'particle' argument for 'particle' function." +warning.config.function.particle.missing_color: "Issue found in file - The config '' is missing the required 'color' argument for 'particle' function." +warning.config.function.particle.missing_from: "Issue found in file - The config '' is missing the required 'from' argument for 'particle' function." +warning.config.function.particle.missing_to: "Issue found in file - The config '' is missing the required 'to' argument for 'particle' function." +warning.config.function.particle.missing_item: "Issue found in file - The config '' is missing the required 'item' argument for 'particle' function." +warning.config.function.particle.missing_block_state: "Issue found in file - The config '' is missing the required 'block-state' argument for 'particle' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 983dc9e9c..4f15d6a9f 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -324,6 +324,12 @@ warning.config.function.place_block.missing_block_state: "在文件 Issue found in file - The config '' is missing the required 'food' argument for 'set_food' function." warning.config.function.set_saturation.missing_saturation: "Issue found in file - The config '' is missing the required 'saturation' argument for 'set_saturation' function." warning.config.function.play_sound.missing_sound: "Issue found in file - The config '' is missing the required 'sound' argument for 'play_sound' function." +warning.config.function.particle.missing_particle: "Issue found in file - The config '' is missing the required 'particle' argument for 'particle' function." +warning.config.function.particle.missing_color: "Issue found in file - The config '' is missing the required 'color' argument for 'particle' function." +warning.config.function.particle.missing_from: "Issue found in file - The config '' is missing the required 'from' argument for 'particle' function." +warning.config.function.particle.missing_to: "Issue found in file - The config '' is missing the required 'to' argument for 'particle' function." +warning.config.function.particle.missing_item: "Issue found in file - The config '' is missing the required 'item' argument for 'particle' function." +warning.config.function.particle.missing_block_state: "Issue found in file - The config '' is missing the required 'block-state' argument for 'particle' function." warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index abaf50b8d..1ac765bcd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -293,7 +293,7 @@ public class ItemEventListener implements Listener { Cancellable dummy = Cancellable.dummy(); CustomItem customItem = optionalCustomItem.get(); PlayerOptionalContext context = PlayerOptionalContext.of(this.plugin.adapt(event.getPlayer()), ContextHolder.builder() - .withParameter(DirectContextParameters.CONSUMED_ITEM, wrapped) + .withParameter(DirectContextParameters.ITEM_IN_HAND, wrapped) .withParameter(DirectContextParameters.EVENT, dummy) .withParameter(DirectContextParameters.HAND, event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND) ); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ColorUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ColorUtils.java new file mode 100644 index 000000000..18fcde2d3 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ColorUtils.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.bukkit.util; + +import org.bukkit.Color; + +public final class ColorUtils { + private ColorUtils() {} + + public static Color toBukkit(net.momirealms.craftengine.core.util.Color color) { + return Color.fromARGB(color.a(), color.r(), color.g(), color.b()); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java index dc8c5aeba..a6697c9c2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java @@ -1,7 +1,9 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.util.VersionHelper; -import org.bukkit.Particle; +import net.momirealms.craftengine.core.world.particle.*; +import org.bukkit.*; public final class ParticleUtils { private ParticleUtils() {} @@ -21,4 +23,18 @@ public final class ParticleUtils { public static final Particle HAPPY_VILLAGER = getParticle("HAPPY_VILLAGER"); public static final Particle BUBBLE = getParticle("BUBBLE"); + + public static Object toBukkitParticleData(ParticleData particleData, Context context, World world, double x, double y, double z) { + return switch (particleData) { + case BlockStateData data -> BlockStateUtils.fromBlockData(data.blockState().handle()); + case ColorData data -> ColorUtils.toBukkit(data.color()); + case DustData data -> new Particle.DustOptions(ColorUtils.toBukkit(data.color()), data.size()); + case DustTransitionData data -> new Particle.DustTransition(ColorUtils.toBukkit(data.from()), ColorUtils.toBukkit(data.to()), data.size()); + case ItemStackData data -> data.item().getItem(); + case JavaTypeData data -> data.data(); + case VibrationData data -> new Vibration(new Vibration.Destination.BlockDestination(new Location(world, x + data.destinationX().getDouble(context), y + data.destinationY().getDouble(context), y + data.destinationZ().getDouble(context))), data.arrivalTime().getInt(context)); + case TrailData data -> new Particle.Trail(new Location(world, x + data.targetX().getDouble(context), y + data.targetZ().getDouble(context), z + data.targetZ().getDouble(context)), ColorUtils.toBukkit(data.color()), data.duration().getInt(context)); + default -> null; + }; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index c1b6949a5..218b01d34 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -1,11 +1,10 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.util.EntityUtils; -import net.momirealms.craftengine.bukkit.util.ItemUtils; -import net.momirealms.craftengine.bukkit.util.SoundUtils; +import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -13,12 +12,17 @@ import net.momirealms.craftengine.core.world.BlockInWorld; import net.momirealms.craftengine.core.world.Position; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldHeight; +import net.momirealms.craftengine.core.world.particle.ParticleData; import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.Registry; import org.bukkit.SoundCategory; import org.bukkit.entity.EntityType; import org.bukkit.entity.ExperienceOrb; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.nio.file.Path; import java.util.UUID; @@ -99,6 +103,14 @@ public class BukkitWorld implements World { platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundCategory.BLOCKS, volume, pitch); } + @Override + public void spawnParticle(Position location, Key particle, int count, double xOffset, double yOffset, double zOffset, double speed, @Nullable ParticleData extraData, @NotNull Context context) { + Particle particleType = Registry.PARTICLE_TYPE.get(KeyUtils.toNamespacedKey(particle)); + if (particleType == null) return; + org.bukkit.World platformWorld = platformWorld(); + platformWorld.spawnParticle(particleType, location.x(), location.y(), location.z(), count, xOffset, yOffset, zOffset, speed, extraData == null ? null : ParticleUtils.toBukkitParticleData(extraData, context, platformWorld, location.x(), location.y(), location.z())); + } + @Override public long time() { return platformWorld().getTime(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/DelayedInitBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/DelayedInitBlockState.java new file mode 100644 index 000000000..253601aaa --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/DelayedInitBlockState.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.core.block; + +import net.momirealms.craftengine.core.plugin.CraftEngine; + +public class DelayedInitBlockState { + private final String state; + private BlockStateWrapper packedBlockState; + + public DelayedInitBlockState(String state) { + this.state = state; + } + + public BlockStateWrapper getState() { + if (this.packedBlockState == null) { + this.packedBlockState = CraftEngine.instance().blockManager().createPackedBlockState(state); + if (this.packedBlockState == null) { + CraftEngine.instance().logger().warn("Could not create block state: " + this.state); + } + } + return this.packedBlockState; + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/DelayedInitItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/DelayedInitItem.java new file mode 100644 index 000000000..2e6db264f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/DelayedInitItem.java @@ -0,0 +1,23 @@ +package net.momirealms.craftengine.core.item; + +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Key; + +public class DelayedInitItem { + private final Key itemId; + private Item item; + + public DelayedInitItem(Key itemId) { + this.itemId = itemId; + } + + public Item getItem() { + if (this.item == null) { + this.item = CraftEngine.instance().itemManager().createWrappedItem(this.itemId, null); + if (this.item == null) { + CraftEngine.instance().logger().warn("Could not create item: " + this.itemId); + } + } + return this.item; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index 785a00c6d..af0e99be2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.pack.host.impl; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.Scheduler; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; @@ -30,10 +31,12 @@ public class SelfHostHttpServer { private static SelfHostHttpServer instance; private final Cache oneTimePackUrls = Caffeine.newBuilder() .maximumSize(256) + .scheduler(Scheduler.systemScheduler()) .expireAfterAccess(1, TimeUnit.MINUTES) .build(); private final Cache ipAccessCache = Caffeine.newBuilder() .maximumSize(256) + .scheduler(Scheduler.systemScheduler()) .expireAfterAccess(10, TimeUnit.MINUTES) .build(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java index 9eed4f51b..f85e82333 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java @@ -20,7 +20,6 @@ public abstract class AbstractChainParameterContext extends AbstractCommonContex CHAIN_PARAMETERS.put(DirectContextParameters.MAIN_HAND_ITEM, itemProvider); CHAIN_PARAMETERS.put(DirectContextParameters.OFF_HAND_ITEM, itemProvider); CHAIN_PARAMETERS.put(DirectContextParameters.FURNITURE_ITEM, itemProvider); - CHAIN_PARAMETERS.put(DirectContextParameters.CONSUMED_ITEM, itemProvider); CHAIN_PARAMETERS.put(DirectContextParameters.ITEM_IN_HAND, itemProvider); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index ae0c66bd3..c8c0559bf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -33,6 +33,7 @@ public class EventFunctions { register(CommonFunctions.SET_FOOD, new SetFoodFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.SET_SATURATION, new SetSaturationFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.PLAY_SOUND, new PlaySoundFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.PARTICLE, new ParticleFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index 82de72647..e8369e3fa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -23,4 +23,5 @@ public final class CommonFunctions { public static final Key SET_SATURATION = Key.of("craftengine:saturation"); public static final Key DROP_LOOT = Key.of("craftengine:drop_loot"); public static final Key SWING_HAND = Key.of("craftengine:swing_hand"); + public static final Key PLUGIN_EXP = Key.of("craftengine:plugin_exp"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java new file mode 100644 index 000000000..098f09d2c --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java @@ -0,0 +1,135 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.block.DelayedInitBlockState; +import net.momirealms.craftengine.core.item.DelayedInitItem; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Color; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.Position; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; +import net.momirealms.craftengine.core.world.particle.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ParticleFunction extends AbstractConditionalFunction { + public static final Map, ParticleData>> DATA_TYPES = new HashMap<>(); + + static { + registerParticleData(map -> new BlockStateData( + new DelayedInitBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("block-state"), "warning.config.function.particle.missing_block_state"))), + ParticleTypes.BLOCK, ParticleTypes.FALLING_DUST, ParticleTypes.DUST_PILLAR, ParticleTypes.BLOCK_CRUMBLE, ParticleTypes.BLOCK_MARKER); + registerParticleData(map -> new ColorData( + Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(","))), + ParticleTypes.ENTITY_EFFECT, ParticleTypes.TINTED_LEAVES); + registerParticleData(map -> new JavaTypeData( + ResourceConfigUtils.getAsFloat(map.get("charge"), "charge")), + ParticleTypes.SCULK_CHARGE); + registerParticleData(map -> new JavaTypeData( + ResourceConfigUtils.getAsInt(map.get("shriek"), "shriek")), + ParticleTypes.SHRIEK); + registerParticleData(map -> new DustData( + Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")), + ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")), + ParticleTypes.DUST); + registerParticleData(map -> new DustTransitionData( + Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("from"), "warning.config.function.particle.missing_from").split(",")), + Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("to"), "warning.config.function.particle.missing_to").split(",")), + ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")), + ParticleTypes.DUST_COLOR_TRANSITION); + registerParticleData(map -> new ItemStackData( + new DelayedInitItem(Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("item"), "warning.config.function.particle.missing_item")))), + ParticleTypes.ITEM); + registerParticleData(map -> new VibrationData( + NumberProviders.fromObject(map.getOrDefault("target-x", 0)), + NumberProviders.fromObject(map.getOrDefault("target-y", 0)), + NumberProviders.fromObject(map.getOrDefault("target-z", 0)), + NumberProviders.fromObject(map.getOrDefault("arrival-time", 10))), + ParticleTypes.VIBRATION); + registerParticleData(map -> new TrailData( + NumberProviders.fromObject(map.getOrDefault("target-x", 0)), + NumberProviders.fromObject(map.getOrDefault("target-y", 0)), + NumberProviders.fromObject(map.getOrDefault("target-z", 0)), + Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")), + NumberProviders.fromObject(map.getOrDefault("duration", 10))), + ParticleTypes.TRAIL); + } + + public static void registerParticleData(java.util.function.Function, ParticleData> function, Key... types) { + for (Key type : types) { + DATA_TYPES.put(type, function); + } + } + + private final Key particleType; + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final NumberProvider count; + private final NumberProvider xOffset; + private final NumberProvider yOffset; + private final NumberProvider zOffset; + private final NumberProvider speed; + private final ParticleData particleData; + + public ParticleFunction(Key particleType, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider count, + NumberProvider xOffset, NumberProvider yOffset, NumberProvider zOffset, NumberProvider speed, ParticleData particleData, List> predicates) { + super(predicates); + this.particleType = particleType; + this.count = count; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.speed = speed; + this.x = x; + this.y = y; + this.z = z; + this.particleData = particleData; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isPresent()) { + World world = optionalWorldPosition.get().world(); + Position position = new Vec3d(this.x.getDouble(ctx), this.y.getDouble(ctx), this.z.getDouble(ctx)); + world.spawnParticle(position, this.particleType, this.count.getInt(ctx), this.xOffset.getDouble(ctx), this.yOffset.getDouble(ctx), this.zOffset.getDouble(ctx), this.speed.getDouble(ctx), this.particleData, ctx); + } + } + + @Override + public Key type() { + return CommonFunctions.PARTICLE; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Key particleType = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("particle"), "warning.config.function.particle.missing_particle")); + NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); + NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); + NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); + NumberProvider count = NumberProviders.fromObject(arguments.getOrDefault("count", 1)); + NumberProvider xOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-x", 0)); + NumberProvider yOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-y", 0)); + NumberProvider zOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-z", 0)); + NumberProvider speed = NumberProviders.fromObject(arguments.getOrDefault("speed", 0)); + return new ParticleFunction<>(particleType, x, y, z, count, xOffset, yOffset, zOffset, speed, + Optional.ofNullable(ParticleFunction.DATA_TYPES.get(particleType)).map(it -> it.apply(arguments)).orElse(null), getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java index c5fbeae29..b2d94cc6a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.block.DelayedInitBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.Condition; @@ -48,25 +49,6 @@ public class PlaceBlockFunction extends AbstractConditional return CommonFunctions.PLACE_BLOCK; } - public static class DelayedInitBlockState { - private final String state; - private BlockStateWrapper packedBlockState; - - public DelayedInitBlockState(String state) { - this.state = state; - } - - public BlockStateWrapper getState() { - if (this.packedBlockState == null) { - this.packedBlockState = CraftEngine.instance().blockManager().createPackedBlockState(state); - if (this.packedBlockState == null) { - CraftEngine.instance().logger().warn("Could not create block state: " + this.state); - } - } - return this.packedBlockState; - } - } - public static class FactoryImpl extends AbstractFactory { public FactoryImpl(java.util.function.Function, Condition> factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java index 495739c3b..eae49c92b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java @@ -26,7 +26,6 @@ public final class DirectContextParameters { public static final ContextKey LAST_RANDOM = ContextKey.direct("last_random"); public static final ContextKey WORLD = ContextKey.direct("world"); public static final ContextKey> FURNITURE_ITEM = ContextKey.direct("furniture_item"); - public static final ContextKey> CONSUMED_ITEM = ContextKey.direct("consumed_item"); public static final ContextKey> ITEM_IN_HAND = ContextKey.direct("item_in_hand"); public static final ContextKey FALLING_BLOCK = ContextKey.direct("falling_block"); public static final ContextKey EXPLOSION_RADIUS = ContextKey.direct("explosion_radius"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Color.java b/core/src/main/java/net/momirealms/craftengine/core/util/Color.java new file mode 100644 index 000000000..24da61b00 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Color.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.util; + +import java.util.Arrays; + +public class Color { + private static final byte DEFAULT_ALPHA = (byte) 255; + private final byte r; + private final byte g; + private final byte b; + private final byte a; + + public Color(byte r, byte g, byte b, byte a) { + this.b = b; + this.g = g; + this.r = r; + this.a = a; + } + + public Color(byte r, byte g, byte b) { + this(r, g, b, DEFAULT_ALPHA); + } + + public static Color fromString(String[] strings) { + if (strings.length == 3) { + return new Color(Byte.parseByte(strings[0]), Byte.parseByte(strings[1]), Byte.parseByte(strings[2])); + } else if (strings.length == 4) { + return new Color(Byte.parseByte(strings[0]), Byte.parseByte(strings[1]), Byte.parseByte(strings[2]), Byte.parseByte(strings[3])); + } else { + throw new IllegalArgumentException("Invalid color format: " + Arrays.toString(strings)); + } + } + + public byte a() { + return a; + } + + public byte b() { + return b; + } + + public byte g() { + return g; + } + + public byte r() { + return r; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index 0dacaa8e4..f49424a47 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -2,10 +2,14 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.particle.ParticleData; +import org.jetbrains.annotations.NotNull; +import javax.annotation.Nullable; import java.nio.file.Path; import java.util.UUID; @@ -43,5 +47,7 @@ public interface World { playBlockSound(location, data.id(), data.volume(), data.pitch()); } + void spawnParticle(Position location, Key particle, int count, double xOffset, double yOffset, double zOffset, double speed, @Nullable ParticleData extraData, @NotNull Context context); + long time(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java new file mode 100644 index 000000000..09a835011 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.block.DelayedInitBlockState; + +public class BlockStateData implements ParticleData { + private final DelayedInitBlockState blockState; + + public BlockStateData(DelayedInitBlockState blockState) { + this.blockState = blockState; + } + + public BlockStateWrapper blockState() { + return blockState.getState(); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/ColorData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ColorData.java new file mode 100644 index 000000000..e2a2b295d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ColorData.java @@ -0,0 +1,15 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.util.Color; + +public class ColorData implements ParticleData { + private final Color color; + + public ColorData(Color color) { + this.color = color; + } + + public Color color() { + return color; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustData.java new file mode 100644 index 000000000..a00b2cc72 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustData.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.util.Color; + +public class DustData implements ParticleData { + private final Color color; + private final float size; + + public DustData(Color color, float size) { + this.color = color; + this.size = size; + } + + public Color color() { + return color; + } + + public float size() { + return size; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustTransitionData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustTransitionData.java new file mode 100644 index 000000000..c4edbd9e2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustTransitionData.java @@ -0,0 +1,27 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.util.Color; + +public class DustTransitionData implements ParticleData { + private final Color from; + private final Color to; + private final float size; + + public DustTransitionData(Color from, Color to, float size) { + this.from = from; + this.to = to; + this.size = size; + } + + public Color from() { + return from; + } + + public Color to() { + return to; + } + + public float size() { + return size; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java new file mode 100644 index 000000000..17eaa1fb9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.item.DelayedInitItem; +import net.momirealms.craftengine.core.item.Item; + +public class ItemStackData implements ParticleData { + private final DelayedInitItem item; + + public ItemStackData(DelayedInitItem item) { + this.item = item; + } + + public Item item() { + return item.getItem(); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/JavaTypeData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/JavaTypeData.java new file mode 100644 index 000000000..052e01f3d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/JavaTypeData.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.world.particle; + +public class JavaTypeData implements ParticleData { + private final Object data; + + public JavaTypeData(Object data) { + this.data = data; + } + + public Object data() { + return data; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleData.java new file mode 100644 index 000000000..dfb22cfc3 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleData.java @@ -0,0 +1,4 @@ +package net.momirealms.craftengine.core.world.particle; + +public interface ParticleData { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleTypes.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleTypes.java new file mode 100644 index 000000000..7bd64ca92 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleTypes.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.util.Key; + +public final class ParticleTypes { + private ParticleTypes() {} + + public static final Key ENTITY_EFFECT = Key.of("entity_effect"); + public static final Key DUST = Key.of("dust"); + public static final Key ITEM = Key.of("item"); + public static final Key BLOCK = Key.of("block"); + public static final Key FALLING_DUST = Key.of("falling_dust"); + public static final Key DUST_COLOR_TRANSITION = Key.of("dust_color_transition"); + public static final Key SCULK_CHARGE = Key.of("sculk_charge"); + public static final Key SHRIEK = Key.of("shriek"); + public static final Key TINTED_LEAVES = Key.of("tinted_leaves"); + public static final Key DUST_PILLAR = Key.of("dust_pillar"); + public static final Key BLOCK_CRUMBLE = Key.of("block_crumble"); + public static final Key BLOCK_MARKER = Key.of("block_marker"); + public static final Key TRAIL = Key.of("trail"); + public static final Key VIBRATION = Key.of("vibration"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/TrailData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/TrailData.java new file mode 100644 index 000000000..8ee59c346 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/TrailData.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.util.Color; + +public class TrailData implements ParticleData { + private final NumberProvider targetX; + private final NumberProvider targetY; + private final NumberProvider targetZ; + private final Color color; + private final NumberProvider duration; + + public TrailData(NumberProvider targetX, NumberProvider targetY, NumberProvider targetZ, Color color, NumberProvider duration) { + this.color = color; + this.duration = duration; + this.targetX = targetX; + this.targetY = targetY; + this.targetZ = targetZ; + } + + public Color color() { + return color; + } + + public NumberProvider duration() { + return duration; + } + + public NumberProvider targetX() { + return targetX; + } + + public NumberProvider targetY() { + return targetY; + } + + public NumberProvider targetZ() { + return targetZ; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/VibrationData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/VibrationData.java new file mode 100644 index 000000000..1f8da18a2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/VibrationData.java @@ -0,0 +1,33 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; + +public class VibrationData implements ParticleData { + private final NumberProvider destinationX; + private final NumberProvider destinationY; + private final NumberProvider destinationZ; + private final NumberProvider arrivalTime; + + public VibrationData(NumberProvider destinationX, NumberProvider destinationY, NumberProvider destinationZ, NumberProvider arrivalTime) { + this.arrivalTime = arrivalTime; + this.destinationX = destinationX; + this.destinationY = destinationY; + this.destinationZ = destinationZ; + } + + public NumberProvider arrivalTime() { + return arrivalTime; + } + + public NumberProvider destinationX() { + return destinationX; + } + + public NumberProvider destinationY() { + return destinationY; + } + + public NumberProvider destinationZ() { + return destinationZ; + } +} From a965d231a78813b46fbbd2dcf9091fb4a8e3554e Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 22 May 2025 23:57:54 +0800 Subject: [PATCH 28/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=8D=AF=E6=B0=B4?= =?UTF-8?q?=E6=95=88=E6=9E=9C=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/plants.yml | 7 +- .../bukkit/api/event/FurnitureBreakEvent.java | 1 - .../api/event/FurnitureInteractEvent.java | 1 - .../bukkit/api/event/FurniturePlaceEvent.java | 1 - .../plugin/user/BukkitServerPlayer.java | 21 ++++-- .../bukkit/util/ParticleUtils.java | 5 +- .../core/entity/player/Player.java | 4 ++ .../plugin/context/event/EventFunctions.java | 1 + .../context/function/ActionBarFunction.java | 4 +- .../context/function/CommandFunction.java | 4 +- .../context/function/MessageFunction.java | 4 +- .../context/function/OpenWindowFunction.java | 3 +- .../context/function/PlaceBlockFunction.java | 2 - .../function/PotionEffectFunction.java | 69 +++++++++++++++++++ .../context/function/SetFoodFunction.java | 22 ++++-- .../function/SetSaturationFunction.java | 22 ++++-- .../context/function/TitleFunction.java | 4 +- 17 files changed, 136 insertions(+), 39 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 3fde1cb5a..89e99122c 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -216,9 +216,10 @@ blocks: z: " + 0.5" particle: "minecraft:end_rod" count: 15 - offset-x: 0.4 - offset-y: 0.4 - offset-z: 0.4 + offset-x: 0.05 + offset-y: 0.05 + offset-z: 0.05 + speed: 0.1 - type: play_sound sound: minecraft:entity.enderman.teleport x: " + 0.5" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java index db42cb252..087004c50 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.api.event; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; -import net.momirealms.craftengine.core.entity.furniture.Furniture; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java index b89bb7ba3..a9a523484 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.api.event; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; -import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.player.InteractionHand; import org.bukkit.Location; import org.bukkit.entity.Player; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java index e6f1405c1..8ea0c9645 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.api.event; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; -import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.player.InteractionHand; import org.bukkit.Location; import org.bukkit.entity.Player; 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 3dce61b66..40fac266a 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 @@ -28,16 +28,15 @@ import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; -import org.bukkit.FluidCollisionMode; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.SoundCategory; +import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.Block; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; import org.bukkit.util.RayTraceResult; import org.jetbrains.annotations.Nullable; @@ -858,4 +857,18 @@ public class BukkitServerPlayer extends Player { public void setSaturation(float saturation) { this.platformPlayer().setSaturation(saturation); } + + @Override + public void addPotionEffect(Key potionEffectType, int duration, int amplifier, boolean ambient, boolean particles) { + PotionEffectType type = Registry.POTION_EFFECT_TYPE.get(KeyUtils.toNamespacedKey(potionEffectType)); + if (type == null) return; + this.platformPlayer().addPotionEffect(new PotionEffect(type, duration, amplifier, ambient, particles)); + } + + @Override + public void removePotionEffect(Key potionEffectType) { + PotionEffectType type = Registry.POTION_EFFECT_TYPE.get(KeyUtils.toNamespacedKey(potionEffectType)); + if (type == null) return; + this.platformPlayer().removePotionEffect(type); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java index a6697c9c2..e0ba3ccd0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java @@ -3,7 +3,10 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.particle.*; -import org.bukkit.*; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.Vibration; +import org.bukkit.World; public final class ParticleUtils { private ParticleUtils() {} diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index c0132edf8..4a5f8f7a8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -124,4 +124,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract float saturation(); public abstract void setSaturation(float saturation); + + public abstract void addPotionEffect(Key potionEffectType, int duration, int amplifier, boolean ambient, boolean particles); + + public abstract void removePotionEffect(Key potionEffectType); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index c8c0559bf..b2ce2de15 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -34,6 +34,7 @@ public class EventFunctions { register(CommonFunctions.SET_SATURATION, new SetSaturationFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.PLAY_SOUND, new PlaySoundFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.PARTICLE, new ParticleFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.POTION_EFFECT, new PotionEffectFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java index 4e04272f7..9f3781528 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java @@ -14,7 +14,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -import java.util.Optional; public class ActionBarFunction extends AbstractConditionalFunction { private final TextProvider message; @@ -28,9 +27,8 @@ public class ActionBarFunction extends AbstractConditionalF @Override public void runInternal(CTX ctx) { - Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { - owner.ifPresent(it -> { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { it.sendActionBar(AdventureHelper.miniMessage().deserialize(this.message.get(ctx), ctx.tagResolvers())); }); } else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java index 61a4137c4..d85f44950 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java @@ -16,7 +16,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -import java.util.Optional; public class CommandFunction extends AbstractConditionalFunction { private final List command; @@ -33,9 +32,8 @@ public class CommandFunction extends AbstractConditionalFun @Override public void runInternal(CTX ctx) { if (this.asPlayer) { - Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { - owner.ifPresent(it -> { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { for (TextProvider c : this.command) { it.performCommand(c.get(ctx)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java index eeee93a4f..8c43e06f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java @@ -15,7 +15,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -import java.util.Optional; public class MessageFunction extends AbstractConditionalFunction { private final List messages; @@ -31,9 +30,8 @@ public class MessageFunction extends AbstractConditionalFun @Override public void runInternal(CTX ctx) { - Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { - owner.ifPresent(it -> { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { for (TextProvider c : this.messages) { it.sendMessage(AdventureHelper.miniMessage().deserialize(c.get(ctx), ctx.tagResolvers()), this.overlay); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java index 53dd47587..9799f63e2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java @@ -35,9 +35,8 @@ public class OpenWindowFunction extends AbstractConditional @Override public void runInternal(CTX ctx) { - Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { - owner.ifPresent(it -> { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { CraftEngine.instance().guiManager().openInventory(it, this.guiType); if (this.optionalTitle != null) { CraftEngine.instance().guiManager().updateInventoryTitle(it, AdventureHelper.miniMessage().deserialize(this.optionalTitle.get(ctx), ctx.tagResolvers())); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java index b2d94cc6a..b5ee0bbeb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java @@ -1,9 +1,7 @@ package net.momirealms.craftengine.core.plugin.context.function; -import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.DelayedInitBlockState; import net.momirealms.craftengine.core.block.UpdateOption; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java new file mode 100644 index 000000000..461e838ed --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java @@ -0,0 +1,69 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.*; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; + +public class PotionEffectFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; + private final Key potionEffectType; + private final NumberProvider duration; + private final NumberProvider amplifier; + private final boolean ambient; + private final boolean particles; + + public PotionEffectFunction(Key potionEffectType, NumberProvider duration, NumberProvider amplifier, boolean ambient, boolean particles, PlayerSelector selector, List> predicates) { + super(predicates); + this.potionEffectType = potionEffectType; + this.duration = duration; + this.amplifier = amplifier; + this.selector = selector; + this.ambient = ambient; + this.particles = particles; + } + + @Override + public void runInternal(CTX ctx) { + if (this.selector == null) { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { + it.addPotionEffect(this.potionEffectType, this.duration.getInt(ctx), this.amplifier.getInt(ctx), this.ambient, this.particles); + }); + } else { + for (Player target : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(target, ContextHolder.EMPTY)); + target.addPotionEffect(this.potionEffectType, this.duration.getInt(relationalContext), this.amplifier.getInt(relationalContext), this.ambient, this.particles); + } + } + } + + @Override + public Key type() { + return CommonFunctions.POTION_EFFECT; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Key effectType = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("potion-effect"), "warning.config.function.potion_effect.missing_potion_effect")); + NumberProvider duration = NumberProviders.fromObject(arguments.get("duration")); + NumberProvider amplifier = NumberProviders.fromObject(arguments.get("amplifier")); + boolean ambient = (boolean) arguments.getOrDefault("ambient", false); + boolean particles = (boolean) arguments.getOrDefault("particles", true); + return new PotionEffectFunction<>(effectType, duration, amplifier, ambient, particles, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java index fcd05f71a..ebb1705a3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java @@ -1,11 +1,12 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.*; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -14,19 +15,28 @@ import java.util.Map; import java.util.Optional; public class SetFoodFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; private final NumberProvider count; private final boolean add; - public SetFoodFunction(NumberProvider count, boolean add, List> predicates) { + public SetFoodFunction(NumberProvider count, boolean add, PlayerSelector selector, List> predicates) { super(predicates); this.count = count; this.add = add; + this.selector = selector; } @Override public void runInternal(CTX ctx) { - Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); - optionalPlayer.ifPresent(player -> player.setFoodLevel(this.add ? player.foodLevel() + this.count.getInt(ctx) : this.count.getInt(ctx))); + if (this.selector == null) { + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + optionalPlayer.ifPresent(player -> player.setFoodLevel(this.add ? player.foodLevel() + this.count.getInt(ctx) : this.count.getInt(ctx))); + } else { + for (Player target : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(target, ContextHolder.EMPTY)); + target.setFoodLevel(this.add ? target.foodLevel() + this.count.getInt(relationalContext) : this.count.getInt(relationalContext)); + } + } } @Override @@ -44,7 +54,7 @@ public class SetFoodFunction extends AbstractConditionalFun public Function create(Map arguments) { Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("food"), "warning.config.function.set_food.missing_food"); boolean add = (boolean) arguments.getOrDefault("add", false); - return new SetFoodFunction<>(NumberProviders.fromObject(value), add, getPredicates(arguments)); + return new SetFoodFunction<>(NumberProviders.fromObject(value), add, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java index 86634543f..7afedc1c5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java @@ -1,11 +1,12 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.*; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -14,19 +15,28 @@ import java.util.Map; import java.util.Optional; public class SetSaturationFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; private final NumberProvider count; private final boolean add; - public SetSaturationFunction(NumberProvider count, boolean add, List> predicates) { + public SetSaturationFunction(NumberProvider count, boolean add, PlayerSelector selector, List> predicates) { super(predicates); this.count = count; this.add = add; + this.selector = selector; } @Override public void runInternal(CTX ctx) { - Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); - optionalPlayer.ifPresent(player -> player.setSaturation(this.add ? player.saturation() + this.count.getFloat(ctx) : this.count.getFloat(ctx))); + if (this.selector == null) { + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + optionalPlayer.ifPresent(player -> player.setSaturation(this.add ? player.saturation() + this.count.getFloat(ctx) : this.count.getFloat(ctx))); + } else { + for (Player target : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(target, ContextHolder.EMPTY)); + target.setSaturation(this.add ? target.saturation() + this.count.getFloat(relationalContext) : this.count.getFloat(relationalContext)); + } + } } @Override @@ -44,7 +54,7 @@ public class SetSaturationFunction extends AbstractConditio public Function create(Map arguments) { Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("saturation"), "warning.config.function.set_saturation.missing_saturation"); boolean add = (boolean) arguments.getOrDefault("add", false); - return new SetSaturationFunction<>(NumberProviders.fromObject(value), add, getPredicates(arguments)); + return new SetSaturationFunction<>(NumberProviders.fromObject(value), add, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java index 28900c5a1..43eb8d195 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java @@ -15,7 +15,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -import java.util.Optional; public class TitleFunction extends AbstractConditionalFunction { private final PlayerSelector selector; @@ -38,9 +37,8 @@ public class TitleFunction extends AbstractConditionalFunct @Override public void runInternal(CTX ctx) { - Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { - owner.ifPresent(it -> it.sendTitle( + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> it.sendTitle( AdventureHelper.miniMessage().deserialize(this.main.get(ctx), ctx.tagResolvers()), AdventureHelper.miniMessage().deserialize(this.sub.get(ctx), ctx.tagResolvers()), this.fadeIn.getInt(ctx), this.stay.getInt(ctx), this.fadeOut.getInt(ctx) From e5a372b0481bb244ccb86735208a3aa89c37500e Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 23 May 2025 00:05:03 +0800 Subject: [PATCH 29/89] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=B8=89=E5=8F=89=E6=88=9F=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projectile/BukkitProjectileManager.java | 33 ++++++++----------- .../plugin/command/feature/TestCommand.java | 1 - .../plugin/network/PacketConsumers.java | 2 +- .../plugin/user/BukkitServerPlayer.java | 6 ++-- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java index 6bef2fecf..9fb5c698f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.entity.projectile; +import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent; import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; import io.papermc.paper.event.player.PlayerStopUsingItemEvent; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; @@ -21,6 +22,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityPortalEvent; import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.event.world.EntitiesLoadEvent; @@ -57,18 +59,15 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { return Optional.ofNullable(this.projectiles.get(entityId)); } - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onProjectileLaunch(ProjectileLaunchEvent event) { - Projectile projectile = event.getEntity(); - handleProjectileLoad(projectile); + handleProjectileLoad(event.getEntity()); } - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - public void onEntitiesLoad(EntitiesLoadEvent event) { - for (Entity entity : event.getEntities()) { - if (entity instanceof Projectile projectile) { - handleProjectileLoad(projectile); - } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) + public void onEntityAdd(EntityAddToWorldEvent event) { + if (event.getEntity() instanceof Projectile projectile) { + handleProjectileLoad(projectile); } } @@ -99,10 +98,9 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { @EventHandler public void onPlayerInteract(PlayerItemConsumeEvent event) { - ItemStack item = event.getItem(); - String type = getType(item); + String type = getType(event.getItem()); if (type == null) return; - if (type.equals("bow") || type.equals("spear")) { + if (type.equals("bow") || type.equals("trident")) { event.setCancelled(true); } } @@ -114,17 +112,14 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { if (type == null) return; int ticksHeldFor = event.getTicksHeldFor(); Player player = event.getPlayer(); - if (type.equals("bow")) { - if (ticksHeldFor < 3) return; - // player.sendMessage("可以投出自定义弓: " + item.getType() + " 持续 " + ticksHeldFor + " 刻"); - } else if (type.equals("trident")) { + if (type.equals("trident")) { if (ticksHeldFor < 10) return; - // player.sendMessage("可以投出自定义三叉戟: " + item.getType() + " 持续 " + ticksHeldFor + " 刻"); Object nmsItemStack = FastNMS.INSTANCE.field$CraftItemStack$handle(item); Object nmsServerLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(player); - boolean success = TridentRelease.releaseUsing(nmsItemStack, nmsServerLevel, nmsEntity); - // player.sendMessage("释放成功: " + success); + TridentRelease.releaseUsing(nmsItemStack, nmsServerLevel, nmsEntity); + } else if (type.equals("bow")) { + if (ticksHeldFor < 3) return; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 8ce4d7495..00e8c84de 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; -import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.core.plugin.CraftEngine; 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 9a18a9994..2719be684 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 @@ -1617,7 +1617,7 @@ public class PacketConsumers { Object removePacket = Reflections.constructor$ClientboundRemoveEntitiesPacket.newInstance(entityIdsArray); DynamicPriorityTracker.UpdateResult result = user.visualFurnitureView().addOrUpdateElement(new DynamicPriorityTracker.Element(entityId, distance, removePacket)); for (DynamicPriorityTracker.Element element : result.getEntered()) { - LoadedFurniture updateFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); + BukkitFurniture updateFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); if (updateFurniture == null || !updateFurniture.isValid()) continue; user.sendPacket(updateFurniture.spawnPacket(player), false); } 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 debbbe0d0..b04238a43 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 @@ -4,8 +4,8 @@ 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.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; -import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -382,13 +382,13 @@ public class BukkitServerPlayer extends Player { if (!Config.enableMaxVisibleFurniture()) return; if (visualFurnitureView().getTotalMembers() <= Config.maxVisibleFurniture()) return; for (DynamicPriorityTracker.Element element : visualFurnitureView().getAllElements()) { - LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); if (furniture == null || !furniture.isValid()) continue; double distance = furniture.location().distanceSquared(platformPlayer().getLocation()); DynamicPriorityTracker.Element newElement = new DynamicPriorityTracker.Element(element.entityId(), distance, element.removePacket()); DynamicPriorityTracker.UpdateResult result = visualFurnitureView().addOrUpdateElement(newElement); for (DynamicPriorityTracker.Element resultElement : result.getEntered()) { - LoadedFurniture updateFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(resultElement.entityId()); + BukkitFurniture updateFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(resultElement.entityId()); if (updateFurniture == null || !updateFurniture.isValid()) continue; sendPacket(updateFurniture.spawnPacket(platformPlayer()), false); } From 768b5de5ba31a61bcde5d3970cf3247c5b0553b0 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 23 May 2025 00:34:57 +0800 Subject: [PATCH 30/89] =?UTF-8?q?fix(bukkit):=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E9=83=A8=E5=88=861.21.4=E7=89=88=E6=9C=AC=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=89=93=E5=BC=80=E5=AE=B9=E5=99=A8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/plugin/gui/BukkitGuiManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java index 9062dc5b6..f08eca613 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java @@ -7,6 +7,7 @@ import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.gui.*; +import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -16,9 +17,11 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.MenuType; public class BukkitGuiManager implements GuiManager, Listener { + private static final boolean useNewOpenInventory = ReflectionUtils.getDeclaredMethod(InventoryView.class, void.class, new String[]{"open"}) != null; private final BukkitCraftEngine plugin; public BukkitGuiManager(BukkitCraftEngine plugin) { @@ -39,7 +42,7 @@ public class BukkitGuiManager implements GuiManager, Listener { @Override public void openInventory(net.momirealms.craftengine.core.entity.player.Player player, GuiType guiType) { Player bukkitPlayer = (Player) player.platformPlayer(); - if (VersionHelper.isOrAbove1_21_4()) { + if (useNewOpenInventory) { switch (guiType) { case ANVIL -> MenuType.ANVIL.create(bukkitPlayer).open(); case LOOM -> MenuType.LOOM.create(bukkitPlayer).open(); From fb20cc73979f84deba37c190477bdd63fd088e25 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 23 May 2025 02:01:03 +0800 Subject: [PATCH 31/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86leveler=20exp?= =?UTF-8?q?=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/compatibility/build.gradle.kts | 2 + .../BukkitCompatibilityManager.java | 42 ++++++++++-- .../leveler/AuraSkillsLevelerProvider.java | 19 ++++++ .../src/main/resources/translations/en.yml | 3 + .../src/main/resources/translations/zh_cn.yml | 21 +++--- .../bukkit/plugin/BukkitCraftEngine.java | 2 +- .../furniture/AbstractFurnitureManager.java | 4 +- .../craftengine/core/plugin/CraftEngine.java | 1 + .../craftengine/core/plugin/Plugin.java | 1 + .../CompatibilityManager.java | 11 ++- .../plugin/compatibility/LevelerProvider.java | 10 +++ .../plugin/compatibility/ModelProvider.java | 8 +++ .../plugin/context/event/EventFunctions.java | 1 + .../context/function/CommonFunctions.java | 2 +- .../context/function/LevelerExpFunction.java | 67 +++++++++++++++++++ 15 files changed, 172 insertions(+), 22 deletions(-) create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/leveler/AuraSkillsLevelerProvider.java rename core/src/main/java/net/momirealms/craftengine/core/plugin/{ => compatibility}/CompatibilityManager.java (59%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/LevelerProvider.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/ModelProvider.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts index db481a7c5..55151de14 100644 --- a/bukkit/compatibility/build.gradle.kts +++ b/bukkit/compatibility/build.gradle.kts @@ -41,6 +41,8 @@ dependencies { compileOnly("com.viaversion:viaversion-api:5.3.2") // Skript compileOnly("com.github.SkriptLang:Skript:2.11.0") + // AuraSkills + compileOnly("dev.aurelium:auraskills-api-bukkit:2.2.4") // FAWE compileOnly(platform("com.intellectualsites.bom:bom-newest:1.52")) compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Core") diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java index a4a72da12..4e00a179d 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.compatibility.bettermodel.BetterModelMo import net.momirealms.craftengine.bukkit.compatibility.item.MMOItemsProvider; import net.momirealms.craftengine.bukkit.compatibility.item.NeigeItemsProvider; import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor; +import net.momirealms.craftengine.bukkit.compatibility.leveler.AuraSkillsLevelerProvider; import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineModel; import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineUtils; import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; @@ -16,24 +17,36 @@ import net.momirealms.craftengine.bukkit.compatibility.worldedit.WorldEditBlockR import net.momirealms.craftengine.bukkit.font.BukkitFontManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.core.entity.furniture.AbstractExternalModel; +import net.momirealms.craftengine.core.entity.furniture.ExternalModel; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.CompatibilityManager; +import net.momirealms.craftengine.core.plugin.compatibility.CompatibilityManager; +import net.momirealms.craftengine.core.plugin.compatibility.LevelerProvider; +import net.momirealms.craftengine.core.plugin.compatibility.ModelProvider; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldManager; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; import java.util.UUID; public class BukkitCompatibilityManager implements CompatibilityManager { private final BukkitCraftEngine plugin; + private final Map modelProviders; + private final Map levelerProviders; private boolean hasPlaceholderAPI; private boolean hasViaVersion; public BukkitCompatibilityManager(BukkitCraftEngine plugin) { this.plugin = plugin; + this.modelProviders = new HashMap<>(Map.of( + "ModelEngine", ModelEngineModel::new, + "BetterModel", BetterModelModel::new + )); + this.levelerProviders = new HashMap<>(); } @Override @@ -85,6 +98,14 @@ public class BukkitCompatibilityManager implements CompatibilityManager { this.initLuckPermsHook(); logHook("LuckPerms"); } + if (this.isPluginEnabled("AuraSkills")) { + this.registerLevelerProvider("AuraSkills", new AuraSkillsLevelerProvider()); + } + } + + @Override + public void registerLevelerProvider(String plugin, LevelerProvider provider) { + this.levelerProviders.put(plugin, provider); } private void logHook(String plugin) { @@ -92,13 +113,22 @@ public class BukkitCompatibilityManager implements CompatibilityManager { } @Override - public AbstractExternalModel createModelEngineModel(String id) { - return new ModelEngineModel(id); + public void addLevelerExp(Player player, String plugin, String target, double value) { + Optional.ofNullable(this.levelerProviders.get(plugin)).ifPresentOrElse(leveler -> leveler.addExp(player, target, value), + () -> this.plugin.logger().warn("[Compatibility] '" + plugin + "' leveler provider not found")); } @Override - public AbstractExternalModel createBetterModelModel(String id) { - return new BetterModelModel(id); + public int getLevel(Player player, String plugin, String target) { + return Optional.ofNullable(this.levelerProviders.get(plugin)).map(leveler -> leveler.getLevel(player, target)).orElseGet(() -> { + this.plugin.logger().warn("[Compatibility] '" + plugin + "' leveler provider not found"); + return 0; + }); + } + + @Override + public ExternalModel createModel(String plugin, String id) { + return this.modelProviders.get(plugin).createModel(id); } @Override diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/leveler/AuraSkillsLevelerProvider.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/leveler/AuraSkillsLevelerProvider.java new file mode 100644 index 000000000..9189f2e30 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/leveler/AuraSkillsLevelerProvider.java @@ -0,0 +1,19 @@ +package net.momirealms.craftengine.bukkit.compatibility.leveler; + +import dev.aurelium.auraskills.api.AuraSkillsApi; +import dev.aurelium.auraskills.api.registry.NamespacedId; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.compatibility.LevelerProvider; + +public class AuraSkillsLevelerProvider implements LevelerProvider { + + @Override + public void addExp(Player player, String target, double amount) { + AuraSkillsApi.get().getUser(player.uuid()).addSkillXp(AuraSkillsApi.get().getGlobalRegistry().getSkill(NamespacedId.fromDefault(target)), amount); + } + + @Override + public int getLevel(Player player, String target) { + return AuraSkillsApi.get().getUser(player.uuid()).getSkillLevel(AuraSkillsApi.get().getGlobalRegistry().getSkill(NamespacedId.fromDefault(target))); + } +} diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index fdfa1323b..c268cd1a0 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -330,6 +330,9 @@ warning.config.function.particle.missing_from: "Issue found in file Issue found in file - The config '' is missing the required 'to' argument for 'particle' function." warning.config.function.particle.missing_item: "Issue found in file - The config '' is missing the required 'item' argument for 'particle' function." warning.config.function.particle.missing_block_state: "Issue found in file - The config '' is missing the required 'block-state' argument for 'particle' function." +warning.config.function.leveler_exp.missing_count: "Issue found in file - The config '' is missing the required 'count' argument for 'leveler_exp' function." +warning.config.function.leveler_exp.missing_leveler: "Issue found in file - The config '' is missing the required 'leveler' argument for 'leveler_exp' function." +warning.config.function.leveler_exp.missing_plugin: "Issue found in file - The config '' is missing the required 'plugin' argument for 'leveler_exp' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 4f15d6a9f..ba48283e0 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -321,15 +321,18 @@ warning.config.function.open_window.missing_gui_type: "在文件 warning.config.function.open_window.invalid_gui_type: "在文件 中发现问题 - 配置项 '' 为 'open_window' 函数使用了无效的 GUI 类型 . 允许的类型: []。" warning.config.function.run.missing_functions: "在文件 中发现问题 - 配置项 '' 缺少 'run' 函数必需的 'functions' 参数" warning.config.function.place_block.missing_block_state: "在文件 中发现问题 - 配置项 '' 缺少 'place_block' 函数必需的 'block-state' 参数." -warning.config.function.set_food.missing_food: "Issue found in file - The config '' is missing the required 'food' argument for 'set_food' function." -warning.config.function.set_saturation.missing_saturation: "Issue found in file - The config '' is missing the required 'saturation' argument for 'set_saturation' function." -warning.config.function.play_sound.missing_sound: "Issue found in file - The config '' is missing the required 'sound' argument for 'play_sound' function." -warning.config.function.particle.missing_particle: "Issue found in file - The config '' is missing the required 'particle' argument for 'particle' function." -warning.config.function.particle.missing_color: "Issue found in file - The config '' is missing the required 'color' argument for 'particle' function." -warning.config.function.particle.missing_from: "Issue found in file - The config '' is missing the required 'from' argument for 'particle' function." -warning.config.function.particle.missing_to: "Issue found in file - The config '' is missing the required 'to' argument for 'particle' function." -warning.config.function.particle.missing_item: "Issue found in file - The config '' is missing the required 'item' argument for 'particle' function." -warning.config.function.particle.missing_block_state: "Issue found in file - The config '' is missing the required 'block-state' argument for 'particle' function." +warning.config.function.set_food.missing_food: "在文件 中发现问题 - 配置项 '' 缺少 'set_food' 函数必需的 'food' 参数" +warning.config.function.set_saturation.missing_saturation: "在文件 中发现问题 - 配置项 '' 缺少 'set_saturation' 函数必需的 'saturation' 参数" +warning.config.function.play_sound.missing_sound: "在文件 中发现问题 - 配置项 '' 缺少 'play_sound' 函数必需的 'sound' 参数" +warning.config.function.particle.missing_particle: "在文件 中发现问题 - 配置项 '' 缺少 'particle' 函数必需的 'particle' 参数" +warning.config.function.particle.missing_color: "在文件 中发现问题 - 配置项 '' 缺少 'particle' 函数必需的 'color' 参数" +warning.config.function.particle.missing_from: "在文件 中发现问题 - 配置项 '' 缺少 'particle' 函数必需的 'from' 参数" +warning.config.function.particle.missing_to: "在文件 中发现问题 - 配置项 '' 缺少 'particle' 函数必需的 'to' 参数" +warning.config.function.particle.missing_item: "在文件 中发现问题 - 配置项 '' 缺少 'particle' 函数必需的 'item' 参数" +warning.config.function.particle.missing_block_state: "在文件 中发现问题 - 配置项 '' 缺少 'particle' 函数必需的 'block-state' 参数" +warning.config.function.leveler_exp.missing_count: "在文件 中发现问题 - 配置项 '' 缺少 'leveler_exp' 函数必需的 'count' 参数" +warning.config.function.leveler_exp.missing_leveler: "在文件 中发现问题 - 配置项 '' 缺少 'leveler_exp' 函数必需的 'leveler' 参数" +warning.config.function.leveler_exp.missing_plugin: "在文件 中发现问题 - 配置项 '' 缺少 'leveler_exp' 函数必需的 'plugin' 参数" warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" 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 6d5f8f262..72f05d54c 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 @@ -26,7 +26,7 @@ import net.momirealms.craftengine.bukkit.util.EventUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.item.ItemManager; -import net.momirealms.craftengine.core.plugin.CompatibilityManager; +import net.momirealms.craftengine.core.plugin.compatibility.CompatibilityManager; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.classpath.ReflectionClassPathAppender; import net.momirealms.craftengine.core.plugin.command.sender.SenderFactory; 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 index 5e28da9ac..d8980df7b 100644 --- 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 @@ -116,9 +116,9 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { // external model providers Optional externalModel; if (placementArguments.containsKey("model-engine")) { - externalModel = Optional.of(plugin.compatibilityManager().createModelEngineModel(placementArguments.get("model-engine").toString())); + externalModel = Optional.of(plugin.compatibilityManager().createModel("ModelEngine", placementArguments.get("model-engine").toString())); } else if (placementArguments.containsKey("better-model")) { - externalModel = Optional.of(plugin.compatibilityManager().createBetterModelModel(placementArguments.get("better-model").toString())); + externalModel = Optional.of(plugin.compatibilityManager().createModel("BetterModel", placementArguments.get("better-model").toString())); } else { externalModel = Optional.empty(); } 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 df20daeff..cf5e56691 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 @@ -12,6 +12,7 @@ import net.momirealms.craftengine.core.pack.PackManager; 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.compatibility.CompatibilityManager; 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; 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 cbb4feb74..ea2888a6d 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 @@ -11,6 +11,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.compatibility.CompatibilityManager; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.template.TemplateManager; import net.momirealms.craftengine.core.plugin.context.GlobalVariableManager; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CompatibilityManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java similarity index 59% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/CompatibilityManager.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java index 7749be015..5afa56e2b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CompatibilityManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java @@ -1,6 +1,7 @@ -package net.momirealms.craftengine.core.plugin; +package net.momirealms.craftengine.core.plugin.compatibility; import net.momirealms.craftengine.core.entity.furniture.AbstractExternalModel; +import net.momirealms.craftengine.core.entity.furniture.ExternalModel; import net.momirealms.craftengine.core.entity.player.Player; import java.util.UUID; @@ -13,9 +14,13 @@ public interface CompatibilityManager { void onDelayedEnable(); - AbstractExternalModel createModelEngineModel(String id); + void registerLevelerProvider(String plugin, LevelerProvider provider); - AbstractExternalModel createBetterModelModel(String id); + void addLevelerExp(Player player, String plugin, String target, double value); + + int getLevel(Player player, String plugin, String target); + + ExternalModel createModel(String plugin, String id); int interactionToBaseEntity(int id); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/LevelerProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/LevelerProvider.java new file mode 100644 index 000000000..228115d40 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/LevelerProvider.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.plugin.compatibility; + +import net.momirealms.craftengine.core.entity.player.Player; + +public interface LevelerProvider { + + void addExp(Player player, String target, double amount); + + int getLevel(Player player, String target); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/ModelProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/ModelProvider.java new file mode 100644 index 000000000..f636bf857 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/ModelProvider.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.plugin.compatibility; + +import net.momirealms.craftengine.core.entity.furniture.ExternalModel; + +public interface ModelProvider { + + ExternalModel createModel(String id); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index b2ce2de15..bc07135d2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -35,6 +35,7 @@ public class EventFunctions { register(CommonFunctions.PLAY_SOUND, new PlaySoundFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.PARTICLE, new ParticleFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.POTION_EFFECT, new PotionEffectFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.LEVELER_EXP, new LevelerExpFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index e8369e3fa..a1011a396 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -23,5 +23,5 @@ public final class CommonFunctions { public static final Key SET_SATURATION = Key.of("craftengine:saturation"); public static final Key DROP_LOOT = Key.of("craftengine:drop_loot"); public static final Key SWING_HAND = Key.of("craftengine:swing_hand"); - public static final Key PLUGIN_EXP = Key.of("craftengine:plugin_exp"); + public static final Key LEVELER_EXP = Key.of("craftengine:leveler_exp"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java new file mode 100644 index 000000000..4c546ad3b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java @@ -0,0 +1,67 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.*; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class LevelerExpFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; + private final NumberProvider count; + private final String leveler; + private final String plugin; + + public LevelerExpFunction(NumberProvider count, String leveler, String plugin, PlayerSelector selector, List> predicates) { + super(predicates); + this.count = count; + this.leveler = leveler; + this.plugin = plugin; + this.selector = selector; + } + + @Override + public void runInternal(CTX ctx) { + if (this.selector == null) { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { + CraftEngine.instance().compatibilityManager().addLevelerExp(it, this.plugin, this.leveler, this.count.getDouble(ctx)); + }); + } else { + for (Player target : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(target, ContextHolder.EMPTY)); + CraftEngine.instance().compatibilityManager().addLevelerExp(target, this.plugin, this.leveler, this.count.getDouble(relationalContext)); + } + } + } + + @Override + public Key type() { + return CommonFunctions.LEVELER_EXP; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Object count = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("count"), "warning.config.function.leveler_exp.missing_count"); + String leveler = ResourceConfigUtils.requireNonEmptyStringOrThrow("leveler", "warning.config.function.leveler_exp.missing_leveler"); + String plugin = ResourceConfigUtils.requireNonEmptyStringOrThrow("plugin", "warning.config.function.leveler_exp.missing_plugin"); + return new LevelerExpFunction<>(NumberProviders.fromObject(count), leveler, plugin, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); + } + } +} From 35c4e22f2027b98ad85bba6a3b4645c7c0de78aa Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 23 May 2025 04:49:42 +0800 Subject: [PATCH 32/89] =?UTF-8?q?refactor(bukkit):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E5=8F=AF=E8=A7=81=E5=AE=B6=E5=85=B7=E6=95=B0?= =?UTF-8?q?=E9=87=8F=E7=9A=84=E9=99=90=E5=88=B6=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/commands.yml | 7 - bukkit/loader/src/main/resources/config.yml | 4 - .../plugin/command/BukkitCommandManager.java | 3 +- .../SetMaxVisibleFurnitureCommand.java | 36 ---- .../plugin/command/feature/TestCommand.java | 32 +-- .../plugin/network/PacketConsumers.java | 53 +---- .../plugin/user/BukkitServerPlayer.java | 48 ----- .../craftengine/core/plugin/CraftEngine.java | 3 - .../core/plugin/config/Config.java | 12 -- .../core/plugin/network/NetWorkUser.java | 5 - .../core/util/DynamicPriorityTracker.java | 194 ------------------ gradle.properties | 2 +- 12 files changed, 20 insertions(+), 379 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java diff --git a/bukkit/loader/src/main/resources/commands.yml b/bukkit/loader/src/main/resources/commands.yml index 313d117b4..fdf4e1613 100644 --- a/bukkit/loader/src/main/resources/commands.yml +++ b/bukkit/loader/src/main/resources/commands.yml @@ -111,13 +111,6 @@ list_resource: - /craftengine resource list - /ce resource list -set_max_visible_furniture: - enable: false - permission: ce.command.player.set_max_visible_furniture - usage: - - /craftengine feature set-max-visible-furniture - - /ce feature set-max-visible-furniture - # Debug commands debug_set_block: enable: true diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 8d6d19bfe..18053ebc2 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -181,10 +181,6 @@ furniture: # interaction (best performance) # boat (better compatibility with some anti-cheat plugin) collision-entity-type: interaction - # Limit the maximum amount of furniture that players can see by default - max-visible-furniture: - enable: false - amount: 100 emoji: chat: true 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 40cbc68ee..c1f1c3f39 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 @@ -52,8 +52,7 @@ public class BukkitCommandManager extends AbstractCommandManager new DisableResourceCommand(this, plugin), new ListResourceCommand(this, plugin), new UploadPackCommand(this, plugin), - new SendResourcePackCommand(this, plugin), - new SetMaxVisibleFurnitureCommand(this, plugin) + new SendResourcePackCommand(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/SetMaxVisibleFurnitureCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java deleted file mode 100644 index e71b6f43d..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SetMaxVisibleFurnitureCommand.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.momirealms.craftengine.bukkit.plugin.command.feature; - -import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.incendo.cloud.Command; -import org.incendo.cloud.CommandManager; -import org.incendo.cloud.parser.standard.IntegerParser; - -public class SetMaxVisibleFurnitureCommand extends BukkitCommandFeature { - - public SetMaxVisibleFurnitureCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { - super(commandManager, plugin); - } - - @Override - public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { - return builder - .senderType(Player.class) - .required("max", IntegerParser.integerParser(1)) - .handler(context -> { - // 需要找一个更好的存储方案去兼容跨服和在初始化的时候加载 - BukkitServerPlayer cePlayer = plugin().adapt(context.sender()); - Integer max = context.get("max"); - cePlayer.setMaxVisibleFurniture(max, true); - }); - } - - @Override - public String getFeatureID() { - return "set_max_visible_furniture"; - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 00e8c84de..ab1b59966 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,8 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import org.bukkit.Material; @@ -40,27 +38,19 @@ public class TestCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .senderType(Player.class) - // .required("reset", BooleanParser.booleanParser()) - // .required("setTag", NamespacedKeyParser.namespacedKeyParser()) - // .required("targetBlock", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { - // @Override - // public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - // return CompletableFuture.completedFuture(TARGET_BLOCK_SUGGESTIONS); - // } - // })) + .required("reset", BooleanParser.booleanParser()) + .required("setTag", NamespacedKeyParser.namespacedKeyParser()) + .required("targetBlock", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return CompletableFuture.completedFuture(TARGET_BLOCK_SUGGESTIONS); + } + })) .handler(context -> { Player player = context.sender(); - BukkitServerPlayer cePlayer = plugin().adapt(player); - player.sendMessage("visualFurnitureView: " + cePlayer.visualFurnitureView().getTotalMembers()); - player.sendMessage(cePlayer.visualFurnitureView() + "\n==============================="); - // cePlayer.visualFurnitureView().getAllElements().forEach(element -> { - // LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); - // if (furniture == null || !player.canSee(furniture.baseEntity())) { - // cePlayer.visualFurnitureView().removeByEntityId(element.entityId()); - // player.sendMessage("remove: " + element.entityId()); - // } - // }); - // player.sendMessage("visualFurnitureView2: " + cePlayer.visualFurnitureView().getTotalMembers()); + player.sendMessage("开始测试"); + NamespacedKey key = context.get("setTag"); + player.sendMessage("结束测试"); }); } 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 2719be684..66f26b85a 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 @@ -1600,33 +1600,8 @@ public class PacketConsumers { // Furniture BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId); if (furniture != null) { - Player player = (Player) user.platformPlayer(); - List fakeEntityIds = furniture.fakeEntityIds(); - user.entityPacketHandlers().computeIfAbsent(entityId, k -> new FurniturePacketHandler(fakeEntityIds)); - if (Config.enableMaxVisibleFurniture()) { - if (user.visualFurnitureView().getTotalMembers() <= Config.maxVisibleFurniture()) { - user.sendPacket(furniture.spawnPacket(player), false); - } - int[] entityIdsArray = new int[fakeEntityIds.size() + 2]; - entityIdsArray[0] = -114514; - entityIdsArray[1] = entityId; - for (int i = 0; i < fakeEntityIds.size(); i++) { - entityIdsArray[i + 2] = fakeEntityIds.get(i); - } - double distance = furniture.location().distanceSquared(player.getLocation()); - Object removePacket = Reflections.constructor$ClientboundRemoveEntitiesPacket.newInstance(entityIdsArray); - DynamicPriorityTracker.UpdateResult result = user.visualFurnitureView().addOrUpdateElement(new DynamicPriorityTracker.Element(entityId, distance, removePacket)); - for (DynamicPriorityTracker.Element element : result.getEntered()) { - BukkitFurniture updateFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); - if (updateFurniture == null || !updateFurniture.isValid()) continue; - user.sendPacket(updateFurniture.spawnPacket(player), false); - } - for (DynamicPriorityTracker.Element element : result.getExited()) { - user.sendPacket(element.removePacket(), false); - } - } else { - user.sendPacket(furniture.spawnPacket(player), false); - } + user.entityPacketHandlers().computeIfAbsent(entityId, k -> new FurniturePacketHandler(furniture.fakeEntityIds())); + user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { event.setCancelled(true); } @@ -1668,25 +1643,11 @@ public class PacketConsumers { FriendlyByteBuf buf = event.getBuffer(); boolean isChange = false; IntList intList = buf.readIntIdList(); - int first = intList.getFirst(); - if (first != -114514) { - for (int i = 0, size = intList.size(); i < size; i++) { - int entityId = intList.getInt(i); - EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); - if (handler != null && handler.handleEntitiesRemove(intList)) { - user.visualFurnitureView().removeByEntityId(entityId); - isChange = true; - } - } - } else { - intList.removeFirst(); - isChange = true; - for (int i = 0, size = intList.size(); i < size; i++) { - int entityId = intList.getInt(i); - EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); - if (handler != null) { - handler.handleEntitiesRemove(intList); - } + for (int i = 0, size = intList.size(); i < size; i++) { + int entityId = intList.getInt(i); + EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); + if (handler != null && handler.handleEntitiesRemove(intList)) { + isChange = true; } } if (isChange) { 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 b04238a43..40fac266a 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 @@ -4,8 +4,6 @@ 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.entity.furniture.BukkitFurniture; -import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -25,7 +23,6 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; import net.momirealms.craftengine.core.util.Direction; -import net.momirealms.craftengine.core.util.DynamicPriorityTracker; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; @@ -40,7 +37,6 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; -import org.bukkit.persistence.PersistentDataType; import org.bukkit.util.RayTraceResult; import org.jetbrains.annotations.Nullable; @@ -50,7 +46,6 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class BukkitServerPlayer extends Player { - public static final NamespacedKey MAX_VISIBLE_FURNITURE_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:max_visible_furniture")); private final BukkitCraftEngine plugin; // handshake private ProtocolVersion protocolVersion = ProtocolVersion.UNKNOWN; @@ -99,10 +94,8 @@ public class BukkitServerPlayer extends Player { // cache interaction range here private int lastUpdateInteractionRangeTick; private double cachedInteractionRange; - private Integer maxVisibleFurniture = -1; private final Map entityTypeView = new ConcurrentHashMap<>(); - private final DynamicPriorityTracker visualFurnitureView = new DynamicPriorityTracker(); public BukkitServerPlayer(BukkitCraftEngine plugin, Channel channel) { this.channel = channel; @@ -114,9 +107,6 @@ public class BukkitServerPlayer extends Player { this.serverPlayerRef = new WeakReference<>(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)); this.uuid = player.getUniqueId(); this.name = player.getName(); - this.maxVisibleFurniture = player.getPersistentDataContainer() - .getOrDefault(MAX_VISIBLE_FURNITURE_KEY, PersistentDataType.INTEGER, -1); - this.visualFurnitureView.setMaxVisibleFurniture(this.maxVisibleFurniture); } @Override @@ -353,7 +343,6 @@ public class BukkitServerPlayer extends Player { } if (this.gameTicks % 30 == 0) { this.updateGUI(); - this.updateVisualFurnitureView(); } if (this.isDestroyingBlock) { this.tickBlockDestroy(); @@ -378,26 +367,6 @@ public class BukkitServerPlayer extends Player { } } - private void updateVisualFurnitureView() { - if (!Config.enableMaxVisibleFurniture()) return; - if (visualFurnitureView().getTotalMembers() <= Config.maxVisibleFurniture()) return; - for (DynamicPriorityTracker.Element element : visualFurnitureView().getAllElements()) { - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(element.entityId()); - if (furniture == null || !furniture.isValid()) continue; - double distance = furniture.location().distanceSquared(platformPlayer().getLocation()); - DynamicPriorityTracker.Element newElement = new DynamicPriorityTracker.Element(element.entityId(), distance, element.removePacket()); - DynamicPriorityTracker.UpdateResult result = visualFurnitureView().addOrUpdateElement(newElement); - for (DynamicPriorityTracker.Element resultElement : result.getEntered()) { - BukkitFurniture updateFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(resultElement.entityId()); - if (updateFurniture == null || !updateFurniture.isValid()) continue; - sendPacket(updateFurniture.spawnPacket(platformPlayer()), false); - } - for (DynamicPriorityTracker.Element resultElement : result.getExited()) { - sendPacket(resultElement.removePacket(), false); - } - } - } - @Override public float getDestroyProgress(Object blockState, BlockPos pos) { return FastNMS.INSTANCE.method$BlockStateBase$getDestroyProgress(blockState, serverPlayer(), FastNMS.INSTANCE.field$CraftWorld$ServerLevel(platformPlayer().getWorld()), LocationUtils.toBlockPos(pos)); @@ -773,23 +742,6 @@ public class BukkitServerPlayer extends Player { return this.entityTypeView; } - @Override - public DynamicPriorityTracker visualFurnitureView() { - return this.visualFurnitureView; - } - - @Override - public void setMaxVisibleFurniture(int maxVisibleFurniture, boolean fromCommand) { - if (fromCommand) { - platformPlayer().getPersistentDataContainer() - .set(MAX_VISIBLE_FURNITURE_KEY, PersistentDataType.INTEGER, maxVisibleFurniture); - this.maxVisibleFurniture = maxVisibleFurniture; - } - this.visualFurnitureView.setMaxVisibleFurniture( - this.maxVisibleFurniture == -1 ? maxVisibleFurniture : this.maxVisibleFurniture - ); - } - public void setResendSound() { resentSoundTick = gameTicks(); } 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 96d399ae3..304a9abed 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,9 +132,6 @@ public abstract class CraftEngine implements Plugin { long time1 = System.currentTimeMillis(); // firstly reload main config this.config.load(); - for (Player player : this.networkManager().onlineUsers()) { - player.setMaxVisibleFurniture(Config.maxVisibleFurniture(), false); - } // reset debugger this.debugger = Config.debug() ? (s) -> logger.info("[Debug] " + s.get()) : (s) -> {}; // now we reload the translations 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 6099fd69d..be96fe1ed 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 @@ -110,8 +110,6 @@ public class Config { protected Map furniture$handle_invalid_furniture_on_chunk_load$mapping; protected boolean furniture$hide_base_entity; protected ColliderType furniture$collision_entity_type; - protected boolean furniture$max_visible_furniture_enable; - protected int furniture$max_visible_furniture_amount; protected boolean block$sound_system$enable; protected boolean block$simplify_adventure_break_check; @@ -302,8 +300,6 @@ public class Config { furniture$handle_invalid_furniture_on_chunk_load$mapping = builder.build(); furniture$hide_base_entity = config.getBoolean("furniture.hide-base-entity", true); furniture$collision_entity_type = ColliderType.valueOf(config.getString("furniture.collision-entity-type", "interaction").toUpperCase(Locale.ENGLISH)); - furniture$max_visible_furniture_enable = config.getBoolean("furniture.max-visible-furniture.enable", false); - furniture$max_visible_furniture_amount = config.getInt("furniture.max-visible-furniture.amount", 100); // block block$sound_system$enable = config.getBoolean("block.sound-system.enable", true); @@ -421,14 +417,6 @@ public class Config { return instance.resource_pack$supported_version$min; } - public static boolean enableMaxVisibleFurniture() { - return instance.furniture$max_visible_furniture_enable; - } - - public static int maxVisibleFurniture() { - return instance.furniture$max_visible_furniture_amount; - } - public static float packMaxVersion() { return instance.resource_pack$supported_version$max; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index a0283efab..cf9442fee 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.plugin.network; import io.netty.channel.Channel; import net.momirealms.craftengine.core.plugin.Plugin; -import net.momirealms.craftengine.core.util.DynamicPriorityTracker; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.ApiStatus; @@ -44,10 +43,6 @@ public interface NetWorkUser { Map entityPacketHandlers(); - DynamicPriorityTracker visualFurnitureView(); - - void setMaxVisibleFurniture(int maxVisibleFurniture, boolean fromCommand); - boolean clientModEnabled(); void setClientModState(boolean enable); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java b/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java deleted file mode 100644 index f538a6269..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/DynamicPriorityTracker.java +++ /dev/null @@ -1,194 +0,0 @@ -package net.momirealms.craftengine.core.util; - -import net.momirealms.craftengine.core.plugin.config.Config; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantLock; - -public class DynamicPriorityTracker { - - public static class Element { - private final int entityId; - private volatile double distance; - private final Object removePacket; - - public Element(int entityId, double distance, Object removePacket) { - this.entityId = entityId; - this.distance = distance; - this.removePacket = removePacket; - } - - public int entityId() { - return entityId; - } - public double distance() { - return distance; - } - public void setDistance(double distance) { - this.distance = distance; - } - public Object removePacket() { - return removePacket; - } - - @Override - public String toString() { - return "Element{" + - "entityId=" + entityId + - ", distance=" + distance + - ", removePacket=" + removePacket + - '}'; - } - } - - public static class UpdateResult { - private final List entered = new ArrayList<>(); - private final List exited = new ArrayList<>(); - - public List getEntered() { - return entered; - } - public List getExited() { - return exited; - } - - void addEntered(Element e) { - entered.add(e); - } - void addExited(Element e) { - exited.add(e); - } - - @Override - public String toString() { - return "UpdateResult{" + - "entered=" + entered + - ", exited=" + exited + - '}'; - } - } - - private Integer maxVisibleFurniture; - private final PriorityQueue maxHeap; - private final Map elementMap = new ConcurrentHashMap<>(); - private final Set inHeapSet = ConcurrentHashMap.newKeySet(); - private final ReentrantLock heapLock = new ReentrantLock(); - - public DynamicPriorityTracker() { - this.maxVisibleFurniture = Config.maxVisibleFurniture(); - this.maxHeap = new PriorityQueue<>((a, b) -> Double.compare(b.distance, a.distance)); - } - - public void setMaxVisibleFurniture(int maxVisibleFurniture) { - this.maxVisibleFurniture = maxVisibleFurniture; - } - - public UpdateResult addOrUpdateElement(Element newElement) { - UpdateResult result = new UpdateResult(); - heapLock.lock(); - try { - Element existing = elementMap.get(newElement.entityId); - - if (existing != null) { - return handleExistingElement(existing, newElement, result); - } else { - return handleNewElement(newElement, result); - } - } finally { - heapLock.unlock(); - } - } - - private UpdateResult handleNewElement(Element newElement, UpdateResult result) { - elementMap.put(newElement.entityId, newElement); - - if (maxHeap.size() < maxVisibleFurniture) { - maxHeap.offer(newElement); - inHeapSet.add(newElement.entityId); - result.addEntered(newElement); - } else if (maxHeap.peek() != null && newElement.distance < maxHeap.peek().distance) { - Element removed = maxHeap.poll(); - inHeapSet.remove(removed.entityId); - result.addExited(removed); - - maxHeap.offer(newElement); - inHeapSet.add(newElement.entityId); - result.addEntered(newElement); - } - return result; - } - - private UpdateResult handleExistingElement(Element existing, Element newElement, UpdateResult result) { - existing.setDistance(newElement.distance); - - boolean wasInHeap = inHeapSet.contains(existing.entityId); - boolean nowInHeap = checkIfShouldBeInHeap(existing.distance); - - if (wasInHeap) { - maxHeap.remove(existing); - maxHeap.offer(existing); - } else if (nowInHeap) { - if (maxHeap.size() < maxVisibleFurniture) { - maxHeap.offer(existing); - inHeapSet.add(existing.entityId); - result.addEntered(existing); - } else if (maxHeap.peek() != null && existing.distance < maxHeap.peek().distance) { - Element removed = maxHeap.poll(); - inHeapSet.remove(removed.entityId); - result.addExited(removed); - - maxHeap.offer(existing); - inHeapSet.add(existing.entityId); - result.addEntered(existing); - } - } - return result; - } - - private boolean checkIfShouldBeInHeap(double distance) { - if (maxHeap.size() < maxVisibleFurniture) return true; - return maxHeap.peek() != null && distance < maxHeap.peek().distance; - } - - public int getTotalMembers() { - heapLock.lock(); - try { - return elementMap.size(); - } finally { - heapLock.unlock(); - } - } - - public List getAllElements() { - heapLock.lock(); - try { - return List.copyOf(elementMap.values()); - } finally { - heapLock.unlock(); - } - } - - public void removeByEntityId(int entityId) { - heapLock.lock(); - try { - Element removed = elementMap.remove(entityId); - if (removed != null) { - maxHeap.remove(removed); - inHeapSet.remove(entityId); - } - } finally { - heapLock.unlock(); - } - } - - @Override - public String toString() { - return "DynamicPriorityTracker{" + - "maxHeap=" + maxHeap + - ", elementMap=" + elementMap + - ", inHeapSet=" + inHeapSet + - ", heapLock=" + heapLock + - '}'; - } -} diff --git a/gradle.properties b/gradle.properties index afbc44234..c17776f19 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] project_version=0.0.54.6 -config_version=34 +config_version=33 lang_version=13 project_group=net.momirealms latest_supported_version=1.21.5 From 4624d57cc4ed7388d1b3a30ffd1ec7cf29b8b73d Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 23 May 2025 04:51:13 +0800 Subject: [PATCH 33/89] =?UTF-8?q?refactor(bukkit):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E5=8F=AF=E8=A7=81=E5=AE=B6=E5=85=B7=E6=95=B0?= =?UTF-8?q?=E9=87=8F=E7=9A=84=E9=99=90=E5=88=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/net/momirealms/craftengine/core/plugin/CraftEngine.java | 1 - 1 file changed, 1 deletion(-) 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 c24dc315a..cf5e56691 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 @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.plugin; import net.momirealms.craftengine.core.advancement.AdvancementManager; 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.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.item.ItemManager; From 1edafae8247072cdf8c0c129ed92ebcbfd2f380c Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 23 May 2025 04:56:44 +0800 Subject: [PATCH 34/89] =?UTF-8?q?fix(bukkit):=20=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=E4=B8=8D=E4=BC=9A=E5=86=85=E5=AD=98=E6=B3=84=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/entity/projectile/BukkitProjectileManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java index 9fb5c698f..1bc6d280d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java @@ -64,6 +64,11 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { handleProjectileLoad(event.getEntity()); } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onEntityPortal(EntityPortalEvent event) { + this.projectiles.remove(event.getEntity().getEntityId()); + } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) public void onEntityAdd(EntityAddToWorldEvent event) { if (event.getEntity() instanceof Projectile projectile) { From da567115ede474ae7275602ffc3d0b743912dc05 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 23 May 2025 05:04:12 +0800 Subject: [PATCH 35/89] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dtags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/default/configuration/plants.yml | 1 + .../craftengine/bukkit/util/Reflections.java | 1 - .../craftengine/bukkit/util/TagUtils.java | 15 +++++++++------ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 89e99122c..953afbe86 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -248,6 +248,7 @@ blocks: - type: set_count add: true count: -1 + - type: swing_hand states: properties: age: 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 a8a39911e..22c58dbbf 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 @@ -88,7 +88,6 @@ public class Reflections { ) ); - public static final Class clazz$ClientboundSetActionBarTextPacket = requireNonNull( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundSetActionBarTextPacket") diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java index 28e6e971e..530ccc248 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/TagUtils.java @@ -43,11 +43,14 @@ public final class TagUtils { public static Object createUpdateTagsPacket(Map> tags) { Map registriesNetworkPayload = (Map) FastNMS.INSTANCE.method$TagNetworkSerialization$serializeTagsToNetwork(); Map modified = new HashMap<>(); - for (Map.Entry> entry : tags.entrySet()) { - Object existingPayload = registriesNetworkPayload.get(entry.getKey()); - if (existingPayload == null) continue; + for (Map.Entry payload : registriesNetworkPayload.entrySet()) { + List overrides = tags.get(payload.getKey()); + if (overrides == null || overrides.isEmpty()) { + modified.put(payload.getKey(), payload.getValue()); + continue; + } FriendlyByteBuf deserializeBuf = new FriendlyByteBuf(Unpooled.buffer()); - FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$write(existingPayload, deserializeBuf); + FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$write(payload.getValue(), deserializeBuf); Map originalTags = deserializeBuf.readMap( FriendlyByteBuf::readUtf, FriendlyByteBuf::readIntIdList @@ -58,7 +61,7 @@ public final class TagUtils { reversedTags.computeIfAbsent(id, k -> new ArrayList<>()).add(tagEntry.getKey()); } } - for (TagEntry tagEntry : entry.getValue()) { + for (TagEntry tagEntry : overrides) { reversedTags.remove(tagEntry.id); for (String tag : tagEntry.tags) { reversedTags.computeIfAbsent(tagEntry.id, k -> new ArrayList<>()).add(tag); @@ -76,7 +79,7 @@ public final class TagUtils { FriendlyByteBuf::writeIntIdList ); Object mergedPayload = FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$read(serializeBuf); - modified.put(entry.getKey(), mergedPayload); + modified.put(payload.getKey(), mergedPayload); } return FastNMS.INSTANCE.constructor$ClientboundUpdateTagsPacket(modified); } From 70572717c25bdf74b6802b62495452624b588a06 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 23 May 2025 05:10:31 +0800 Subject: [PATCH 36/89] .7 --- .../entity/projectile/BukkitProjectileManager.java | 9 +++++++++ gradle.properties | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java index 1bc6d280d..e087909c1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java @@ -76,6 +76,15 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { } } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onEntitiesLoad(EntitiesLoadEvent event) { + for (Entity entity : event.getEntities()) { + if (entity instanceof Projectile projectile) { + handleProjectileLoad(projectile); + } + } + } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) public void onEntityRemove(EntityRemoveFromWorldEvent event) { this.projectiles.remove(event.getEntity().getEntityId()); diff --git a/gradle.properties b/gradle.properties index c17776f19..03cc96751 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.54.6 +project_version=0.0.54.7 config_version=33 lang_version=13 project_group=net.momirealms From 5ce44d6cda1a7edba3241179569f9ac8be9fb26f Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 23 May 2025 05:18:34 +0800 Subject: [PATCH 37/89] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B8=B8=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E5=8C=BA=E5=9D=97=E5=BC=B9=E5=B0=84=E7=89=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/projectile/BukkitProjectileManager.java | 10 ++++++++++ .../craftengine/fabric/client/config/ModConfig.java | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java index e087909c1..0b63e8dc9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java @@ -17,6 +17,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; +import org.bukkit.World; import org.bukkit.entity.*; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -29,6 +30,7 @@ import org.bukkit.event.world.EntitiesLoadEvent; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -47,6 +49,14 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { @Override public void delayedInit() { Bukkit.getPluginManager().registerEvents(this, this.plugin.bootstrap()); + for (World world : Bukkit.getWorlds()) { + List entities = world.getEntities(); + for (Entity entity : entities) { + if (entity instanceof Projectile projectile) { + handleProjectileLoad(projectile); + } + } + } } @Override diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java index dc6689b15..085b3371a 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java @@ -18,7 +18,7 @@ import java.nio.file.Path; public class ModConfig { private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("craft-engine-fabric-mod/config.yml"); public static boolean enableNetwork = false; - public static boolean enableCancelBlockUpdate = false; + public static boolean enableCancelBlockUpdate = true; public static Screen getConfigScreen(Screen parent) { ConfigBuilder builder = ConfigBuilder.create() From ce55fceb16b563154828baef16484768b8c36426 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 23 May 2025 05:36:04 +0800 Subject: [PATCH 38/89] =?UTF-8?q?=E8=BF=9C=E7=A6=BBawssdk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/build.gradle.kts | 5 +- .../core/pack/host/impl/S3Host.java | 235 ------------------ 2 files changed, 2 insertions(+), 238 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3Host.java diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 2ddde0188..b4b762304 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -52,13 +52,12 @@ dependencies { compileOnly("com.mojang:datafixerupper:${rootProject.properties["datafixerupper_version"]}") // Aho-Corasick java implementation compileOnly("org.ahocorasick:ahocorasick:${rootProject.properties["ahocorasick_version"]}") - // Amazon S3 - compileOnly("software.amazon.awssdk:s3:${rootProject.properties["amazon_awssdk_version"]}") - compileOnly("software.amazon.awssdk:netty-nio-client:${rootProject.properties["amazon_awssdk_version"]}") // EvalEx compileOnly("com.ezylang:EvalEx:${rootProject.properties["evalex_version"]}") // Jimfs compileOnly("com.google.jimfs:jimfs:${rootProject.properties["jimfs_version"]}") + // S3 + implementation("net.momirealms:craft-engine-s3:0.1") } java { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3Host.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3Host.java deleted file mode 100644 index 21f20a97d..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3Host.java +++ /dev/null @@ -1,235 +0,0 @@ -package net.momirealms.craftengine.core.pack.host.impl; - -import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; -import net.momirealms.craftengine.core.pack.host.ResourcePackHost; -import net.momirealms.craftengine.core.pack.host.ResourcePackHostFactory; -import net.momirealms.craftengine.core.pack.host.ResourcePackHosts; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.locale.LocalizedException; -import net.momirealms.craftengine.core.util.HashUtils; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; -import software.amazon.awssdk.auth.signer.AwsS3V4Signer; -import software.amazon.awssdk.core.async.AsyncRequestBody; -import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; -import software.amazon.awssdk.http.async.SdkAsyncHttpClient; -import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient; -import software.amazon.awssdk.http.nio.netty.ProxyConfiguration; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.s3.S3AsyncClient; -import software.amazon.awssdk.services.s3.S3AsyncClientBuilder; -import software.amazon.awssdk.services.s3.model.HeadObjectRequest; -import software.amazon.awssdk.services.s3.model.NoSuchKeyException; -import software.amazon.awssdk.services.s3.model.PutObjectRequest; -import software.amazon.awssdk.services.s3.presigner.S3Presigner; -import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest; - -import java.net.URI; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.time.Duration; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; - -public class S3Host implements ResourcePackHost { - public static final Factory FACTORY = new Factory(); - private final S3AsyncClient s3AsyncClient; - private final S3Presigner preSigner; - private final String bucket; - private final String uploadPath; - private final String cdnDomain; - private final String cdnProtocol; - private final Duration validity; - - public S3Host( - S3AsyncClient s3AsyncClient, - S3Presigner preSigner, - String bucket, - String uploadPath, - String cdnDomain, - String cdnProtocol, - Duration validity - ) { - this.s3AsyncClient = s3AsyncClient; - this.preSigner = preSigner; - this.bucket = bucket; - this.uploadPath = uploadPath; - this.cdnDomain = cdnDomain; - this.cdnProtocol = cdnProtocol; - this.validity = validity; - } - - @Override - public boolean canUpload() { - return true; - } - - @Override - public Key type() { - return ResourcePackHosts.S3; - } - - @Override - public CompletableFuture> requestResourcePackDownloadLink(UUID player) { - return this.s3AsyncClient.headObject(HeadObjectRequest.builder() - .bucket(this.bucket) - .key(this.uploadPath) - .build()) - .handle((headResponse, exception) -> { - if (exception != null) { - Throwable cause = exception.getCause(); - if (cause instanceof NoSuchKeyException) { - CraftEngine.instance().logger().warn("[S3] Resource pack not found in bucket '" + this.bucket + "'. Path: " + this.uploadPath); - return Collections.emptyList(); - } else { - CraftEngine.instance().logger().warn( - "[S3] Failed to retrieve resource pack metadata. Reason: " + - cause.getClass().getSimpleName() + " - " + cause.getMessage() - ); - throw new CompletionException("Metadata request failed for path: " + this.uploadPath, cause); - } - } - String sha1 = headResponse.metadata().get("sha1"); - if (sha1 == null) { - CraftEngine.instance().logger().warn("[S3] Missing SHA-1 checksum in object metadata. Path: " + this.uploadPath); - throw new CompletionException(new IllegalStateException("Missing SHA-1 metadata for S3 object: " + this.uploadPath)); - } - GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder() - .signatureDuration(this.validity) - .getObjectRequest(b -> b.bucket(this.bucket).key(this.uploadPath)) - .build(); - return Collections.singletonList( - ResourcePackDownloadData.of( - replaceWithCdnUrl(this.preSigner.presignGetObject(presignRequest).url()), - UUID.nameUUIDFromBytes(sha1.getBytes(StandardCharsets.UTF_8)), - sha1 - ) - ); - }); - } - - @Override - public CompletableFuture upload(Path resourcePackPath) { - String sha1 = HashUtils.calculateLocalFileSha1(resourcePackPath); - PutObjectRequest putObjectRequest = PutObjectRequest.builder() - .bucket(this.bucket) - .key(this.uploadPath) - .metadata(Map.of("sha1", sha1)) - .build(); - long uploadStart = System.currentTimeMillis(); - CraftEngine.instance().logger().info("[S3] Initiating resource pack upload to '" + this.uploadPath + "'"); - return this.s3AsyncClient.putObject(putObjectRequest, AsyncRequestBody.fromFile(resourcePackPath)) - .handle((response, exception) -> { - if (exception != null) { - Throwable cause = exception instanceof CompletionException ? - exception.getCause() : - exception; - CraftEngine.instance().logger().warn( - "[S3] Upload failed for path '" + this.uploadPath + "'. Error: " + - cause.getClass().getSimpleName() + " - " + cause.getMessage() - ); - throw new CompletionException("Failed to upload to S3 path: " + this.uploadPath, cause); - } - CraftEngine.instance().logger().info( - "[S3] Successfully uploaded resource pack to '" + this.uploadPath + "' in " + - (System.currentTimeMillis() - uploadStart) + " ms" - ); - return null; - }); - } - - private String replaceWithCdnUrl(URL originalUrl) { - if (this.cdnDomain == null) return originalUrl.toString(); - return this.cdnProtocol + "://" + this.cdnDomain - + originalUrl.getPath() - + (originalUrl.getQuery() != null ? "?" + originalUrl.getQuery() : ""); - } - - public static class Factory implements ResourcePackHostFactory { - - @Override - @SuppressWarnings("deprecation") - public ResourcePackHost create(Map arguments) { - boolean useEnv = (boolean) arguments.getOrDefault("use-environment-variables", false); - String endpoint = Optional.ofNullable(arguments.get("endpoint")).map(String::valueOf).orElse(null); - if (endpoint == null || endpoint.isEmpty()) { - throw new LocalizedException("warning.config.host.s3.missing_endpoint"); - } - String protocol = arguments.getOrDefault("protocol", "https").toString(); - boolean usePathStyle = (boolean) arguments.getOrDefault("path-style", false); - String bucket = Optional.ofNullable(arguments.get("bucket")).map(String::valueOf).orElse(null); - if (bucket == null || bucket.isEmpty()) { - throw new LocalizedException("warning.config.host.s3.missing_bucket"); - } - String region = arguments.getOrDefault("region", "auto").toString(); - String accessKeyId = useEnv ? System.getenv("CE_S3_ACCESS_KEY_ID") : Optional.ofNullable(arguments.get("access-key-id")).map(String::valueOf).orElse(null); - if (accessKeyId == null || accessKeyId.isEmpty()) { - throw new LocalizedException("warning.config.host.s3.missing_access_key"); - } - String accessKeySecret = useEnv ? System.getenv("CE_S3_ACCESS_KEY_SECRET") : Optional.ofNullable(arguments.get("access-key-secret")).map(String::valueOf).orElse(null); - if (accessKeySecret == null || accessKeySecret.isEmpty()) { - throw new LocalizedException("warning.config.host.s3.missing_secret"); - } - String uploadPath = arguments.getOrDefault("upload-path", "craftengine/resource_pack.zip").toString(); - if (uploadPath == null || uploadPath.isEmpty()) { - throw new LocalizedException("warning.config.host.s3.missing_upload_path"); - } - boolean useLegacySignature = (boolean) arguments.getOrDefault("use-legacy-signature", true); - Duration validity = Duration.ofSeconds((int) arguments.getOrDefault("validity", 10)); - - Map cdn = MiscUtils.castToMap(arguments.get("cdn"), true); - String cdnDomain = null; - String cdnProtocol = "https"; - if (cdn != null) { - cdnDomain = Optional.ofNullable(arguments.get("domain")).map(String::valueOf).orElse(null); - cdnProtocol = arguments.getOrDefault("protocol", "https").toString(); - } - - AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKeyId, accessKeySecret); - - S3AsyncClientBuilder s3AsyncClientBuilder = S3AsyncClient.builder() - .endpointOverride(URI.create(protocol + "://" + endpoint)) - .region(Region.of(region)) - .credentialsProvider(StaticCredentialsProvider.create(credentials)) - .serviceConfiguration(b -> b.pathStyleAccessEnabled(usePathStyle)); - - if (useLegacySignature) { - s3AsyncClientBuilder.overrideConfiguration(b -> b - .putAdvancedOption(SdkAdvancedClientOption.SIGNER, AwsS3V4Signer.create()) - ); - } - - Map proxySetting = MiscUtils.castToMap(arguments.get("proxy"), true); - if (proxySetting != null) { - String host = ResourceConfigUtils.requireNonEmptyStringOrThrow(proxySetting.get("host"), () -> new LocalizedException("warning.config.host.proxy.missing_host")); - int port = ResourceConfigUtils.getAsInt(proxySetting.get("port"), "port"); - if (port <= 0 || port > 65535) { - throw new LocalizedException("warning.config.host.proxy.missing_port"); - } - String scheme = ResourceConfigUtils.requireNonEmptyStringOrThrow(proxySetting.get("scheme"), () -> new LocalizedException("warning.config.host.proxy.missing_scheme")); - String username = Optional.ofNullable(proxySetting.get("username")).map(String::valueOf).orElse(null); - String password = Optional.ofNullable(proxySetting.get("password")).map(String::valueOf).orElse(null); - ProxyConfiguration.Builder builder = ProxyConfiguration.builder().host(host).port(port).scheme(scheme); - if (username != null) builder.username(username); - if (password != null) builder.password(password); - SdkAsyncHttpClient httpClient = NettyNioAsyncHttpClient.builder().proxyConfiguration(builder.build()).build(); - s3AsyncClientBuilder.httpClient(httpClient); - } - - S3AsyncClient s3AsyncClient = s3AsyncClientBuilder.build(); - - S3Presigner preSigner = S3Presigner.builder() - .endpointOverride(URI.create(protocol + "://" + endpoint)) - .region(Region.of(region)) - .credentialsProvider(StaticCredentialsProvider.create(credentials)) - .build(); - - return new S3Host(s3AsyncClient, preSigner, bucket, uploadPath, cdnDomain, cdnProtocol, validity); - } - } -} \ No newline at end of file From 0d41230dd9c0e7d783a5b13e97f20b84b0545b27 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 23 May 2025 06:16:44 +0800 Subject: [PATCH 39/89] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=B8=89=E5=8F=89=E6=88=9F=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/momirealms/craftengine/core/plugin/CraftEngine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 cf5e56691..c9c1be83b 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 @@ -222,7 +222,6 @@ public abstract class CraftEngine implements Plugin { this.fontManager.delayedInit(); this.vanillaLootManager.delayedInit(); this.advancementManager.delayedInit(); - this.projectileManager.delayedInit(); // reload the plugin try { this.reloadPlugin(Runnable::run, Runnable::run, true); @@ -230,6 +229,7 @@ public abstract class CraftEngine implements Plugin { this.logger.warn("Failed to reload plugin on enable stage", e); } // must be after reloading because this process loads furniture + this.projectileManager.delayedInit(); this.worldManager.delayedInit(); this.furnitureManager.delayedInit(); // set up some platform extra tasks From 2cf856028c1a1292a1b8f4e81815b520c741d179 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 23 May 2025 19:10:36 +0800 Subject: [PATCH 40/89] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=90=8D=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BlockEventListener.java | 4 +- .../block/behavior/CropBlockBehavior.java | 2 +- .../item/listener/ItemEventListener.java | 6 +- .../core/block/BlockStateHolder.java | 36 +++++----- .../core/block/ImmutableBlockState.java | 2 +- .../core/block/VanillaBlockState.java | 23 ++++++- .../core/pack/AbstractPackManager.java | 66 +++++-------------- .../MatchBlockPropertyCondition.java | 2 +- .../parameter/BlockParameterProvider.java | 2 +- .../parameter/DirectContextParameters.java | 2 +- 10 files changed, 67 insertions(+), 78 deletions(-) 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 436a2d9df..042c1d32f 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 @@ -168,7 +168,7 @@ public class BlockEventListener implements Listener { Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) - .withParameter(DirectContextParameters.BLOCK_STATE, state) + .withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state) .withParameter(DirectContextParameters.EVENT, cancellable) .withParameter(DirectContextParameters.POSITION, position) .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) @@ -304,7 +304,7 @@ public class BlockEventListener implements Listener { .withParameter(DirectContextParameters.EVENT, cancellable) .withParameter(DirectContextParameters.POSITION, new WorldPosition(new BukkitWorld(event.getWorld()), LocationUtils.toVec3d(location))) .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) - .withParameter(DirectContextParameters.BLOCK_STATE, state) + .withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state) ), EventTrigger.STEP); if (cancellable.isCancelled()) { event.setCancelled(true); 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 29b2f7e4e..a8d14c48f 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 @@ -149,7 +149,7 @@ public class CropBlockBehavior extends BushBlockBehavior { int i = this.getAge(immutableBlockState) + this.boneMealBonus.getInt( SimpleContext.of( ContextHolder.builder() - .withParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, immutableBlockState) .withParameter(DirectContextParameters.POSITION, new WorldPosition(new BukkitWorld(world), Vec3d.atCenterOf(new Vec3i(x, y, z)))) .build() ) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index 1ac765bcd..50fd9bd38 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -101,7 +101,7 @@ public class ItemEventListener implements Listener { CustomBlock customBlock = immutableBlockState.owner().value(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) - .withParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, immutableBlockState) .withParameter(DirectContextParameters.HAND, hand) .withParameter(DirectContextParameters.EVENT, dummy) .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation())) @@ -175,7 +175,7 @@ public class ItemEventListener implements Listener { Cancellable dummy = Cancellable.dummy(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) - .withOptionalParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withOptionalParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, immutableBlockState) .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation())) .withParameter(DirectContextParameters.HAND, hand) @@ -219,7 +219,7 @@ public class ItemEventListener implements Listener { Cancellable dummy = Cancellable.dummy(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) - .withOptionalParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withOptionalParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, immutableBlockState) .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation())) .withParameter(DirectContextParameters.HAND, hand) diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java index 7d9c265b3..445f9c518 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java @@ -19,7 +19,7 @@ public class BlockStateHolder { } public Holder owner() { - return owner; + return this.owner; } public > ImmutableBlockState cycle(Property property) { @@ -38,14 +38,14 @@ public class BlockStateHolder { @Override public String toString() { - if (propertyMap.isEmpty()) { - return owner.value().id().toString(); + if (this.propertyMap.isEmpty()) { + return this.owner.value().id().toString(); } - return owner.value().id() + "[" + getPropertiesAsString() + "]"; + return this.owner.value().id() + "[" + getPropertiesAsString() + "]"; } public String getPropertiesAsString() { - return propertyMap.entrySet().stream() + return this.propertyMap.entrySet().stream() .map(entry -> { Property property = entry.getKey(); return property.name() + "=" + Property.formatValue(property, entry.getValue()); @@ -54,17 +54,17 @@ public class BlockStateHolder { } public Collection> getProperties() { - return Collections.unmodifiableSet(propertyMap.keySet()); + return Collections.unmodifiableSet(this.propertyMap.keySet()); } public > boolean contains(Property property) { - return propertyMap.containsKey(property); + return this.propertyMap.containsKey(property); } public > T get(Property property) { T value = getNullable(property); if (value == null) { - throw new IllegalArgumentException("Property " + property + " not found in " + owner.value().id()); + throw new IllegalArgumentException("Property " + property + " not found in " + this.owner.value().id()); } return value; } @@ -75,19 +75,19 @@ public class BlockStateHolder { @Nullable public > T getNullable(Property property) { - Comparable value = propertyMap.get(property); + Comparable value = this.propertyMap.get(property); return value != null ? property.valueClass().cast(value) : null; } public , V extends T> ImmutableBlockState with(Property property, V value) { - if (!propertyMap.containsKey(property)) { - throw new IllegalArgumentException("Property " + property + " not found in " + owner.value().id()); + if (!this.propertyMap.containsKey(property)) { + throw new IllegalArgumentException("Property " + property + " not found in " + this.owner.value().id()); } return withInternal(property, value); } private , V extends T> ImmutableBlockState withInternal(Property property, V newValue) { - if (newValue.equals(propertyMap.get(property))) { + if (newValue.equals(this.propertyMap.get(property))) { return (ImmutableBlockState) this; } @@ -96,20 +96,20 @@ public class BlockStateHolder { throw new IllegalArgumentException("Invalid value " + newValue + " for property " + property); } - return withMap.get(property)[index]; + return this.withMap.get(property)[index]; } public void createWithMap(Map, Comparable>, ImmutableBlockState> states) { - if (withMap != null) { + if (this.withMap != null) { throw new IllegalStateException("WithMap already initialized"); } - Reference2ObjectArrayMap, ImmutableBlockState[]> map = new Reference2ObjectArrayMap<>(propertyMap.size()); + Reference2ObjectArrayMap, ImmutableBlockState[]> map = new Reference2ObjectArrayMap<>(this.propertyMap.size()); - for (Property property : propertyMap.keySet()) { + for (Property property : this.propertyMap.keySet()) { ImmutableBlockState[] statesArray = property.possibleValues().stream() .map(value -> { - Map, Comparable> testMap = new Reference2ObjectArrayMap<>(propertyMap); + Map, Comparable> testMap = new Reference2ObjectArrayMap<>(this.propertyMap); testMap.put(property, value); ImmutableBlockState state = states.get(testMap); if (state == null) { @@ -126,6 +126,6 @@ public class BlockStateHolder { } public Map, Comparable> propertyEntries() { - return Collections.unmodifiableMap(propertyMap); + return Collections.unmodifiableMap(this.propertyMap); } } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index 68747718d..0123b54d9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -144,6 +144,6 @@ public class ImmutableBlockState extends BlockStateHolder { if (block == null) return List.of(); LootTable lootTable = (LootTable) block.lootTable(); if (lootTable == null) return List.of(); - return lootTable.getRandomItems(builder.withParameter(DirectContextParameters.BLOCK_STATE, this).build(), world, player); + return lootTable.getRandomItems(builder.withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, this).build(), world, player); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlockState.java index 9e811011f..e86fcd003 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/VanillaBlockState.java @@ -2,5 +2,26 @@ package net.momirealms.craftengine.core.block; import net.momirealms.craftengine.core.util.Key; -public record VanillaBlockState(Key type, String properties, int registryId) { +public class VanillaBlockState { + private final Key type; + private final String properties; + private final int registryId; + + public VanillaBlockState(Key type, String properties, int registryId) { + this.properties = properties; + this.registryId = registryId; + this.type = type; + } + + public String properties() { + return properties; + } + + public int registryId() { + return registryId; + } + + public Key type() { + return type; + } } 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 a91f3b95d..22cd977ae 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 @@ -477,29 +477,27 @@ public abstract class AbstractPackManager implements PackManager { for (CachedConfigSection cached : entry.getValue()) { for (Map.Entry configEntry : cached.config().entrySet()) { String key = configEntry.getKey(); + Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); try { - Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); - try { - if (parser.supportsParsingObject()) { - parser.parseObject(cached.pack(), cached.filePath(), id, configEntry.getValue()); - } else if (predicate.test(parser)) { - if (configEntry.getValue() instanceof Map configSection0) { - Map configSection1 = castToMap(configSection0, false); - if ((boolean) configSection1.getOrDefault("enable", true)) { - parser.parseSection(cached.pack(), cached.filePath(), id, plugin.templateManager().applyTemplates(configSection1)); - } - } else { - TranslationManager.instance().log("warning.config.structure.not_section", cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName()); + if (parser.supportsParsingObject()) { + parser.parseObject(cached.pack(), cached.filePath(), id, configEntry.getValue()); + } else if (predicate.test(parser)) { + if (configEntry.getValue() instanceof Map configSection0) { + Map configSection1 = castToMap(configSection0, false); + if ((boolean) configSection1.getOrDefault("enable", true)) { + parser.parseSection(cached.pack(), cached.filePath(), id, plugin.templateManager().applyTemplates(configSection1)); } + } else { + TranslationManager.instance().log("warning.config.structure.not_section", cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName()); } - } catch (LocalizedException e) { - if (e instanceof LocalizedResourceConfigException exception) { - exception.setPath(cached.filePath()); - exception.setId(cached.prefix() + "." + key); - } - TranslationManager.instance().log(e.node(), e.arguments()); - this.plugin.debug(e::node); } + } catch (LocalizedException e) { + if (e instanceof LocalizedResourceConfigException exception) { + exception.setPath(cached.filePath()); + exception.setId(cached.prefix() + "." + key); + } + TranslationManager.instance().log(e.node(), e.arguments()); + this.plugin.debug(e::node); } catch (Exception e) { this.plugin.logger().warn("Unexpected error loading file " + cached.filePath() + " - '" + parser.sectionId()[0] + "." + key + "'. Please find the cause according to the stacktrace or seek developer help.", e); } @@ -522,36 +520,6 @@ public abstract class AbstractPackManager implements PackManager { } } -// private static void initFileSystemProvider() { -// String osName = System.getProperty("os.name").toLowerCase(); -// String providerClass = null; -// if (osName.contains("win")) { -// providerClass = "sun.nio.fs.WindowsFileSystemProvider"; -// } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) { -// providerClass = "sun.nio.fs.LinuxFileSystemProvider"; -// } else if (osName.contains("mac")) { -// providerClass = "sun.nio.fs.MacOSXFileSystemProvider"; -// } -// if (providerClass != null) { -// try { -// System.setProperty("java.nio.file.spi.DefaultFileSystemProvider", providerClass); -// } catch (Exception ignored) {} -// } -// } -// -// private static void deleteDirectory(Path folder) throws IOException { -// if (!Files.exists(folder)) return; -// try (Stream walk = Files.walk(folder)) { -// walk.sorted(Comparator.reverseOrder()) -// .parallel() -// .forEach(path -> { -// try { -// Files.delete(path); -// } catch (IOException ignored) {} -// }); -// } -// } - @Override public void generateResourcePack() throws IOException { this.plugin.logger().info("Generating resource pack..."); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java index 44ae3625b..b8a213d27 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java @@ -29,7 +29,7 @@ public class MatchBlockPropertyCondition implements Conditi @Override public boolean test(CTX ctx) { - return ctx.getOptionalParameter(DirectContextParameters.BLOCK_STATE).map(state -> { + return ctx.getOptionalParameter(DirectContextParameters.CUSTOM_BLOCK_STATE).map(state -> { CustomBlock block = state.owner().value(); for (Pair property : this.properties) { Property propertyIns = block.getProperty(property.left()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java index e707aca80..1aac69f9c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/BlockParameterProvider.java @@ -19,7 +19,7 @@ public class BlockParameterProvider implements ChainParameterProvider EXPLOSION_RADIUS = ContextKey.direct("explosion_radius"); public static final ContextKey PLAYER = ContextKey.direct("player"); public static final ContextKey ENTITY = ContextKey.direct("entity"); - public static final ContextKey BLOCK_STATE = ContextKey.direct("custom_block_state"); + public static final ContextKey CUSTOM_BLOCK_STATE = ContextKey.direct("custom_block_state"); public static final ContextKey COORDINATE = ContextKey.direct("coordinate"); public static final ContextKey POSITION = ContextKey.direct("position"); public static final ContextKey NAME = ContextKey.direct("name"); From e5b61222dd47b918ffc9c21dbb61fdd623b4c064 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 23 May 2025 19:35:04 +0800 Subject: [PATCH 41/89] Update SelfHostHttpServer.java --- .../pack/host/impl/SelfHostHttpServer.java | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index af0e99be2..530116109 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -32,12 +32,12 @@ public class SelfHostHttpServer { private final Cache oneTimePackUrls = Caffeine.newBuilder() .maximumSize(256) .scheduler(Scheduler.systemScheduler()) - .expireAfterAccess(1, TimeUnit.MINUTES) + .expireAfterWrite(1, TimeUnit.MINUTES) .build(); private final Cache ipAccessCache = Caffeine.newBuilder() .maximumSize(256) .scheduler(Scheduler.systemScheduler()) - .expireAfterAccess(10, TimeUnit.MINUTES) + .expireAfterWrite(10, TimeUnit.MINUTES) .build(); private ExecutorService threadPool; @@ -84,7 +84,7 @@ public class SelfHostHttpServer { this.threadPool = Executors.newFixedThreadPool(1); this.server = HttpServer.create(new InetSocketAddress("::", port), 0); this.server.createContext("/download", new ResourcePackHandler()); - this.server.createContext("/metrics", this::handleMetrics); +// this.server.createContext("/metrics", this::handleMetrics); this.server.setExecutor(this.threadPool); this.server.start(); CraftEngine.instance().logger().info("HTTP server started on port: " + port); @@ -180,29 +180,34 @@ public class SelfHostHttpServer { private class ResourcePackHandler implements HttpHandler { @Override public void handle(HttpExchange exchange) throws IOException { - totalRequests.incrementAndGet(); + try { + totalRequests.incrementAndGet(); - String clientIp = getClientIp(exchange); - if (checkRateLimit(clientIp)) { - handleBlockedRequest(exchange, 429, "Rate limit exceeded"); - return; - } - if (useToken) { - String token = parseToken(exchange); - if (!validateToken(token)) { - handleBlockedRequest(exchange, 403, "Invalid token"); + String clientIp = getClientIp(exchange); + if (checkRateLimit(clientIp)) { + handleBlockedRequest(exchange, 429, "Rate limit exceeded"); return; } + if (useToken) { + String token = parseToken(exchange); + if (!validateToken(token)) { + handleBlockedRequest(exchange, 403, "Invalid token"); + return; + } + } + if (!validateClient(exchange)) { + handleBlockedRequest(exchange, 403, "Invalid client"); + return; + } + if (resourcePackBytes == null) { + handleBlockedRequest(exchange, 404, "Resource pack missing"); + return; + } + sendResourcePack(exchange); + } catch (Exception e) { + handleBlockedRequest(exchange, 500, "Internal error"); + CraftEngine.instance().logger().warn("Request handling failed", e); } - if (!validateClient(exchange)) { - handleBlockedRequest(exchange, 403, "Invalid client"); - return; - } - if (resourcePackBytes == null) { - handleBlockedRequest(exchange, 404, "Resource pack missing"); - return; - } - sendResourcePack(exchange); } private String getClientIp(HttpExchange exchange) { From c34ec302120efc277de8aac942d8e541fe1fb2b6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 23 May 2025 20:32:04 +0800 Subject: [PATCH 42/89] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=BA=A4=E4=BA=92?= =?UTF-8?q?=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/behavior/BushBlockBehavior.java | 4 +- .../block/behavior/CropBlockBehavior.java | 35 +++++ .../block/behavior/GrassBlockBehavior.java | 42 ++++++ .../block/behavior/SaplingBlockBehavior.java | 32 +++++ .../behavior/StrippableBlockBehavior.java | 107 ++++++++++++++- .../bukkit/item/BukkitItemManager.java | 4 - .../bukkit/item/behavior/AxeItemBehavior.java | 122 ------------------ .../item/behavior/BoneMealItemBehavior.java | 83 ------------ .../item/behavior/BukkitItemBehaviors.java | 4 - .../item/listener/ItemEventListener.java | 36 +++++- .../bukkit/plugin/BukkitCraftEngine.java | 2 +- .../bukkit/plugin/gui/BukkitGuiManager.java | 1 - .../block/behavior/AbstractBlockBehavior.java | 6 + .../core/item/context/UseOnContext.java | 4 + .../compatibility/CompatibilityManager.java | 1 - .../context/function/LevelerExpFunction.java | 3 - 16 files changed, 258 insertions(+), 228 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 381c9152f..6c1d87c11 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -137,7 +137,9 @@ public class BushBlockBehavior extends BukkitBlockBehavior { } protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException { - if (this.any) return true; + if (this.any) { + return belowState != Reflections.instance$Blocks$AIR$defaultState; + } for (Object tag : this.tagsCanSurviveOn) { if ((boolean) Reflections.method$BlockStateBase$hasTag.invoke(belowState, tag)) { return true; 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 a8d14c48f..5581362a0 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.ParticleUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorld; @@ -12,6 +13,11 @@ import net.momirealms.craftengine.core.block.UpdateOption; 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.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemKeys; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.SimpleContext; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; @@ -125,6 +131,35 @@ public class CropBlockBehavior extends BushBlockBehavior { this.performBoneMeal(args[0], args[2], args[3]); } + @Override + public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { + Item item = context.getItem(); + if (item == null || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) + return InteractionResult.PASS; + if (isMaxAge(state)) + return InteractionResult.PASS; + boolean sendSwing = false; + try { + Object visualState = state.vanillaBlockState().handle(); + Object visualStateBlock = Reflections.method$BlockStateBase$getBlock.invoke(visualState); + if (Reflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) { + boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState); + if (!is) { + sendSwing = true; + } + } else { + sendSwing = true; + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to check visual state bone meal state", e); + return InteractionResult.FAIL; + } + if (sendSwing) { + context.getPlayer().swingHand(context.getHand()); + } + return InteractionResult.SUCCESS; + } + private void performBoneMeal(Object level, Object pos, Object state) throws InvocationTargetException, IllegalAccessException { ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); if (immutableBlockState == null || immutableBlockState.isEmpty()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java index 14b4efb72..a6763fedb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java @@ -3,14 +3,23 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.ParticleUtils; import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemKeys; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.World; +import org.bukkit.block.Block; import java.util.Map; @@ -57,6 +66,39 @@ public class GrassBlockBehavior extends BukkitBlockBehavior { return true; } + @SuppressWarnings("DuplicatedCode") + @Override + public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { + Item item = context.getItem(); + if (item == null || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) + return InteractionResult.PASS; + BlockPos pos = context.getClickedPos(); + BukkitBlockInWorld upper = (BukkitBlockInWorld) context.getLevel().getBlockAt(pos.x(), pos.y() + 1, pos.z()); + Block block = upper.block(); + if (!block.isEmpty()) + return InteractionResult.PASS; + boolean sendSwing = false; + try { + Object visualState = state.vanillaBlockState().handle(); + Object visualStateBlock = Reflections.method$BlockStateBase$getBlock.invoke(visualState); + if (Reflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) { + boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState); + if (!is) { + sendSwing = true; + } + } else { + sendSwing = true; + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to check visual state bone meal state", e); + return InteractionResult.FAIL; + } + if (sendSwing) { + context.getPlayer().swingHand(context.getHand()); + } + return InteractionResult.SUCCESS; + } + @Override public void performBoneMeal(Object thisBlock, Object[] args) { FastNMS.INSTANCE.method$GrassBlock$performBoneMeal(args[0], args[1], args[2], args[3], thisBlock); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java index 6242f1103..7511e265a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java @@ -9,6 +9,10 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemKeys; +import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; @@ -135,6 +139,34 @@ public class SaplingBlockBehavior extends BushBlockBehavior { this.increaseStage(args[0], args[2], args[3], args[1]); } + @SuppressWarnings("DuplicatedCode") + @Override + public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { + Item item = context.getItem(); + if (item == null || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) + return InteractionResult.PASS; + boolean sendSwing = false; + try { + Object visualState = state.vanillaBlockState().handle(); + Object visualStateBlock = Reflections.method$BlockStateBase$getBlock.invoke(visualState); + if (Reflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) { + boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState); + if (!is) { + sendSwing = true; + } + } else { + sendSwing = true; + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to check visual state bone meal state", e); + return InteractionResult.FAIL; + } + if (sendSwing) { + context.getPlayer().swingHand(context.getHand()); + } + return InteractionResult.SUCCESS; + } + public static class Factory implements BlockBehaviorFactory { @SuppressWarnings("unchecked") diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java index f1a2478fe..5e9b41d6f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java @@ -1,15 +1,42 @@ package net.momirealms.craftengine.bukkit.block.behavior; +import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemKeys; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.shared.block.BlockBehavior; +import net.momirealms.sparrow.nbt.CompoundTag; +import org.bukkit.GameEvent; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.block.Block; +import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; import java.util.Map; +import java.util.Optional; public class StrippableBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); + private static final Key AXE_STRIP_SOUND = Key.of("minecraft:item.axe.strip"); private final Key stripped; public StrippableBlockBehavior(CustomBlock block, Key stripped) { @@ -18,7 +45,85 @@ public class StrippableBlockBehavior extends BukkitBlockBehavior { } public Key stripped() { - return stripped; + return this.stripped; + } + + @SuppressWarnings("unchecked") + @Override + public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { + Item item = (Item) context.getItem(); + if (item == null) { + return InteractionResult.PASS; + } + Optional> optionalCustomItem = item.getCustomItem(); + if (optionalCustomItem.isEmpty()) { + if (!item.is(ItemTags.AXES)) + return InteractionResult.PASS; + } else { + CustomItem customItem = optionalCustomItem.get(); + if (!customItem.settings().tags().contains(ItemTags.AXES) && !item.is(ItemTags.AXES)) + return InteractionResult.PASS; + } + + Player player = context.getPlayer(); + // no adventure mode + if (player.isAdventureMode()) { + return InteractionResult.PASS; + } + Item offHandItem = player.getItemInHand(InteractionHand.OFF_HAND); + // is using a shield + if (context.getHand() == InteractionHand.MAIN_HAND && offHandItem != null && offHandItem.vanillaId().equals(ItemKeys.SHIELD) && !player.isSecondaryUseActive()) { + return InteractionResult.PASS; + } + + Optional optionalNewCustomBlock = BukkitBlockManager.instance().blockById(stripped()); + if (optionalNewCustomBlock.isEmpty()) { + CraftEngine.instance().logger().warn("stripped block " + stripped() + " does not exist"); + return InteractionResult.FAIL; + } + CustomBlock newCustomBlock = optionalNewCustomBlock.get(); + CompoundTag compoundTag = state.propertiesNbt(); + ImmutableBlockState newState = newCustomBlock.getBlockState(compoundTag); + + org.bukkit.entity.Player bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer()); + + BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos()); + Block block = clicked.block(); + // Call bukkit event + EntityChangeBlockEvent event = new EntityChangeBlockEvent(bukkitPlayer, block, BlockStateUtils.fromBlockData(newState.customBlockState().handle())); + if (EventUtils.fireAndCheckCancel(event)) { + return InteractionResult.FAIL; + } + + BlockPos pos = context.getClickedPos(); + context.getLevel().playBlockSound(Vec3d.atCenterOf(pos), AXE_STRIP_SOUND, 1, 1); + CraftEngineBlocks.place(block.getLocation(), newState, UpdateOption.UPDATE_ALL_IMMEDIATE, false); + block.getWorld().sendGameEvent(bukkitPlayer, GameEvent.BLOCK_CHANGE, new Vector(pos.x(), pos.y(), pos.z())); + Material material = MaterialUtils.getMaterial(item.vanillaId()); + bukkitPlayer.setStatistic(Statistic.USE_ITEM, material, bukkitPlayer.getStatistic(Statistic.USE_ITEM, material) + 1); + + // resend swing if it's not interactable on client side + if (!InteractUtils.isInteractable( + bukkitPlayer, BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), + context.getHitResult(), item + ) || player.isSecondaryUseActive()) { + player.swingHand(context.getHand()); + } + // shrink item amount + if (VersionHelper.isOrAbove1_20_5()) { + Object itemStack = item.getLiteralObject(); + Object serverPlayer = player.serverPlayer(); + Object equipmentSlot = context.getHand() == InteractionHand.MAIN_HAND ? Reflections.instance$EquipmentSlot$MAINHAND : Reflections.instance$EquipmentSlot$OFFHAND; + try { + Reflections.method$ItemStack$hurtAndBreak.invoke(itemStack, 1, serverPlayer, equipmentSlot); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to hurt itemStack", e); + } + } else { + ItemStack itemStack = item.getItem(); + itemStack.damage(1, bukkitPlayer); + } + return InteractionResult.SUCCESS; } public static class Factory implements BlockBehaviorFactory { 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 f51b4ee82..f72ecec0e 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 @@ -1,8 +1,6 @@ package net.momirealms.craftengine.bukkit.item; import com.saicone.rtag.item.ItemTagStream; -import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior; -import net.momirealms.craftengine.bukkit.item.behavior.BoneMealItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior; import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory; @@ -42,10 +40,8 @@ import java.util.function.Function; public class BukkitItemManager extends AbstractItemManager { static { - registerVanillaItemExtraBehavior(AxeItemBehavior.INSTANCE, ItemKeys.AXES); registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKETS); registerVanillaItemExtraBehavior(BucketItemBehavior.INSTANCE, ItemKeys.BUCKET); - registerVanillaItemExtraBehavior(BoneMealItemBehavior.INSTANCE, ItemKeys.BONE_MEAL); } private static BukkitItemManager instance; 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 deleted file mode 100644 index d1e6b038e..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ /dev/null @@ -1,122 +0,0 @@ -package net.momirealms.craftengine.bukkit.item.behavior; - -import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.block.behavior.StrippableBlockBehavior; -import net.momirealms.craftengine.bukkit.util.*; -import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; -import net.momirealms.craftengine.core.block.CustomBlock; -import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.block.UpdateOption; -import net.momirealms.craftengine.core.entity.player.InteractionHand; -import net.momirealms.craftengine.core.entity.player.InteractionResult; -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.item.behavior.ItemBehavior; -import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; -import net.momirealms.craftengine.core.item.context.UseOnContext; -import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.Vec3d; -import net.momirealms.sparrow.nbt.CompoundTag; -import org.bukkit.GameEvent; -import org.bukkit.Material; -import org.bukkit.Statistic; -import org.bukkit.block.Block; -import org.bukkit.event.entity.EntityChangeBlockEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.util.Vector; - -import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; - -public class AxeItemBehavior extends ItemBehavior { - public static final Factory FACTORY = new Factory(); - public static final AxeItemBehavior INSTANCE = new AxeItemBehavior(); - private static final Key AXE_STRIP_SOUND = Key.of("minecraft:item.axe.strip"); - - @SuppressWarnings("unchecked") - @Override - public InteractionResult useOnBlock(UseOnContext context) { - BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos()); - Block block = clicked.block(); - ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); - if (state == null || state.isEmpty()) return InteractionResult.PASS; - - if (!(state.behavior() instanceof StrippableBlockBehavior blockBehavior)) { - return InteractionResult.PASS; - } - - Player player = context.getPlayer(); - // no adventure mode - if (player.isAdventureMode()) { - return InteractionResult.PASS; - } - - Item offHandItem = (Item) player.getItemInHand(InteractionHand.OFF_HAND); - // is using a shield - if (context.getHand() == InteractionHand.MAIN_HAND && offHandItem != null && offHandItem.vanillaId().equals(ItemKeys.SHIELD) && !player.isSecondaryUseActive()) { - return InteractionResult.PASS; - } - - Optional optionalNewCustomBlock = BukkitBlockManager.instance().blockById(blockBehavior.stripped()); - if (optionalNewCustomBlock.isEmpty()) { - CraftEngine.instance().logger().warn("stripped block " + blockBehavior.stripped() + " does not exist"); - return InteractionResult.FAIL; - } - CustomBlock newCustomBlock = optionalNewCustomBlock.get(); - CompoundTag compoundTag = state.propertiesNbt(); - ImmutableBlockState newState = newCustomBlock.getBlockState(compoundTag); - - org.bukkit.entity.Player bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer()); - // Call bukkit event - EntityChangeBlockEvent event = new EntityChangeBlockEvent(bukkitPlayer, block, BlockStateUtils.fromBlockData(newState.customBlockState().handle())); - if (EventUtils.fireAndCheckCancel(event)) { - return InteractionResult.PASS; - } - - BlockPos pos = context.getClickedPos(); - context.getLevel().playBlockSound(Vec3d.atCenterOf(pos), AXE_STRIP_SOUND, 1, 1); - CraftEngineBlocks.place(block.getLocation(), newState, UpdateOption.UPDATE_ALL_IMMEDIATE, false); - block.getWorld().sendGameEvent(bukkitPlayer, GameEvent.BLOCK_CHANGE, new Vector(pos.x(), pos.y(), pos.z())); - Item item = (Item) context.getItem(); - Material material = MaterialUtils.getMaterial(item.vanillaId()); - bukkitPlayer.setStatistic(Statistic.USE_ITEM, material, bukkitPlayer.getStatistic(Statistic.USE_ITEM, material) + 1); - - // resend swing if it's not interactable on client side - if (!InteractUtils.isInteractable( - bukkitPlayer, BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), - context.getHitResult(), item - ) || player.isSecondaryUseActive()) { - player.swingHand(context.getHand()); - } - // shrink item amount - if (VersionHelper.isOrAbove1_20_5()) { - Object itemStack = item.getLiteralObject(); - Object serverPlayer = player.serverPlayer(); - Object equipmentSlot = context.getHand() == InteractionHand.MAIN_HAND ? Reflections.instance$EquipmentSlot$MAINHAND : Reflections.instance$EquipmentSlot$OFFHAND; - try { - Reflections.method$ItemStack$hurtAndBreak.invoke(itemStack, 1, serverPlayer, equipmentSlot); - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to hurt itemStack", e); - } - } else { - ItemStack itemStack = item.getItem(); - itemStack.damage(1, bukkitPlayer); - } - return InteractionResult.SUCCESS; - } - - public static class Factory implements ItemBehaviorFactory { - - @Override - public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { - return INSTANCE; - } - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java deleted file mode 100644 index 2996694ed..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java +++ /dev/null @@ -1,83 +0,0 @@ -package net.momirealms.craftengine.bukkit.item.behavior; - -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.block.behavior.CropBlockBehavior; -import net.momirealms.craftengine.bukkit.block.behavior.GrassBlockBehavior; -import net.momirealms.craftengine.bukkit.block.behavior.SaplingBlockBehavior; -import net.momirealms.craftengine.bukkit.nms.FastNMS; -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.BukkitBlockInWorld; -import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.entity.player.InteractionResult; -import net.momirealms.craftengine.core.item.behavior.ItemBehavior; -import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; -import net.momirealms.craftengine.core.item.context.UseOnContext; -import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.Key; -import org.bukkit.block.Block; - -import java.nio.file.Path; -import java.util.Map; - -public class BoneMealItemBehavior extends ItemBehavior { - public static final Factory FACTORY = new Factory(); - public static final BoneMealItemBehavior INSTANCE = new BoneMealItemBehavior(); - - @Override - public InteractionResult useOnBlock(UseOnContext context) { - if (context.getPlayer().isAdventureMode()) { - return InteractionResult.PASS; - } - - BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos()); - Block block = clicked.block(); - ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); - if (state == null || state.isEmpty()) return InteractionResult.PASS; - - boolean shouldHandle =false; - if (state.behavior() instanceof CropBlockBehavior blockBehavior) { - if (!blockBehavior.isMaxAge(state)) { - shouldHandle = true; - } - } else if (state.behavior() instanceof SaplingBlockBehavior) { - shouldHandle = true; - } else if (state.behavior() instanceof GrassBlockBehavior) { - if (block.getLocation().add(0, 1, 0).getBlock().isEmpty()) { - shouldHandle = true; - } - } - - if (!shouldHandle) return InteractionResult.PASS; - - boolean sendSwing = false; - try { - Object visualState = state.vanillaBlockState().handle(); - Object visualStateBlock = Reflections.method$BlockStateBase$getBlock.invoke(visualState); - if (Reflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) { - boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState); - if (!is) { - sendSwing = true; - } - } else { - sendSwing = true; - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to check visual state bone meal state", e); - } - if (sendSwing) { - context.getPlayer().swingHand(context.getHand()); - } - return InteractionResult.SUCCESS; - } - - public static class Factory implements ItemBehaviorFactory { - - @Override - public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { - return INSTANCE; - } - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java index ed3e35737..f8081572b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java @@ -8,19 +8,15 @@ public class BukkitItemBehaviors extends ItemBehaviors { public static final Key BLOCK_ITEM = Key.from("craftengine:block_item"); public static final Key ON_LIQUID_BLOCK_ITEM = Key.from("craftengine:liquid_collision_block_item"); public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item"); - public static final Key AXE_ITEM = Key.from("craftengine:axe_item"); public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item"); public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item"); - public static final Key BONE_MEAL_ITEM = Key.from("craftengine:bone_meal_item"); public static void init() { register(EMPTY, EmptyItemBehavior.FACTORY); register(BLOCK_ITEM, BlockItemBehavior.FACTORY); register(ON_LIQUID_BLOCK_ITEM, LiquidCollisionBlockItemBehavior.FACTORY); register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY); - register(AXE_ITEM, AxeItemBehavior.FACTORY); register(WATER_BUCKET_ITEM, WaterBucketItemBehavior.FACTORY); register(BUCKET_ITEM, BucketItemBehavior.FACTORY); - register(BONE_MEAL_ITEM, BoneMealItemBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index 50fd9bd38..19cc4e5ce 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.item.CustomItem; @@ -75,6 +76,17 @@ public class ItemEventListener implements Listener { ImmutableBlockState immutableBlockState = null; int stateId = BlockStateUtils.blockStateToId(blockState); Item itemInHand = serverPlayer.getItemInHand(hand); + Location interactionPoint = event.getInteractionPoint(); + + + + BlockHitResult hitResult = null; + if (action == Action.RIGHT_CLICK_BLOCK && interactionPoint != null) { + Direction direction = DirectionUtils.toDirection(event.getBlockFace()); + BlockPos pos = LocationUtils.toBlockPos(block.getLocation()); + Vec3d vec3d = new Vec3d(interactionPoint.getX(), interactionPoint.getY(), interactionPoint.getZ()); + hitResult = new BlockHitResult(vec3d, direction, pos, false); + } // 处理自定义方块 if (!BlockStateUtils.isVanillaBlock(stateId)) { @@ -83,7 +95,7 @@ public class ItemEventListener implements Listener { CustomBlockInteractEvent interactEvent = new CustomBlockInteractEvent( player, block.getLocation(), - event.getInteractionPoint(), + interactionPoint, immutableBlockState, block, event.getBlockFace(), @@ -113,6 +125,20 @@ public class ItemEventListener implements Listener { event.setCancelled(true); return; } + + if (hitResult != null) { + UseOnContext useOnContext = new UseOnContext(serverPlayer, hand, itemInHand, hitResult); + if (immutableBlockState.behavior() instanceof AbstractBlockBehavior behavior) { + InteractionResult result = behavior.useOnBlock(useOnContext, immutableBlockState); + if (result == InteractionResult.SUCCESS_AND_CANCEL) { + event.setCancelled(true); + return; + } + if (result != InteractionResult.PASS) { + return; + } + } + } } Optional> optionalCustomItem = itemInHand == null ? Optional.empty() : itemInHand.getCustomItem(); @@ -121,7 +147,6 @@ public class ItemEventListener implements Listener { // interact block with items if (hasItem && action == Action.RIGHT_CLICK_BLOCK) { - Location interactionPoint = event.getInteractionPoint(); // some plugins would trigger this event without interaction point if (interactionPoint == null) { if (hasCustomItem) { @@ -129,10 +154,6 @@ public class ItemEventListener implements Listener { } return; } - Direction direction = DirectionUtils.toDirection(event.getBlockFace()); - BlockPos pos = LocationUtils.toBlockPos(block.getLocation()); - Vec3d vec3d = new Vec3d(interactionPoint.getX(), interactionPoint.getY(), interactionPoint.getZ()); - BlockHitResult hitResult = new BlockHitResult(vec3d, direction, pos, false); // handle block item if (itemInHand.isBlockItem()) { @@ -200,9 +221,10 @@ public class ItemEventListener implements Listener { if (!serverPlayer.isSecondaryUseActive() && interactable) { return; } + UseOnContext useOnContext = new UseOnContext(serverPlayer, hand, itemInHand, hitResult); // 依次执行物品行为 for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) { - InteractionResult result = itemBehavior.useOnBlock(new UseOnContext(serverPlayer, hand, hitResult)); + InteractionResult result = itemBehavior.useOnBlock(useOnContext); if (result == InteractionResult.SUCCESS_AND_CANCEL) { event.setCancelled(true); 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 72f05d54c..ab28f1adf 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 @@ -26,10 +26,10 @@ import net.momirealms.craftengine.bukkit.util.EventUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.item.ItemManager; -import net.momirealms.craftengine.core.plugin.compatibility.CompatibilityManager; 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.compatibility.CompatibilityManager; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.dependency.Dependencies; import net.momirealms.craftengine.core.plugin.dependency.Dependency; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java index f08eca613..30201b3d2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java @@ -8,7 +8,6 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.gui.*; import net.momirealms.craftengine.core.util.ReflectionUtils; -import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/AbstractBlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/AbstractBlockBehavior.java index ae8d38e1e..1a6dbbc56 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/AbstractBlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/AbstractBlockBehavior.java @@ -2,7 +2,9 @@ package net.momirealms.craftengine.core.block.behavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; +import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.shared.block.BlockBehavior; public abstract class AbstractBlockBehavior extends BlockBehavior { @@ -15,4 +17,8 @@ public abstract class AbstractBlockBehavior extends BlockBehavior { public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { return state; } + + public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { + return InteractionResult.PASS; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java b/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java index e07191478..cb65aff39 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java @@ -20,6 +20,10 @@ public class UseOnContext { this(player.world(), player, hand, player.getItemInHand(hand), hit); } + public UseOnContext(Player player, InteractionHand hand, Item stack, BlockHitResult hit) { + this(player.world(), player, hand, stack, hit); + } + public UseOnContext(World world, Player player, InteractionHand hand, Item stack, BlockHitResult hit) { this.player = player; this.hand = hand; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java index 5afa56e2b..83b15f39b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.core.plugin.compatibility; -import net.momirealms.craftengine.core.entity.furniture.AbstractExternalModel; import net.momirealms.craftengine.core.entity.furniture.ExternalModel; import net.momirealms.craftengine.core.entity.player.Player; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java index 4c546ad3b..9d9edff9e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.*; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; @@ -9,13 +8,11 @@ import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; -import net.momirealms.craftengine.core.plugin.context.text.TextProvider; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.List; import java.util.Map; -import java.util.Optional; public class LevelerExpFunction extends AbstractConditionalFunction { private final PlayerSelector selector; From d0e242900848052198ad857b21798f883dbd03cc Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 23 May 2025 21:33:39 +0800 Subject: [PATCH 43/89] =?UTF-8?q?=E5=8A=A0=E7=82=B9=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/commands.yml | 7 ++++ .../bukkit/pack/BukkitPackManager.java | 1 + .../plugin/command/BukkitCommandManager.java | 1 + .../feature/DebugHostStatusCommand.java | 39 +++++++++++++++++++ .../pack/host/impl/SelfHostHttpServer.java | 18 +++++++-- 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugHostStatusCommand.java diff --git a/bukkit/loader/src/main/resources/commands.yml b/bukkit/loader/src/main/resources/commands.yml index fdf4e1613..0a4a2616f 100644 --- a/bukkit/loader/src/main/resources/commands.yml +++ b/bukkit/loader/src/main/resources/commands.yml @@ -175,6 +175,13 @@ debug_is_section_injected: - /craftengine debug is-section-injected - /ce debug is-section-injected +debug_host_status: + enable: true + permission: ce.command.debug.host_status + usage: + - /craftengine debug host-status + - /ce debug host-status + debug_test: enable: true permission: ce.command.debug.test 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 918953dee..59490e1a4 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 @@ -121,6 +121,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { return; } if (!Config.sendPackOnUpload()) return; + CraftEngine.instance().logger().info("Complete uploading resource pack"); for (BukkitServerPlayer player : this.plugin.networkManager().onlineUsers()) { sendResourcePack(player); } 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 c1f1c3f39..0da8fe6dd 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 @@ -39,6 +39,7 @@ public class BukkitCommandManager extends AbstractCommandManager new SearchUsageAdminCommand(this, plugin), new TestCommand(this, plugin), new DebugGetBlockStateRegistryIdCommand(this, plugin), + new DebugHostStatusCommand(this, plugin), new DebugGetBlockInternalIdCommand(this, plugin), new DebugAppearanceStateUsageCommand(this, plugin), new DebugRealStateUsageCommand(this, plugin), diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugHostStatusCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugHostStatusCommand.java new file mode 100644 index 000000000..6402c8f98 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugHostStatusCommand.java @@ -0,0 +1,39 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.md_5.bungee.chat.ComponentSerializer; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; +import net.momirealms.craftengine.core.pack.host.impl.SelfHostHttpServer; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.plugin.command.sender.Sender; +import org.bukkit.Chunk; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.incendo.cloud.Command; + +public class DebugHostStatusCommand extends BukkitCommandFeature { + + public DebugHostStatusCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { + return builder + .handler(context -> { + Sender sender = plugin().senderFactory().wrap(context.sender()); + sender.sendMessage(Component.text("Self Host status: " + (SelfHostHttpServer.instance().isAlive() ? "on" : "off"))); + byte[] pack = SelfHostHttpServer.instance().resourcePackBytes(); + sender.sendMessage(Component.text("Resource Pack Bytes: " + (pack == null ? "null" : pack.length))); + }); + } + + @Override + public String getFeatureID() { + return "debug_host_status"; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index 530116109..0d617ce0c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -55,7 +55,7 @@ public class SelfHostHttpServer { private boolean denyNonMinecraft = true; private boolean useToken; - private volatile byte[] resourcePackBytes; + private byte[] resourcePackBytes; private String packHash; private UUID packUUID; @@ -93,6 +93,14 @@ public class SelfHostHttpServer { } } + public boolean isAlive() { + return this.server != null; + } + + public byte[] resourcePackBytes() { + return resourcePackBytes; + } + public static SelfHostHttpServer instance() { if (instance == null) { instance = new SelfHostHttpServer(); @@ -173,6 +181,7 @@ public class SelfHostHttpServer { this.server = null; if (this.threadPool != null) { this.threadPool.shutdownNow(); + this.threadPool = null; } } } @@ -262,8 +271,11 @@ public class SelfHostHttpServer { try (OutputStream os = exchange.getResponseBody()) { os.write(resourcePackBytes); } catch (IOException e) { - CraftEngine.instance().logger().warn("Failed to send resource pack", e); - throw e; + if (!e.getMessage().contains("abort") && !e.getMessage().contains("reset")) { + CraftEngine.instance().logger().warn("Failed to send resource pack", e); + throw e; + } + CraftEngine.instance().debug(() -> "Client aborted resource pack download: " + e.getMessage()); } } From 3530be68a460d55092c415185d766d74a6e28bae Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 23 May 2025 22:51:25 +0800 Subject: [PATCH 44/89] =?UTF-8?q?=E4=BD=BF=E7=94=A8netty=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?self=20host?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/commands.yml | 7 - .../plugin/command/BukkitCommandManager.java | 1 - .../feature/DebugHostStatusCommand.java | 39 -- core/build.gradle.kts | 1 + .../core/pack/host/impl/S3HostFactory.java | 1 - .../pack/host/impl/SelfHostHttpServer.java | 432 +++++++++--------- .../craftengine/core/plugin/CraftEngine.java | 1 + gradle.properties | 2 +- 8 files changed, 225 insertions(+), 259 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugHostStatusCommand.java diff --git a/bukkit/loader/src/main/resources/commands.yml b/bukkit/loader/src/main/resources/commands.yml index 0a4a2616f..fdf4e1613 100644 --- a/bukkit/loader/src/main/resources/commands.yml +++ b/bukkit/loader/src/main/resources/commands.yml @@ -175,13 +175,6 @@ debug_is_section_injected: - /craftengine debug is-section-injected - /ce debug is-section-injected -debug_host_status: - enable: true - permission: ce.command.debug.host_status - usage: - - /craftengine debug host-status - - /ce debug host-status - debug_test: enable: true permission: ce.command.debug.test 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 0da8fe6dd..c1f1c3f39 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 @@ -39,7 +39,6 @@ public class BukkitCommandManager extends AbstractCommandManager new SearchUsageAdminCommand(this, plugin), new TestCommand(this, plugin), new DebugGetBlockStateRegistryIdCommand(this, plugin), - new DebugHostStatusCommand(this, plugin), new DebugGetBlockInternalIdCommand(this, plugin), new DebugAppearanceStateUsageCommand(this, plugin), new DebugRealStateUsageCommand(this, plugin), diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugHostStatusCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugHostStatusCommand.java deleted file mode 100644 index 6402c8f98..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugHostStatusCommand.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.momirealms.craftengine.bukkit.plugin.command.feature; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import net.md_5.bungee.chat.ComponentSerializer; -import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; -import net.momirealms.craftengine.core.pack.host.impl.SelfHostHttpServer; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import net.momirealms.craftengine.core.plugin.command.sender.Sender; -import org.bukkit.Chunk; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.incendo.cloud.Command; - -public class DebugHostStatusCommand extends BukkitCommandFeature { - - public DebugHostStatusCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { - super(commandManager, plugin); - } - - @Override - public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { - return builder - .handler(context -> { - Sender sender = plugin().senderFactory().wrap(context.sender()); - sender.sendMessage(Component.text("Self Host status: " + (SelfHostHttpServer.instance().isAlive() ? "on" : "off"))); - byte[] pack = SelfHostHttpServer.instance().resourcePackBytes(); - sender.sendMessage(Component.text("Resource Pack Bytes: " + (pack == null ? "null" : pack.length))); - }); - } - - @Override - public String getFeatureID() { - return "debug_host_status"; - } -} diff --git a/core/build.gradle.kts b/core/build.gradle.kts index b4b762304..7af5d3bbe 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -41,6 +41,7 @@ dependencies { compileOnly("org.apache.logging.log4j:log4j-core:${rootProject.properties["log4j_version"]}") // Netty compileOnly("io.netty:netty-all:${rootProject.properties["netty_version"]}") + compileOnly("io.netty:netty-codec-http:${rootProject.properties["netty_version"]}") // Cache compileOnly("com.github.ben-manes.caffeine:caffeine:${rootProject.properties["caffeine_version"]}") // Compression diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3HostFactory.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3HostFactory.java index 5de2fa3b0..3f52ff790 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3HostFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3HostFactory.java @@ -15,7 +15,6 @@ public class S3HostFactory implements ResourcePackHostFactory { public ResourcePackHost create(Map arguments) { CraftEngine.instance().dependencyManager().loadDependencies( List.of( - Dependencies.NETTY_HTTP, Dependencies.NETTY_HTTP2, Dependencies.REACTIVE_STREAMS, Dependencies.AMAZON_AWSSDK_S3, diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index 0d617ce0c..8a42bb490 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -3,15 +3,19 @@ package net.momirealms.craftengine.core.pack.host.impl; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Scheduler; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.*; +import io.netty.util.CharsetUtil; import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; import net.momirealms.craftengine.core.plugin.CraftEngine; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -19,30 +23,26 @@ import java.nio.file.Files; import java.nio.file.Path; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; import java.util.UUID; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; public class SelfHostHttpServer { private static SelfHostHttpServer instance; + + // Caffeine缓存和统计计数器 private final Cache oneTimePackUrls = Caffeine.newBuilder() .maximumSize(256) .scheduler(Scheduler.systemScheduler()) .expireAfterWrite(1, TimeUnit.MINUTES) .build(); + private final Cache ipAccessCache = Caffeine.newBuilder() .maximumSize(256) .scheduler(Scheduler.systemScheduler()) .expireAfterWrite(10, TimeUnit.MINUTES) .build(); - private ExecutorService threadPool; - private HttpServer server; - private final AtomicLong totalRequests = new AtomicLong(); private final AtomicLong blockedRequests = new AtomicLong(); @@ -59,47 +59,9 @@ public class SelfHostHttpServer { private String packHash; private UUID packUUID; - public void updateProperties(String ip, - int port, - String url, - boolean denyNonMinecraft, - String protocol, - int maxRequests, - int resetInternal, - boolean token) { - this.ip = ip; - this.url = url; - this.denyNonMinecraft = denyNonMinecraft; - this.protocol = protocol; - this.rateLimit = maxRequests; - this.rateLimitInterval = resetInternal; - this.useToken = token; - if (port <= 0 || port > 65535) { - throw new IllegalArgumentException("Invalid port number: " + port); - } - if (port == this.port && this.server != null) return; - if (this.server != null) disable(); - this.port = port; - try { - this.threadPool = Executors.newFixedThreadPool(1); - this.server = HttpServer.create(new InetSocketAddress("::", port), 0); - this.server.createContext("/download", new ResourcePackHandler()); -// this.server.createContext("/metrics", this::handleMetrics); - this.server.setExecutor(this.threadPool); - this.server.start(); - CraftEngine.instance().logger().info("HTTP server started on port: " + port); - } catch (IOException e) { - CraftEngine.instance().logger().warn("Failed to start HTTP server", e); - } - } - - public boolean isAlive() { - return this.server != null; - } - - public byte[] resourcePackBytes() { - return resourcePackBytes; - } + private EventLoopGroup bossGroup; + private EventLoopGroup workerGroup; + private Channel serverChannel; public static SelfHostHttpServer instance() { if (instance == null) { @@ -108,21 +70,31 @@ public class SelfHostHttpServer { return instance; } - @Nullable - public ResourcePackDownloadData generateOneTimeUrl() { - if (this.resourcePackBytes == null) { - return null; + public void updateProperties(String ip, + int port, + String url, + boolean denyNonMinecraft, + String protocol, + int maxRequests, + int resetInterval, + boolean token) { + this.ip = ip; + this.url = url; + this.denyNonMinecraft = denyNonMinecraft; + this.protocol = protocol; + this.rateLimit = maxRequests; + this.rateLimitInterval = resetInterval; + this.useToken = token; + + if (port <= 0 || port > 65535) { + throw new IllegalArgumentException("Invalid port: " + port); } - if (!this.useToken) { - return new ResourcePackDownloadData(url() + "download", this.packUUID, this.packHash); - } - String token = UUID.randomUUID().toString(); - this.oneTimePackUrls.put(token, true); - return new ResourcePackDownloadData( - url() + "download?token=" + URLEncoder.encode(token, StandardCharsets.UTF_8), - this.packUUID, - this.packHash - ); + + if (this.port == port && serverChannel != null) return; + disable(); + + this.port = port; + initializeServer(); } public String url() { @@ -132,6 +104,189 @@ public class SelfHostHttpServer { return this.protocol + "://" + this.ip + ":" + this.port + "/"; } + private void initializeServer() { + bossGroup = new NioEventLoopGroup(1); + workerGroup = new NioEventLoopGroup(); + + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast(new HttpServerCodec()); + pipeline.addLast(new HttpObjectAggregator(1048576)); + pipeline.addLast(new RequestHandler()); + } + }); + try { + serverChannel = b.bind(port).sync().channel(); + CraftEngine.instance().logger().info("Netty HTTP server started on port: " + port); + } catch (InterruptedException e) { + CraftEngine.instance().logger().warn("Failed to start Netty server", e); + Thread.currentThread().interrupt(); + } + } + + @ChannelHandler.Sharable + private class RequestHandler extends SimpleChannelInboundHandler { + @Override + protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { + totalRequests.incrementAndGet(); + + try { + String clientIp = ((InetSocketAddress) ctx.channel().remoteAddress()) + .getAddress().getHostAddress(); + + if (checkRateLimit(clientIp)) { + sendError(ctx, HttpResponseStatus.TOO_MANY_REQUESTS, "Rate limit exceeded"); + blockedRequests.incrementAndGet(); + return; + } + + QueryStringDecoder queryDecoder = new QueryStringDecoder(request.uri()); + String path = queryDecoder.path(); + + if ("/download".equals(path)) { + handleDownload(ctx, request, queryDecoder); + } else if ("/metrics".equals(path)) { + handleMetrics(ctx); + } else { + sendError(ctx, HttpResponseStatus.NOT_FOUND, "Not Found"); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Request handling failed", e); + sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, "Internal Error"); + } + } + + private void handleDownload(ChannelHandlerContext ctx, FullHttpRequest request, QueryStringDecoder queryDecoder) { + if (useToken) { + String token = queryDecoder.parameters().getOrDefault("token", java.util.Collections.emptyList()).stream().findFirst().orElse(null); + if (!validateToken(token)) { + sendError(ctx, HttpResponseStatus.FORBIDDEN, "Invalid token"); + blockedRequests.incrementAndGet(); + return; + } + } + + if (denyNonMinecraft) { + String userAgent = request.headers().get(HttpHeaderNames.USER_AGENT); + if (userAgent == null || !userAgent.startsWith("Minecraft Java/")) { + sendError(ctx, HttpResponseStatus.FORBIDDEN, "Invalid client"); + blockedRequests.incrementAndGet(); + return; + } + } + + if (resourcePackBytes == null) { + sendError(ctx, HttpResponseStatus.NOT_FOUND, "Resource pack missing"); + blockedRequests.incrementAndGet(); + return; + } + + FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.OK, + Unpooled.wrappedBuffer(resourcePackBytes) + ); + response.headers() + .set(HttpHeaderNames.CONTENT_TYPE, "application/zip") + .set(HttpHeaderNames.CONTENT_LENGTH, resourcePackBytes.length); + + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + } + + private void handleMetrics(ChannelHandlerContext ctx) { + String metrics = "# TYPE total_requests counter\n" + + "total_requests " + totalRequests.get() + "\n" + + "# TYPE blocked_requests counter\n" + + "blocked_requests " + blockedRequests.get(); + + FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.OK, + Unpooled.copiedBuffer(metrics, CharsetUtil.UTF_8) + ); + response.headers() + .set(HttpHeaderNames.CONTENT_TYPE, "text/plain") + .set(HttpHeaderNames.CONTENT_LENGTH, metrics.length()); + + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + } + + private boolean checkRateLimit(String clientIp) { + IpAccessRecord record = ipAccessCache.getIfPresent(clientIp); + long now = System.currentTimeMillis(); + + if (record == null) { + record = new IpAccessRecord(now, 1); + ipAccessCache.put(clientIp, record); + return false; + } + + if (now - record.lastAccessTime > rateLimitInterval) { + record.lastAccessTime = now; + record.accessCount = 1; + return false; + } + + return ++record.accessCount > rateLimit; + } + + private boolean validateToken(String token) { + if (token == null || token.length() != 36) return false; + Boolean valid = oneTimePackUrls.getIfPresent(token); + if (valid != null) { + oneTimePackUrls.invalidate(token); + return true; + } + return false; + } + + private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status, String message) { + FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + status, + Unpooled.copiedBuffer(message, CharsetUtil.UTF_8) + ); + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + CraftEngine.instance().logger().warn("Channel error", cause); + ctx.close(); + } + } + + @Nullable + public ResourcePackDownloadData generateOneTimeUrl() { + if (this.resourcePackBytes == null) return null; + + if (!this.useToken) { + return new ResourcePackDownloadData(url() + "download", this.packUUID, this.packHash); + } + + String token = UUID.randomUUID().toString(); + oneTimePackUrls.put(token, true); + return new ResourcePackDownloadData( + url() + "download?token=" + URLEncoder.encode(token, StandardCharsets.UTF_8), + packUUID, + packHash + ); + } + + public void disable() { + if (serverChannel != null) { + serverChannel.close().awaitUninterruptibly(); + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + serverChannel = null; + } + } + public void readResourcePack(Path path) { try { if (Files.exists(path)) { @@ -162,151 +317,8 @@ public class SelfHostHttpServer { } } - private void handleMetrics(HttpExchange exchange) throws IOException { - String metrics = "# TYPE total_requests counter\n" - + "total_requests " + totalRequests.get() + "\n" - + "# TYPE blocked_requests counter\n" - + "blocked_requests " + blockedRequests.get(); - - exchange.getResponseHeaders().set("Content-Type", "text/plain"); - exchange.sendResponseHeaders(200, metrics.length()); - try (OutputStream os = exchange.getResponseBody()) { - os.write(metrics.getBytes(StandardCharsets.UTF_8)); - } - } - - public void disable() { - if (this.server != null) { - this.server.stop(0); - this.server = null; - if (this.threadPool != null) { - this.threadPool.shutdownNow(); - this.threadPool = null; - } - } - } - - private class ResourcePackHandler implements HttpHandler { - @Override - public void handle(HttpExchange exchange) throws IOException { - try { - totalRequests.incrementAndGet(); - - String clientIp = getClientIp(exchange); - if (checkRateLimit(clientIp)) { - handleBlockedRequest(exchange, 429, "Rate limit exceeded"); - return; - } - if (useToken) { - String token = parseToken(exchange); - if (!validateToken(token)) { - handleBlockedRequest(exchange, 403, "Invalid token"); - return; - } - } - if (!validateClient(exchange)) { - handleBlockedRequest(exchange, 403, "Invalid client"); - return; - } - if (resourcePackBytes == null) { - handleBlockedRequest(exchange, 404, "Resource pack missing"); - return; - } - sendResourcePack(exchange); - } catch (Exception e) { - handleBlockedRequest(exchange, 500, "Internal error"); - CraftEngine.instance().logger().warn("Request handling failed", e); - } - } - - private String getClientIp(HttpExchange exchange) { - return exchange.getRemoteAddress().getAddress().getHostAddress(); - } - - private boolean checkRateLimit(String clientIp) { - IpAccessRecord record = ipAccessCache.getIfPresent(clientIp); - long now = System.currentTimeMillis(); - if (record == null) { - record = new IpAccessRecord(now, 1); - ipAccessCache.put(clientIp, record); - } else { - if (now - record.lastAccessTime > rateLimitInterval) { - record = new IpAccessRecord(now, 1); - ipAccessCache.put(clientIp, record); - } else { - record.accessCount++; - } - } - return record.accessCount > rateLimit; - } - - private String parseToken(HttpExchange exchange) { - Map params = parseQuery(exchange.getRequestURI().getQuery()); - return params.get("token"); - } - - private boolean validateToken(String token) { - if (token == null || token.length() != 36) return false; - - Boolean valid = oneTimePackUrls.getIfPresent(token); - if (valid != null) { - oneTimePackUrls.invalidate(token); - return true; - } - return false; - } - - private boolean validateClient(HttpExchange exchange) { - if (!denyNonMinecraft) return true; - - String userAgent = exchange.getRequestHeaders().getFirst("User-Agent"); - return userAgent != null && userAgent.startsWith("Minecraft Java/"); - } - - private void sendResourcePack(HttpExchange exchange) throws IOException { - exchange.getResponseHeaders().set("Content-Type", "application/zip"); - exchange.getResponseHeaders().set("Content-Length", String.valueOf(resourcePackBytes.length)); - exchange.sendResponseHeaders(200, resourcePackBytes.length); - - try (OutputStream os = exchange.getResponseBody()) { - os.write(resourcePackBytes); - } catch (IOException e) { - if (!e.getMessage().contains("abort") && !e.getMessage().contains("reset")) { - CraftEngine.instance().logger().warn("Failed to send resource pack", e); - throw e; - } - CraftEngine.instance().debug(() -> "Client aborted resource pack download: " + e.getMessage()); - } - } - - private void handleBlockedRequest(HttpExchange exchange, int code, String reason) throws IOException { - blockedRequests.incrementAndGet(); - CraftEngine.instance().debug(() -> - String.format("Blocked request [%s] %s: %s", - code, - exchange.getRemoteAddress(), - reason) - ); - exchange.sendResponseHeaders(code, -1); - exchange.close(); - } - - private Map parseQuery(String query) { - Map params = new HashMap<>(); - if (query == null) return params; - - for (String pair : query.split("&")) { - int idx = pair.indexOf("="); - String key = idx > 0 ? pair.substring(0, idx) : pair; - String value = idx > 0 ? pair.substring(idx + 1) : ""; - params.put(key, value); - } - return params; - } - } - private static class IpAccessRecord { - final long lastAccessTime; + long lastAccessTime; int accessCount; IpAccessRecord(long lastAccessTime, int accessCount) { 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 c9c1be83b..5996289c3 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 @@ -315,6 +315,7 @@ public abstract class CraftEngine implements Plugin { Dependencies.AHO_CORASICK, Dependencies.LZ4, Dependencies.EVALEX, + Dependencies.NETTY_HTTP, Dependencies.JIMFS, Dependencies.COMMONS_IMAGING ); diff --git a/gradle.properties b/gradle.properties index 03cc96751..ccb8b0586 100644 --- a/gradle.properties +++ b/gradle.properties @@ -42,7 +42,7 @@ commons_imaging_version=1.0.0-alpha6 sparrow_nbt_version=0.7.3 sparrow_util_version=0.47 fastutil_version=8.5.15 -netty_version=4.1.119.Final +netty_version=4.1.121.Final joml_version=1.10.8 datafixerupper_version=6.0.8 mojang_brigadier_version=1.0.18 From eeb7b54926927c3ce23e025905fafaabe18a91f5 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 24 May 2025 01:40:39 +0800 Subject: [PATCH 45/89] =?UTF-8?q?=E6=8B=92=E7=BB=9D=E6=89=93=E5=8C=85?= =?UTF-8?q?=E6=97=A0=E6=95=88=E7=9A=84=E5=90=8E=E7=BC=80=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/pack/AbstractPackManager.java | 14 ++++++++++---- .../craftengine/core/pack/PackManager.java | 4 ++++ .../core/pack/host/impl/SelfHostHttpServer.java | 5 +---- .../craftengine/core/util/FileUtils.java | 10 ++++++++++ 4 files changed, 25 insertions(+), 8 deletions(-) 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 22cd977ae..f0be59d10 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 @@ -1173,7 +1173,7 @@ public abstract class AbstractPackManager implements PackManager { .map(Pack::resourcePackFolder) .toList()); folders.addAll(Config.foldersToMerge().stream() - .map(it -> plugin.dataFolderPath().getParent().resolve(it)) + .map(it -> this.plugin.dataFolderPath().getParent().resolve(it)) .filter(Files::exists) .toList()); for (Path sourceFolder : folders) { @@ -1188,7 +1188,7 @@ public abstract class AbstractPackManager implements PackManager { } } List externalZips = Config.zipsToMerge().stream() - .map(it -> plugin.dataFolderPath().getParent().resolve(it)) + .map(it -> this.plugin.dataFolderPath().getParent().resolve(it)) .filter(Files::exists) .filter(Files::isRegularFile) .filter(file -> file.getFileName().toString().endsWith(".zip")) @@ -1208,14 +1208,17 @@ public abstract class AbstractPackManager implements PackManager { private void processRegularFile(Path file, BasicFileAttributes attrs, Path sourceFolder, @Nullable FileSystem fs, Map> conflictChecker, Map previousFiles) throws IOException { + if (!ALLOWED_FILE_EXTENSIONS.contains(FileUtils.getExtension(file))) { + return; + } CachedAssetFile cachedAsset = previousFiles.get(file); long lastModified = attrs.lastModifiedTime().toMillis(); long size = attrs.size(); if (cachedAsset != null && cachedAsset.lastModified() == lastModified && cachedAsset.size() == size) { - cachedAssetFiles.put(file, cachedAsset); + this.cachedAssetFiles.put(file, cachedAsset); } else { cachedAsset = new CachedAssetFile(Files.readAllBytes(file), lastModified, size); - cachedAssetFiles.put(file, cachedAsset); + this.cachedAssetFiles.put(file, cachedAsset); } if (fs == null) return; Path relative = sourceFolder.relativize(file); @@ -1234,6 +1237,9 @@ public abstract class AbstractPackManager implements PackManager { if (entryAttrs.isDirectory()) { return FileVisitResult.CONTINUE; } + if (!ALLOWED_FILE_EXTENSIONS.contains(FileUtils.getExtension(entry))) { + return FileVisitResult.CONTINUE; + } Path entryPathInZip = zipRoot.relativize(entry); Path sourcePath = Path.of(zipFile + "!" + entryPathInZip); CachedAssetFile cachedAsset = previousFiles.get(sourcePath); 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 839de5886..489cbd44d 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,8 +9,12 @@ import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.nio.file.Path; import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public interface PackManager extends Manageable { + Set ALLOWED_FILE_EXTENSIONS = new HashSet<>(List.of("png", "txt", "json", "fsh", "vsh", "mcmeta", "zip", "ogg")); void loadResources(boolean recipe); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index 8a42bb490..1706684c2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -29,14 +29,11 @@ import java.util.concurrent.atomic.AtomicLong; public class SelfHostHttpServer { private static SelfHostHttpServer instance; - - // Caffeine缓存和统计计数器 private final Cache oneTimePackUrls = Caffeine.newBuilder() .maximumSize(256) .scheduler(Scheduler.systemScheduler()) .expireAfterWrite(1, TimeUnit.MINUTES) .build(); - private final Cache ipAccessCache = Caffeine.newBuilder() .maximumSize(256) .scheduler(Scheduler.systemScheduler()) @@ -144,7 +141,7 @@ public class SelfHostHttpServer { blockedRequests.incrementAndGet(); return; } - + QueryStringDecoder queryDecoder = new QueryStringDecoder(request.uri()); String path = queryDecoder.path(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java index ac23e93a2..1d2a9a5b6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java @@ -11,6 +11,16 @@ public class FileUtils { private FileUtils() {} + public static String getExtension(Path path) { + final String name = path.getFileName().toString(); + int index = name.lastIndexOf('.'); + if (index == -1) { + return ""; + } else { + return name.substring(index + 1); + } + } + public static String pathWithoutExtension(String path) { int i = path.lastIndexOf('.'); return i == -1 ? path : path.substring(0, i); From 530630b5274922509552298300c4c42eaefa6df7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 24 May 2025 01:47:58 +0800 Subject: [PATCH 46/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E8=8D=AF=E6=B0=B4=E6=95=88=E6=9E=9C=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 2 + .../src/main/resources/translations/zh_cn.yml | 2 + .../plugin/context/event/EventFunctions.java | 1 + .../context/function/CommonFunctions.java | 1 + .../function/PotionEffectFunction.java | 4 +- .../function/RemovePotionEffectFunction.java | 56 +++++++++++++++++++ 6 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index c268cd1a0..7d447ee04 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -333,6 +333,8 @@ warning.config.function.particle.missing_block_state: "Issue found in fi warning.config.function.leveler_exp.missing_count: "Issue found in file - The config '' is missing the required 'count' argument for 'leveler_exp' function." warning.config.function.leveler_exp.missing_leveler: "Issue found in file - The config '' is missing the required 'leveler' argument for 'leveler_exp' function." warning.config.function.leveler_exp.missing_plugin: "Issue found in file - The config '' is missing the required 'plugin' argument for 'leveler_exp' function." +warning.config.function.remove_potion_effect.missing_potion_effect: "Issue found in file - The config '' is missing the required 'potion-effect' argument for 'remove_potion_effect' function." +warning.config.function.potion_effect.missing_potion_effect: "Issue found in file - The config '' is missing the required 'potion-effect' argument for 'potion_effect' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index ba48283e0..756a7cbf3 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -333,6 +333,8 @@ warning.config.function.particle.missing_block_state: "在文件 warning.config.function.leveler_exp.missing_count: "在文件 中发现问题 - 配置项 '' 缺少 'leveler_exp' 函数必需的 'count' 参数" warning.config.function.leveler_exp.missing_leveler: "在文件 中发现问题 - 配置项 '' 缺少 'leveler_exp' 函数必需的 'leveler' 参数" warning.config.function.leveler_exp.missing_plugin: "在文件 中发现问题 - 配置项 '' 缺少 'leveler_exp' 函数必需的 'plugin' 参数" +warning.config.function.remove_potion_effect.missing_potion_effect: "Issue found in file - The config '' is missing the required 'potion-effect' argument for 'remove_potion_effect' function." +warning.config.function.potion_effect.missing_potion_effect: "Issue found in file - The config '' is missing the required 'potion-effect' argument for 'potion_effect' function." warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index bc07135d2..1392d6f6a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -35,6 +35,7 @@ public class EventFunctions { register(CommonFunctions.PLAY_SOUND, new PlaySoundFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.PARTICLE, new ParticleFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.POTION_EFFECT, new PotionEffectFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.REMOVE_POTION_EFFECT, new RemovePotionEffectFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.LEVELER_EXP, new LevelerExpFunction.FactoryImpl<>(EventConditions::fromMap)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index a1011a396..3431302fe 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -14,6 +14,7 @@ public final class CommonFunctions { public static final Key PARTICLE = Key.of("craftengine:particle"); public static final Key PLAY_SOUND = Key.of("craftengine:play_sound"); public static final Key POTION_EFFECT = Key.of("craftengine:potion_effect"); + public static final Key REMOVE_POTION_EFFECT = Key.of("craftengine:remove_potion_effect"); public static final Key BREAK_BLOCK = Key.of("craftengine:break_block"); public static final Key CANCEL_EVENT = Key.of("craftengine:cancel_event"); public static final Key UPDATE_INTERACTION_TICK = Key.of("craftengine:update_interaction_tick"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java index 461e838ed..ff13ddde0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java @@ -59,8 +59,8 @@ public class PotionEffectFunction extends AbstractCondition @Override public Function create(Map arguments) { Key effectType = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("potion-effect"), "warning.config.function.potion_effect.missing_potion_effect")); - NumberProvider duration = NumberProviders.fromObject(arguments.get("duration")); - NumberProvider amplifier = NumberProviders.fromObject(arguments.get("amplifier")); + NumberProvider duration = NumberProviders.fromObject(arguments.getOrDefault("duration", 20)); + NumberProvider amplifier = NumberProviders.fromObject(arguments.getOrDefault("amplifier", 0)); boolean ambient = (boolean) arguments.getOrDefault("ambient", false); boolean particles = (boolean) arguments.getOrDefault("particles", true); return new PotionEffectFunction<>(effectType, duration, amplifier, ambient, particles, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java new file mode 100644 index 000000000..ae48f30aa --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java @@ -0,0 +1,56 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.*; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; + +public class RemovePotionEffectFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; + private final Key potionEffectType; + + public RemovePotionEffectFunction(Key potionEffectType, PlayerSelector selector, List> predicates) { + super(predicates); + this.potionEffectType = potionEffectType; + this.selector = selector; + } + + @Override + public void runInternal(CTX ctx) { + if (this.selector == null) { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { + it.removePotionEffect(this.potionEffectType); + }); + } else { + for (Player target : this.selector.get(ctx)) { + target.removePotionEffect(this.potionEffectType); + } + } + } + + @Override + public Key type() { + return CommonFunctions.REMOVE_POTION_EFFECT; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Key effectType = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("potion-effect"), "warning.config.function.remove_potion_effect.missing_potion_effect")); + return new RemovePotionEffectFunction<>(effectType, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); + } + } +} From 38cd8f7a8812c1165b76c215c1a73e20fb9a6500 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 24 May 2025 02:04:21 +0800 Subject: [PATCH 47/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=90=84=E7=A7=8D?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 8 +++- .../src/main/resources/translations/zh_cn.yml | 8 +++- .../craftengine/core/loot/LootConditions.java | 5 ++- .../context/condition/CommonConditions.java | 3 ++ .../condition/StringContainsCondition.java | 40 +++++++++++++++++++ ...dition.java => StringEqualsCondition.java} | 10 ++--- .../condition/StringRegexCondition.java | 40 +++++++++++++++++++ .../plugin/context/event/EventConditions.java | 5 ++- .../function/RemovePotionEffectFunction.java | 5 +-- 9 files changed, 110 insertions(+), 14 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringContainsCondition.java rename core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/{EqualsCondition.java => StringEqualsCondition.java} (79%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringRegexCondition.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 7d447ee04..54b446877 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -91,8 +91,12 @@ warning.config.condition.match_item.missing_id: "Issue found in file Issue found in file - The config '' is missing the required 'enchantment' argument for 'table_bonus' condition." warning.config.condition.table_bonus.missing_chances: "Issue found in file - The config '' is missing the required 'chances' argument for 'table_bonus' condition." warning.config.condition.permission.missing_permission: "Issue found in file - The config '' is missing the required 'permission' argument for 'permission' condition." -warning.config.condition.equals.missing_value1: "Issue found in file - The config '' is missing the required 'value1' argument for 'equals' condition." -warning.config.condition.equals.missing_value2: "Issue found in file - The config '' is missing the required 'value2' argument for 'equals' condition." +warning.config.condition.string_equals.missing_value1: "Issue found in file - The config '' is missing the required 'value1' argument for 'string_equals' condition." +warning.config.condition.string_equals.missing_value2: "Issue found in file - The config '' is missing the required 'value2' argument for 'string_equals' condition." +warning.config.condition.string_contains.missing_value1: "Issue found in file - The config '' is missing the required 'value1' argument for 'string_contains' condition." +warning.config.condition.string_contains.missing_value2: "Issue found in file - The config '' is missing the required 'value2' argument for 'string_contains' condition." +warning.config.condition.string_regex.missing_value: "Issue found in file - The config '' is missing the required 'value' argument for 'string_regex' condition." +warning.config.condition.string_regex.missing_regex: "Issue found in file - The config '' is missing the required 'regex' argument for 'string_regex' condition." warning.config.condition.expression.missing_expression: "Issue found in file - The config '' is missing the required 'expression' argument for 'expression' condition." warning.config.condition.is_null.missing_argument: "Issue found in file - The config '' is missing the required 'argument' argument for 'is_null' condition." warning.config.condition.hand.missing_hand: "Issue found in file - The config '' is missing the required 'hand' argument for 'hand' condition." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 756a7cbf3..7ecef97c7 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -91,8 +91,12 @@ warning.config.condition.match_item.missing_id: "在文件 发 warning.config.condition.table_bonus.missing_enchantment: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'enchantment' 参数" warning.config.condition.table_bonus.missing_chances: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'chances' 参数" warning.config.condition.permission.missing_permission: "在文件 中发现问题 - 配置项 '' 缺少 'permission' 条件必需的 'permission' 参数" -warning.config.condition.equals.missing_value1: "在文件 中发现问题 - 配置项 '' 缺少 'equals' 条件必需的 'value1' 参数" -warning.config.condition.equals.missing_value2: "在文件 中发现问题 - 配置项 '' 缺少 'equals' 条件必需的 'value2' 参数" +warning.config.condition.string_equals.missing_value1: "在文件 中发现问题 - 配置项 '' 缺少 'string_equals' 条件必需的 'value1' 参数" +warning.config.condition.string_equals.missing_value2: "在文件 中发现问题 - 配置项 '' 缺少 'string_equals' 条件必需的 'value2' 参数" +warning.config.condition.string_contains.missing_value1: "在文件 中发现问题 - 配置项 '' 缺少 'string_contains' 条件必需的 'value1' 参数" +warning.config.condition.string_contains.missing_value2: "在文件 中发现问题 - 配置项 '' 缺少 'string_contains' 条件必需的 'value2' 参数" +warning.config.condition.string_regex.missing_value: "在文件 中发现问题 - 配置项 '' 缺少 'string_regex' 条件必需的 'value' 参数" +warning.config.condition.string_regex.missing_regex: "在文件 中发现问题 - 配置项 '' 缺少 'string_regex' 条件必需的 'regex' 参数" warning.config.condition.expression.missing_expression: "在文件 中发现问题 - 配置项 '' 缺少 'expression' 条件必需的 'expression' 参数" warning.config.condition.is_null.missing_argument: "在文件 发现问题 - 配置项 '' 缺少 'is_null' 条件的必需的 'argument' 参数." warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java index 26798ceb1..0f43e96d8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java @@ -31,7 +31,10 @@ public class LootConditions { register(CommonConditions.RANDOM, new RandomCondition.FactoryImpl<>()); register(CommonConditions.DISTANCE, new DistanceCondition.FactoryImpl<>()); register(CommonConditions.PERMISSION, new PermissionCondition.FactoryImpl<>()); - register(CommonConditions.EQUALS, new EqualsCondition.FactoryImpl<>()); + register(CommonConditions.EQUALS, new StringEqualsCondition.FactoryImpl<>()); + register(CommonConditions.STRING_REGEX, new StringRegexCondition.FactoryImpl<>()); + register(CommonConditions.STRING_EQUALS, new StringEqualsCondition.FactoryImpl<>()); + register(CommonConditions.STRING_CONTAINS, new StringContainsCondition.FactoryImpl<>()); register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>()); register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>()); register(CommonConditions.HAND, new HandCondition.FactoryImpl<>()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java index 44a588cb9..3279302ad 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java @@ -19,6 +19,9 @@ public final class CommonConditions { public static final Key DISTANCE = Key.from("craftengine:distance"); public static final Key PERMISSION = Key.from("craftengine:permission"); public static final Key EQUALS = Key.from("craftengine:equals"); + public static final Key STRING_EQUALS = Key.from("craftengine:string_equals"); + public static final Key STRING_CONTAINS = Key.from("craftengine:string_contains"); + public static final Key STRING_REGEX = Key.from("craftengine:regex"); public static final Key EXPRESSION = Key.from("craftengine:expression"); public static final Key IS_NULL = Key.from("craftengine:is_null"); public static final Key HAND = Key.from("craftengine:hand"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringContainsCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringContainsCondition.java new file mode 100644 index 000000000..702bc54d9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringContainsCondition.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public class StringContainsCondition implements Condition { + private final TextProvider value1; + private final TextProvider value2; + + public StringContainsCondition(TextProvider value1, TextProvider value2) { + this.value1 = value1; + this.value2 = value2; + } + + @Override + public Key type() { + return CommonConditions.STRING_CONTAINS; + } + + @Override + public boolean test(CTX ctx) { + return this.value1.get(ctx).contains(this.value2.get(ctx)); + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + String value1 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value1"), "warning.config.condition.string_contains.missing_value1"); + String value2 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value2"), "warning.config.condition.string_contains.missing_value2"); + return new StringContainsCondition<>(TextProviders.fromString(value1), TextProviders.fromString(value2)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringEqualsCondition.java similarity index 79% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringEqualsCondition.java index 68a84533c..d00160f58 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EqualsCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringEqualsCondition.java @@ -9,11 +9,11 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; -public class EqualsCondition implements Condition { +public class StringEqualsCondition implements Condition { private final TextProvider value1; private final TextProvider value2; - public EqualsCondition(TextProvider value1, TextProvider value2) { + public StringEqualsCondition(TextProvider value1, TextProvider value2) { this.value1 = value1; this.value2 = value2; } @@ -32,9 +32,9 @@ public class EqualsCondition implements Condition { @Override public Condition create(Map arguments) { - String value1 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value1"), "warning.config.condition.equals.missing_value1"); - String value2 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value2"), "warning.config.condition.equals.missing_value2"); - return new EqualsCondition<>(TextProviders.fromString(value1), TextProviders.fromString(value2)); + String value1 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value1"), "warning.config.condition.string_equals.missing_value1"); + String value2 = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value2"), "warning.config.condition.string_equals.missing_value2"); + return new StringEqualsCondition<>(TextProviders.fromString(value1), TextProviders.fromString(value2)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringRegexCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringRegexCondition.java new file mode 100644 index 000000000..122e14bf2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/StringRegexCondition.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public class StringRegexCondition implements Condition { + private final TextProvider value; + private final TextProvider regex; + + public StringRegexCondition(TextProvider value, TextProvider regex) { + this.value = value; + this.regex = regex; + } + + @Override + public Key type() { + return CommonConditions.STRING_REGEX; + } + + @Override + public boolean test(CTX ctx) { + return this.value.get(ctx).matches(this.regex.get(ctx)); + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + String value = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("value"), "warning.config.condition.string_regex.missing_value"); + String regex = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("regex"), "warning.config.condition.string_regex.missing_regex"); + return new StringRegexCondition<>(TextProviders.fromString(value), TextProviders.fromString(regex)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java index 3c93dd0e0..4d5d5ebcf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java @@ -29,7 +29,10 @@ public class EventConditions { register(CommonConditions.RANDOM, new RandomCondition.FactoryImpl<>()); register(CommonConditions.DISTANCE, new DistanceCondition.FactoryImpl<>()); register(CommonConditions.PERMISSION, new PermissionCondition.FactoryImpl<>()); - register(CommonConditions.EQUALS, new EqualsCondition.FactoryImpl<>()); + register(CommonConditions.EQUALS, new StringEqualsCondition.FactoryImpl<>()); + register(CommonConditions.STRING_REGEX, new StringRegexCondition.FactoryImpl<>()); + register(CommonConditions.STRING_EQUALS, new StringEqualsCondition.FactoryImpl<>()); + register(CommonConditions.STRING_CONTAINS, new StringContainsCondition.FactoryImpl<>()); register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>()); register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>()); register(CommonConditions.HAND, new HandCondition.FactoryImpl<>()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java index ae48f30aa..df290c3c3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java @@ -1,9 +1,8 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.context.*; -import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; -import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; From 33095f5b8192c39c6141ee9a3e8e313564b46888 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 24 May 2025 03:01:20 +0800 Subject: [PATCH 48/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0cooldown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 4 + .../src/main/resources/translations/zh_cn.yml | 12 ++- .../plugin/network/BukkitNetworkManager.java | 22 +++++- .../plugin/user/BukkitServerPlayer.java | 22 ++++++ .../core/entity/player/Player.java | 5 ++ .../core/plugin/context/CooldownData.java | 75 +++++++++++++++++++ .../context/condition/CommonConditions.java | 1 + .../context/condition/CooldownCondition.java | 43 +++++++++++ .../plugin/context/event/EventConditions.java | 1 + .../plugin/context/event/EventFunctions.java | 2 + .../context/function/CommonFunctions.java | 2 + .../function/RemoveCooldownFunction.java | 69 +++++++++++++++++ .../function/RemovePotionEffectFunction.java | 19 +++-- .../context/function/SetCooldownFunction.java | 72 ++++++++++++++++++ .../craftengine/core/util/TimeUtils.java | 62 +++++++++++++++ 15 files changed, 401 insertions(+), 10 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CooldownCondition.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemoveCooldownFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetCooldownFunction.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/TimeUtils.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 54b446877..3fb06992d 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -101,6 +101,7 @@ warning.config.condition.expression.missing_expression: "Issue found in warning.config.condition.is_null.missing_argument: "Issue found in file - The config '' is missing the required 'argument' argument for 'is_null' condition." warning.config.condition.hand.missing_hand: "Issue found in file - The config '' is missing the required 'hand' argument for 'hand' condition." warning.config.condition.hand.invalid_hand: "Issue found in file - The config '' is using an invalid 'hand' argument '' for 'hand' condition. Allowed hand types: []" +warning.config.condition.cooldown.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'cooldown' condition." warning.config.structure.not_section: "Issue found in file - The config '' is expected to be a config section while it's actually a(n) ''." warning.config.image.duplicate: "Issue found in file - Duplicated image ''. Please check if there is the same configuration in other files." warning.config.image.missing_height: "Issue found in file - The image '' is missing the required 'height' argument." @@ -339,6 +340,9 @@ warning.config.function.leveler_exp.missing_leveler: "Issue found in fil warning.config.function.leveler_exp.missing_plugin: "Issue found in file - The config '' is missing the required 'plugin' argument for 'leveler_exp' function." warning.config.function.remove_potion_effect.missing_potion_effect: "Issue found in file - The config '' is missing the required 'potion-effect' argument for 'remove_potion_effect' function." warning.config.function.potion_effect.missing_potion_effect: "Issue found in file - The config '' is missing the required 'potion-effect' argument for 'potion_effect' function." +warning.config.function.set_cooldown.missing_time: "Issue found in file - The config '' is missing the required 'time' argument for 'set_cooldown' function." +warning.config.function.set_cooldown.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'set_cooldown' function." +warning.config.function.remove_cooldown.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'remove_cooldown' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 7ecef97c7..804f0414b 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -100,8 +100,9 @@ warning.config.condition.string_regex.missing_regex: "在文件 warning.config.condition.expression.missing_expression: "在文件 中发现问题 - 配置项 '' 缺少 'expression' 条件必需的 'expression' 参数" warning.config.condition.is_null.missing_argument: "在文件 发现问题 - 配置项 '' 缺少 'is_null' 条件的必需的 'argument' 参数." warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" -warning.config.condition.hand.missing_hand: "Issue found in file - The config '' is missing the required 'hand' argument for 'hand' condition." -warning.config.condition.hand.invalid_hand: "Issue found in file - The config '' is using an invalid 'hand' argument '' for 'hand' condition. Allowed hand types: []" +warning.config.condition.hand.missing_hand: "在文件 发现问题 - 配置项 '' 缺少 'hand' 条件必需的 'hand' 参数" +warning.config.condition.hand.invalid_hand: "在文件 发现问题 - 配置项 '' 使用了无效的 'hand' 参数 ''('hand' 条件)。允许的手部类型: []" +warning.config.condition.cooldown.missing_id: "在文件 发现问题 - 配置项 '' 缺少 'cooldown' 条件必需的 'id' 参数" warning.config.image.duplicate: "在文件 发现问题 - 重复的图片配置 '' 请检查其他文件中是否存在相同配置" warning.config.image.missing_height: "在文件 发现问题 - 图片 '' 缺少必需的 'height' 参数" warning.config.image.height_ascent_conflict: "在文件 发现问题 - 图片 '' 违反位图规则: 'height' 参数 '' 必须不小于 'ascent' 参数 ''" @@ -337,8 +338,11 @@ warning.config.function.particle.missing_block_state: "在文件 warning.config.function.leveler_exp.missing_count: "在文件 中发现问题 - 配置项 '' 缺少 'leveler_exp' 函数必需的 'count' 参数" warning.config.function.leveler_exp.missing_leveler: "在文件 中发现问题 - 配置项 '' 缺少 'leveler_exp' 函数必需的 'leveler' 参数" warning.config.function.leveler_exp.missing_plugin: "在文件 中发现问题 - 配置项 '' 缺少 'leveler_exp' 函数必需的 'plugin' 参数" -warning.config.function.remove_potion_effect.missing_potion_effect: "Issue found in file - The config '' is missing the required 'potion-effect' argument for 'remove_potion_effect' function." -warning.config.function.potion_effect.missing_potion_effect: "Issue found in file - The config '' is missing the required 'potion-effect' argument for 'potion_effect' function." +warning.config.function.remove_potion_effect.missing_potion_effect: "在文件 中发现问题 - 配置项 '' 缺少 'remove_potion_effect' 函数必需的 'potion-effect' 参数" +warning.config.function.potion_effect.missing_potion_effect: "在文件 中发现问题 - 配置项 '' 缺少 'potion_effect' 函数必需的 'potion-effect' 参数" +warning.config.function.set_cooldown.missing_time: "在文件 中发现问题 - 配置项 '' 缺少 'set_cooldown' 函数必需的 'time' 参数" +warning.config.function.set_cooldown.missing_id: "在文件 中发现问题 - 配置项 '' 缺少 'set_cooldown' 函数必需的 'id' 参数" +warning.config.function.remove_cooldown.missing_id: "在文件 中发现问题 - 配置项 '' 缺少 'remove_cooldown' 函数必需的 'id' 参数" warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" 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 d5998aed6..82b8ea92a 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 @@ -12,8 +12,10 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20_5; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.CooldownData; import net.momirealms.craftengine.core.plugin.network.*; import net.momirealms.craftengine.core.util.*; import org.bukkit.Bukkit; @@ -24,10 +26,12 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.messaging.PluginMessageListener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.IOException; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; @@ -191,17 +195,33 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(priority = EventPriority.LOWEST) public void onPlayerQuit(PlayerQuitEvent event) { Player player = event.getPlayer(); Channel channel = getChannel(player); NetWorkUser user = removeUser(channel); if (user == null) return; + saveCooldown(player, user); handleDisconnection(channel); this.onlineUsers.remove(player.getUniqueId()); this.resetUserArray(); } + private void saveCooldown(Player player, NetWorkUser user) { + if (user instanceof BukkitServerPlayer serverPlayer) { + CooldownData cd = serverPlayer.cooldown(); + if (cd != null) { + try { + byte[] data = CooldownData.toBytes(cd); + player.getPersistentDataContainer().set(KeyUtils.toNamespacedKey(CooldownData.COOLDOWN_KEY), PersistentDataType.BYTE_ARRAY, data); + } catch (IOException e) { + player.getPersistentDataContainer().remove(KeyUtils.toNamespacedKey(CooldownData.COOLDOWN_KEY)); + this.plugin.logger().warn("Failed to save cooldown for player " + player.getName(), e); + } + } + } + } + private void resetUserArray() { this.onlineUserArray = this.onlineUsers.values().toArray(new BukkitServerPlayer[0]); } 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 40fac266a..ad1375138 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 @@ -19,6 +19,7 @@ import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.context.CooldownData; import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; @@ -35,11 +36,13 @@ import org.bukkit.block.Block; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.persistence.PersistentDataType; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.util.RayTraceResult; import org.jetbrains.annotations.Nullable; +import java.io.IOException; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.util.*; @@ -94,6 +97,8 @@ public class BukkitServerPlayer extends Player { // cache interaction range here private int lastUpdateInteractionRangeTick; private double cachedInteractionRange; + // cooldown data + private CooldownData cooldownData; private final Map entityTypeView = new ConcurrentHashMap<>(); @@ -107,6 +112,13 @@ public class BukkitServerPlayer extends Player { this.serverPlayerRef = new WeakReference<>(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)); this.uuid = player.getUniqueId(); this.name = player.getName(); + byte[] bytes = player.getPersistentDataContainer().get(KeyUtils.toNamespacedKey(CooldownData.COOLDOWN_KEY), PersistentDataType.BYTE_ARRAY); + try { + this.cooldownData = CooldownData.fromBytes(bytes); + } catch (IOException e) { + this.cooldownData = new CooldownData(); + this.plugin.logger().warn("Failed to parse cooldown data", e); + } } @Override @@ -871,4 +883,14 @@ public class BukkitServerPlayer extends Player { if (type == null) return; this.platformPlayer().removePotionEffect(type); } + + @Override + public void clearPotionEffects() { + this.platformPlayer().clearActivePotionEffects(); + } + + @Override + public CooldownData cooldown() { + return this.cooldownData; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index 4a5f8f7a8..5e0309c97 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.entity.player; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.CooldownData; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.BlockPos; @@ -128,4 +129,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract void addPotionEffect(Key potionEffectType, int duration, int amplifier, boolean ambient, boolean particles); public abstract void removePotionEffect(Key potionEffectType); + + public abstract void clearPotionEffects(); + + public abstract CooldownData cooldown(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java new file mode 100644 index 000000000..f693e573f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java @@ -0,0 +1,75 @@ +package net.momirealms.craftengine.core.plugin.context; + +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.LongTag; +import net.momirealms.sparrow.nbt.NBT; +import net.momirealms.sparrow.nbt.Tag; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class CooldownData { + public static final Key COOLDOWN_KEY = Key.of("craftengine:cooldown"); + private final Map cooldownMap = Collections.synchronizedMap(new HashMap<>()); + + public boolean isOnCooldown(String key) { + long currentTime = System.currentTimeMillis(); + if (this.cooldownMap.containsKey(key)) { + long expirationTime = this.cooldownMap.get(key); + return currentTime < expirationTime; + } + return false; + } + + public void setCooldown(String key, long duration) { + this.cooldownMap.put(key, System.currentTimeMillis() + duration); + } + + public void addCooldown(String key, long duration) { + if (this.cooldownMap.containsKey(key)) { + this.cooldownMap.put(key, this.cooldownMap.get(key) + duration); + } else { + setCooldown(key, duration); + } + } + + public void removeCooldown(String key) { + this.cooldownMap.remove(key); + } + + public void clearCooldowns() { + this.cooldownMap.clear(); + } + + public static byte[] toBytes(CooldownData data) throws IOException { + CompoundTag tag = new CompoundTag(); + long currentTime = System.currentTimeMillis(); + for (Map.Entry entry : data.cooldownMap.entrySet()) { + if (currentTime < entry.getValue()) { + tag.putLong(entry.getKey(), entry.getValue()); + } + } + return NBT.toBytes(tag); + } + + public static CooldownData fromBytes(byte[] data) throws IOException { + if (data == null || data.length == 0) return new CooldownData(); + CooldownData cd = new CooldownData(); + long currentTime = System.currentTimeMillis(); + CompoundTag tag = NBT.fromBytes(data); + if (tag != null) { + for (Map.Entry entry : tag.tags.entrySet()) { + if (entry.getValue() instanceof LongTag longTag) { + long expire = longTag.getAsLong(); + if (currentTime < expire) { + cd.setCooldown(entry.getKey(), expire); + } + } + } + } + return cd; + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java index 3279302ad..43ac2cb0d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java @@ -18,6 +18,7 @@ public final class CommonConditions { public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); public static final Key DISTANCE = Key.from("craftengine:distance"); public static final Key PERMISSION = Key.from("craftengine:permission"); + public static final Key COOLDOWN = Key.from("craftengine:cooldown"); public static final Key EQUALS = Key.from("craftengine:equals"); public static final Key STRING_EQUALS = Key.from("craftengine:string_equals"); public static final Key STRING_CONTAINS = Key.from("craftengine:string_contains"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CooldownCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CooldownCondition.java new file mode 100644 index 000000000..785866de7 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CooldownCondition.java @@ -0,0 +1,43 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; +import java.util.Optional; + +public class CooldownCondition implements Condition { + private final String key; + + public CooldownCondition(String key) { + this.key = key; + } + + @Override + public Key type() { + return CommonConditions.COOLDOWN; + } + + @Override + public boolean test(CTX ctx) { + Optional player = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + if (player.isPresent()) { + Player p = player.get(); + return p.cooldown().isOnCooldown(this.key); + } + return false; + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("id"), "warning.config.condition.cooldown.missing_id"); + return new CooldownCondition<>(id); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java index 4d5d5ebcf..a46d7a09b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java @@ -36,6 +36,7 @@ public class EventConditions { register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>()); register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>()); register(CommonConditions.HAND, new HandCondition.FactoryImpl<>()); + register(CommonConditions.COOLDOWN, new CooldownCondition.FactoryImpl<>()); } public static void register(Key key, ConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index 1392d6f6a..8613eb5c4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -37,6 +37,8 @@ public class EventFunctions { register(CommonFunctions.POTION_EFFECT, new PotionEffectFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.REMOVE_POTION_EFFECT, new RemovePotionEffectFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.LEVELER_EXP, new LevelerExpFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.SET_COOLDOWN, new SetCooldownFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.REMOVE_COOLDOWN, new RemoveCooldownFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index 3431302fe..7f490b6d9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -21,6 +21,8 @@ public final class CommonFunctions { public static final Key SET_COUNT = Key.of("craftengine:set_count"); public static final Key PLACE_BLOCK = Key.of("craftengine:place_block"); public static final Key SET_FOOD = Key.of("craftengine:food"); + public static final Key SET_COOLDOWN = Key.of("craftengine:set_cooldown"); + public static final Key REMOVE_COOLDOWN = Key.of("craftengine:remove_cooldown"); public static final Key SET_SATURATION = Key.of("craftengine:saturation"); public static final Key DROP_LOOT = Key.of("craftengine:drop_loot"); public static final Key SWING_HAND = Key.of("craftengine:swing_hand"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemoveCooldownFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemoveCooldownFunction.java new file mode 100644 index 000000000..7463d8bf2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemoveCooldownFunction.java @@ -0,0 +1,69 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.CooldownData; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class RemoveCooldownFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; + private final String id; + private final boolean all; + + public RemoveCooldownFunction(String id, boolean all, PlayerSelector selector, List> predicates) { + super(predicates); + this.selector = selector; + this.id = id; + this.all = all; + } + + @Override + public void runInternal(CTX ctx) { + if (this.selector == null) { + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + optionalPlayer.ifPresent(player -> { + CooldownData data = player.cooldown(); + if (this.all) data.clearCooldowns(); + else data.removeCooldown(this.id); + }); + } else { + for (Player target : this.selector.get(ctx)) { + CooldownData data = target.cooldown(); + if (this.all) data.clearCooldowns(); + else data.removeCooldown(this.id); + } + } + } + + @Override + public Key type() { + return CommonFunctions.REMOVE_COOLDOWN; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + boolean all = (boolean) arguments.getOrDefault("all", false); + if (all) { + return new RemoveCooldownFunction<>(null, true, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); + } else { + String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("id"), "warning.config.function.remove_cooldown.missing_id"); + return new RemoveCooldownFunction<>(id, false, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java index df290c3c3..cc0148996 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemovePotionEffectFunction.java @@ -15,22 +15,26 @@ import java.util.Map; public class RemovePotionEffectFunction extends AbstractConditionalFunction { private final PlayerSelector selector; private final Key potionEffectType; + private final boolean all; - public RemovePotionEffectFunction(Key potionEffectType, PlayerSelector selector, List> predicates) { + public RemovePotionEffectFunction(Key potionEffectType, boolean all, PlayerSelector selector, List> predicates) { super(predicates); this.potionEffectType = potionEffectType; this.selector = selector; + this.all = all; } @Override public void runInternal(CTX ctx) { if (this.selector == null) { ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { - it.removePotionEffect(this.potionEffectType); + if (this.all) it.clearPotionEffects(); + else it.removePotionEffect(this.potionEffectType); }); } else { for (Player target : this.selector.get(ctx)) { - target.removePotionEffect(this.potionEffectType); + if (this.all) target.clearPotionEffects(); + else target.removePotionEffect(this.potionEffectType); } } } @@ -48,8 +52,13 @@ public class RemovePotionEffectFunction extends AbstractCon @Override public Function create(Map arguments) { - Key effectType = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("potion-effect"), "warning.config.function.remove_potion_effect.missing_potion_effect")); - return new RemovePotionEffectFunction<>(effectType, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); + boolean all = (boolean) arguments.getOrDefault("all", false); + if (all) { + return new RemovePotionEffectFunction<>(null, true, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); + } else { + Key effectType = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("potion-effect"), "warning.config.function.remove_potion_effect.missing_potion_effect")); + return new RemovePotionEffectFunction<>(effectType, false, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); + } } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetCooldownFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetCooldownFunction.java new file mode 100644 index 000000000..68eb002d6 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetCooldownFunction.java @@ -0,0 +1,72 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.*; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.TimeUtils; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class SetCooldownFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; + private final TextProvider time; + private final String id; + private final boolean add; + + public SetCooldownFunction(TextProvider time, String id, boolean add, PlayerSelector selector, List> predicates) { + super(predicates); + this.time = time; + this.add = add; + this.selector = selector; + this.id = id; + } + + @Override + public void runInternal(CTX ctx) { + if (this.selector == null) { + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + optionalPlayer.ifPresent(player -> { + long millis = TimeUtils.parseToMillis(this.time.get(ctx)); + CooldownData data = player.cooldown(); + if (this.add) data.addCooldown(this.id, millis); + else data.setCooldown(this.id, millis); + }); + } else { + for (Player target : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(target, ContextHolder.EMPTY)); + long millis = TimeUtils.parseToMillis(this.time.get(relationalContext)); + CooldownData data = target.cooldown(); + if (this.add) data.addCooldown(this.id, millis); + else data.setCooldown(this.id, millis); + } + } + } + + @Override + public Key type() { + return CommonFunctions.SET_COOLDOWN; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("id"), "warning.config.function.set_cooldown.missing_id"); + String time = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("time"), "warning.config.function.set_cooldown.missing_time"); + boolean add = (boolean) arguments.getOrDefault("add", false); + return new SetCooldownFunction<>(TextProviders.fromString(time), id, add, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/TimeUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/TimeUtils.java new file mode 100644 index 000000000..072e4d74a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/TimeUtils.java @@ -0,0 +1,62 @@ +package net.momirealms.craftengine.core.util; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class TimeUtils { + private TimeUtils() {} + + private static final Map TIME_UNITS = new HashMap<>(Map.of( + 'w', 604800000L, + 'd', 86400000L, + 'h', 3600000L, + 'm', 60000L, + 's', 1000L + )); + + private static final Pattern TIME_PATTERN = Pattern.compile("(\\d+)([dhmsDwHMSW])", Pattern.CASE_INSENSITIVE); + + public static long parseToMillis(String timeStr) { + if (timeStr == null || timeStr.trim().isEmpty()) { + throw new IllegalArgumentException("Time string cannot be null or empty"); + } + String trimmedStr = timeStr.trim(); + if (trimmedStr.matches("^\\d+$")) { + return Long.parseLong(trimmedStr); + } + long totalMillis = 0; + Matcher matcher = TIME_PATTERN.matcher(trimmedStr); + int lastEnd = 0; + while (matcher.find()) { + if (matcher.start() != lastEnd) { + throw new IllegalArgumentException("Invalid characters in time string: " + + trimmedStr.substring(lastEnd, matcher.start())); + } + lastEnd = matcher.end(); + long value = Long.parseLong(matcher.group(1)); + if (value < 0) { + throw new IllegalArgumentException("Time value cannot be negative: " + value); + } + char unit = Character.toLowerCase(matcher.group(2).charAt(0)); + if (!TIME_UNITS.containsKey(unit)) { + throw new IllegalArgumentException("Unknown time unit: " + unit); + } + try { + totalMillis = Math.addExact(totalMillis, Math.multiplyExact(value, TIME_UNITS.get(unit))); + } catch (ArithmeticException e) { + throw new IllegalArgumentException("Time value too large, would overflow long: " + timeStr); + } + } + + if (lastEnd != trimmedStr.length()) { + throw new IllegalArgumentException("Invalid time format at position " + lastEnd + + ": " + trimmedStr.substring(lastEnd)); + } + if (totalMillis < 0) { + throw new IllegalArgumentException("Resulting time cannot be negative"); + } + return totalMillis; + } +} From 85ab8505d871530b8fb69fd87f3d4210a0a6332f Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 24 May 2025 03:01:28 +0800 Subject: [PATCH 49/89] Update gradle.properties --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index ccb8b0586..dcf4e8a42 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.54.7 +project_version=0.0.54.8 config_version=33 -lang_version=13 +lang_version=14 project_group=net.momirealms latest_supported_version=1.21.5 From d3ae85f9cb50d1aa7ae6efe613d796bf7eed438b Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 24 May 2025 03:34:22 +0800 Subject: [PATCH 50/89] =?UTF-8?q?=E6=8C=81=E4=B9=85=E5=8C=96=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E5=86=B7=E5=8D=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/commands.yml | 7 ++++ .../src/main/resources/translations/en.yml | 2 +- .../src/main/resources/translations/zh_cn.yml | 2 +- .../plugin/command/BukkitCommandManager.java | 1 + .../feature/DebugClearCooldownCommand.java | 33 +++++++++++++++++ .../plugin/network/BukkitNetworkManager.java | 35 +++++++++---------- .../core/plugin/context/CooldownData.java | 9 ++++- .../context/condition/CommonConditions.java | 2 +- ...ondition.java => OnCooldownCondition.java} | 10 +++--- .../plugin/context/event/EventConditions.java | 2 +- 10 files changed, 74 insertions(+), 29 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugClearCooldownCommand.java rename core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/{CooldownCondition.java => OnCooldownCondition.java} (79%) diff --git a/bukkit/loader/src/main/resources/commands.yml b/bukkit/loader/src/main/resources/commands.yml index fdf4e1613..d600a8e7c 100644 --- a/bukkit/loader/src/main/resources/commands.yml +++ b/bukkit/loader/src/main/resources/commands.yml @@ -175,6 +175,13 @@ debug_is_section_injected: - /craftengine debug is-section-injected - /ce debug is-section-injected +debug_clear_cooldown: + enable: true + permission: ce.command.debug.clear_cooldown + usage: + - /craftengine debug clear-cooldown + - /ce debug clear-cooldown + debug_test: enable: true permission: ce.command.debug.test diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 3fb06992d..0ee61b98d 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -101,7 +101,7 @@ warning.config.condition.expression.missing_expression: "Issue found in warning.config.condition.is_null.missing_argument: "Issue found in file - The config '' is missing the required 'argument' argument for 'is_null' condition." warning.config.condition.hand.missing_hand: "Issue found in file - The config '' is missing the required 'hand' argument for 'hand' condition." warning.config.condition.hand.invalid_hand: "Issue found in file - The config '' is using an invalid 'hand' argument '' for 'hand' condition. Allowed hand types: []" -warning.config.condition.cooldown.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'cooldown' condition." +warning.config.condition.on_cooldown.missing_id: "Issue found in file - The config '' is missing the required 'id' argument for 'on_cooldown' condition." warning.config.structure.not_section: "Issue found in file - The config '' is expected to be a config section while it's actually a(n) ''." warning.config.image.duplicate: "Issue found in file - Duplicated image ''. Please check if there is the same configuration in other files." warning.config.image.missing_height: "Issue found in file - The image '' is missing the required 'height' argument." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 804f0414b..1b87ce60b 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -102,7 +102,7 @@ warning.config.condition.is_null.missing_argument: "在文件 warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" warning.config.condition.hand.missing_hand: "在文件 发现问题 - 配置项 '' 缺少 'hand' 条件必需的 'hand' 参数" warning.config.condition.hand.invalid_hand: "在文件 发现问题 - 配置项 '' 使用了无效的 'hand' 参数 ''('hand' 条件)。允许的手部类型: []" -warning.config.condition.cooldown.missing_id: "在文件 发现问题 - 配置项 '' 缺少 'cooldown' 条件必需的 'id' 参数" +warning.config.condition.on_cooldown.missing_id: "在文件 发现问题 - 配置项 '' 缺少 'on_cooldown' 条件必需的 'id' 参数" warning.config.image.duplicate: "在文件 发现问题 - 重复的图片配置 '' 请检查其他文件中是否存在相同配置" warning.config.image.missing_height: "在文件 发现问题 - 图片 '' 缺少必需的 'height' 参数" warning.config.image.height_ascent_conflict: "在文件 发现问题 - 图片 '' 违反位图规则: 'height' 参数 '' 必须不小于 'ascent' 参数 ''" 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 c1f1c3f39..0eee9c0aa 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 @@ -41,6 +41,7 @@ public class BukkitCommandManager extends AbstractCommandManager new DebugGetBlockStateRegistryIdCommand(this, plugin), new DebugGetBlockInternalIdCommand(this, plugin), new DebugAppearanceStateUsageCommand(this, plugin), + new DebugClearCooldownCommand(this, plugin), new DebugRealStateUsageCommand(this, plugin), new DebugItemDataCommand(this, plugin), new DebugSetBlockCommand(this, plugin), diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugClearCooldownCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugClearCooldownCommand.java new file mode 100644 index 000000000..757627d11 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugClearCooldownCommand.java @@ -0,0 +1,33 @@ +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.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import org.bukkit.command.CommandSender; +import org.incendo.cloud.Command; +import org.incendo.cloud.bukkit.parser.PlayerParser; + +public class DebugClearCooldownCommand extends BukkitCommandFeature { + + public DebugClearCooldownCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { + return builder + .required("player", PlayerParser.playerParser()) + .handler(context -> { + BukkitServerPlayer serverPlayer = plugin().adapt(context.get("player")); + serverPlayer.cooldown().clearCooldowns(); + plugin().senderFactory().wrap(context.sender()).sendMessage(Component.text("Done clearing cooldowns!")); + }); + } + + @Override + public String getFeatureID() { + return "debug_clear_cooldown"; + } +} 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 82b8ea92a..df14f8079 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 @@ -198,26 +198,21 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @EventHandler(priority = EventPriority.LOWEST) public void onPlayerQuit(PlayerQuitEvent event) { Player player = event.getPlayer(); - Channel channel = getChannel(player); - NetWorkUser user = removeUser(channel); - if (user == null) return; - saveCooldown(player, user); - handleDisconnection(channel); - this.onlineUsers.remove(player.getUniqueId()); - this.resetUserArray(); + BukkitServerPlayer serverPlayer = this.onlineUsers.remove(player.getUniqueId()); + if (serverPlayer != null) { + this.resetUserArray(); + this.saveCooldown(player, serverPlayer.cooldown()); + } } - private void saveCooldown(Player player, NetWorkUser user) { - if (user instanceof BukkitServerPlayer serverPlayer) { - CooldownData cd = serverPlayer.cooldown(); - if (cd != null) { - try { - byte[] data = CooldownData.toBytes(cd); - player.getPersistentDataContainer().set(KeyUtils.toNamespacedKey(CooldownData.COOLDOWN_KEY), PersistentDataType.BYTE_ARRAY, data); - } catch (IOException e) { - player.getPersistentDataContainer().remove(KeyUtils.toNamespacedKey(CooldownData.COOLDOWN_KEY)); - this.plugin.logger().warn("Failed to save cooldown for player " + player.getName(), e); - } + private void saveCooldown(Player player, CooldownData cd) { + if (cd != null && player != null) { + try { + byte[] data = CooldownData.toBytes(cd); + player.getPersistentDataContainer().set(KeyUtils.toNamespacedKey(CooldownData.COOLDOWN_KEY), PersistentDataType.BYTE_ARRAY, data); + } catch (IOException e) { + player.getPersistentDataContainer().remove(KeyUtils.toNamespacedKey(CooldownData.COOLDOWN_KEY)); + this.plugin.logger().warn("Failed to save cooldown for player " + player.getName(), e); } } } @@ -465,7 +460,9 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes String encoderName = pipeline.names().contains("outbound_config") ? "outbound_config" : "encoder"; pipeline.addBefore(encoderName, PACKET_ENCODER, new PluginChannelEncoder(user)); - channel.closeFuture().addListener((ChannelFutureListener) future -> handleDisconnection(user.nettyChannel())); + channel.closeFuture().addListener((ChannelFutureListener) future -> { + handleDisconnection(user.nettyChannel()); + }); setUser(channel, user); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java index f693e573f..235888530 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java @@ -65,11 +65,18 @@ public class CooldownData { if (entry.getValue() instanceof LongTag longTag) { long expire = longTag.getAsLong(); if (currentTime < expire) { - cd.setCooldown(entry.getKey(), expire); + cd.cooldownMap.put(entry.getKey(), expire); } } } } return cd; } + + @Override + public String toString() { + return "CooldownData{" + + "cooldownMap=" + cooldownMap + + '}'; + } } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java index 43ac2cb0d..a5521169c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java @@ -18,7 +18,7 @@ public final class CommonConditions { public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); public static final Key DISTANCE = Key.from("craftengine:distance"); public static final Key PERMISSION = Key.from("craftengine:permission"); - public static final Key COOLDOWN = Key.from("craftengine:cooldown"); + public static final Key ON_COOLDOWN = Key.from("craftengine:on_cooldown"); public static final Key EQUALS = Key.from("craftengine:equals"); public static final Key STRING_EQUALS = Key.from("craftengine:string_equals"); public static final Key STRING_CONTAINS = Key.from("craftengine:string_contains"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CooldownCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/OnCooldownCondition.java similarity index 79% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CooldownCondition.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/OnCooldownCondition.java index 785866de7..fd47802b5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CooldownCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/OnCooldownCondition.java @@ -10,16 +10,16 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; import java.util.Optional; -public class CooldownCondition implements Condition { +public class OnCooldownCondition implements Condition { private final String key; - public CooldownCondition(String key) { + public OnCooldownCondition(String key) { this.key = key; } @Override public Key type() { - return CommonConditions.COOLDOWN; + return CommonConditions.ON_COOLDOWN; } @Override @@ -36,8 +36,8 @@ public class CooldownCondition implements Condition { @Override public Condition create(Map arguments) { - String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("id"), "warning.config.condition.cooldown.missing_id"); - return new CooldownCondition<>(id); + String id = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("id"), "warning.config.condition.on_cooldown.missing_id"); + return new OnCooldownCondition<>(id); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java index a46d7a09b..5e6a110fa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java @@ -36,7 +36,7 @@ public class EventConditions { register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>()); register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>()); register(CommonConditions.HAND, new HandCondition.FactoryImpl<>()); - register(CommonConditions.COOLDOWN, new CooldownCondition.FactoryImpl<>()); + register(CommonConditions.ON_COOLDOWN, new OnCooldownCondition.FactoryImpl<>()); } public static void register(Key key, ConditionFactory factory) { From 4431a4a45455dfc4028596714a0cc26a2cebc8d0 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sat, 24 May 2025 04:24:54 +0800 Subject: [PATCH 51/89] =?UTF-8?q?feat(core):=20=E4=BC=98=E5=8C=96=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E5=8C=85=E6=96=87=E4=BB=B6=E8=BF=87=E6=BB=A4=E6=9C=BA?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 5 +++++ .../craftengine/core/pack/AbstractPackManager.java | 4 ++-- .../momirealms/craftengine/core/pack/PackManager.java | 1 - .../craftengine/core/plugin/config/Config.java | 11 +++++++---- gradle.properties | 2 +- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 18053ebc2..209d0ad90 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -65,6 +65,11 @@ resource-pack: - BetterModel/build merge-external-zip-files: - CustomNameplates/resourcepack.zip + exclude-file-suffixes: + - "md" + - "psd" + - "bbmodel" + - "db" delivery: # Send the resource pack on joining the server send-on-join: true 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 f0be59d10..ae5ed2825 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 @@ -1208,7 +1208,7 @@ public abstract class AbstractPackManager implements PackManager { private void processRegularFile(Path file, BasicFileAttributes attrs, Path sourceFolder, @Nullable FileSystem fs, Map> conflictChecker, Map previousFiles) throws IOException { - if (!ALLOWED_FILE_EXTENSIONS.contains(FileUtils.getExtension(file))) { + if (Config.excludeFileSuffixes().contains(FileUtils.getExtension(file))) { return; } CachedAssetFile cachedAsset = previousFiles.get(file); @@ -1237,7 +1237,7 @@ public abstract class AbstractPackManager implements PackManager { if (entryAttrs.isDirectory()) { return FileVisitResult.CONTINUE; } - if (!ALLOWED_FILE_EXTENSIONS.contains(FileUtils.getExtension(entry))) { + if (Config.excludeFileSuffixes().contains(FileUtils.getExtension(entry))) { return FileVisitResult.CONTINUE; } Path entryPathInZip = zipRoot.relativize(entry); 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 489cbd44d..b18d3f952 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,7 +14,6 @@ import java.util.List; import java.util.Set; public interface PackManager extends Manageable { - Set ALLOWED_FILE_EXTENSIONS = new HashSet<>(List.of("png", "txt", "json", "fsh", "vsh", "mcmeta", "zip", "ogg")); void loadResources(boolean recipe); 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 be96fe1ed..c42a25a44 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 @@ -34,10 +34,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; public class Config { @@ -59,6 +56,7 @@ public class Config { protected List resource_pack$duplicated_files_handler; protected List resource_pack$merge_external_folders; protected List resource_pack$merge_external_zips; + protected Set resource_pack$exclude_file_suffixes; protected boolean resource_pack$protection$crash_tools$method_1; protected boolean resource_pack$protection$crash_tools$method_2; @@ -220,6 +218,7 @@ public class Config { resource_pack$supported_version$max = getVersion(config.get("resource-pack.supported-version.max", "LATEST").toString()); resource_pack$merge_external_folders = config.getStringList("resource-pack.merge-external-folders"); resource_pack$merge_external_zips = config.getStringList("resource-pack.merge-external-zip-files"); + resource_pack$exclude_file_suffixes = new HashSet<>(config.getStringList("resource-pack.exclude-file-suffixes", List.of("md", "psd", "bbmodel", "db"))); resource_pack$delivery$send_on_join = config.getBoolean("resource-pack.delivery.send-on-join", true); resource_pack$delivery$resend_on_upload = config.getBoolean("resource-pack.delivery.resend-on-upload", true); resource_pack$delivery$kick_if_declined = config.getBoolean("resource-pack.delivery.kick-if-declined", true); @@ -469,6 +468,10 @@ public class Config { return instance.resource_pack$merge_external_zips; } + public static Set excludeFileSuffixes() { + return instance.resource_pack$exclude_file_suffixes; + } + public static boolean kickOnDeclined() { return instance.resource_pack$delivery$kick_if_declined; } diff --git a/gradle.properties b/gradle.properties index dcf4e8a42..9571f5bed 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] project_version=0.0.54.8 -config_version=33 +config_version=34 lang_version=14 project_group=net.momirealms latest_supported_version=1.21.5 From 539dcd7d8f24cd68a64865a24e9a0ebaf246eb95 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 24 May 2025 17:37:00 +0800 Subject: [PATCH 52/89] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 6 +---- .../item/behavior/BukkitItemBehaviors.java | 1 + .../bukkit/util/ParticleUtils.java | 23 +++++++++++++++++++ .../craftengine/bukkit/world/BukkitWorld.java | 2 +- .../craftengine/core/item/Helmet.java | 15 ++++++++++++ .../craftengine/core/item/ItemSettings.java | 16 +++++++++++++ .../core/item/behavior/ItemBehavior.java | 5 ++++ .../core/pack/AbstractPackManager.java | 4 ++-- .../core/pack/LoadingSequence.java | 4 +++- .../craftengine/core/pack/Pack.java | 2 +- .../core/pack/ResourceLocation.java | 2 +- .../core/plugin/config/Config.java | 8 +++---- .../context/function/LevelerExpFunction.java | 4 ++-- gradle.properties | 2 +- 14 files changed, 76 insertions(+), 18 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/Helmet.java diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 209d0ad90..48742ce2d 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -65,11 +65,7 @@ resource-pack: - BetterModel/build merge-external-zip-files: - CustomNameplates/resourcepack.zip - exclude-file-suffixes: - - "md" - - "psd" - - "bbmodel" - - "db" + exclude-file-extensions: ["md", "psd", "bbmodel", "db", "ini"] delivery: # Send the resource pack on joining the server send-on-join: true diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java index f8081572b..91dc42d40 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java @@ -10,6 +10,7 @@ public class BukkitItemBehaviors extends ItemBehaviors { public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item"); public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item"); public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item"); + public static final Key HAT_ITEM = Key.from("craftengine:hat_item"); public static void init() { register(EMPTY, EmptyItemBehavior.FACTORY); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java index e0ba3ccd0..a15f0091f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java @@ -1,14 +1,23 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.particle.*; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.Vibration; import org.bukkit.World; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; public final class ParticleUtils { + private static final Map CACHE = new HashMap<>(); + private ParticleUtils() {} public static Particle getParticle(String particle) { @@ -24,6 +33,20 @@ public final class ParticleUtils { } } + @Nullable + public static Particle getParticle(Key particle) { + return CACHE.computeIfAbsent(particle, k -> { + try { + Object nmsParticle = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$PARTICLE_TYPE, KeyUtils.toResourceLocation(particle)); + if (nmsParticle == null) return null; + return FastNMS.INSTANCE.method$CraftParticle$toBukkit(nmsParticle); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to get particle: " + particle, e); + return null; + } + }); + } + public static final Particle HAPPY_VILLAGER = getParticle("HAPPY_VILLAGER"); public static final Particle BUBBLE = getParticle("BUBBLE"); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index 218b01d34..7008c0825 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -105,7 +105,7 @@ public class BukkitWorld implements World { @Override public void spawnParticle(Position location, Key particle, int count, double xOffset, double yOffset, double zOffset, double speed, @Nullable ParticleData extraData, @NotNull Context context) { - Particle particleType = Registry.PARTICLE_TYPE.get(KeyUtils.toNamespacedKey(particle)); + Particle particleType = ParticleUtils.getParticle(particle); if (particleType == null) return; org.bukkit.World platformWorld = platformWorld(); platformWorld.spawnParticle(particleType, location.x(), location.y(), location.z(), count, xOffset, yOffset, zOffset, speed, extraData == null ? null : ParticleUtils.toBukkitParticleData(extraData, context, platformWorld, location.x(), location.y(), location.z())); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Helmet.java b/core/src/main/java/net/momirealms/craftengine/core/item/Helmet.java new file mode 100644 index 000000000..0235c411e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Helmet.java @@ -0,0 +1,15 @@ +package net.momirealms.craftengine.core.item; + +import net.momirealms.craftengine.core.sound.SoundData; + +public class Helmet { + private final SoundData equipSound; + + public Helmet(SoundData equipSound) { + this.equipSound = equipSound; + } + + public SoundData equipSound() { + return equipSound; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java index c2f41b13c..a9f93ebb5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.item.modifier.EquippableModifier; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +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.ResourceConfigUtils; @@ -28,6 +29,7 @@ public class ItemSettings { boolean canPlaceRelatedVanillaBlock = false; ProjectileMeta projectileMeta; boolean dyeable = true; + Helmet helmet = null; private ItemSettings() {} @@ -105,6 +107,11 @@ public class ItemSettings { return anvilRepairItems; } + @Nullable + public Helmet helmet() { + return helmet; + } + @Nullable public EquipmentGeneration equipment() { return equipment; @@ -155,6 +162,11 @@ public class ItemSettings { return this; } + public ItemSettings helmet(Helmet helmet) { + this.helmet = helmet; + return this; + } + @FunctionalInterface public interface Modifier { @@ -229,6 +241,10 @@ public class ItemSettings { String type = args.getOrDefault("type", "none").toString(); return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, scale, translation, rotation, type)); })); + registerFactory("helmet", (value -> { + Map args = MiscUtils.castToMap(value, false); + return settings -> settings.helmet(new Helmet(SoundData.create(args.getOrDefault("equip-sound", "minecraft:intentionally_empty"), 1f, 1f))); + })); registerFactory("dyeable", (value -> { boolean bool = (boolean) value; return settings -> settings.dyeable(bool); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehavior.java index 3c73c14e7..cd243ad72 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehavior.java @@ -15,4 +15,9 @@ public abstract class ItemBehavior { public InteractionResult use(World world, Player player, InteractionHand hand) { return InteractionResult.PASS; } + + // TODO + public InteractionResult useOnEntity() { + return InteractionResult.PASS; + } } 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 ae5ed2825..d0ded6b10 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 @@ -1208,7 +1208,7 @@ public abstract class AbstractPackManager implements PackManager { private void processRegularFile(Path file, BasicFileAttributes attrs, Path sourceFolder, @Nullable FileSystem fs, Map> conflictChecker, Map previousFiles) throws IOException { - if (Config.excludeFileSuffixes().contains(FileUtils.getExtension(file))) { + if (Config.excludeFileExtensions().contains(FileUtils.getExtension(file))) { return; } CachedAssetFile cachedAsset = previousFiles.get(file); @@ -1237,7 +1237,7 @@ public abstract class AbstractPackManager implements PackManager { if (entryAttrs.isDirectory()) { return FileVisitResult.CONTINUE; } - if (Config.excludeFileSuffixes().contains(FileUtils.getExtension(entry))) { + if (Config.excludeFileExtensions().contains(FileUtils.getExtension(entry))) { return FileVisitResult.CONTINUE; } Path entryPathInZip = zipRoot.relativize(entry); 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 b684aa54f..496ce89e6 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 @@ -1,6 +1,8 @@ package net.momirealms.craftengine.core.pack; -public class LoadingSequence { +public final class LoadingSequence { + private LoadingSequence() {} + public static final int TEMPLATE = 0; public static final int GLOBAL_VAR = 10; public static final int LANG = 20; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/Pack.java b/core/src/main/java/net/momirealms/craftengine/core/pack/Pack.java index 3953b2076..331469c9e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/Pack.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/Pack.java @@ -12,7 +12,7 @@ import java.nio.file.Path; * This class provides access to the resource pack folder * and configuration folder within the specified directory. */ -public class Pack { +public final class Pack { private final Path folder; private final PackMeta meta; private final boolean enabled; 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 471e5ead5..4e580df18 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 @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.pack; -public class ResourceLocation { +public final class ResourceLocation { public static boolean isValid(final String resourceLocation) { int index = resourceLocation.indexOf(":"); 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 c42a25a44..d081b5e87 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 @@ -56,7 +56,7 @@ public class Config { protected List resource_pack$duplicated_files_handler; protected List resource_pack$merge_external_folders; protected List resource_pack$merge_external_zips; - protected Set resource_pack$exclude_file_suffixes; + protected Set resource_pack$exclude_file_extensions; protected boolean resource_pack$protection$crash_tools$method_1; protected boolean resource_pack$protection$crash_tools$method_2; @@ -218,7 +218,7 @@ public class Config { resource_pack$supported_version$max = getVersion(config.get("resource-pack.supported-version.max", "LATEST").toString()); resource_pack$merge_external_folders = config.getStringList("resource-pack.merge-external-folders"); resource_pack$merge_external_zips = config.getStringList("resource-pack.merge-external-zip-files"); - resource_pack$exclude_file_suffixes = new HashSet<>(config.getStringList("resource-pack.exclude-file-suffixes", List.of("md", "psd", "bbmodel", "db"))); + resource_pack$exclude_file_extensions = new HashSet<>(config.getStringList("resource-pack.exclude-file-extensions")); resource_pack$delivery$send_on_join = config.getBoolean("resource-pack.delivery.send-on-join", true); resource_pack$delivery$resend_on_upload = config.getBoolean("resource-pack.delivery.resend-on-upload", true); resource_pack$delivery$kick_if_declined = config.getBoolean("resource-pack.delivery.kick-if-declined", true); @@ -468,8 +468,8 @@ public class Config { return instance.resource_pack$merge_external_zips; } - public static Set excludeFileSuffixes() { - return instance.resource_pack$exclude_file_suffixes; + public static Set excludeFileExtensions() { + return instance.resource_pack$exclude_file_extensions; } public static boolean kickOnDeclined() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java index 9d9edff9e..dd369f792 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/LevelerExpFunction.java @@ -56,8 +56,8 @@ public class LevelerExpFunction extends AbstractConditional @Override public Function create(Map arguments) { Object count = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("count"), "warning.config.function.leveler_exp.missing_count"); - String leveler = ResourceConfigUtils.requireNonEmptyStringOrThrow("leveler", "warning.config.function.leveler_exp.missing_leveler"); - String plugin = ResourceConfigUtils.requireNonEmptyStringOrThrow("plugin", "warning.config.function.leveler_exp.missing_plugin"); + String leveler = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("leveler"), "warning.config.function.leveler_exp.missing_leveler"); + String plugin = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("plugin"), "warning.config.function.leveler_exp.missing_plugin"); return new LevelerExpFunction<>(NumberProviders.fromObject(count), leveler, plugin, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); } } diff --git a/gradle.properties b/gradle.properties index 9571f5bed..3bb2f44ca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.65.25 +nms_helper_version=0.65.26 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From de47525c3bc76649944cd1cfaa9ad74a9b14d34a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 25 May 2025 02:52:33 +0800 Subject: [PATCH 53/89] =?UTF-8?q?=E7=BA=A2=E7=9F=B3=E5=9F=BA=E7=A1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/blocks.yml | 69 ++++ .../default/configuration/categories.yml | 4 +- .../resources/default/configuration/i18n.yml | 2 + .../textures/block/custom/copper_coil.png | Bin 0 -> 213 bytes .../textures/block/custom/copper_coil_on.png | Bin 0 -> 223 bytes .../block/custom/copper_coil_on_side.png | Bin 0 -> 208 bytes .../block/custom/copper_coil_side.png | Bin 0 -> 194 bytes .../src/main/resources/translations/en.yml | 1 + .../src/main/resources/translations/zh_cn.yml | 1 + .../block/behavior/BukkitBlockBehaviors.java | 2 + .../block/behavior/LampBlockBehavior.java | 65 ++++ .../block/behavior/LeavesBlockBehavior.java | 79 ++-- .../plugin/injector/BukkitInjector.java | 17 + .../craftengine/bukkit/util/Reflections.java | 12 + .../craftengine/bukkit/world/BukkitWorld.java | 6 +- .../UnsafeCompositeBlockBehavior.java | 154 ++++++++ .../craftengine/core/item/EmptyItem.java | 342 ++++++++++++++++++ .../craftengine/core/item/ItemKeys.java | 1 + .../craftengine/core/pack/PackManager.java | 3 - .../core/plugin/gui/GuiElement.java | 2 +- .../gui/category/ItemBrowserManagerImpl.java | 43 ++- gradle.properties | 4 +- .../mod/block/CraftEngineBlock.java | 12 + server-mod/v1_20_5/build.gradle.kts | 2 +- .../mod/block/CraftEngineBlock.java | 14 + .../mod/block/CraftEngineBlock.java | 14 + .../shared/block/BlockBehavior.java | 13 + 27 files changed, 810 insertions(+), 52 deletions(-) create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on_side.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_side.png create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/EmptyItem.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml index b979b00a7..613b1a6a9 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml @@ -201,6 +201,75 @@ items#misc: parent: "minecraft:block/cube_all" textures: "all": "minecraft:block/custom/solid_gunpowder_block" + default:copper_coil: + material: nether_brick + custom-model-data: 3004 + data: + item-name: "" + model: + type: "minecraft:model" + path: "minecraft:item/custom/copper_coil" + generation: + parent: "minecraft:block/custom/copper_coil" + behavior: + type: block_item + block: + loot: + template: "default:loot_table/basic" + arguments: + item: default:copper_coil + settings: + template: + - default:sound/metal + - default:pickaxe_power/level_1 + overrides: + hardness: 3.0 + resistance: 4.5 + replaceable: false + is-redstone-conductor: true + is-suffocating: true + instrument: BASEDRUM + map-color: 45 + item: default:copper_coil + behavior: + type: lamp_block + states: + properties: + lit: + type: boolean + default: false + appearances: + off: + state: "cactus:0" + model: + path: "minecraft:block/custom/copper_coil" + generation: + parent: "minecraft:block/cactus" + textures: + "particle": "minecraft:block/custom/copper_coil" + "bottom": "minecraft:block/custom/copper_coil" + "top": "minecraft:block/custom/copper_coil" + "side": "minecraft:block/custom/copper_coil_side" + on: + state: "cactus:1" + model: + path: "minecraft:block/custom/copper_coil_on" + generation: + parent: "minecraft:block/cactus" + textures: + "particle": "minecraft:block/custom/copper_coil_on" + "bottom": "minecraft:block/custom/copper_coil_on" + "top": "minecraft:block/custom/copper_coil_on" + "side": "minecraft:block/custom/copper_coil_on_side" + variants: + lit=false: + appearance: "off" + id: 0 + lit=true: + appearance: "on" + id: 1 + settings: + luminance: 8 recipes#misc: default:chinese_lantern: type: shaped diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml index fd442e990..d111185e9 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml @@ -65,4 +65,6 @@ categories: - default:solid_gunpowder_block - default:ender_pearl_flower_seeds - default:gui_head_size_1 - - default:gui_head_size_4 \ No newline at end of file + - default:gui_head_size_4 + - minecraft:air + - default:copper_coil \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml index 99e6d9705..602c85f0f 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml @@ -34,6 +34,7 @@ i18n: item.netherite_anvil: "Netherite Anvil" item.gunpowder_block: "GunPowder Block" item.solid_gunpowder_block: "Solid GunPowder Block" + item.copper_coil: "Copper Coil" category.default.name: "Default Assets" category.default.lore: "Contains the default configuration of CraftEngine" category.palm_tree: "Palm Tree" @@ -78,6 +79,7 @@ i18n: item.netherite_anvil: "下界合金砧" item.gunpowder_block: "火药粉末" item.solid_gunpowder_block: "凝固火药块" + item.copper_coil: "铜线圈" category.default.name: "默认资产" category.default.lore: "包含了CraftEngine的默认配置" category.palm_tree: "棕榈树" diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil.png new file mode 100644 index 0000000000000000000000000000000000000000..40f04a5a8a5c862cb49ed761311034260299935c GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!fo(Ey(i*X2!0YDt6f~Sf1;em!RUf(DUDN0 zm{sEqgcYl4yHKwTG21bUe$1DpfQUopnjbre1^>bP0l+XkK DNt{W7 literal 0 HcmV?d00001 diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on.png new file mode 100644 index 0000000000000000000000000000000000000000..3e59193cbd727d647cb052089fa16984de53ef5c GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!fo=>VS)*X2EaktacjvrLp}xt4wi$#55N4^7hB4h^xW)-r$W-y z4HA=?jhBdP{M+=Oo^fWu7FG#{=H+aY*LIMcRKQ*m z?loLe&5O literal 0 HcmV?d00001 diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_side.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_side.png new file mode 100644 index 0000000000000000000000000000000000000000..859f0234bf27f0afaf17b0f60cc68d6058037d41 GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!fo{s5m4*T+pco08n^Oe|*wSp5J0U-_!uOP~~MNswPKko%wE z_clI|ffk-Fjv*Ddk`fYA9GH4^cy!KaFlZcTVVV$P(8RzenxJ_o&0*@pphg4M*<3SZ j>Wl;aIGxzez{tj6a*!!7seZpH&Issue found in file Issue found in file - The block '' is missing the required 'age' property for 'sugar_cane_block' behavior." warning.config.block.behavior.leaves.missing_persistent: "Issue found in file - The block '' is missing the required 'persistent' property for 'leaves_block' behavior." warning.config.block.behavior.leaves.missing_distance: "Issue found in file - The block '' is missing the required 'distance' property for 'leaves_block' behavior." +warning.config.block.behavior.lamp.missing_lit: "Issue found in file - The block '' is missing the required 'lit' property for 'lamp_block' behavior." warning.config.block.behavior.sapling.missing_stage: "Issue found in file - The block '' is missing the required 'stage' property for 'sapling_block' behavior." warning.config.block.behavior.sapling.missing_feature: "Issue found in file - The block '' is missing the required 'feature' argument for 'sapling_block' behavior." warning.config.block.behavior.strippable.missing_stripped: "Issue found in file - The block '' is missing the required 'stripped' argument for 'strippable_block' behavior." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 1b87ce60b..d9feadebf 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -239,6 +239,7 @@ warning.config.block.behavior.crop.missing_age: "在文件 发 warning.config.block.behavior.sugar_cane.missing_age: "在文件 发现问题 - 方块 '' 的 'sugar_cane_block' 行为缺少必需的 'age' 属性" warning.config.block.behavior.leaves.missing_persistent: "在文件 发现问题 - 方块 '' 的 'leaves_block' 行为缺少必需的 'persistent' 属性" warning.config.block.behavior.leaves.missing_distance: "在文件 发现问题 - 方块 '' 的 'leaves_block' 行为缺少必需的 'distance' 属性" +warning.config.block.behavior.lamp.missing_lit: "在文件 发现问题 - 方块 '' 的 'lamp_block' 行为缺少必需的 'lit' 属性" warning.config.block.behavior.sapling.missing_stage: "在文件 发现问题 - 方块 '' 的 'sapling_block' 行为缺少必需的 'stage' 属性" warning.config.block.behavior.sapling.missing_feature: "在文件 发现问题 - 方块 '' 的 'sapling_block' 行为缺少必需的 'feature' 参数" warning.config.block.behavior.strippable.missing_stripped: "在文件 发现问题 - 方块 '' 的 'strippable_block' 行为缺少必需的 'stripped' 参数" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index 1ebf13dc8..2b36c888f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -17,6 +17,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key SUGARCANE_BLOCK = Key.from("craftengine:sugar_cane_block"); public static final Key CROP_BLOCK = Key.from("craftengine:crop_block"); public static final Key GRASS_BLOCK = Key.from("craftengine:grass_block"); + public static final Key LAMP_BLOCK = Key.from("craftengine:lamp_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -32,5 +33,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(SUGARCANE_BLOCK, SugarCaneBlockBehavior.FACTORY); register(CROP_BLOCK, CropBlockBehavior.FACTORY); register(GRASS_BLOCK, GrassBlockBehavior.FACTORY); + register(LAMP_BLOCK, LampBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java new file mode 100644 index 000000000..56ff8079c --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java @@ -0,0 +1,65 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.shared.block.BlockBehavior; + +import java.util.Map; +import java.util.concurrent.Callable; + +public class LampBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final Property litProperty; + + public LampBlockBehavior(CustomBlock block, Property litProperty) { + super(block); + this.litProperty = litProperty; + } + + @Override + public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object blockState = args[0]; + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (state == null || state.isEmpty()) return; + Object world = args[1]; + Object blockPos = args[2]; + if (state.get(this.litProperty) && !FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) { + // TODO Call Event + FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2); + } + } + + @Override + public void neighborChanged(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object blockState = args[0]; + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (state == null || state.isEmpty()) return; + Object world = args[1]; + Object blockPos = args[2]; + boolean lit = state.get(this.litProperty); + if (lit != FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) { + if (lit) { + Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 4); + } else { + // TODO Call Event + FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2); + } + } + } + + @SuppressWarnings("unchecked") + public static class Factory implements BlockBehaviorFactory { + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Property lit = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("lit"), "warning.config.block.behavior.lamp.missing_lit"); + return new LampBlockBehavior(block, lit); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java index 0da9cba81..d6206696d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java @@ -30,6 +30,7 @@ import org.bukkit.event.block.LeavesDecayEvent; import org.jetbrains.annotations.Nullable; import java.util.Map; +import java.util.Optional; import java.util.concurrent.Callable; public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { @@ -78,10 +79,14 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { neighborState = args[2]; } ImmutableBlockState thisState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); - if (thisState != null && thisState.behavior() instanceof LeavesBlockBehavior behavior) { - int distance = behavior.getDistanceAt(neighborState) + 1; - if (distance != 1 || behavior.getDistance(thisState) != distance) { - Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 1); + if (thisState != null) { + Optional optionalBehavior = thisState.behavior().getAs(LeavesBlockBehavior.class); + if (optionalBehavior.isPresent()) { + LeavesBlockBehavior behavior = optionalBehavior.get(); + int distance = behavior.getDistanceAt(neighborState) + 1; + if (distance != 1 || behavior.getDistance(thisState) != distance) { + Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 1); + } } } return blockState; @@ -93,13 +98,17 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { Object level = args[1]; Object blockPos = args[2]; ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); - if (currentState != null && !currentState.isEmpty() && currentState.behavior() instanceof LeavesBlockBehavior behavior) { - ImmutableBlockState newState = behavior.updateDistance(currentState, level, blockPos); - if (newState != currentState) { - if (blockState == newState.customBlockState().handle()) { - Reflections.method$BlockStateBase$updateNeighbourShapes.invoke(blockState, level, blockPos, UpdateOption.UPDATE_ALL.flags(), 512); - } else { - FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); + if (currentState != null && !currentState.isEmpty()) { + Optional optionalBehavior = currentState.behavior().getAs(LeavesBlockBehavior.class); + if (optionalBehavior.isPresent()) { + LeavesBlockBehavior behavior = optionalBehavior.get(); + ImmutableBlockState newState = behavior.updateDistance(currentState, level, blockPos); + if (newState != currentState) { + if (blockState == newState.customBlockState().handle()) { + Reflections.method$BlockStateBase$updateNeighbourShapes.invoke(blockState, level, blockPos, UpdateOption.UPDATE_ALL.flags(), 512); + } else { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); + } } } } @@ -110,25 +119,31 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { Object level = args[1]; Object blockPos = args[2]; ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0])); - if (immutableBlockState != null && immutableBlockState.behavior() instanceof LeavesBlockBehavior behavior && behavior.isDecaying(immutableBlockState)) { - World bukkitWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(level); - BlockPos pos = LocationUtils.fromBlockPos(blockPos); - // call bukkit event - LeavesDecayEvent event = new LeavesDecayEvent(bukkitWorld.getBlockAt(pos.x(), pos.y(), pos.z())); - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - FastNMS.INSTANCE.method$Level$removeBlock(level, blockPos, false); - if (isWaterLogged(immutableBlockState)) { - bukkitWorld.setBlockData(pos.x(), pos.y(), pos.z(), Material.WATER.createBlockData()); - } - net.momirealms.craftengine.core.world.World world = new BukkitWorld(bukkitWorld); - WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); - ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(DirectContextParameters.POSITION, position); - for (Item item : immutableBlockState.getDrops(builder, world, null)) { - world.dropItemNaturally(position, item); + if (immutableBlockState != null) { + Optional optionalBehavior = immutableBlockState.behavior().getAs(LeavesBlockBehavior.class); + if (optionalBehavior.isPresent()) { + LeavesBlockBehavior behavior = optionalBehavior.get(); + if (behavior.isDecaying(immutableBlockState)) { + World bukkitWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(level); + BlockPos pos = LocationUtils.fromBlockPos(blockPos); + // call bukkit event + LeavesDecayEvent event = new LeavesDecayEvent(bukkitWorld.getBlockAt(pos.x(), pos.y(), pos.z())); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + FastNMS.INSTANCE.method$Level$removeBlock(level, blockPos, false); + if (isWaterLogged(immutableBlockState)) { + bukkitWorld.setBlockData(pos.x(), pos.y(), pos.z(), Material.WATER.createBlockData()); + } + net.momirealms.craftengine.core.world.World world = new BukkitWorld(bukkitWorld); + WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position); + for (Item item : immutableBlockState.getDrops(builder, world, null)) { + world.dropItemNaturally(position, item); + } + } } } } @@ -164,8 +179,8 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { return (int) Reflections.method$StateHolder$getValue.invoke(blockState, distanceProperty); } else { ImmutableBlockState anotherBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id); - if (!(anotherBlockState.behavior() instanceof LeavesBlockBehavior otherBehavior)) return this.maxDistance; - return otherBehavior.getDistance(anotherBlockState); + Optional optionalAnotherBehavior = anotherBlockState.behavior().getAs(LeavesBlockBehavior.class); + return optionalAnotherBehavior.map(leavesBlockBehavior -> leavesBlockBehavior.getDistance(anotherBlockState)).orElse(this.maxDistance); } } 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 60f26221c..a90781574 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 @@ -318,6 +318,9 @@ public class BukkitInjector { .and(ElementMatchers.takesArgument(1, Reflections.clazz$LevelReader).or(ElementMatchers.takesArgument(1, Reflections.clazz$Direction))) .and(ElementMatchers.named("updateShape").or(ElementMatchers.named("a")))) .intercept(MethodDelegation.to(UpdateShapeInterceptor.INSTANCE)) + // neighborChanged + .method(ElementMatchers.is(Reflections.method$BlockBehaviour$neighborChanged)) + .intercept(MethodDelegation.to(NeighborChangedInterceptor.INSTANCE)) // // getFluidState // .method(ElementMatchers.returns(Reflections.clazz$FluidState) // .and(ElementMatchers.takesArgument(0, Reflections.clazz$BlockState))) @@ -1078,6 +1081,20 @@ public class BukkitInjector { } } } + + public static class NeighborChangedInterceptor { + public static final NeighborChangedInterceptor INSTANCE = new NeighborChangedInterceptor(); + + @RuntimeType + public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((BehaviorHolder) thisObj).getBehaviorHolder(); + try { + holder.value().neighborChanged(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run neighborChanged", e); + } + } + } // // public static class PickUpBlockInterceptor { // public static final PickUpBlockInterceptor INSTANCE = new PickUpBlockInterceptor(); 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 22c58dbbf..9e67f24c6 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 @@ -6791,4 +6791,16 @@ public class Reflections { } } + public static final Class clazz$Orientation = + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.level.redstone.Orientation", + "world.level.redstone.Orientation" + ); + + public static final Method method$BlockBehaviour$neighborChanged = requireNonNull( + VersionHelper.isOrAbove1_21_2() ? + ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$Orientation, boolean.class) : + Optional.ofNullable(ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$BlockPos, boolean.class)) + .orElse(ReflectionUtils.getMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$BlockPos, boolean.class)) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index 7008c0825..839f8055a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -1,7 +1,10 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.bukkit.util.EntityUtils; +import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.ParticleUtils; +import net.momirealms.craftengine.bukkit.util.SoundUtils; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Context; @@ -15,7 +18,6 @@ import net.momirealms.craftengine.core.world.WorldHeight; import net.momirealms.craftengine.core.world.particle.ParticleData; import org.bukkit.Location; import org.bukkit.Particle; -import org.bukkit.Registry; import org.bukkit.SoundCategory; import org.bukkit.entity.EntityType; import org.bukkit.entity.ExperienceOrb; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java new file mode 100644 index 000000000..21bb9d76d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java @@ -0,0 +1,154 @@ +package net.momirealms.craftengine.core.block.behavior; + +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.context.BlockPlaceContext; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.shared.block.BlockBehavior; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.Callable; + +public class UnsafeCompositeBlockBehavior extends AbstractBlockBehavior { + private final AbstractBlockBehavior[] behaviors; + + public UnsafeCompositeBlockBehavior(CustomBlock customBlock, List behaviors) { + super(customBlock); + this.behaviors = behaviors.toArray(new AbstractBlockBehavior[0]); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getAs(Class tClass) { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (tClass.isInstance(behavior)) { + return Optional.of((T) behavior); + } + } + return Optional.empty(); + } + + @Override + public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { + for (AbstractBlockBehavior behavior : this.behaviors) { + InteractionResult result = behavior.useOnBlock(context, state); + if (result != InteractionResult.PASS) { + return result; + } + } + return super.useOnBlock(context, state); + } + + @Override + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { + for (AbstractBlockBehavior behavior : this.behaviors) { + state = behavior.updateStateForPlacement(context, state); + } + return state; + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + args[0] = behavior.updateShape(thisBlock, args, superMethod); + } + return args[0]; + } + + @Override + public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.tick(thisBlock, args, superMethod); + } + } + + @Override + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.randomTick(thisBlock, args, superMethod); + } + } + + @Override + public Object rotate(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + args[0] = behavior.rotate(thisBlock, args, superMethod); + } + return args[0]; + } + + @Override + public Object mirror(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + args[0] = behavior.mirror(thisBlock, args, superMethod); + } + return args[0]; + } + + @Override + public void performBoneMeal(Object thisBlock, Object[] args) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.performBoneMeal(thisBlock, args); + } + } + + @Override + public void onPlace(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.onPlace(thisBlock, args, superMethod); + } + } + + @Override + public void onLand(Object thisBlock, Object[] args) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.onLand(thisBlock, args); + } + } + + @Override + public void onBrokenAfterFall(Object thisBlock, Object[] args) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.onBrokenAfterFall(thisBlock, args); + } + } + + @Override + public void neighborChanged(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.neighborChanged(thisBlock, args, superMethod); + } + } + + @Override + public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (behavior.isValidBoneMealTarget(thisBlock, args)) { + return true; + } + } + return false; + } + + @Override + public boolean isBoneMealSuccess(Object thisBlock, Object[] args) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (behavior.isBoneMealSuccess(thisBlock, args)) { + return true; + } + } + return false; + } + + @Override + public boolean canSurvive(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (!behavior.canSurvive(thisBlock, args, superMethod)) { + return false; + } + } + return true; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/EmptyItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/EmptyItem.java new file mode 100644 index 000000000..5fcfdbefb --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/EmptyItem.java @@ -0,0 +1,342 @@ +//package net.momirealms.craftengine.core.item; +// +//import com.google.gson.JsonElement; +//import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +//import net.momirealms.craftengine.core.util.Key; +// +//import java.util.List; +//import java.util.Optional; +// +//public class EmptyItem implements Item { +// private final I item; +// +// public EmptyItem(I item) { +// this.item = item; +// } +// +// @Override +// public Item addEnchantment(Enchantment enchantment) { +// return this; +// } +// +// @Override +// public Optional> getCustomItem() { +// return Optional.empty(); +// } +// +// @Override +// public Optional> getItemBehavior() { +// return Optional.empty(); +// } +// +// @Override +// public boolean isCustomItem() { +// return false; +// } +// +// @Override +// public boolean isBlockItem() { +// return false; +// } +// +// @Override +// public Key id() { +// return ItemKeys.AIR; +// } +// +// @Override +// public Key vanillaId() { +// return ItemKeys.AIR; +// } +// +// @Override +// public Optional customId() { +// return Optional.empty(); +// } +// +// @Override +// public Item customId(Key id) { +// return this; +// } +// +// @Override +// public int count() { +// return 0; +// } +// +// @Override +// public Item count(int amount) { +// return this; +// } +// +// @Override +// public Item trim(Trim trim) { +// return this; +// } +// +// @Override +// public Optional trim() { +// return Optional.empty(); +// } +// +// @Override +// public Item customModelData(Integer data) { +// return this; +// } +// +// @Override +// public Optional customModelData() { +// return Optional.empty(); +// } +// +// @Override +// public Item damage(Integer data) { +// return this; +// } +// +// @Override +// public Optional damage() { +// return Optional.empty(); +// } +// +// @Override +// public Item repairCost(Integer data) { +// return this; +// } +// +// @Override +// public Optional repairCost() { +// return Optional.empty(); +// } +// +// @Override +// public Item maxDamage(Integer data) { +// return this; +// } +// +// @Override +// public Optional maxDamage() { +// return Optional.empty(); +// } +// +// @Override +// public Item dyedColor(Integer data) { +// return this; +// } +// +// @Override +// public Optional dyedColor() { +// return Optional.empty(); +// } +// +// @Override +// public Item customName(String displayName) { +// return this; +// } +// +// @Override +// public Optional customName() { +// return Optional.empty(); +// } +// +// @Override +// public Item itemName(String itemName) { +// return this; +// } +// +// @Override +// public Optional itemName() { +// return Optional.empty(); +// } +// +// @Override +// public Item itemModel(String itemModel) { +// return this; +// } +// +// @Override +// public Optional itemModel() { +// return Optional.empty(); +// } +// +// @Override +// public Item tooltipStyle(String tooltipStyle) { +// return this; +// } +// +// @Override +// public Optional tooltipStyle() { +// return Optional.empty(); +// } +// +// @Override +// public Item lore(List lore) { +// return this; +// } +// +// @Override +// public Optional jukeboxSong() { +// return Optional.empty(); +// } +// +// @Override +// public Item jukeboxSong(JukeboxPlayable song) { +// return this; +// } +// +// @Override +// public Optional equippable() { +// return Optional.empty(); +// } +// +// @Override +// public Item equippable(EquipmentData equipmentData) { +// return this; +// } +// +// @Override +// public Optional> lore() { +// return Optional.empty(); +// } +// +// @Override +// public Item unbreakable(boolean unbreakable) { +// return this; +// } +// +// @Override +// public boolean unbreakable() { +// return false; +// } +// +// @Override +// public Item skull(String data) { +// return this; +// } +// +// @Override +// public Optional getEnchantment(Key enchantmentId) { +// return Optional.empty(); +// } +// +// @Override +// public Item setEnchantments(List enchantments) { +// return this; +// } +// +// @Override +// public Item setStoredEnchantments(List enchantments) { +// return this; +// } +// +// @Override +// public Item addStoredEnchantment(Enchantment enchantment) { +// return this; +// } +// +// @Override +// public Item itemFlags(List flags) { +// return this; +// } +// +// @Override +// public Object getTag(Object... path) { +// return null; +// } +// +// @Override +// public Item setTag(Object value, Object... path) { +// return this; +// } +// +// @Override +// public boolean hasTag(Object... path) { +// return false; +// } +// +// @Override +// public boolean removeTag(Object... path) { +// return false; +// } +// +// @Override +// public boolean hasComponent(Object type) { +// return false; +// } +// +// @Override +// public void removeComponent(Object type) { +// } +// +// @Override +// public Object getComponent(Object type) { +// return null; +// } +// +// @Override +// public Object getJavaTypeComponent(Object type) { +// return null; +// } +// +// @Override +// public JsonElement getJsonTypeComponent(Object type) { +// return null; +// } +// +// @Override +// public void setComponent(Object type, Object value) { +// } +// +// @Override +// public void resetComponent(Object type) { +// } +// +// @Override +// public I getItem() { +// return this.item; +// } +// +// @Override +// public I load() { +// return this.item; +// } +// +// @Override +// public int maxStackSize() { +// return 0; +// } +// +// @Override +// public Item maxStackSize(int amount) { +// return this; +// } +// +// @Override +// public Item copyWithCount(int count) { +// return this; +// } +// +// @Override +// public boolean is(Key itemTag) { +// return false; +// } +// +// @Override +// public Object getLiteralObject() { +// return null; +// } +// +// @Override +// public Item mergeCopy(Item another) { +// return this; +// } +// +// @Override +// public void merge(Item another) { +// } +// +// @Override +// public byte[] toByteArray() { +// return new byte[0]; +// } +//} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index de7c072ac..f5fc439c2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -29,6 +29,7 @@ public class ItemKeys { public static final Key BONE_MEAL = Key.of("minecraft:bone_meal"); public static final Key ENCHANTED_BOOK = Key.of("minecraft:enchanted_book"); public static final Key TOTEM_OF_UNDYING = Key.of("minecraft:totem_of_undying"); + public static final Key BARRIER = Key.of("minecraft:barrier"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE 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 b18d3f952..839de5886 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,9 +9,6 @@ import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.nio.file.Path; import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; public interface PackManager extends Manageable { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java index c48418575..cbecc4ba5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java @@ -129,7 +129,7 @@ public interface GuiElement { @Override public Item item() { - return gui().itemAt(index).item(); + return gui().itemAt(this.index).item(); } @Override 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 2e9d1e6d0..7fc4915ef 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 @@ -1,5 +1,8 @@ package net.momirealms.craftengine.core.plugin.gui.category; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; @@ -243,12 +246,18 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { if (subCategory == null) return null; Item item = this.plugin.itemManager().createWrappedItem(subCategory.icon(), player); if (item == null) { - this.plugin.logger().warn("Can't not find item " + subCategory.icon() + " for category icon"); - return null; + if (!subCategory.icon().equals(ItemKeys.AIR)) { + this.plugin.logger().warn("Can't find item " + subCategory.icon() + " as icon for sub category " + subCategoryId); + item = this.plugin.itemManager().createWrappedItem(ItemKeys.BARRIER, player); + item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); + item.lore(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); + item.load(); + } + } else { + item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); + item.lore(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); + item.load(); } - item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); - item.lore(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); - item.load(); return new ItemWithAction(item, (element, click) -> { click.cancel(); player.playSound(Constants.SOUND_CLICK_BUTTON); @@ -257,21 +266,35 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } else { Key itemId = Key.of(it); Item item = this.plugin.itemManager().createWrappedItem(itemId, player); - if (item == null) return null; + boolean canGoFurther; + if (item == null) { + if (!itemId.equals(ItemKeys.AIR)) { + this.plugin.logger().warn("Can't find item " + itemId + " for category " + categoryId); + item = this.plugin.itemManager().createWrappedItem(ItemKeys.BARRIER, player); + item.customName(AdventureHelper.componentToJson(Component.text(it).decoration(TextDecoration.ITALIC, TextDecoration.State.FALSE).color(NamedTextColor.RED))); + } + canGoFurther = false; + } else { + canGoFurther = true; + } return new ItemWithAction(item, (e, c) -> { c.cancel(); + Item eItem = e.item(); + if (!canGoFurther) { + return; + } if (player.isCreativeMode() && player.hasPermission(GET_ITEM_PERMISSION)) { if (MIDDLE_CLICK.contains(c.type()) && c.itemOnCursor() == null) { - Item newItem = this.plugin.itemManager().createWrappedItem(e.item().id(), player); + Item newItem = this.plugin.itemManager().createWrappedItem(eItem.id(), player); newItem.count(newItem.maxStackSize()); c.setItemOnCursor(newItem); return; } if (SHIFT_LEFT.equals(c.type())) { - player.giveItem(this.plugin.itemManager().createWrappedItem(e.item().id(), player)); + player.giveItem(this.plugin.itemManager().createWrappedItem(eItem.id(), player)); return; } else if (SHIFT_RIGHT.equals(c.type())) { - Item newItem = this.plugin.itemManager().createWrappedItem(e.item().id(), player); + Item newItem = this.plugin.itemManager().createWrappedItem(eItem.id(), player); newItem.count(newItem.maxStackSize()); player.giveItem(newItem); return; @@ -294,7 +317,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }); } - }).filter(Objects::nonNull).toList(); + }).toList(); PagedGui.builder() .addIngredients(itemList) diff --git a/gradle.properties b/gradle.properties index 3bb2f44ca..ef3d4750e 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.54.8 +project_version=0.0.54.9 config_version=34 lang_version=14 project_group=net.momirealms @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.65.26 +nms_helper_version=0.65.27 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 diff --git a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index 52214c52a..daeeba57c 100644 --- a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -225,4 +225,16 @@ public class CraftEngineBlock extends Block LOGGER.error(e); } } + + @Override + public void neighborChanged(@NotNull BlockState state, @NotNull Level world, @NotNull BlockPos pos, @NotNull Block sourceBlock, @NotNull BlockPos sourcePos, boolean notify) { + try { + this.behaviorHolder.value().neighborChanged(this, new Object[]{state, world, pos, sourceBlock, sourcePos, notify}, () -> { + super.neighborChanged(state, world, pos, sourceBlock, sourcePos, notify); + return null; + }); + } catch (Exception e) { + LOGGER.error(e); + } + } } diff --git a/server-mod/v1_20_5/build.gradle.kts b/server-mod/v1_20_5/build.gradle.kts index 38964e5ad..bcc393e9d 100644 --- a/server-mod/v1_20_5/build.gradle.kts +++ b/server-mod/v1_20_5/build.gradle.kts @@ -44,7 +44,7 @@ artifacts { tasks { shadowJar { archiveClassifier = "" - archiveFileName = "${rootProject.name}-ignite-mod-${rootProject.properties["project_version"]}+mc1.20.5-1.21.4-mojmap.jar" + archiveFileName = "${rootProject.name}-ignite-mod-${rootProject.properties["project_version"]}+mc1.21.2-1.21.4-mojmap.jar" destinationDirectory.set(file("$rootDir/target")) } } diff --git a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index 4e37a60ef..fdde40516 100644 --- a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -12,6 +12,7 @@ import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.Orientation; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.momirealms.craftengine.mod.CraftEnginePlugin; @@ -21,6 +22,7 @@ import net.momirealms.craftengine.shared.block.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class CraftEngineBlock extends Block implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock { @@ -226,4 +228,16 @@ public class CraftEngineBlock extends Block LOGGER.error(e); } } + + @Override + protected void neighborChanged(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { + try { + this.behaviorHolder.value().neighborChanged(this, new Object[]{state, level, pos, neighborBlock, orientation, movedByPiston}, () -> { + super.neighborChanged(state, level, pos, neighborBlock, orientation, movedByPiston); + return null; + }); + } catch (Exception e) { + LOGGER.error(e); + } + } } diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index 212e34087..fedc24dd6 100644 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -12,6 +12,7 @@ import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.Orientation; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.momirealms.craftengine.mod.CraftEnginePlugin; @@ -21,6 +22,7 @@ import net.momirealms.craftengine.shared.block.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class CraftEngineBlock extends Block implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock { @@ -226,4 +228,16 @@ public class CraftEngineBlock extends Block LOGGER.error(e); } } + + @Override + protected void neighborChanged(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { + try { + this.behaviorHolder.value().neighborChanged(this, new Object[]{state, level, pos, neighborBlock, orientation, movedByPiston}, () -> { + super.neighborChanged(state, level, pos, neighborBlock, orientation, movedByPiston); + return null; + }); + } catch (Exception e) { + LOGGER.error(e); + } + } } diff --git a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java index 24e08c8b3..5c4987cab 100644 --- a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java +++ b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java @@ -1,9 +1,18 @@ package net.momirealms.craftengine.shared.block; +import java.util.Optional; import java.util.concurrent.Callable; public abstract class BlockBehavior { + @SuppressWarnings("unchecked") + public Optional getAs(Class tClass) { + if (tClass.isInstance(this)) { + return Optional.of((T) this); + } + return Optional.empty(); + } + public Object rotate(Object thisBlock, Object[] args, Callable superMethod) throws Exception { return superMethod.call(); } @@ -16,6 +25,10 @@ public abstract class BlockBehavior { return superMethod.call(); } + public void neighborChanged(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + superMethod.call(); + } + public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { superMethod.call(); } From 5c827ddf629e51976c01a9656db246e1d2857487 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 25 May 2025 21:15:51 +0800 Subject: [PATCH 54/89] =?UTF-8?q?=E6=B7=B7=E5=90=88=E6=96=B9=E5=9D=97?= =?UTF-8?q?=E8=A1=8C=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 2 +- .../bukkit/block/BukkitCustomBlock.java | 6 +- .../AbstractCanSurviveBlockBehavior.java | 77 ++++++++++++ .../block/behavior/BukkitBlockBehaviors.java | 6 +- .../block/behavior/BushBlockBehavior.java | 83 +++---------- .../behavior/ConcretePowderBlockBehavior.java | 17 ++- .../block/behavior/CropBlockBehavior.java | 19 ++- .../block/behavior/FallingBlockBehavior.java | 6 +- .../block/behavior/HangingBlockBehavior.java | 7 +- .../block/behavior/LampBlockBehavior.java | 22 +++- .../behavior/NearLiquidBlockBehavior.java | 102 ++++++++++++++++ .../block/behavior/OnLiquidBlockBehavior.java | 34 +++++- .../block/behavior/SaplingBlockBehavior.java | 14 +-- ...or.java => VerticalCropBlockBehavior.java} | 114 ++++-------------- .../bukkit/util/LocationUtils.java | 8 +- .../core/block/AbstractCustomBlock.java | 16 ++- .../craftengine/core/block/CustomBlock.java | 2 +- .../craftengine/core/block/EmptyBlock.java | 3 +- .../core/block/InactiveCustomBlock.java | 3 +- .../UnsafeCompositeBlockBehavior.java | 24 +++- .../core/pack/AbstractPackManager.java | 4 + .../craftengine/core/util/MiscUtils.java | 11 ++ gradle.properties | 2 +- .../shared/block/BlockBehavior.java | 2 +- 24 files changed, 361 insertions(+), 223 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/{SugarCaneBlockBehavior.java => VerticalCropBlockBehavior.java} (54%) 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 4f3b93ee7..4bbd48d83 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 @@ -428,7 +428,7 @@ public class BukkitBlockManager extends AbstractBlockManager { .properties(properties) .settings(settings) .lootTable(LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), true))) - .behavior(MiscUtils.castToMap(section.get("behavior"), true)) + .behavior(MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors"))) .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) .build(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index 443c63c44..592862fde 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -41,7 +41,7 @@ public class BukkitCustomBlock extends AbstractCustomBlock { @NotNull Map variantMapper, @NotNull BlockSettings settings, @NotNull Map>> events, - @Nullable Map behavior, + @Nullable List> behavior, @Nullable LootTable lootTable ) { super(id, holder, properties, appearances, variantMapper, settings, events, behavior, lootTable); @@ -159,7 +159,7 @@ public class BukkitCustomBlock extends AbstractCustomBlock { protected Map appearances; protected Map variantMapper; protected BlockSettings settings; - protected Map behavior; + protected List> behavior; protected LootTable lootTable; protected Map>> events; @@ -180,7 +180,7 @@ public class BukkitCustomBlock extends AbstractCustomBlock { } @Override - public Builder behavior(Map behavior) { + public Builder behavior(List> behavior) { this.behavior = behavior; return this; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java new file mode 100644 index 000000000..16e915a1b --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java @@ -0,0 +1,77 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +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; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.WorldEvents; +import net.momirealms.craftengine.core.world.WorldPosition; + +import java.util.concurrent.Callable; + +public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavior { + + protected AbstractCanSurviveBlockBehavior(CustomBlock customBlock) { + super(customBlock); + } + + @Override + public boolean canSurvive(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object state = args[0]; + Object world = args[1]; + Object pos = args[2]; + return canSurvive(thisBlock, state, world, pos); + } + + @Override + public void onPlace(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object world = args[1]; + Object blockPos = args[2]; + Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2); + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object level; + Object blockPos; + Object state = args[0]; + if (VersionHelper.isOrAbove1_21_2()) { + level = args[1]; + blockPos = args[3]; + } else { + level = args[3]; + blockPos = args[4]; + } + int stateId = BlockStateUtils.blockStateToId(state); + ImmutableBlockState previousState = BukkitBlockManager.instance().getImmutableBlockState(stateId); + if (previousState == null || previousState.isEmpty()) { + return state; + } + if (!canSurvive(thisBlock, new Object[] {state, level, blockPos}, () -> true)) { + BlockPos pos = LocationUtils.fromBlockPos(blockPos); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); + WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position); + for (Item item : previousState.getDrops(builder, world, null)) { + world.dropItemNaturally(position, item); + } + world.playBlockSound(position, previousState.sounds().breakSound()); + FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId); + return Reflections.method$Block$defaultBlockState.invoke(Reflections.instance$Blocks$AIR); + } + return state; + } + + protected abstract boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws Exception; +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index 2b36c888f..b0942ed95 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -12,9 +12,10 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key STRIPPABLE_BLOCK = Key.from("craftengine:strippable_block"); public static final Key SAPLING_BLOCK = Key.from("craftengine:sapling_block"); public static final Key ON_LIQUID_BLOCK = Key.from("craftengine:on_liquid_block"); + public static final Key NEAR_LIQUID_BLOCK = Key.from("craftengine:near_liquid_block"); public static final Key WATERLOGGED_BLOCK = Key.from("craftengine:waterlogged_block"); public static final Key CONCRETE_POWDER_BLOCK = Key.from("craftengine:concrete_powder_block"); - public static final Key SUGARCANE_BLOCK = Key.from("craftengine:sugar_cane_block"); + public static final Key VERTICAL_CROP_BLOCK = Key.from("craftengine:vertical_crop_block"); public static final Key CROP_BLOCK = Key.from("craftengine:crop_block"); public static final Key GRASS_BLOCK = Key.from("craftengine:grass_block"); public static final Key LAMP_BLOCK = Key.from("craftengine:lamp_block"); @@ -28,9 +29,10 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(STRIPPABLE_BLOCK, StrippableBlockBehavior.FACTORY); register(SAPLING_BLOCK, SaplingBlockBehavior.FACTORY); register(ON_LIQUID_BLOCK, OnLiquidBlockBehavior.FACTORY); + register(NEAR_LIQUID_BLOCK, NearLiquidBlockBehavior.FACTORY); register(WATERLOGGED_BLOCK, WaterLoggedBlockBehavior.FACTORY); register(CONCRETE_POWDER_BLOCK, ConcretePowderBlockBehavior.FACTORY); - register(SUGARCANE_BLOCK, SugarCaneBlockBehavior.FACTORY); + register(VERTICAL_CROP_BLOCK, VerticalCropBlockBehavior.FACTORY); register(CROP_BLOCK, CropBlockBehavior.FACTORY); register(GRASS_BLOCK, GrassBlockBehavior.FACTORY); register(LAMP_BLOCK, LampBlockBehavior.FACTORY); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 6c1d87c11..11cf0c44b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -4,23 +4,13 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.BlockTags; -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; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.Tuple; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.Vec3d; -import net.momirealms.craftengine.core.world.WorldEvents; -import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -28,76 +18,31 @@ import org.bukkit.NamespacedKey; import org.bukkit.Registry; import java.util.*; -import java.util.concurrent.Callable; -public class BushBlockBehavior extends BukkitBlockBehavior { +public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { public static final Factory FACTORY = new Factory(); protected final List tagsCanSurviveOn; protected final Set blocksCansSurviveOn; protected final Set customBlocksCansSurviveOn; protected final boolean any; + protected final boolean stackable; - public BushBlockBehavior(CustomBlock block, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + public BushBlockBehavior(CustomBlock block, boolean stackable, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { super(block); + this.stackable = stackable; this.tagsCanSurviveOn = tagsCanSurviveOn; this.blocksCansSurviveOn = blocksCansSurviveOn; this.customBlocksCansSurviveOn = customBlocksCansSurviveOn; this.any = this.tagsCanSurviveOn.isEmpty() && this.blocksCansSurviveOn.isEmpty() && this.customBlocksCansSurviveOn.isEmpty(); } - @Override - public void onPlace(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - Object world = args[1]; - Object blockPos = args[2]; - Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2); - } - - @Override - public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - Object level; - Object blockPos; - Object state = args[0]; - if (VersionHelper.isOrAbove1_21_2()) { - level = args[1]; - blockPos = args[3]; - } else { - level = args[3]; - blockPos = args[4]; - } - if (!canSurvive(thisBlock, state, level, blockPos)) { - int stateId = BlockStateUtils.blockStateToId(state); - ImmutableBlockState previousState = BukkitBlockManager.instance().getImmutableBlockState(stateId); - if (previousState != null && !previousState.isEmpty()) { - BlockPos pos = LocationUtils.fromBlockPos(blockPos); - net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); - WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); - ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(DirectContextParameters.POSITION, position); - for (Item item : previousState.getDrops(builder, world, null)) { - world.dropItemNaturally(position, item); - } - world.playBlockSound(position, previousState.sounds().breakSound()); - FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId); - } - return Reflections.method$Block$defaultBlockState.invoke(Reflections.instance$Blocks$AIR); - } - return super.updateShape(thisBlock, args, superMethod); - } - - @Override - public boolean canSurvive(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - Object state = args[0]; - Object world = args[1]; - Object pos = args[2]; - return canSurvive(thisBlock, state, world, pos); - } - public static class Factory implements BlockBehaviorFactory { @Override public BlockBehavior create(CustomBlock block, Map arguments) { Tuple, Set, Set> tuple = readTagsAndState(arguments, false); - return new BushBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right()); + boolean stackable = (boolean) arguments.getOrDefault("stackable", false); + return new BushBlockBehavior(block, stackable, tuple.left(), tuple.mid(), tuple.right()); } } @@ -127,7 +72,8 @@ public class BushBlockBehavior extends BukkitBlockBehavior { return new Tuple<>(mcTags, mcBlocks, customBlocks); } - protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { + @Override + protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws Exception { int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); @@ -151,12 +97,17 @@ public class BushBlockBehavior extends BukkitBlockBehavior { return true; } } else { - ImmutableBlockState previousState = BukkitBlockManager.instance().getImmutableBlockState(id); - if (previousState != null && !previousState.isEmpty()) { - if (this.customBlocksCansSurviveOn.contains(previousState.owner().value().id().toString())) { + ImmutableBlockState belowCustomState = BukkitBlockManager.instance().getImmutableBlockState(id); + if (belowCustomState != null && !belowCustomState.isEmpty()) { + if (stackable) { + if (belowCustomState.owner().value() == super.customBlock) { + return true; + } + } + if (this.customBlocksCansSurviveOn.contains(belowCustomState.owner().value().id().toString())) { return true; } - if (this.customBlocksCansSurviveOn.contains(previousState.toString())) { + if (this.customBlocksCansSurviveOn.contains(belowCustomState.toString())) { return true; } } 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 e15ae9e6f..5fb2dff7a 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 @@ -25,15 +25,14 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; -// TODO Inject FallingBlockEntity? -public class ConcretePowderBlockBehavior extends FallingBlockBehavior { +public class ConcretePowderBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); - private final Key targetBlock; + private final Key targetBlock; // TODO 更宽泛的,使用state,似乎也不是很好的方案? private Object defaultBlockState; private ImmutableBlockState defaultImmutableBlockState; - public ConcretePowderBlockBehavior(CustomBlock block, float hurtAmount, int maxHurt, Key targetBlock) { - super(block, hurtAmount, maxHurt); + public ConcretePowderBlockBehavior(CustomBlock block, Key targetBlock) { + super(block); this.targetBlock = targetBlock; } @@ -79,7 +78,7 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior { return super.updateStateForPlacement(context, state); } } - } catch (ReflectiveOperationException e) { + } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to update state for placement " + context.getClickedPos(), e); } return super.updateStateForPlacement(context, state); @@ -118,7 +117,7 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior { } } } - return super.updateShape(thisBlock, args, superMethod); + return args[0]; } private static boolean shouldSolidify(Object level, Object blockPos, Object blockState) throws ReflectiveOperationException { @@ -155,10 +154,8 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { - float hurtAmount = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("hurt-amount", -1f), "hurt-amount"); - int hurtMax = ResourceConfigUtils.getAsInt(arguments.getOrDefault("max-hurt", -1), "max-hurt"); String solidBlock = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("solid-block"), "warning.config.block.behavior.concrete.missing_solid"); - return new ConcretePowderBlockBehavior(block, hurtAmount, hurtMax, Key.of(solidBlock)); + return new ConcretePowderBlockBehavior(block, Key.of(solidBlock)); } } } 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 5581362a0..df47ace39 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 @@ -25,7 +25,6 @@ import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.Tuple; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.Vec3i; import net.momirealms.craftengine.core.world.WorldPosition; @@ -33,12 +32,10 @@ import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.World; import java.lang.reflect.InvocationTargetException; -import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.Callable; -public class CropBlockBehavior extends BushBlockBehavior { +public class CropBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final IntegerProperty ageProperty; private final float growSpeed; @@ -46,9 +43,8 @@ public class CropBlockBehavior extends BushBlockBehavior { private final boolean isBoneMealTarget; private final NumberProvider boneMealBonus; - public CropBlockBehavior(CustomBlock block, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, - Property ageProperty, float growSpeed, int minGrowLight, boolean isBoneMealTarget, NumberProvider boneMealBonus) { - super(block, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + public CropBlockBehavior(CustomBlock block, Property ageProperty, float growSpeed, int minGrowLight, boolean isBoneMealTarget, NumberProvider boneMealBonus) { + super(block); this.ageProperty = (IntegerProperty) ageProperty; this.growSpeed = growSpeed; this.minGrowLight = minGrowLight; @@ -105,8 +101,10 @@ public class CropBlockBehavior extends BushBlockBehavior { } @Override - protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { - return hasSufficientLight(world, blockPos) && super.canSurvive(thisBlock, state, world, blockPos); + public boolean canSurvive(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object world = args[1]; + Object pos = args[2]; + return hasSufficientLight(world, pos); } @Override @@ -204,13 +202,12 @@ public class CropBlockBehavior extends BushBlockBehavior { @SuppressWarnings("unchecked") @Override public BlockBehavior create(CustomBlock block, Map arguments) { - Tuple, Set, Set> tuple = readTagsAndState(arguments, false); Property ageProperty = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("age"), "warning.config.block.behavior.crop.missing_age"); int minGrowLight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("light-requirement", 9), "light-requirement"); float growSpeed = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("grow-speed", 0.125f), "grow-speed"); boolean isBoneMealTarget = (boolean) arguments.getOrDefault("is-bone-meal-target", true); NumberProvider boneMealAgeBonus = NumberProviders.fromObject(arguments.getOrDefault("bone-meal-age-bonus", 1)); - return new CropBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right(), ageProperty, growSpeed, minGrowLight, isBoneMealTarget, boneMealAgeBonus); + return new CropBlockBehavior(block, ageProperty, growSpeed, minGrowLight, isBoneMealTarget, boneMealAgeBonus); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java index fb98a3e5f..48cd63cb8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java @@ -51,7 +51,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { blockPos = args[4]; } Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2); - return super.updateShape(thisBlock, args, superMethod); + return args[0]; } @Override @@ -109,6 +109,8 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { @Override public void onLand(Object thisBlock, Object[] args) throws Exception { Object fallingBlock = args[4]; + Object level = args[0]; + Object pos = args[1]; Object entityData = Reflections.field$Entity$entityData.get(fallingBlock); boolean isSilent = (boolean) Reflections.method$SynchedEntityData$get.invoke(entityData, Reflections.instance$Entity$DATA_SILENT); if (!isSilent) { @@ -116,8 +118,6 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { int stateId = BlockStateUtils.blockStateToId(blockState); ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId); if (immutableBlockState == null || immutableBlockState.isEmpty()) return; - Object level = args[0]; - Object pos = args[1]; net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); world.playBlockSound(Vec3d.atCenterOf(LocationUtils.fromBlockPos(pos)), immutableBlockState.sounds().landSound()); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java index 7366aad9d..a11b68890 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java @@ -13,8 +13,8 @@ import java.util.Set; public class HangingBlockBehavior extends BushBlockBehavior { public static final Factory FACTORY = new Factory(); - public HangingBlockBehavior(CustomBlock block, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { - super(block, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + public HangingBlockBehavior(CustomBlock block, boolean stackable, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + super(block, stackable, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); } @Override @@ -32,7 +32,8 @@ public class HangingBlockBehavior extends BushBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { Tuple, Set, Set> tuple = readTagsAndState(arguments, true); - return new HangingBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right()); + boolean stackable = (boolean) arguments.getOrDefault("stackable", false); + return new HangingBlockBehavior(block, stackable, tuple.left(), tuple.mid(), tuple.right()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java index 56ff8079c..fd6f67e78 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java @@ -3,11 +3,13 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; 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.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.shared.block.BlockBehavior; @@ -23,6 +25,13 @@ public class LampBlockBehavior extends BukkitBlockBehavior { this.litProperty = litProperty; } + @Override + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { + Object level = context.getLevel().serverWorld(); + state = state.with(this.litProperty, FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, LocationUtils.toBlockPos(context.getClickedPos()))); + return state; + } + @Override public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { Object blockState = args[0]; @@ -30,9 +39,16 @@ public class LampBlockBehavior extends BukkitBlockBehavior { if (state == null || state.isEmpty()) return; Object world = args[1]; Object blockPos = args[2]; - if (state.get(this.litProperty) && !FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) { - // TODO Call Event - FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2); + if (state.get(this.litProperty)) { + if (!FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) { + // TODO Call Event + FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2); + } + } else { + if (FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) { + // TODO Call Event + FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2); + } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java new file mode 100644 index 000000000..fd40a6b95 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java @@ -0,0 +1,102 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +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.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.shared.block.BlockBehavior; + +import java.util.List; +import java.util.Map; + +public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior { + private static final List WATER = List.of(Reflections.instance$Fluids$WATER, Reflections.instance$Fluids$FLOWING_WATER); + private static final List LAVA = List.of(Reflections.instance$Fluids$LAVA, Reflections.instance$Fluids$FLOWING_LAVA); + public static final Factory FACTORY = new Factory(); + private final boolean onWater; + private final boolean onLava; + private final boolean stackable; + private final BlockPos[] positions; + + public NearLiquidBlockBehavior(CustomBlock block, BlockPos[] positions, boolean stackable, boolean onWater, boolean onLava) { + super(block); + this.onWater = onWater; + this.onLava = onLava; + this.stackable = stackable; + this.positions = positions; + } + + public boolean onWater() { + return this.onWater; + } + + public boolean onLava() { + return this.onLava; + } + + public static class Factory implements BlockBehaviorFactory { + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + List liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water"))); + boolean stackable = (boolean) arguments.getOrDefault("stackable", false); + List positionsToCheck = MiscUtils.getAsStringList(arguments.getOrDefault("positions", List.of())); + if (positionsToCheck.isEmpty()) { + return new NearLiquidBlockBehavior(block, new BlockPos[]{new BlockPos(0,-1,0)}, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava")); + } else { + BlockPos[] pos = new BlockPos[positionsToCheck.size()]; + for (int i = 0; i < pos.length; i++) { + String[] split = positionsToCheck.get(i).split(","); + pos[i] = new BlockPos(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2])); + } + return new NearLiquidBlockBehavior(block, pos, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava")); + } + } + } + + @Override + protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { + int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); + int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); + int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); + if (this.stackable) { + Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y - 1, z); + Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos); + int id = BlockStateUtils.blockStateToId(belowState); + if (!BlockStateUtils.isVanillaBlock(id)) { + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id); + if (immutableBlockState.owner().value() == super.customBlock) { + return true; + } + } + } + for (BlockPos pos : positions) { + Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x + pos.x(), y + pos.y(), z + pos.z()); + Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos); + if (mayPlaceOn(belowState, world, belowPos)) { + return true; + } + } + return false; + } + + protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException { + Object fluidState = Reflections.method$Level$getFluidState.invoke(world, belowPos); + Object fluidStateAbove = Reflections.method$Level$getFluidState.invoke(world, LocationUtils.above(belowPos)); + if (Reflections.method$FluidState$getType.invoke(fluidStateAbove) != Reflections.instance$Fluids$EMPTY) { + return false; + } + if (this.onWater && (WATER.contains(Reflections.method$FluidState$getType.invoke(fluidState)) || Reflections.field$StateHolder$owner.get(belowState) == Reflections.instance$Blocks$ICE)) { + return true; + } + if (this.onLava && LAVA.contains(Reflections.method$FluidState$getType.invoke(fluidState))) { + return true; + } + return false; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java index dda596013..cb73eeaab 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java @@ -1,25 +1,30 @@ package net.momirealms.craftengine.bukkit.block.behavior; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +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.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.shared.block.BlockBehavior; import java.util.List; import java.util.Map; -import java.util.Set; -public class OnLiquidBlockBehavior extends BushBlockBehavior { +public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior { public static final Factory FACTORY = new Factory(); private final boolean onWater; private final boolean onLava; + private final boolean stackable; - public OnLiquidBlockBehavior(CustomBlock block, boolean onWater, boolean onLava) { - super(block, List.of(), Set.of(), Set.of()); + public OnLiquidBlockBehavior(CustomBlock block, boolean stackable, boolean onWater, boolean onLava) { + super(block); this.onWater = onWater; this.onLava = onLava; + this.stackable = stackable; } public boolean onWater() { @@ -34,12 +39,31 @@ public class OnLiquidBlockBehavior extends BushBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { List liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water"))); - return new OnLiquidBlockBehavior(block, liquidTypes.contains("water"), liquidTypes.contains("lava")); + boolean stackable = (boolean) arguments.getOrDefault("stackable", false); + return new OnLiquidBlockBehavior(block, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava")); } } @Override + protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { + int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); + int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); + int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); + Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y - 1, z); + Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos); + return mayPlaceOn(belowState, world, belowPos); + } + protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException { + if (this.stackable) { + int id = BlockStateUtils.blockStateToId(belowState); + if (!BlockStateUtils.isVanillaBlock(id)) { + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id); + if (immutableBlockState.owner().value() == super.customBlock) { + return true; + } + } + } Object fluidState = Reflections.method$Level$getFluidState.invoke(world, belowPos); Object fluidStateAbove = Reflections.method$Level$getFluidState.invoke(world, LocationUtils.above(belowPos)); if (Reflections.method$FluidState$getType.invoke(fluidStateAbove) != Reflections.instance$Fluids$EMPTY) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java index 7511e265a..c83b5ff1a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java @@ -17,26 +17,23 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.Tuple; import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.Location; import org.bukkit.World; -import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.Callable; -public class SaplingBlockBehavior extends BushBlockBehavior { +public class SaplingBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final Key feature; private final Property stageProperty; private final double boneMealSuccessChance; private final float growSpeed; - public SaplingBlockBehavior(CustomBlock block, Key feature, Property stageProperty, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, double boneMealSuccessChance, float growSpeed) { - super(block, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + public SaplingBlockBehavior(CustomBlock block, Key feature, Property stageProperty, double boneMealSuccessChance, float growSpeed) { + super(block); this.feature = feature; this.stageProperty = stageProperty; this.boneMealSuccessChance = boneMealSuccessChance; @@ -53,7 +50,7 @@ public class SaplingBlockBehavior extends BushBlockBehavior { Object blockPos = args[2]; Object blockState = args[0]; Object aboveBlockPos = LocationUtils.above(blockPos); - if ((int) Reflections.method$LevelReader$getMaxLocalRawBrightness.invoke(world, aboveBlockPos) >= 9 && (float) RandomUtils.generateRandomFloat(0, 1) < growSpeed) { + if ((int) Reflections.method$LevelReader$getMaxLocalRawBrightness.invoke(world, aboveBlockPos) >= 9 && RandomUtils.generateRandomFloat(0, 1) < growSpeed) { increaseStage(world, blockPos, blockState, args[3]); } } @@ -175,8 +172,7 @@ public class SaplingBlockBehavior extends BushBlockBehavior { String feature = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("feature"), "warning.config.block.behavior.sapling.missing_feature"); Property stageProperty = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("stage"), "warning.config.block.behavior.sapling.missing_stage"); double boneMealSuccessChance = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("bone-meal-success-chance", 0.45), "bone-meal-success-chance"); - Tuple, Set, Set> tuple = readTagsAndState(arguments, false); - return new SaplingBlockBehavior(block, Key.of(feature), stageProperty, tuple.left(), tuple.mid(), tuple.right(), boneMealSuccessChance, + return new SaplingBlockBehavior(block, Key.of(feature), stageProperty, boneMealSuccessChance, ResourceConfigUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1.0 / 7.0), "grow-speed")); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java similarity index 54% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java index 7606c343c..039010453 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java @@ -15,37 +15,32 @@ import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldEvents; import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.shared.block.BlockBehavior; -import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.Callable; -public class SugarCaneBlockBehavior extends BushBlockBehavior { +public class VerticalCropBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); - private static final List WATER = List.of(Reflections.instance$Fluids$WATER, Reflections.instance$Fluids$FLOWING_WATER); - private static final List LAVA = List.of(Reflections.instance$Fluids$LAVA, Reflections.instance$Fluids$FLOWING_LAVA); - private static final List HORIZON_DIRECTIONS = List.of(Reflections.instance$Direction$NORTH, Reflections.instance$Direction$EAST, Reflections.instance$Direction$SOUTH, Reflections.instance$Direction$WEST); private final int maxHeight; - private final boolean nearWater; - private final boolean nearLava; private final IntegerProperty ageProperty; private final float growSpeed; + private final boolean direction; - public SugarCaneBlockBehavior(CustomBlock customBlock, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, Property ageProperty, - int maxHeight, boolean nearWater, boolean nearLava, float growSpeed) { - super(customBlock, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); - this.nearWater = nearWater; - this.nearLava = nearLava; + public VerticalCropBlockBehavior(CustomBlock customBlock, Property ageProperty, + int maxHeight, float growSpeed, boolean direction) { + super(customBlock); this.maxHeight = maxHeight; this.ageProperty = (IntegerProperty) ageProperty; this.growSpeed = growSpeed; + this.direction = direction; } @Override @@ -53,11 +48,11 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { Object blockState = args[0]; Object level = args[1]; Object blockPos = args[2]; - if (!canSurvive(thisBlock, blockState, level, blockPos)) { + if (!canSurvive(thisBlock, args, () -> true)) { int stateId = BlockStateUtils.blockStateToId(blockState); ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(stateId); if (currentState != null && !currentState.isEmpty()) { - // break the sugar cane + // break the crop FastNMS.INSTANCE.method$Level$removeBlock(level, blockPos, false); net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos))); @@ -85,7 +80,7 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { } Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 1); // return state, do not call super. - return superMethod.call(); + return args[0]; } @Override @@ -94,15 +89,15 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { Object level = args[1]; Object blockPos = args[2]; // above block is empty - if (FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.above(blockPos)) == Reflections.instance$Blocks$AIR$defaultState) { + if (FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, (this.direction ? LocationUtils.above(blockPos) : LocationUtils.below(blockPos))) == Reflections.instance$Blocks$AIR$defaultState) { int currentHeight = 1; BlockPos currentPos = LocationUtils.fromBlockPos(blockPos); ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); if (currentState != null && !currentState.isEmpty()) { while (true) { - Object belowPos = LocationUtils.toBlockPos(currentPos.x(), currentPos.y() - currentHeight, currentPos.z()); - Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, belowPos); - ImmutableBlockState belowImmutableState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(belowState)); + Object nextPos = LocationUtils.toBlockPos(currentPos.x(), this.direction ? currentPos.y() - currentHeight : currentPos.y() + currentHeight, currentPos.z()); + Object nextState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, nextPos); + ImmutableBlockState belowImmutableState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(nextState)); if (belowImmutableState != null && !belowImmutableState.isEmpty() && belowImmutableState.owner() == currentState.owner()) { currentHeight++; } else { @@ -116,11 +111,11 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { if (currentHeight < this.maxHeight) { int age = currentState.get(ageProperty); if (age >= this.ageProperty.max || RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) { - Object abovePos = LocationUtils.above(blockPos); + Object nextPos = this.direction ? LocationUtils.above(blockPos) : LocationUtils.below(blockPos); if (VersionHelper.isOrAbove1_21_5()) { - Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, super.customBlock.defaultState().customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); + Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, nextPos, super.customBlock.defaultState().customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); } else { - Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, super.customBlock.defaultState().customBlockState().handle()); + Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, nextPos, super.customBlock.defaultState().customBlockState().handle()); } FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, currentState.with(this.ageProperty, this.ageProperty.min).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); } else if (RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) { @@ -130,81 +125,16 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { } } - @Override - protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { - int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); - int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); - int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); - Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y - 1, z); - Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos); - int id = BlockStateUtils.blockStateToId(belowState); - // 如果下方是同种方块 - if (!BlockStateUtils.isVanillaBlock(id)) { - ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id); - if (immutableBlockState.owner().value() == super.customBlock) { - return true; - } - } - if (!super.mayPlaceOn(belowState, world, belowPos)) { - return false; - } - // 如果不需要依靠流体 - if (!this.nearWater && !this.nearLava) { - return true; - } - // 需要流体 - if (this.nearWater) { - if (hasNearbyLiquid(world, belowPos, true)) { - return true; - } - } - if (this.nearLava) { - if (hasNearbyLiquid(world, belowPos, false)) { - return true; - } - } - return false; - } - - private boolean hasNearbyLiquid(Object world, Object blockPos, boolean waterOrLava) throws ReflectiveOperationException { - for (Object direction : HORIZON_DIRECTIONS) { - Object relativePos = Reflections.method$BlockPos$relative.invoke(blockPos, direction); - if (waterOrLava) { - // water - Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, relativePos); - if (Reflections.method$BlockStateBase$getBlock.invoke(blockState) == Reflections.instance$Blocks$ICE) { - return true; - } - Object fluidState = Reflections.method$Level$getFluidState.invoke(world, relativePos); - Object fluidType = Reflections.method$FluidState$getType.invoke(fluidState); - if (WATER.contains(fluidType)) { - return true; - } - } else { - // lava - Object fluidState = Reflections.method$Level$getFluidState.invoke(world, relativePos); - Object fluidType = Reflections.method$FluidState$getType.invoke(fluidState); - if (LAVA.contains(fluidType)) { - return true; - } - } - } - return false; - } - public static class Factory implements BlockBehaviorFactory { @SuppressWarnings("unchecked") @Override public BlockBehavior create(CustomBlock block, Map arguments) { - Tuple, Set, Set> tuple = readTagsAndState(arguments, false); Property ageProperty = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("age"), "warning.config.block.behavior.sugar_cane.missing_age"); int maxHeight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("max-height", 3), "max-height"); - List nearbyLiquids = MiscUtils.getAsStringList(arguments.getOrDefault("required-adjacent-liquids", List.of())); - boolean nearWater = nearbyLiquids.contains("water"); - boolean nearLava = nearbyLiquids.contains("lava"); - return new SugarCaneBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right(), ageProperty, maxHeight, nearWater, nearLava, - ResourceConfigUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1), "grow-speed")); + boolean direction = arguments.getOrDefault("direction", "up").toString().equalsIgnoreCase("up"); + return new VerticalCropBlockBehavior(block, ageProperty, maxHeight, + ResourceConfigUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1), "grow-speed"), direction); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java index bb3d7feec..c7fa13c15 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java @@ -37,10 +37,14 @@ public class LocationUtils { return toBlockPos(pos.x(), pos.y(), pos.z()); } - public static Object above(Object blockPos) throws ReflectiveOperationException { + public static Object above(Object blockPos) { return toBlockPos(FastNMS.INSTANCE.field$Vec3i$x(blockPos), FastNMS.INSTANCE.field$Vec3i$y(blockPos) + 1, FastNMS.INSTANCE.field$Vec3i$z(blockPos)); } + public static Object below(Object blockPos) { + return toBlockPos(FastNMS.INSTANCE.field$Vec3i$x(blockPos), FastNMS.INSTANCE.field$Vec3i$y(blockPos) - 1, FastNMS.INSTANCE.field$Vec3i$z(blockPos)); + } + public static Object toBlockPos(int x, int y, int z) { return FastNMS.INSTANCE.constructor$BlockPos(x, y, z); } @@ -49,7 +53,7 @@ public class LocationUtils { return new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); } - public static BlockPos fromBlockPos(Object pos) throws ReflectiveOperationException { + public static BlockPos fromBlockPos(Object pos) { return new BlockPos( FastNMS.INSTANCE.field$Vec3i$x(pos), FastNMS.INSTANCE.field$Vec3i$y(pos), diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java index aa39e69c3..c91a7bacf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.block; import com.google.common.collect.ImmutableMap; import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.behavior.BlockBehaviors; +import net.momirealms.craftengine.core.block.behavior.UnsafeCompositeBlockBehavior; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.loot.LootTable; @@ -14,6 +15,7 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.shared.block.BlockBehavior; +import net.momirealms.craftengine.shared.block.EmptyBlockBehavior; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; import org.jetbrains.annotations.NotNull; @@ -42,7 +44,7 @@ public abstract class AbstractCustomBlock implements CustomBlock { @NotNull Map variantMapper, @NotNull BlockSettings settings, @NotNull Map>> events, - @Nullable Map behavior, + @NotNull List> behaviorConfig, @Nullable LootTable lootTable ) { holder.bindValue(this); @@ -53,7 +55,17 @@ public abstract class AbstractCustomBlock implements CustomBlock { this.events = events; this.variantProvider = new BlockStateVariantProvider(holder, ImmutableBlockState::new, properties); this.defaultState = this.variantProvider.getDefaultState(); - this.behavior = BlockBehaviors.fromMap(this, behavior); + if (behaviorConfig.isEmpty()) { + this.behavior = new EmptyBlockBehavior(); + } else if (behaviorConfig.size() == 1) { + this.behavior = BlockBehaviors.fromMap(this, behaviorConfig.get(0)); + } else { + List behaviors = new ArrayList<>(); + for (Map config : behaviorConfig) { + behaviors.add((AbstractBlockBehavior) BlockBehaviors.fromMap(this, config)); + } + this.behavior = new UnsafeCompositeBlockBehavior(this, behaviors); + } List> placements = new ArrayList<>(4); for (Map.Entry> propertyEntry : this.properties.entrySet()) { placements.add(Property.createStateForPlacement(propertyEntry.getKey(), propertyEntry.getValue())); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java index 5b0585f86..0ff330d4b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java @@ -43,7 +43,7 @@ public interface CustomBlock { Builder appearances(Map appearances); - Builder behavior(Map behavior); + Builder behavior(List> behavior); Builder lootTable(LootTable lootTable); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java index 1e24acdc0..d6e65cf34 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.block; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; +import java.util.List; import java.util.Map; public class EmptyBlock extends AbstractCustomBlock { @@ -10,7 +11,7 @@ public class EmptyBlock extends AbstractCustomBlock { public static ImmutableBlockState STATE; public EmptyBlock(Key id, Holder.Reference holder) { - super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), null, null); + super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), List.of(), null); INSTANCE = this; STATE = defaultState(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java index 29ee6e7a0..70bfa59b9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java @@ -6,13 +6,14 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.CompoundTag; import java.util.HashMap; +import java.util.List; import java.util.Map; public class InactiveCustomBlock extends AbstractCustomBlock { private final Map cachedData = new HashMap<>(); public InactiveCustomBlock(Key id, Holder.Reference holder) { - super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), null, null); + super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), List.of(), null); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java index 21bb9d76d..58f844744 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java @@ -51,10 +51,14 @@ public class UnsafeCompositeBlockBehavior extends AbstractBlockBehavior { @Override public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object previous = args[0]; for (AbstractBlockBehavior behavior : this.behaviors) { - args[0] = behavior.updateShape(thisBlock, args, superMethod); + Object processed = behavior.updateShape(thisBlock, args, superMethod); + if (processed != previous) { + return processed; + } } - return args[0]; + return previous; } @Override @@ -73,18 +77,26 @@ public class UnsafeCompositeBlockBehavior extends AbstractBlockBehavior { @Override public Object rotate(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object previous = args[0]; for (AbstractBlockBehavior behavior : this.behaviors) { - args[0] = behavior.rotate(thisBlock, args, superMethod); + Object processed = behavior.rotate(thisBlock, args, superMethod); + if (processed != previous) { + return processed; + } } - return args[0]; + return previous; } @Override public Object mirror(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object previous = args[0]; for (AbstractBlockBehavior behavior : this.behaviors) { - args[0] = behavior.mirror(thisBlock, args, superMethod); + Object processed = behavior.mirror(thisBlock, args, superMethod); + if (processed != previous) { + return processed; + } } - return args[0]; + return previous; } @Override 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 d0ded6b10..22ed3e10b 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 @@ -346,6 +346,10 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/netherite_anvil_top.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/solid_gunpowder_block.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/gunpowder_block.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_side.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on_side.png"); // items plugin.saveResource("resources/default/configuration/items.yml"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_rod.png"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java index 3e9c4ba60..d3c9b178b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java @@ -23,6 +23,17 @@ public class MiscUtils { throw new IllegalArgumentException("Expected Map, got: " + (obj == null ? null : obj.getClass().getSimpleName())); } + @SuppressWarnings("unchecked") + public static List> getAsMapList(Object obj) { + if (obj == null) return List.of(); + if (obj instanceof List list) { + return (List>) list; + } else if (obj instanceof Map) { + return List.of((Map) obj); + } + throw new IllegalArgumentException("Expected MapList/Map, got: " + obj.getClass().getSimpleName()); + } + public static List getAsStringList(Object o) { List list = new ArrayList<>(); if (o instanceof List) { diff --git a/gradle.properties b/gradle.properties index ef3d4750e..b9f802a04 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.54.9 +project_version=0.0.54.10 config_version=34 lang_version=14 project_group=net.momirealms diff --git a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java index 5c4987cab..a39948fb9 100644 --- a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java +++ b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java @@ -22,7 +22,7 @@ public abstract class BlockBehavior { } public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - return superMethod.call(); + return args[0]; } public void neighborChanged(Object thisBlock, Object[] args, Callable superMethod) throws Exception { From 3128fe355122e2856fb5727fcccc4b68f35cf14d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 25 May 2025 21:16:45 +0800 Subject: [PATCH 55/89] Update default configs --- .../default/configuration/blocks.yml | 11 ++-- .../default/configuration/palm_tree.yml | 19 ++++--- .../default/configuration/plants.yml | 55 ++++++++++++------- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml index 613b1a6a9..ff87524ab 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml @@ -134,9 +134,10 @@ items#misc: behavior: type: block_item block: - behavior: - type: concrete_powder_block - solid-block: default:solid_gunpowder_block + behaviors: + - type: concrete_powder_block + solid-block: default:solid_gunpowder_block + - type: falling_block loot: template: "default:loot_table/basic" arguments: @@ -231,8 +232,8 @@ items#misc: instrument: BASEDRUM map-color: 45 item: default:copper_coil - behavior: - type: lamp_block + behaviors: + - type: lamp_block states: properties: lit: diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/palm_tree.yml b/bukkit/loader/src/main/resources/resources/default/configuration/palm_tree.yml index 610986d96..c9644b233 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/palm_tree.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/palm_tree.yml @@ -230,15 +230,16 @@ items: overrides: item: default:palm_sapling behavior: - type: sapling_block - # This requires you to register a custom tree configuration with data pack - # To prevent errors, we use tree feature from vanilla here - feature: minecraft:fancy_oak - bone-meal-success-chance: 0.45 - bottom-block-tags: - - minecraft:dirt - - minecraft:farmland - - minecraft:sand + - type: bush_block + bottom-block-tags: + - minecraft:dirt + - minecraft:farmland + - minecraft:sand + - type: sapling_block + # This requires you to register a custom tree configuration with data pack + # To prevent errors, we use tree feature from vanilla here + feature: minecraft:fancy_oak + bone-meal-success-chance: 0.45 loot: template: "default:loot_table/basic" arguments: diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 953afbe86..7c7f05927 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -102,6 +102,8 @@ blocks: behavior: type: on_liquid_block liquid-type: water + positions: + - 0,-1,0 loot: template: "default:loot_table/basic" arguments: @@ -121,19 +123,29 @@ blocks: push-reaction: DESTROY map-color: 15 is-randomly-ticking: true - behavior: - type: sugar_cane_block - max-height: 4 - required-adjacent-liquids: lava - grow-speed: 0.333 - bottom-blocks: - - minecraft:netherrack - - minecraft:soul_sand - - minecraft:soul_soil - - minecraft:magma_block - - minecraft:warped_nylium - - minecraft:crimson_nylium - - minecraft:basalt + behaviors: + - type: vertical_crop_block + max-height: 4 + grow-speed: 0.333 + direction: up + - type: bush_block + stackable: true + bottom-blocks: + - minecraft:netherrack + - minecraft:soul_sand + - minecraft:soul_soil + - minecraft:magma_block + - minecraft:warped_nylium + - minecraft:crimson_nylium + - minecraft:basalt + - type: near_liquid_block + liquid-type: lava + stackable: true + positions: + - -1,-1,0 + - 1,-1,0 + - 0,-1,-1 + - 0,-1,1 loot: template: "default:loot_table/basic" arguments: @@ -189,14 +201,15 @@ blocks: push-reaction: DESTROY map-color: 24 is-randomly-ticking: true - behavior: - type: crop_block - grow-speed: 0.25 - light-requirement: 9 - is-bone-meal-target: true - bone-meal-age-bonus: 1 - bottom-blocks: - - minecraft:end_stone + behaviors: + - type: bush_block + bottom-blocks: + - minecraft:end_stone + - type: crop_block + grow-speed: 0.25 + light-requirement: 9 + is-bone-meal-target: true + bone-meal-age-bonus: 1 loot: template: default:loot_table/seed_crop arguments: From 6326ca5808c55084903e258ac5c807059b359e93 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 25 May 2025 21:47:12 +0800 Subject: [PATCH 56/89] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=94=98=E8=94=97?= =?UTF-8?q?=E7=9A=84=E6=8E=89=E8=90=BD=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/plants.yml | 2 + .../AbstractCanSurviveBlockBehavior.java | 33 ++++++++++++++- .../block/behavior/BushBlockBehavior.java | 8 ++-- .../block/behavior/HangingBlockBehavior.java | 8 ++-- .../behavior/NearLiquidBlockBehavior.java | 10 +++-- .../block/behavior/OnLiquidBlockBehavior.java | 8 ++-- .../behavior/VerticalCropBlockBehavior.java | 40 ------------------- 7 files changed, 55 insertions(+), 54 deletions(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 7c7f05927..09e8cce5f 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -130,6 +130,7 @@ blocks: direction: up - type: bush_block stackable: true + delay: 1 bottom-blocks: - minecraft:netherrack - minecraft:soul_sand @@ -140,6 +141,7 @@ blocks: - minecraft:basalt - type: near_liquid_block liquid-type: lava + delay: 1 stackable: true positions: - -1,-1,0 diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java index 16e915a1b..627a1d15b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java @@ -20,9 +20,36 @@ import net.momirealms.craftengine.core.world.WorldPosition; import java.util.concurrent.Callable; public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavior { + protected final int delay; - protected AbstractCanSurviveBlockBehavior(CustomBlock customBlock) { + protected AbstractCanSurviveBlockBehavior(CustomBlock customBlock, int delay) { super(customBlock); + this.delay = delay; + } + + @Override + public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + if (this.delay == 0) return; + Object blockState = args[0]; + Object level = args[1]; + Object blockPos = args[2]; + if (!canSurvive(thisBlock, args, () -> true)) { + int stateId = BlockStateUtils.blockStateToId(blockState); + ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(stateId); + if (currentState != null && !currentState.isEmpty() && currentState.owner().value() == this.customBlock) { + // break the crop + FastNMS.INSTANCE.method$Level$removeBlock(level, blockPos, false); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); + WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos))); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position); + for (Item item : currentState.getDrops(builder, world, null)) { + world.dropItemNaturally(position, item); + } + world.playBlockSound(position, currentState.sounds().breakSound()); + FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId); + } + } } @Override @@ -57,6 +84,10 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio if (previousState == null || previousState.isEmpty()) { return state; } + if (this.delay != 0) { + Reflections.method$LevelAccessor$scheduleTick.invoke(level, blockPos, thisBlock, this.delay); + return state; + } if (!canSurvive(thisBlock, new Object[] {state, level, blockPos}, () -> true)) { BlockPos pos = LocationUtils.fromBlockPos(blockPos); net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 11cf0c44b..819173ed1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.Tuple; import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.Bukkit; @@ -27,8 +28,8 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { protected final boolean any; protected final boolean stackable; - public BushBlockBehavior(CustomBlock block, boolean stackable, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { - super(block); + public BushBlockBehavior(CustomBlock block, int delay, boolean stackable, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + super(block, delay); this.stackable = stackable; this.tagsCanSurviveOn = tagsCanSurviveOn; this.blocksCansSurviveOn = blocksCansSurviveOn; @@ -42,7 +43,8 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { Tuple, Set, Set> tuple = readTagsAndState(arguments, false); boolean stackable = (boolean) arguments.getOrDefault("stackable", false); - return new BushBlockBehavior(block, stackable, tuple.left(), tuple.mid(), tuple.right()); + int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); + return new BushBlockBehavior(block, delay, stackable, tuple.left(), tuple.mid(), tuple.right()); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java index a11b68890..3e061a22f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.Tuple; import net.momirealms.craftengine.shared.block.BlockBehavior; @@ -13,8 +14,8 @@ import java.util.Set; public class HangingBlockBehavior extends BushBlockBehavior { public static final Factory FACTORY = new Factory(); - public HangingBlockBehavior(CustomBlock block, boolean stackable, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { - super(block, stackable, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + public HangingBlockBehavior(CustomBlock block, int delay, boolean stackable, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + super(block, delay, stackable, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); } @Override @@ -33,7 +34,8 @@ public class HangingBlockBehavior extends BushBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { Tuple, Set, Set> tuple = readTagsAndState(arguments, true); boolean stackable = (boolean) arguments.getOrDefault("stackable", false); - return new HangingBlockBehavior(block, stackable, tuple.left(), tuple.mid(), tuple.right()); + int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); + return new HangingBlockBehavior(block, delay, stackable, tuple.left(), tuple.mid(), tuple.right()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java index fd40a6b95..e9e740470 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.shared.block.BlockBehavior; @@ -24,8 +25,8 @@ public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior { private final boolean stackable; private final BlockPos[] positions; - public NearLiquidBlockBehavior(CustomBlock block, BlockPos[] positions, boolean stackable, boolean onWater, boolean onLava) { - super(block); + public NearLiquidBlockBehavior(CustomBlock block, int delay, BlockPos[] positions, boolean stackable, boolean onWater, boolean onLava) { + super(block, delay); this.onWater = onWater; this.onLava = onLava; this.stackable = stackable; @@ -45,16 +46,17 @@ public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { List liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water"))); boolean stackable = (boolean) arguments.getOrDefault("stackable", false); + int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); List positionsToCheck = MiscUtils.getAsStringList(arguments.getOrDefault("positions", List.of())); if (positionsToCheck.isEmpty()) { - return new NearLiquidBlockBehavior(block, new BlockPos[]{new BlockPos(0,-1,0)}, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava")); + return new NearLiquidBlockBehavior(block, delay, new BlockPos[]{new BlockPos(0,-1,0)}, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava")); } else { BlockPos[] pos = new BlockPos[positionsToCheck.size()]; for (int i = 0; i < pos.length; i++) { String[] split = positionsToCheck.get(i).split(","); pos[i] = new BlockPos(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2])); } - return new NearLiquidBlockBehavior(block, pos, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava")); + return new NearLiquidBlockBehavior(block, delay, pos, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava")); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java index cb73eeaab..541b1d40e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.shared.block.BlockBehavior; import java.util.List; @@ -20,8 +21,8 @@ public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior { private final boolean onLava; private final boolean stackable; - public OnLiquidBlockBehavior(CustomBlock block, boolean stackable, boolean onWater, boolean onLava) { - super(block); + public OnLiquidBlockBehavior(CustomBlock block, int delay, boolean stackable, boolean onWater, boolean onLava) { + super(block, delay); this.onWater = onWater; this.onLava = onLava; this.stackable = stackable; @@ -40,7 +41,8 @@ public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { List liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water"))); boolean stackable = (boolean) arguments.getOrDefault("stackable", false); - return new OnLiquidBlockBehavior(block, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava")); + int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); + return new OnLiquidBlockBehavior(block, delay, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava")); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java index 039010453..cc180490c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java @@ -43,46 +43,6 @@ public class VerticalCropBlockBehavior extends BukkitBlockBehavior { this.direction = direction; } - @Override - public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - Object blockState = args[0]; - Object level = args[1]; - Object blockPos = args[2]; - if (!canSurvive(thisBlock, args, () -> true)) { - int stateId = BlockStateUtils.blockStateToId(blockState); - ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(stateId); - if (currentState != null && !currentState.isEmpty()) { - // break the crop - FastNMS.INSTANCE.method$Level$removeBlock(level, blockPos, false); - net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); - WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos))); - ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(DirectContextParameters.POSITION, position); - for (Item item : currentState.getDrops(builder, world, null)) { - world.dropItemNaturally(position, item); - } - world.playBlockSound(position, currentState.sounds().breakSound()); - FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId); - } - } - } - - @Override - public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - Object world; - Object blockPos; - if (VersionHelper.isOrAbove1_21_2()) { - world = args[1]; - blockPos = args[3]; - } else { - world = args[3]; - blockPos = args[4]; - } - Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 1); - // return state, do not call super. - return args[0]; - } - @Override public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { Object blockState = args[0]; From a679027c6af3436b84923335e15628d5c889db5d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 25 May 2025 22:57:50 +0800 Subject: [PATCH 57/89] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A2=B0=E6=92=9E?= =?UTF-8?q?=E4=BD=93=E7=A7=AF=E4=B8=8D=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/blocks.yml | 11 ++++++++++ .../bukkit/block/BukkitBlockShape.java | 11 +++++++--- .../behavior/NearLiquidBlockBehavior.java | 2 +- .../block/behavior/OnLiquidBlockBehavior.java | 2 +- .../plugin/injector/BukkitInjector.java | 18 +++++++++++++++ .../plugin/network/PacketConsumers.java | 2 +- .../plugin/user/BukkitServerPlayer.java | 2 +- .../bukkit/util/BlockStateUtils.java | 6 +---- .../craftengine/bukkit/util/Reflections.java | 22 ++++++++++++++----- gradle.properties | 2 +- .../mod/block/StoneBlockShape.java | 5 +++++ .../mod/block/StoneBlockShape.java | 5 +++++ .../mod/block/StoneBlockShape.java | 5 +++++ .../craftengine/shared/block/BlockShape.java | 2 ++ 14 files changed, 77 insertions(+), 18 deletions(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml index ff87524ab..da5e39a12 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml @@ -314,4 +314,15 @@ recipes#misc: A: "minecraft:gunpowder" result: id: default:gunpowder_block + count: 1 + default:copper_coil: + type: shaped + pattern: + - "AAA" + - "A A" + - "AAA" + ingredients: + A: "minecraft:copper_ingot" + result: + id: default:copper_coil count: 1 \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockShape.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockShape.java index a349d33a9..fb9bcfb8a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockShape.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockShape.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.bukkit.block; -import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.shared.block.BlockShape; public class BukkitBlockShape implements BlockShape { @@ -11,7 +11,12 @@ public class BukkitBlockShape implements BlockShape { } @Override - public Object getShape(Object thisObj, Object[] args) throws Exception { - return Reflections.method$BlockBehaviour$getShape.invoke(Reflections.field$StateHolder$owner.get(this.rawBlockState), this.rawBlockState, args[1], args[2], args[3]); + public Object getShape(Object thisObj, Object[] args) { + return FastNMS.INSTANCE.method$BlockState$getShape(this.rawBlockState, args[1], args[2], args[3]); + } + + @Override + public Object getCollisionShape(Object thisObj, Object[] args) { + return FastNMS.INSTANCE.method$BlockState$getCollisionShape(this.rawBlockState, args[1], args[2], args[3]); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java index e9e740470..dc5554c0f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java @@ -93,7 +93,7 @@ public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior { if (Reflections.method$FluidState$getType.invoke(fluidStateAbove) != Reflections.instance$Fluids$EMPTY) { return false; } - if (this.onWater && (WATER.contains(Reflections.method$FluidState$getType.invoke(fluidState)) || Reflections.field$StateHolder$owner.get(belowState) == Reflections.instance$Blocks$ICE)) { + if (this.onWater && (WATER.contains(Reflections.method$FluidState$getType.invoke(fluidState)) || FastNMS.INSTANCE.method$BlockState$getBlock(belowState) == Reflections.instance$Blocks$ICE)) { return true; } if (this.onLava && LAVA.contains(Reflections.method$FluidState$getType.invoke(fluidState))) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java index 541b1d40e..5fb023c2b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java @@ -71,7 +71,7 @@ public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior { if (Reflections.method$FluidState$getType.invoke(fluidStateAbove) != Reflections.instance$Fluids$EMPTY) { return false; } - if (this.onWater && (Reflections.method$FluidState$getType.invoke(fluidState) == Reflections.instance$Fluids$WATER || Reflections.field$StateHolder$owner.get(belowState) == Reflections.instance$Blocks$ICE)) { + if (this.onWater && (Reflections.method$FluidState$getType.invoke(fluidState) == Reflections.instance$Fluids$WATER || FastNMS.INSTANCE.method$BlockState$getBlock(belowState) == Reflections.instance$Blocks$ICE)) { return true; } if (this.onLava && Reflections.method$FluidState$getType.invoke(fluidState) == Reflections.instance$Fluids$LAVA) { 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 a90781574..4213341cb 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 @@ -248,6 +248,9 @@ public class BukkitInjector { // getShape .method(ElementMatchers.is(Reflections.method$BlockBehaviour$getShape)) .intercept(MethodDelegation.to(GetShapeInterceptor.INSTANCE)) + // getCollisionShape + .method(ElementMatchers.is(Reflections.method$BlockBehaviour$getCollisionShape)) + .intercept(MethodDelegation.to(GetCollisionShapeInterceptor.INSTANCE)) // mirror .method(ElementMatchers.is(Reflections.method$BlockBehaviour$mirror)) .intercept(MethodDelegation.to(MirrorInterceptor.INSTANCE)) @@ -923,6 +926,21 @@ public class BukkitInjector { } } + public static class GetCollisionShapeInterceptor { + public static final GetCollisionShapeInterceptor INSTANCE = new GetCollisionShapeInterceptor(); + + @RuntimeType + public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) throws Exception { + ObjectHolder holder = ((ShapeHolder) thisObj).getShapeHolder(); + try { + return holder.value().getCollisionShape(thisObj, args); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run getCollisionShape", e); + return superMethod.call(); + } + } + } + public static class MirrorInterceptor { public static final MirrorInterceptor INSTANCE = new MirrorInterceptor(); 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 66f26b85a..230f8d88f 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 @@ -1209,7 +1209,7 @@ public class PacketConsumers { // not a custom block if (BlockStateUtils.isVanillaBlock(stateId)) { if (Config.enableSoundSystem()) { - Object blockOwner = Reflections.field$StateHolder$owner.get(blockState); + Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState); if (BukkitBlockManager.instance().isBlockSoundRemoved(blockOwner)) { player.startMiningBlock(pos, blockState, null); return; 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 ad1375138..c84f97b9f 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 @@ -531,7 +531,7 @@ public class BukkitServerPlayer extends Player { // send hit sound if the sound is removed if (currentTick - this.lastHitBlockTime > 3) { - Object blockOwner = Reflections.field$StateHolder$owner.get(this.destroyedState); + Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(this.destroyedState); Object soundType = Reflections.field$BlockBehaviour$soundType.get(blockOwner); Object soundEvent = Reflections.field$SoundType$hitSound.get(soundType); Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); 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 6e167553e..253fadb01 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 @@ -140,11 +140,7 @@ public class BlockStateUtils { } public static Object getBlockOwner(Object blockState) { - try { - return Reflections.field$StateHolder$owner.get(blockState); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } + return FastNMS.INSTANCE.method$BlockState$getBlock(blockState); } public static int physicsEventToId(BlockPhysicsEvent event) throws ReflectiveOperationException { 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 9e67f24c6..72fcbeb70 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 @@ -2523,11 +2523,11 @@ public class Reflections { ) ); - public static final Field field$StateHolder$owner = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$StateHolder, Object.class, 0 - ) - ); +// public static final Field field$StateHolder$owner = requireNonNull( +// ReflectionUtils.getDeclaredField( +// clazz$StateHolder, Object.class, 0 +// ) +// ); public static final Class clazz$CollisionContext = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( @@ -2542,6 +2542,12 @@ public class Reflections { ) ); + public static final Method method$BlockBehaviour$getCollisionShape = requireNonNull( + ReflectionUtils.getDeclaredMethod( + clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getCollisionShape", "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos, clazz$CollisionContext + ) + ); + public static final Method method$BlockBehaviour$tick = requireNonNull( ReflectionUtils.getDeclaredMethod( clazz$BlockBehaviour, void.class, new String[]{"tick", "a"}, clazz$BlockState, clazz$ServerLevel, clazz$BlockPos, clazz$RandomSource @@ -6803,4 +6809,10 @@ public class Reflections { Optional.ofNullable(ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$BlockPos, boolean.class)) .orElse(ReflectionUtils.getMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$BlockPos, boolean.class)) ); + +// public static final Method method$BlockBehaviour$getEntityInsideCollisionShape = requireNonNull( +// ReflectionUtils.getDeclaredMethod( +// clazz$BlockBehaviour, clazz$VoxelShape, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos, clazz$Entity +// ) +// ); } diff --git a/gradle.properties b/gradle.properties index b9f802a04..6179e467c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.65.27 +nms_helper_version=0.65.30 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 diff --git a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java index 6ebc977a6..348530720 100644 --- a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java +++ b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java @@ -17,4 +17,9 @@ public class StoneBlockShape implements BlockShape { public Object getShape(Object thisObj, Object[] args) { return rawBlockState.getShape((BlockGetter) args[1], (BlockPos) args[2], (CollisionContext) args[3]); } + + @Override + public Object getCollisionShape(Object thisObj, Object[] args) { + return rawBlockState.getCollisionShape((BlockGetter) args[1], (BlockPos) args[2], (CollisionContext) args[3]); + } } diff --git a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java index 6ebc977a6..348530720 100644 --- a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java +++ b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java @@ -17,4 +17,9 @@ public class StoneBlockShape implements BlockShape { public Object getShape(Object thisObj, Object[] args) { return rawBlockState.getShape((BlockGetter) args[1], (BlockPos) args[2], (CollisionContext) args[3]); } + + @Override + public Object getCollisionShape(Object thisObj, Object[] args) { + return rawBlockState.getCollisionShape((BlockGetter) args[1], (BlockPos) args[2], (CollisionContext) args[3]); + } } diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java index 6ebc977a6..348530720 100644 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java @@ -17,4 +17,9 @@ public class StoneBlockShape implements BlockShape { public Object getShape(Object thisObj, Object[] args) { return rawBlockState.getShape((BlockGetter) args[1], (BlockPos) args[2], (CollisionContext) args[3]); } + + @Override + public Object getCollisionShape(Object thisObj, Object[] args) { + return rawBlockState.getCollisionShape((BlockGetter) args[1], (BlockPos) args[2], (CollisionContext) args[3]); + } } diff --git a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockShape.java b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockShape.java index 636e09ace..b33a42a03 100644 --- a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockShape.java +++ b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockShape.java @@ -3,4 +3,6 @@ package net.momirealms.craftengine.shared.block; public interface BlockShape { Object getShape(Object thisObj, Object[] args) throws Exception; + + Object getCollisionShape(Object thisObj, Object[] args); } From 0b80a6b592007ec2728e468e32457ac49c17cb8d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 25 May 2025 23:25:58 +0800 Subject: [PATCH 58/89] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=93=9C=E7=BA=BF?= =?UTF-8?q?=E5=9C=88=E5=9C=B0=E5=9B=BE=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/resources/default/configuration/blocks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml index da5e39a12..1f59683ba 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml @@ -230,7 +230,7 @@ items#misc: is-redstone-conductor: true is-suffocating: true instrument: BASEDRUM - map-color: 45 + map-color: 15 item: default:copper_coil behaviors: - type: lamp_block From d4086101cfbfa14206d4edb627214167452ceb41 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 26 May 2025 01:44:57 +0800 Subject: [PATCH 59/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=94=AF=E6=92=91?= =?UTF-8?q?=E5=BD=A2=E7=8A=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockShape.java | 10 +++++++++- .../bukkit/block/BukkitCustomBlock.java | 17 +++++++++++----- .../plugin/injector/BukkitInjector.java | 20 ++++++++++++++++++- .../craftengine/bukkit/util/Reflections.java | 6 ++++++ .../craftengine/core/block/BlockSettings.java | 15 ++++++++++++++ gradle.properties | 4 ++-- .../mod/block/StoneBlockShape.java | 5 +++++ .../mod/block/StoneBlockShape.java | 5 +++++ .../mod/block/StoneBlockShape.java | 5 +++++ .../craftengine/shared/block/BlockShape.java | 2 ++ 10 files changed, 80 insertions(+), 9 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockShape.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockShape.java index fb9bcfb8a..c57f78a20 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockShape.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockShape.java @@ -2,12 +2,15 @@ package net.momirealms.craftengine.bukkit.block; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.shared.block.BlockShape; +import org.jetbrains.annotations.Nullable; public class BukkitBlockShape implements BlockShape { private final Object rawBlockState; + private final Object supportBlockState; - public BukkitBlockShape(Object rawBlockState) { + public BukkitBlockShape(Object rawBlockState, @Nullable Object supportBlockState) { this.rawBlockState = rawBlockState; + this.supportBlockState = supportBlockState == null ? rawBlockState : supportBlockState; } @Override @@ -19,4 +22,9 @@ public class BukkitBlockShape implements BlockShape { public Object getCollisionShape(Object thisObj, Object[] args) { return FastNMS.INSTANCE.method$BlockState$getCollisionShape(this.rawBlockState, args[1], args[2], args[3]); } + + @Override + public Object getSupportShape(Object thisObj, Object[] args) { + return FastNMS.INSTANCE.method$BlockState$getBlockSupportShape(this.supportBlockState, args[1], args[2]); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index 592862fde..7cadd52e3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -21,15 +21,13 @@ import net.momirealms.craftengine.core.util.Tristate; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.shared.ObjectHolder; import net.momirealms.craftengine.shared.block.BlockBehavior; +import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; public class BukkitCustomBlock extends AbstractCustomBlock { @@ -103,7 +101,16 @@ public class BukkitCustomBlock extends AbstractCustomBlock { Field shapeField = mcBlock.getClass().getField("shapeHolder"); @SuppressWarnings("unchecked") ObjectHolder shapeHolder = (ObjectHolder) shapeField.get(mcBlock); - shapeHolder.bindValue(new BukkitBlockShape(state.vanillaBlockState().handle())); + shapeHolder.bindValue(new BukkitBlockShape(state.vanillaBlockState().handle(), Optional.ofNullable(state.settings().supportShapeBlockState()).map(it -> { + try { + Object blockState = BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(it)); + if (!BlockStateUtils.isVanillaBlock(blockState)) return null; + return blockState; + } catch (IllegalArgumentException e) { + CraftEngine.instance().logger().warn("Illegal shape block state: " + it, e); + return null; + } + }).orElse(null))); // bind behavior Field behaviorField = mcBlock.getClass().getField("behaviorHolder"); @SuppressWarnings("unchecked") 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 4213341cb..ad535cb48 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 @@ -73,7 +73,7 @@ import java.util.function.Consumer; public class BukkitInjector { private static final ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); - private static final BukkitBlockShape STONE_SHAPE = new BukkitBlockShape(Reflections.instance$Blocks$STONE$defaultState); + private static final BukkitBlockShape STONE_SHAPE = new BukkitBlockShape(Reflections.instance$Blocks$STONE$defaultState, Reflections.instance$Blocks$STONE$defaultState); private static Class clazz$InjectedPalettedContainer; private static Class clazz$InjectedLevelChunkSection; @@ -251,6 +251,9 @@ public class BukkitInjector { // getCollisionShape .method(ElementMatchers.is(Reflections.method$BlockBehaviour$getCollisionShape)) .intercept(MethodDelegation.to(GetCollisionShapeInterceptor.INSTANCE)) + // getSupportShape + .method(ElementMatchers.is(Reflections.method$BlockBehaviour$getBlockSupportShape)) + .intercept(MethodDelegation.to(GetSupportShapeInterceptor.INSTANCE)) // mirror .method(ElementMatchers.is(Reflections.method$BlockBehaviour$mirror)) .intercept(MethodDelegation.to(MirrorInterceptor.INSTANCE)) @@ -941,6 +944,21 @@ public class BukkitInjector { } } + public static class GetSupportShapeInterceptor { + public static final GetSupportShapeInterceptor INSTANCE = new GetSupportShapeInterceptor(); + + @RuntimeType + public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) throws Exception { + ObjectHolder holder = ((ShapeHolder) thisObj).getShapeHolder(); + try { + return holder.value().getSupportShape(thisObj, args); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run getSupportShape", e); + return superMethod.call(); + } + } + } + public static class MirrorInterceptor { public static final MirrorInterceptor INSTANCE = new MirrorInterceptor(); 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 72fcbeb70..5b3f765a4 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 @@ -2548,6 +2548,12 @@ public class Reflections { ) ); + public static final Method method$BlockBehaviour$getBlockSupportShape = requireNonNull( + ReflectionUtils.getDeclaredMethod( + clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getBlockSupportShape", "b_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos + ) + ); + public static final Method method$BlockBehaviour$tick = requireNonNull( ReflectionUtils.getDeclaredMethod( clazz$BlockBehaviour, void.class, new String[]{"tick", "a"}, clazz$BlockState, clazz$ServerLevel, clazz$BlockPos, clazz$RandomSource 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 79e268a99..71ea2b52f 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 @@ -34,6 +34,7 @@ public class BlockSettings { float incorrectToolSpeed = 0.3f; Set correctTools = Set.of(); String name; + String supportShapeBlockState; private BlockSettings() {} @@ -89,6 +90,7 @@ public class BlockSettings { newSettings.blockLight = settings.blockLight; newSettings.name = settings.name; newSettings.incorrectToolSpeed = settings.incorrectToolSpeed; + newSettings.supportShapeBlockState = settings.supportShapeBlockState; return newSettings; } @@ -192,6 +194,10 @@ public class BlockSettings { return respectToolComponent; } + public String supportShapeBlockState() { + return supportShapeBlockState; + } + public BlockSettings correctTools(Set correctTools) { this.correctTools = correctTools; return this; @@ -317,6 +323,11 @@ public class BlockSettings { return this; } + public BlockSettings supportShapeBlockState(String supportShapeBlockState) { + this.supportShapeBlockState = supportShapeBlockState; + return this; + } + public interface Modifier { void apply(BlockSettings settings); @@ -431,6 +442,10 @@ public class BlockSettings { String name = value.toString(); return settings -> settings.name(name); })); + registerFactory("support-shape", (value -> { + String shape = value.toString(); + return settings -> settings.supportShapeBlockState(shape); + })); } private static void registerFactory(String id, Modifier.Factory factory) { diff --git a/gradle.properties b/gradle.properties index 6179e467c..a771bb053 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.54.10 +project_version=0.0.54.11 config_version=34 lang_version=14 project_group=net.momirealms @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.65.30 +nms_helper_version=0.65.32 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 diff --git a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java index 348530720..8766f8568 100644 --- a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java +++ b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java @@ -22,4 +22,9 @@ public class StoneBlockShape implements BlockShape { public Object getCollisionShape(Object thisObj, Object[] args) { return rawBlockState.getCollisionShape((BlockGetter) args[1], (BlockPos) args[2], (CollisionContext) args[3]); } + + @Override + public Object getSupportShape(Object thisObj, Object[] args) { + return rawBlockState.getBlockSupportShape((BlockGetter) args[1], (BlockPos) args[2]); + } } diff --git a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java index 348530720..8766f8568 100644 --- a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java +++ b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java @@ -22,4 +22,9 @@ public class StoneBlockShape implements BlockShape { public Object getCollisionShape(Object thisObj, Object[] args) { return rawBlockState.getCollisionShape((BlockGetter) args[1], (BlockPos) args[2], (CollisionContext) args[3]); } + + @Override + public Object getSupportShape(Object thisObj, Object[] args) { + return rawBlockState.getBlockSupportShape((BlockGetter) args[1], (BlockPos) args[2]); + } } diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java index 348530720..8766f8568 100644 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/StoneBlockShape.java @@ -22,4 +22,9 @@ public class StoneBlockShape implements BlockShape { public Object getCollisionShape(Object thisObj, Object[] args) { return rawBlockState.getCollisionShape((BlockGetter) args[1], (BlockPos) args[2], (CollisionContext) args[3]); } + + @Override + public Object getSupportShape(Object thisObj, Object[] args) { + return rawBlockState.getBlockSupportShape((BlockGetter) args[1], (BlockPos) args[2]); + } } diff --git a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockShape.java b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockShape.java index b33a42a03..8f11da262 100644 --- a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockShape.java +++ b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockShape.java @@ -5,4 +5,6 @@ public interface BlockShape { Object getShape(Object thisObj, Object[] args) throws Exception; Object getCollisionShape(Object thisObj, Object[] args); + + Object getSupportShape(Object thisObj, Object[] args); } From 4951f37e8fb773cd29f7cade8341b5ea49940238 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 26 May 2025 17:56:50 +0800 Subject: [PATCH 60/89] =?UTF-8?q?=E6=9B=B4=E6=96=B0mod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mod/block/CraftEngineBlock.java | 20 +++++++++++++++++++ .../mod/block/CraftEngineBlock.java | 20 +++++++++++++++++++ .../mod/block/CraftEngineBlock.java | 20 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index daeeba57c..ccba3bc24 100644 --- a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -67,6 +67,26 @@ public class CraftEngineBlock extends Block } } + @Override + public @NotNull VoxelShape getCollisionShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull CollisionContext context) { + try { + return (VoxelShape) this.shapeHolder.value().getCollisionShape(this, new Object[]{state, level, pos, context}); + } catch (Exception e) { + LOGGER.error(e); + return super.getCollisionShape(state, level, pos, context); + } + } + + @Override + public @NotNull VoxelShape getBlockSupportShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos) { + try { + return (VoxelShape) this.shapeHolder.value().getSupportShape(this, new Object[]{state, level, pos}); + } catch (Exception e) { + LOGGER.error(e); + return super.getBlockSupportShape(state, level, pos); + } + } + @Override public @NotNull BlockState rotate(@NotNull BlockState state, @NotNull Rotation rotation) { try { diff --git a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index fdde40516..50381f67b 100644 --- a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -68,6 +68,26 @@ public class CraftEngineBlock extends Block } } + @Override + public @NotNull VoxelShape getCollisionShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull CollisionContext context) { + try { + return (VoxelShape) this.shapeHolder.value().getCollisionShape(this, new Object[]{state, level, pos, context}); + } catch (Exception e) { + LOGGER.error(e); + return super.getCollisionShape(state, level, pos, context); + } + } + + @Override + public @NotNull VoxelShape getBlockSupportShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos) { + try { + return (VoxelShape) this.shapeHolder.value().getSupportShape(this, new Object[]{state, level, pos}); + } catch (Exception e) { + LOGGER.error(e); + return super.getBlockSupportShape(state, level, pos); + } + } + @Override protected @NotNull BlockState rotate(@NotNull BlockState state, @NotNull Rotation rotation) { try { diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index fedc24dd6..218248c70 100644 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -68,6 +68,26 @@ public class CraftEngineBlock extends Block } } + @Override + public @NotNull VoxelShape getCollisionShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull CollisionContext context) { + try { + return (VoxelShape) this.shapeHolder.value().getCollisionShape(this, new Object[]{state, level, pos, context}); + } catch (Exception e) { + LOGGER.error(e); + return super.getCollisionShape(state, level, pos, context); + } + } + + @Override + public @NotNull VoxelShape getBlockSupportShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos) { + try { + return (VoxelShape) this.shapeHolder.value().getSupportShape(this, new Object[]{state, level, pos}); + } catch (Exception e) { + LOGGER.error(e); + return super.getBlockSupportShape(state, level, pos); + } + } + @Override protected @NotNull BlockState rotate(@NotNull BlockState state, @NotNull Rotation rotation) { try { From f08544f82e30e9b5fdd6362dc71075309dbd996e Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 26 May 2025 22:56:55 +0800 Subject: [PATCH 61/89] =?UTF-8?q?=E7=BB=BC=E5=90=88=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 2 -- .../default/configuration/blocks.yml | 16 +++------ .../default/configuration/palm_tree.yml | 2 +- .../default/configuration/templates.yml | 3 ++ .../bukkit/block/BukkitCustomBlock.java | 10 +++++- .../block/behavior/BushBlockBehavior.java | 34 ++++++++----------- .../block/behavior/HangingBlockBehavior.java | 7 ++-- .../behavior/VerticalCropBlockBehavior.java | 7 ---- .../item/listener/DebugStickListener.java | 10 +++--- .../plugin/injector/BukkitInjector.java | 29 +++++++--------- .../bukkit/util/BlockStateUtils.java | 6 +++- .../craftengine/bukkit/util/Reflections.java | 6 ++++ .../craftengine/core/block/BlockSettings.java | 25 +++++++++++--- .../core/plugin/config/Config.java | 6 ++-- gradle.properties | 4 +-- 15 files changed, 91 insertions(+), 76 deletions(-) diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 48742ce2d..b0133160f 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -342,8 +342,6 @@ performance: light-system: # Required for custom light-emitting blocks enable: true - # Turning this option on will reduce lighting system issues to some extent, but will increase server bandwidth consumption. - force-update-light: false chunk-system: # With cache system, those frequently load/unload chunks would consume fewer resources on serialization diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml index 1f59683ba..db308dcbc 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml @@ -21,11 +21,9 @@ items#misc: - default:hardness/wool - default:burn_data/planks - default:sound/wood + - default:settings/solid_1x1x1 overrides: push-reaction: NORMAL - replaceable: false - is-redstone-conductor: true - is-suffocating: false instrument: HARP luminance: 15 map-color: 36 @@ -145,12 +143,10 @@ items#misc: settings: template: - default:sound/sand + - default:settings/solid_1x1x1 overrides: hardness: 0.5 resistance: 0.5 - replaceable: false - is-redstone-conductor: true - is-suffocating: true instrument: SNARE map-color: 45 item: default:gunpowder_block @@ -184,12 +180,10 @@ items#misc: template: - default:sound/sand - default:pickaxe_power/level_1 + - default:settings/solid_1x1x1 overrides: hardness: 1.8 resistance: 1.8 - replaceable: false - is-redstone-conductor: true - is-suffocating: true instrument: BASEDRUM map-color: 45 item: default:solid_gunpowder_block @@ -232,8 +226,8 @@ items#misc: instrument: BASEDRUM map-color: 15 item: default:copper_coil - behaviors: - - type: lamp_block + behavior: + type: lamp_block states: properties: lit: diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/palm_tree.yml b/bukkit/loader/src/main/resources/resources/default/configuration/palm_tree.yml index c9644b233..de1ec717e 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/palm_tree.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/palm_tree.yml @@ -229,7 +229,7 @@ items: template: "default:settings/sapling" overrides: item: default:palm_sapling - behavior: + behaviors: - type: bush_block bottom-block-tags: - minecraft:dirt 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 a281f7e41..ae9b65d76 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml @@ -583,10 +583,13 @@ templates#settings#break_level: templates#settings#blocks: default:settings/solid_1x1x1: is-suffocating: true + replaceable: false is-view-blocking: true + is-redstone-conductor: true can-occlude: true default:settings/transparent_1x1x1: is-suffocating: false + replaceable: false is-view-blocking: false can-occlude: false # sapling diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index 7cadd52e3..b69cc2ece 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -73,7 +73,13 @@ public class BukkitCustomBlock extends AbstractCustomBlock { BlockStateUtils.setHardness(mcBlockState, settings.hardness()); BlockStateUtils.setPushReaction(mcBlockState, settings.pushReaction()); BlockStateUtils.setReplaceable(mcBlockState, settings.replaceable()); - BlockStateUtils.setCanOcclude(mcBlockState, settings.canOcclude()); + if (settings.canOcclude() == Tristate.TRUE) { + BlockStateUtils.setCanOcclude(mcBlockState, true); + } else if (settings.canOcclude() == Tristate.FALSE) { + BlockStateUtils.setCanOcclude(mcBlockState, false); + } else { + BlockStateUtils.setCanOcclude(mcBlockState, BlockStateUtils.isOcclude(state.vanillaBlockState().handle())); + } if (settings.isRedstoneConductor() == Tristate.TRUE) { BlockStateUtils.setIsRedstoneConductor(mcBlockState, StatePredicate.alwaysTrue()); } else if (settings.isRedstoneConductor() == Tristate.FALSE) { @@ -138,6 +144,8 @@ public class BukkitCustomBlock extends AbstractCustomBlock { } // set random tick later BlockStateUtils.setIsRandomlyTicking(mcBlockState, settings.isRandomlyTicking()); + // set propagates skylight + BlockStateUtils.setPropagatesSkylightDown(mcBlockState, settings.propagatesSkylightDown()); // bind tags Object holder = BukkitCraftEngine.instance().blockManager().getMinecraftBlockHolder(state.customBlockState().registryId()); Set tags = new HashSet<>(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 819173ed1..db5beb2ba 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -23,18 +23,18 @@ import java.util.*; public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { public static final Factory FACTORY = new Factory(); protected final List tagsCanSurviveOn; - protected final Set blocksCansSurviveOn; + protected final Set blockStatesCanSurviveOn; protected final Set customBlocksCansSurviveOn; - protected final boolean any; + protected final boolean blacklistMode; protected final boolean stackable; - public BushBlockBehavior(CustomBlock block, int delay, boolean stackable, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + public BushBlockBehavior(CustomBlock block, int delay, boolean blacklist, boolean stackable, List tagsCanSurviveOn, Set blockStatesCanSurviveOn, Set customBlocksCansSurviveOn) { super(block, delay); + this.blacklistMode = blacklist; this.stackable = stackable; this.tagsCanSurviveOn = tagsCanSurviveOn; - this.blocksCansSurviveOn = blocksCansSurviveOn; + this.blockStatesCanSurviveOn = blockStatesCanSurviveOn; this.customBlocksCansSurviveOn = customBlocksCansSurviveOn; - this.any = this.tagsCanSurviveOn.isEmpty() && this.blocksCansSurviveOn.isEmpty() && this.customBlocksCansSurviveOn.isEmpty(); } public static class Factory implements BlockBehaviorFactory { @@ -44,7 +44,8 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { Tuple, Set, Set> tuple = readTagsAndState(arguments, false); boolean stackable = (boolean) arguments.getOrDefault("stackable", false); int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); - return new BushBlockBehavior(block, delay, stackable, tuple.left(), tuple.mid(), tuple.right()); + boolean blacklistMode = (boolean) arguments.getOrDefault("blacklist", false); + return new BushBlockBehavior(block, delay, blacklistMode, stackable, tuple.left(), tuple.mid(), tuple.right()); } } @@ -85,35 +86,30 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { } protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException { - if (this.any) { - return belowState != Reflections.instance$Blocks$AIR$defaultState; - } for (Object tag : this.tagsCanSurviveOn) { if ((boolean) Reflections.method$BlockStateBase$hasTag.invoke(belowState, tag)) { - return true; + return !this.blacklistMode; } } int id = BlockStateUtils.blockStateToId(belowState); if (BlockStateUtils.isVanillaBlock(id)) { - if (!this.blocksCansSurviveOn.isEmpty() && this.blocksCansSurviveOn.contains(belowState)) { - return true; + if (!this.blockStatesCanSurviveOn.isEmpty() && this.blockStatesCanSurviveOn.contains(belowState)) { + return !this.blacklistMode; } } else { ImmutableBlockState belowCustomState = BukkitBlockManager.instance().getImmutableBlockState(id); if (belowCustomState != null && !belowCustomState.isEmpty()) { - if (stackable) { - if (belowCustomState.owner().value() == super.customBlock) { - return true; - } + if (belowCustomState.owner().value() == super.customBlock) { + return this.stackable; } if (this.customBlocksCansSurviveOn.contains(belowCustomState.owner().value().id().toString())) { - return true; + return !this.blacklistMode; } if (this.customBlocksCansSurviveOn.contains(belowCustomState.toString())) { - return true; + return !this.blacklistMode; } } } - return false; + return this.blacklistMode; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java index 3e061a22f..39ff98d0b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java @@ -14,8 +14,8 @@ import java.util.Set; public class HangingBlockBehavior extends BushBlockBehavior { public static final Factory FACTORY = new Factory(); - public HangingBlockBehavior(CustomBlock block, int delay, boolean stackable, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { - super(block, delay, stackable, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + public HangingBlockBehavior(CustomBlock block, int delay, boolean blacklist, boolean stackable, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + super(block, delay, blacklist, stackable, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); } @Override @@ -35,7 +35,8 @@ public class HangingBlockBehavior extends BushBlockBehavior { Tuple, Set, Set> tuple = readTagsAndState(arguments, true); boolean stackable = (boolean) arguments.getOrDefault("stackable", false); int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); - return new HangingBlockBehavior(block, delay, stackable, tuple.left(), tuple.mid(), tuple.right()); + boolean blacklistMode = (boolean) arguments.getOrDefault("blacklist", false); + return new HangingBlockBehavior(block, delay, blacklistMode, stackable, tuple.left(), tuple.mid(), tuple.right()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java index cc180490c..3c36cce5d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/VerticalCropBlockBehavior.java @@ -5,23 +5,16 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; 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; import net.momirealms.craftengine.core.block.UpdateOption; 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.item.Item; -import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.Vec3d; -import net.momirealms.craftengine.core.world.WorldEvents; -import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.shared.block.BlockBehavior; import java.util.Map; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java index 59ef9e2dd..19a70df37 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java @@ -1,9 +1,10 @@ package net.momirealms.craftengine.bukkit.item.listener; +import com.saicone.rtag.RtagItem; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.item.LegacyItemWrapper; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; @@ -13,7 +14,6 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.MiscUtils; import org.bukkit.Material; @@ -73,8 +73,8 @@ public class DebugStickListener implements Listener { ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.empty").arguments(Component.text(blockId))), true); player.sendPacket(systemChatPacket, false); } else { - Item wrapped = BukkitItemManager.instance().wrap(itemInHand); - Object storedData = wrapped.getTag("craftengine:debug_stick_state"); + LegacyItemWrapper wrapped = new LegacyItemWrapper(new RtagItem(itemInHand), itemInHand.getAmount()); + Object storedData = wrapped.get("craftengine:debug_stick_state"); if (storedData == null) storedData = new HashMap<>(); if (storedData instanceof Map map) { Map data = MiscUtils.castToMap(map, false); @@ -96,7 +96,7 @@ public class DebugStickListener implements Listener { } else { currentProperty = getRelative(properties, currentProperty, player.isSecondaryUseActive()); data.put(blockId, currentProperty.name()); - wrapped.setTag(data, "craftengine:debug_stick_state"); + wrapped.set(data, "craftengine:debug_stick_state"); wrapped.load(); Object systemChatPacket = Reflections.constructor$ClientboundSystemChatPacket.newInstance( ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.select") 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 ad535cb48..f3bd26abd 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 @@ -29,6 +29,7 @@ import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.NoteBlockChainUpdateUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.block.BlockKeys; @@ -56,7 +57,6 @@ import net.momirealms.craftengine.core.world.chunk.InjectedHolder; import net.momirealms.craftengine.shared.ObjectHolder; import net.momirealms.craftengine.shared.block.*; import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.Nullable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -809,19 +809,18 @@ public class BukkitInjector { // 如果先前不是空气则标记 if (!previous.isEmpty()) { holder.ceChunk().setDirty(true); - } - if (Config.enableLightSystem() && Config.forceUpdateLight()) { - updateLightIfChanged(holder, previousState, newState, null, y, z, x); + if (Config.enableLightSystem()) { + updateLightIfChanged(holder, previous.vanillaBlockState().handle(), newState, y, z, x); + } } } else { ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); ImmutableBlockState previousImmutableBlockState = section.setBlockState(x, y, z, immutableBlockState); - // 如果之前的自定义块(空气)和当前自定义块不同 - if (previousImmutableBlockState != immutableBlockState) { - holder.ceChunk().setDirty(true); - if (Config.enableLightSystem() && !immutableBlockState.isEmpty()) { - updateLightIfChanged(holder, previousState, newState, immutableBlockState.vanillaBlockState().handle(), y, z, x); - } + if (previousImmutableBlockState == immutableBlockState) return; + holder.ceChunk().setDirty(true); + // 如果新方块的光照属性和客户端认为的不同 + if (Config.enableLightSystem() && !immutableBlockState.isEmpty()) { + updateLightIfChanged(holder, immutableBlockState.vanillaBlockState().handle(), newState, y, z, x); } } } catch (Exception e) { @@ -829,13 +828,11 @@ public class BukkitInjector { } } - protected static void updateLightIfChanged(@This InjectedHolder thisObj, Object previousBlockState, Object newState, @Nullable Object clientSideNewState, int y, int z, int x) throws ReflectiveOperationException { - int previousLight = BlockStateUtils.getLightEmission(previousBlockState); - int newLight = BlockStateUtils.getLightEmission(newState); - if (previousLight != newLight || (clientSideNewState != null && (BlockStateUtils.isOcclude(newState) != BlockStateUtils.isOcclude(clientSideNewState)))) { - CEWorld world = thisObj.ceChunk().world(); + protected static void updateLightIfChanged(@This InjectedHolder thisObj, Object oldState, Object newState, int y, int z, int x) { + CEWorld world = thisObj.ceChunk().world(); + if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(oldState, newState, world.world().serverWorld(), LocationUtils.toBlockPos(x, y, z))) { SectionPos sectionPos = thisObj.cePos(); - List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, Math.max(newLight, previousLight)); + List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15); world.sectionLightUpdated(pos); } } 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 253fadb01..49ab01ffe 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 @@ -189,6 +189,10 @@ public class BlockStateUtils { Reflections.field$BlockStateBase$isRandomlyTicking.set(state, randomlyTicking); } + public static void setPropagatesSkylightDown(Object state, boolean propagatesSkylightDown) throws ReflectiveOperationException { + Reflections.field$BlockStateBase$propagatesSkylightDown.set(state, propagatesSkylightDown); + } + public static void setReplaceable(Object state, boolean replaceable) throws ReflectiveOperationException { Reflections.field$BlockStateBase$replaceable.set(state, replaceable); } @@ -205,7 +209,7 @@ public class BlockStateUtils { Reflections.field$BlockStateBase$canOcclude.set(state, canOcclude); } - public static boolean isOcclude(Object state) throws ReflectiveOperationException { + public static boolean isOcclude(Object state) { return FastNMS.INSTANCE.method$BlockStateBase$canOcclude(state); } 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 5b3f765a4..e8c3f2fa4 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 @@ -2423,6 +2423,12 @@ public class Reflections { ) ); + public static final Field field$BlockStateBase$propagatesSkylightDown = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$BlockStateBase, boolean.class, 11 + ) + ); + public static final Field field$BlockStateBase$requiresCorrectToolForDrops = requireNonNull( ReflectionUtils.getDeclaredField( clazz$BlockStateBase, boolean.class, 5 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 71ea2b52f..aefe694fb 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 @@ -12,11 +12,11 @@ public class BlockSettings { boolean burnable; int burnChance; int fireSpreadChance; - int blockLight = -1; // TODO investigate how starlight works + int blockLight = -1; boolean replaceable; float hardness = 2f; float resistance = 2f; - boolean canOcclude; + Tristate canOcclude = Tristate.UNDEFINED; boolean fluidState; boolean requireCorrectTools; boolean respectToolComponent; @@ -35,6 +35,7 @@ public class BlockSettings { Set correctTools = Set.of(); String name; String supportShapeBlockState; + boolean propagatesSkylightDown; private BlockSettings() {} @@ -91,6 +92,7 @@ public class BlockSettings { newSettings.name = settings.name; newSettings.incorrectToolSpeed = settings.incorrectToolSpeed; newSettings.supportShapeBlockState = settings.supportShapeBlockState; + newSettings.propagatesSkylightDown = settings.propagatesSkylightDown; return newSettings; } @@ -130,7 +132,7 @@ public class BlockSettings { return hardness; } - public boolean canOcclude() { + public Tristate canOcclude() { return canOcclude; } @@ -198,6 +200,10 @@ public class BlockSettings { return supportShapeBlockState; } + public boolean propagatesSkylightDown() { + return propagatesSkylightDown; + } + public BlockSettings correctTools(Set correctTools) { this.correctTools = correctTools; return this; @@ -263,7 +269,7 @@ public class BlockSettings { return this; } - public BlockSettings canOcclude(boolean canOcclude) { + public BlockSettings canOcclude(Tristate canOcclude) { this.canOcclude = canOcclude; return this; } @@ -293,6 +299,11 @@ public class BlockSettings { return this; } + public BlockSettings propagatesSkylightDown(boolean propagatesSkylightDown) { + this.propagatesSkylightDown = propagatesSkylightDown; + return this; + } + public BlockSettings blockLight(int intValue) { this.blockLight = intValue; return this; @@ -362,6 +373,10 @@ public class BlockSettings { boolean booleanValue = (boolean) value; return settings -> settings.isRandomlyTicking(booleanValue); })); + registerFactory("propagate-skylight", (value -> { + boolean booleanValue = (boolean) value; + return settings -> settings.propagatesSkylightDown(booleanValue); + })); registerFactory("push-reaction", (value -> { PushReaction reaction = PushReaction.valueOf(value.toString().toUpperCase(Locale.ENGLISH)); return settings -> settings.pushReaction(reaction); @@ -420,7 +435,7 @@ public class BlockSettings { })); registerFactory("can-occlude", (value -> { boolean booleanValue = (boolean) value; - return settings -> settings.canOcclude(booleanValue); + return settings -> settings.canOcclude(booleanValue ? Tristate.FALSE : Tristate.TRUE); })); registerFactory("correct-tools", (value -> { List tools = MiscUtils.getAsStringList(value); 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 d081b5e87..ba0a8dc36 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 @@ -404,9 +404,9 @@ public class Config { return instance.furniture$handle_invalid_furniture_on_chunk_load$mapping; } - public static boolean forceUpdateLight() { - return instance.light_system$force_update_light; - } +// public static boolean forceUpdateLight() { +// return instance.light_system$force_update_light; +// } public static boolean enableLightSystem() { return instance.light_system$enable; diff --git a/gradle.properties b/gradle.properties index a771bb053..eefd53031 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.54.11 +project_version=0.0.54.12 config_version=34 lang_version=14 project_group=net.momirealms @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.65.32 +nms_helper_version=0.65.33 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 5e35590205b5bb34715d3b44397154dc0b32db68 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Mon, 26 May 2025 23:13:10 +0800 Subject: [PATCH 62/89] =?UTF-8?q?refactor(network):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=BB=A5=E6=8F=90=E9=AB=98=E5=8F=AF=E7=BB=B4=E6=8A=A4=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 38 +++++-------------- .../network/payload/DiscardedPayload.java | 32 ++++++++++++++++ .../{ => payload}/NetWorkDataTypes.java | 2 +- .../plugin/user/BukkitServerPlayer.java | 24 ++++++++++++ .../core/plugin/network/NetWorkUser.java | 5 +++ .../core/plugin/network/NetworkManager.java | 3 ++ 6 files changed, 75 insertions(+), 29 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/DiscardedPayload.java rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/{ => payload}/NetWorkDataTypes.java (96%) 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 230f8d88f..69f0e7333 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 @@ -19,6 +19,8 @@ import net.momirealms.craftengine.bukkit.pack.BukkitPackManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.network.handler.*; +import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; +import net.momirealms.craftengine.bukkit.plugin.network.payload.NetWorkDataTypes; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.ImmutableBlockState; @@ -1969,35 +1971,18 @@ public class PacketConsumers { if (!VersionHelper.isOrAbove1_20_5()) return; Object payload = Reflections.field$ServerboundCustomPayloadPacket$payload.get(packet); if (payload.getClass().equals(Reflections.clazz$DiscardedPayload)) { - Object type = Reflections.method$CustomPacketPayload$type.invoke(payload); - Object id = Reflections.method$CustomPacketPayload$Type$id.invoke(type); - String channel = id.toString(); - if (!channel.equals(NetworkManager.MOD_CHANNEL)) return; - byte[] data; - if (Reflections.method$DiscardedPayload$data != null) { - ByteBuf buf = (ByteBuf) Reflections.method$DiscardedPayload$data.invoke(payload); - data = new byte[buf.readableBytes()]; - buf.readBytes(data); - } else { - data = (byte[]) Reflections.method$DiscardedPayload$dataByteArray.invoke(payload); - } - FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(data)); + DiscardedPayload discardedPayload = DiscardedPayload.decode(payload); + FriendlyByteBuf buf = discardedPayload.toBuffer(); NetWorkDataTypes dataType = NetWorkDataTypes.readType(buf); if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { int clientBlockRegistrySize = dataType.as(Integer.class).decode(buf); int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); if (clientBlockRegistrySize != serverBlockRegistrySize) { - Object kickPacket = Reflections.constructor$ClientboundDisconnectPacket.newInstance( - ComponentUtils.adventureToMinecraft( - Component.translatable( - "disconnect.craftengine.block_registry_mismatch", - TranslationArgument.numeric(clientBlockRegistrySize), - TranslationArgument.numeric(serverBlockRegistrySize) - ) - ) - ); - user.nettyChannel().writeAndFlush(kickPacket); - user.nettyChannel().disconnect(); + user.kick(Component.translatable( + "disconnect.craftengine.block_registry_mismatch", + TranslationArgument.numeric(clientBlockRegistrySize), + TranslationArgument.numeric(serverBlockRegistrySize) + )); return; } user.setClientModState(true); @@ -2007,10 +1992,7 @@ public class PacketConsumers { FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer()); dataType.writeType(bufPayload); dataType.as(Boolean.class).encode(bufPayload, true); - Object channelKey = KeyUtils.toResourceLocation(Key.of(NetworkManager.MOD_CHANNEL)); - Object dataPayload = Reflections.constructor$DiscardedPayload.newInstance(channelKey, bufPayload.array()); - Object responsePacket = Reflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); - user.nettyChannel().writeAndFlush(responsePacket); + user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/DiscardedPayload.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/DiscardedPayload.java new file mode 100644 index 000000000..24f65447e --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/DiscardedPayload.java @@ -0,0 +1,32 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; + +import java.lang.reflect.InvocationTargetException; + +public record DiscardedPayload(Key id, byte[] data) { + public static final boolean useNewMethod = Reflections.method$DiscardedPayload$data == null; + + public static DiscardedPayload decode(Object payload) throws InvocationTargetException, IllegalAccessException { + Object type = Reflections.method$CustomPacketPayload$type.invoke(payload); + Object id = Reflections.method$CustomPacketPayload$Type$id.invoke(type); + Key channel = Key.of(id.toString()); + byte[] data; + if (useNewMethod) { + data = (byte[]) Reflections.method$DiscardedPayload$dataByteArray.invoke(payload); + } else { + ByteBuf buf = (ByteBuf) Reflections.method$DiscardedPayload$data.invoke(payload); + data = new byte[buf.readableBytes()]; + buf.readBytes(data); + } + return new DiscardedPayload(channel, data); + } + + public FriendlyByteBuf toBuffer() { + return new FriendlyByteBuf(Unpooled.wrappedBuffer(this.data())); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java similarity index 96% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java index 50b8e57bf..281d0db70 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/NetWorkDataTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.bukkit.plugin.network; +package net.momirealms.craftengine.bukkit.plugin.network.payload; import net.momirealms.craftengine.core.util.FriendlyByteBuf; 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 c84f97b9f..9c6b7b5ef 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 @@ -287,6 +287,30 @@ public class BukkitServerPlayer extends Player { this.plugin.networkManager().sendPacket(this, packet, immediately); } + @Override + public void sendCustomPayload(Key channel, byte[] data) { + try { + Object channelKey = KeyUtils.toResourceLocation(channel); + Object dataPayload = Reflections.constructor$DiscardedPayload.newInstance(channelKey, data); + Object responsePacket = Reflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload); + this.nettyChannel().writeAndFlush(responsePacket); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to send custom payload to " + name(), e); + } + } + + @Override + public void kick(Component message) { + try { + Object reason = ComponentUtils.adventureToMinecraft(message); + Object kickPacket = Reflections.constructor$ClientboundDisconnectPacket.newInstance(reason); + this.nettyChannel().writeAndFlush(kickPacket); + this.nettyChannel().disconnect(); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to kick " + name(), e); + } + } + @Override public void sendPackets(List packet, boolean immediately) { this.plugin.networkManager().sendPackets(this, packet, immediately); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index cf9442fee..d8fe6ec0c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.plugin.network; import io.netty.channel.Channel; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.plugin.Plugin; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.ApiStatus; @@ -25,6 +26,10 @@ public interface NetWorkUser { void sendPacket(Object packet, boolean immediately); + void sendCustomPayload(Key channel, byte[] data); + + void kick(Component message); + void simulatePacket(Object packet); @ApiStatus.Internal 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 8d2b0c0ba..e24a4ba29 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 @@ -3,6 +3,7 @@ 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 net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -10,6 +11,8 @@ import java.util.List; public interface NetworkManager extends Manageable { String MOD_CHANNEL = "craftengine:payload"; String VIA_CHANNEL = "vv:proxy_details"; + Key MOD_CHANNEL_KEY = Key.of(MOD_CHANNEL); + Key VIA_CHANNEL_KEY = Key.of(VIA_CHANNEL); void setUser(Channel channel, NetWorkUser user); From cfc25df3257c7cf643b13ecf933d8badb80b05bb Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 27 May 2025 00:01:15 +0800 Subject: [PATCH 63/89] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 6 ++- .../network/payload/DiscardedPayload.java | 44 ++++++++++++------- .../plugin/network/payload/Payload.java | 10 +++++ 3 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/Payload.java 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 69f0e7333..3c62cda66 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 @@ -21,6 +21,7 @@ import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.network.handler.*; import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; import net.momirealms.craftengine.bukkit.plugin.network.payload.NetWorkDataTypes; +import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.ImmutableBlockState; @@ -1970,8 +1971,9 @@ public class PacketConsumers { try { if (!VersionHelper.isOrAbove1_20_5()) return; Object payload = Reflections.field$ServerboundCustomPayloadPacket$payload.get(packet); - if (payload.getClass().equals(Reflections.clazz$DiscardedPayload)) { - DiscardedPayload discardedPayload = DiscardedPayload.decode(payload); + if (Reflections.clazz$DiscardedPayload.isInstance(payload)) { + Payload discardedPayload = DiscardedPayload.from(payload); + if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) return; FriendlyByteBuf buf = discardedPayload.toBuffer(); NetWorkDataTypes dataType = NetWorkDataTypes.readType(buf); if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/DiscardedPayload.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/DiscardedPayload.java index 24f65447e..d0319220a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/DiscardedPayload.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/DiscardedPayload.java @@ -3,30 +3,42 @@ package net.momirealms.craftengine.bukkit.plugin.network.payload; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.Key; -import java.lang.reflect.InvocationTargetException; - -public record DiscardedPayload(Key id, byte[] data) { +public record DiscardedPayload(Key channel, Object rawPayload) implements Payload { public static final boolean useNewMethod = Reflections.method$DiscardedPayload$data == null; - public static DiscardedPayload decode(Object payload) throws InvocationTargetException, IllegalAccessException { - Object type = Reflections.method$CustomPacketPayload$type.invoke(payload); - Object id = Reflections.method$CustomPacketPayload$Type$id.invoke(type); - Key channel = Key.of(id.toString()); - byte[] data; - if (useNewMethod) { - data = (byte[]) Reflections.method$DiscardedPayload$dataByteArray.invoke(payload); - } else { - ByteBuf buf = (ByteBuf) Reflections.method$DiscardedPayload$data.invoke(payload); - data = new byte[buf.readableBytes()]; - buf.readBytes(data); + public static DiscardedPayload from(Object payload) { + try { + Object type = Reflections.method$CustomPacketPayload$type.invoke(payload); + Object id = Reflections.method$CustomPacketPayload$Type$id.invoke(type); + Key channel = Key.of(id.toString()); + return new DiscardedPayload(channel, payload); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to create DiscardedPayload", e); + return null; + } + } + + public byte[] getData() { + try { + if (useNewMethod) { + return (byte[]) Reflections.method$DiscardedPayload$dataByteArray.invoke(this.rawPayload()); + } else { + ByteBuf buf = (ByteBuf) Reflections.method$DiscardedPayload$data.invoke(this.rawPayload()); + byte[] data = new byte[buf.readableBytes()]; + buf.readBytes(data); + return data; + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to get data from DiscardedPayload", e); + return new byte[0]; } - return new DiscardedPayload(channel, data); } public FriendlyByteBuf toBuffer() { - return new FriendlyByteBuf(Unpooled.wrappedBuffer(this.data())); + return new FriendlyByteBuf(Unpooled.wrappedBuffer(this.getData())); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/Payload.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/Payload.java new file mode 100644 index 000000000..2c82d9463 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/Payload.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; + +public interface Payload { + FriendlyByteBuf toBuffer(); + + Key channel(); +} From d9960da796137b2d8f96d09c7bcdce37ac0e31d8 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 27 May 2025 04:18:49 +0800 Subject: [PATCH 64/89] =?UTF-8?q?=E6=8B=A6=E6=88=AA=E5=AE=B9=E5=99=A8?= =?UTF-8?q?=E7=89=A9=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 +-- .../bukkit/item/BukkitItemManager.java | 78 +++++++------------ .../plugin/network/BukkitNetworkManager.java | 1 + .../plugin/network/PacketConsumers.java | 46 +++++++++++ .../bukkit/plugin/network/PacketIds.java | 2 + .../plugin/network/id/PacketIds1_20.java | 5 ++ .../plugin/network/id/PacketIds1_20_5.java | 5 ++ .../craftengine/bukkit/util/Reflections.java | 11 +-- .../core/util/FriendlyByteBuf.java | 12 +++ gradle.properties | 2 +- 10 files changed, 110 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 29b3c4950..6e4078716 100644 --- a/README.md +++ b/README.md @@ -129,11 +129,10 @@ The code you contribute will be open-sourced under the GPLv3 license. If you pre 3. Once done, submit a **pull request** for review. We appreciate your contributions! ## Differences Between Versions -| Version | Official Support | Max Players | Online Mode Required | Commercial Use | -|-------------------|------------------|-------------|----------------------|----------------| -| Community Edition | ❌ No | 20 | ✔️ Yes | ✔️ Allowed | -| GitHub Edition | ❌ No | Unlimited | ❌ No | ✔️ Allowed | -| Premium Edition | ✔️ Yes | Unlimited | ❌ No | ✔️ Allowed | +| Version | Official Support | Max Players | Dev Builds | +|-------------------|------------------|-------------|------------| +| Community Edition | ❌ No | 20 | ❌ No | +| Premium Edition | ✔️ Yes | Unlimited | ✔️ Yes | ### 💖 Support the Developer Help sustain CraftEngine's development by going Premium! 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 f72ecec0e..724ff7f4c 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 @@ -60,56 +60,6 @@ public class BukkitItemManager extends AbstractItemManager { this.debugStickListener = new DebugStickListener(plugin); this.armorEventListener = new ArmorEventListener(); this.registerAllVanillaItems(); - if (plugin.hasMod()) { - Class clazz$CustomStreamCodec = ReflectionUtils.getClazz("net.momirealms.craftengine.mod.item.CustomStreamCodec"); - if (clazz$CustomStreamCodec != null) { - Field s2cProcessor = ReflectionUtils.getDeclaredField(clazz$CustomStreamCodec, Function.class, 0); - Field c2sProcessor = ReflectionUtils.getDeclaredField(clazz$CustomStreamCodec, Function.class, 1); - Function s2c = (raw) -> { - ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(raw); - Item wrapped = this.wrap(itemStack.clone()); - Optional> customItem = wrapped.getCustomItem(); - if (customItem.isEmpty()) { - return raw; - } - CustomItem custom = customItem.get(); - if (!custom.hasClientBoundDataModifier()) { - return raw; - } - for (NetworkItemDataProcessor processor : custom.networkItemDataProcessors()) { - processor.toClient(wrapped, ItemBuildContext.EMPTY); - } - wrapped.load(); - return wrapped.getLiteralObject(); - }; - - Function c2s = (raw) -> { - ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(raw); - Item wrapped = this.wrap(itemStack); - Optional> customItem = wrapped.getCustomItem(); - if (customItem.isEmpty()) { - return raw; - } - CustomItem custom = customItem.get(); - if (!custom.hasClientBoundDataModifier()) { - return raw; - } - for (NetworkItemDataProcessor processor : custom.networkItemDataProcessors()) { - processor.toServer(wrapped, ItemBuildContext.EMPTY); - } - wrapped.load(); - return wrapped.getLiteralObject(); - }; - try { - assert s2cProcessor != null; - s2cProcessor.set(null, s2c); - assert c2sProcessor != null; - c2sProcessor.set(null, c2s); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to load custom stream codec", e); - } - } - } } @Override @@ -123,6 +73,34 @@ public class BukkitItemManager extends AbstractItemManager { return instance; } + @SuppressWarnings("DuplicatedCode") + public Optional s2c(ItemStack itemStack, ItemBuildContext context) { + Item wrapped = this.wrap(itemStack.clone()); + if (wrapped == null) return Optional.empty(); + Optional> customItem = wrapped.getCustomItem(); + if (customItem.isEmpty()) return Optional.empty(); + CustomItem custom = customItem.get(); + if (!custom.hasClientBoundDataModifier()) return Optional.empty(); + for (NetworkItemDataProcessor processor : custom.networkItemDataProcessors()) { + processor.toClient(wrapped, context); + } + return Optional.of(wrapped.load()); + } + + @SuppressWarnings("DuplicatedCode") + public Optional c2s(ItemStack itemStack, ItemBuildContext context) { + Item wrapped = this.wrap(itemStack); + if (wrapped == null) return Optional.empty(); + Optional> customItem = wrapped.getCustomItem(); + if (customItem.isEmpty()) return Optional.empty(); + CustomItem custom = customItem.get(); + if (!custom.hasClientBoundDataModifier()) return Optional.empty(); + for (NetworkItemDataProcessor processor : custom.networkItemDataProcessors()) { + processor.toServer(wrapped, context); + } + return Optional.of(wrapped.load()); + } + @Override public Optional> getVanillaItem(Key key) { Material material = Registry.MATERIAL.get(KeyUtils.toNamespacedKey(key)); 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 df14f8079..051d18e54 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 @@ -174,6 +174,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerByteBufPacketConsumer(PacketConsumers.ADD_ENTITY_BYTEBUFFER, this.packetIds.clientboundAddEntityPacket()); registerByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket()); registerByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket()); + registerByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_CONTENT, this.packetIds.clientboundContainerSetContentPacket()); } public static BukkitNetworkManager instance() { 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 230f8d88f..0767a1f3c 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 @@ -13,6 +13,7 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.pack.BukkitPackManager; @@ -27,6 +28,7 @@ import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; @@ -2147,6 +2149,50 @@ public class PacketConsumers { } }; + public static final BiConsumer CONTAINER_SET_CONTENT = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readContainerId(); + int stateId = buf.readVarInt(); + int listSize = buf.readVarInt(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + List items = new ArrayList<>(listSize); + boolean changed = false; + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for (int i = 0; i < listSize; i++) { + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().s2c(itemStack, context); + if (optional.isPresent()) { + items.add(optional.get()); + changed = true; + } else { + items.add(itemStack); + } + } + ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + ItemStack newCarriedItem = carriedItem; + Optional optional = BukkitItemManager.instance().s2c(carriedItem, context); + if (optional.isPresent()) { + changed = true; + newCarriedItem = optional.get(); + } + if (!changed) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeVarInt(listSize); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for (ItemStack itemStack : items) { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, itemStack); + } + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newCarriedItem); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundContainerSetContentPacket", e); + } + }; + public static final TriConsumer RESOURCE_PACK_PUSH = (user, event, packet) -> { try { if (!VersionHelper.isOrAbove1_20_2()) return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java index 3ac33c779..3433c5e56 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java @@ -41,4 +41,6 @@ public interface PacketIds { int clientboundPlayerInfoUpdatePacket(); int clientboundSetScorePacket(); + + int clientboundContainerSetContentPacket(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java index a1c2c9831..ea05910aa 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java @@ -104,4 +104,9 @@ public class PacketIds1_20 implements PacketIds { public int clientboundSetScorePacket() { return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetScorePacket); } + + @Override + public int clientboundContainerSetContentPacket() { + return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundContainerSetContentPacket); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java index ea3437281..f5838edf2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java @@ -103,4 +103,9 @@ public class PacketIds1_20_5 implements PacketIds { public int clientboundSetScorePacket() { return PacketIdFinder.clientboundByName("minecraft:set_score"); } + + @Override + public int clientboundContainerSetContentPacket() { + return PacketIdFinder.clientboundByName("minecraft:container_set_content"); + } } 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 e8c3f2fa4..c7403b55a 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 @@ -6822,9 +6822,10 @@ public class Reflections { .orElse(ReflectionUtils.getMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$BlockPos, boolean.class)) ); -// public static final Method method$BlockBehaviour$getEntityInsideCollisionShape = requireNonNull( -// ReflectionUtils.getDeclaredMethod( -// clazz$BlockBehaviour, clazz$VoxelShape, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos, clazz$Entity -// ) -// ); + public static final Class clazz$ClientboundContainerSetContentPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayOutWindowItems", + "network.protocol.game.ClientboundContainerSetContentPacket" + ) + ); } 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 8f12573cb..a21cc9692 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 @@ -48,6 +48,18 @@ public class FriendlyByteBuf extends ByteBuf { return BlockPos.of(buf.readLong()); } + public int readContainerId() { + return VersionHelper.isOrAbove1_21_2() ? this.readVarInt() : this.readUnsignedByte(); + } + + public void writeContainerId(int id) { + if (VersionHelper.isOrAbove1_21_2()) { + this.writeVarInt(id); + } else { + this.writeByte(id); + } + } + public List readStringList() { int i = this.readVarInt(); List list = new ArrayList<>(i); diff --git a/gradle.properties b/gradle.properties index eefd53031..261a2d7a2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.65.33 +nms_helper_version=0.66 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From d58e68abb2a194bb1e501e0f29869929b5edc41e Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 27 May 2025 11:39:16 +0800 Subject: [PATCH 65/89] =?UTF-8?q?feat(network):=20=E7=9B=91=E5=90=AC?= =?UTF-8?q?=E6=9B=B4=E5=A4=9A=E5=8F=91=E5=8C=85=E7=89=A9=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 5 + .../plugin/network/PacketConsumers.java | 135 +++++++++++++++++- .../bukkit/plugin/network/PacketIds.java | 10 ++ .../plugin/network/id/PacketIdFinder.java | 8 ++ .../plugin/network/id/PacketIds1_20.java | 25 ++++ .../plugin/network/id/PacketIds1_20_5.java | 26 ++++ .../craftengine/bukkit/util/Reflections.java | 36 +++-- gradle.properties | 2 +- 8 files changed, 237 insertions(+), 10 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 051d18e54..9c7b386bb 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 @@ -175,6 +175,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket()); registerByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket()); registerByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_CONTENT, this.packetIds.clientboundContainerSetContentPacket()); + registerByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_SLOT, this.packetIds.clientboundContainerSetSlotPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_CURSOR_ITEM, this.packetIds.clientboundSetCursorItemPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_EQUIPMENT, this.packetIds.clientboundSetEquipmentPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY, this.packetIds.clientboundSetPlayerInventoryPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket()); } public static BukkitNetworkManager instance() { 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 e94c20751..b54d0434d 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 @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.network; +import com.google.common.collect.Lists; import com.mojang.datafixers.util.Either; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -1205,7 +1206,7 @@ public class PacketConsumers { } }; - private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) throws Exception { + private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) { Object action = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$action(packet); if (action == Reflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) { Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world); @@ -2177,6 +2178,138 @@ public class PacketConsumers { } }; + public static final BiConsumer CONTAINER_SET_SLOT = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + int containerId = buf.readContainerId(); + int stateId = buf.readVarInt(); + int slot = buf.readShort(); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + BukkitItemManager.instance().s2c(itemStack, context).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeShort(slot); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundContainerSetSlotPacket", e); + } + }; + + public static final BiConsumer SET_CURSOR_ITEM = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + BukkitItemManager.instance().s2c(itemStack, context).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundSetCursorItemPacket", e); + } + }; + + public static final BiConsumer SET_EQUIPMENT = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + boolean changed = false; + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + int entity = buf.readVarInt(); + List> slots = Lists.newArrayList(); + int _byte; + do { + _byte = buf.readByte(); + Object equipmentSlot = Reflections.instance$EquipmentSlot$values[_byte & 127]; + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().s2c(itemStack, context); + if (optional.isPresent()) { + changed = true; + itemStack = optional.get(); + } + slots.add(com.mojang.datafixers.util.Pair.of(equipmentSlot, itemStack)); + } while ((_byte & -128) != 0); + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(entity); + int i = slots.size(); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for(int j = 0; j < i; ++j) { + com.mojang.datafixers.util.Pair pair = slots.get(j); + Enum equipmentSlot = (Enum) pair.getFirst(); + boolean bl = j != i - 1; + int k = equipmentSlot.ordinal(); + buf.writeByte(bl ? k | -128 : k); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, pair.getSecond()); + } + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEquipmentPacket", e); + } + }; + + public static final BiConsumer SET_PLAYER_INVENTORY = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + int slot = buf.readVarInt(); + BukkitItemManager.instance().s2c(itemStack, context).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(slot); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundSetPlayerInventoryPacket", e); + } + }; + + public static final BiConsumer SET_CREATIVE_MODE_SLOT = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + short slotNum = buf.readShort(); + ItemStack itemStack; + if (VersionHelper.isOrAbove1_20_5()) { + itemStack = FastNMS.INSTANCE.method$ServerboundSetCreativeModeSlotPacket$readItem(friendlyBuf); + } else { + itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + } + BukkitItemManager.instance().c2s(itemStack, context).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeShort(slotNum); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + if (VersionHelper.isOrAbove1_20_5()) { + FastNMS.INSTANCE.method$ServerboundSetCreativeModeSlotPacket$writeItem(newFriendlyBuf, newItemStack); + } else { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + } + }); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); + } + }; + public static final TriConsumer RESOURCE_PACK_PUSH = (user, event, packet) -> { try { if (!VersionHelper.isOrAbove1_20_2()) return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java index 3433c5e56..6ee6e6d43 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java @@ -43,4 +43,14 @@ public interface PacketIds { int clientboundSetScorePacket(); int clientboundContainerSetContentPacket(); + + int clientboundContainerSetSlotPacket(); + + int clientboundSetCursorItemPacket(); + + int clientboundSetEquipmentPacket(); + + int clientboundSetPlayerInventoryPacket(); + + int serverboundSetCreativeModeSlotPacket(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java index fc5594bfe..cff1f93b8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java @@ -43,4 +43,12 @@ public class PacketIdFinder { public static int clientboundByClazz(Class clazz) { return gamePacketIdsByClazz.get("clientbound").getOrDefault(clazz, -1); } + + public static int serverboundByName(String packetName) { + return gamePacketIdsByName.get("serverbound").getOrDefault(packetName, -1); + } + + public static int serverboundByClazz(Class clazz) { + return gamePacketIdsByClazz.get("serverbound").getOrDefault(clazz, -1); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java index ea05910aa..04affb794 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java @@ -109,4 +109,29 @@ public class PacketIds1_20 implements PacketIds { public int clientboundContainerSetContentPacket() { return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundContainerSetContentPacket); } + + @Override + public int clientboundContainerSetSlotPacket() { + return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundContainerSetSlotPacket); + } + + @Override + public int clientboundSetCursorItemPacket() { + return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetCursorItemPacket); + } + + @Override + public int clientboundSetEquipmentPacket() { + return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetEquipmentPacket); + } + + @Override + public int clientboundSetPlayerInventoryPacket() { + return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetPlayerInventoryPacket); + } + + @Override + public int serverboundSetCreativeModeSlotPacket() { + return PacketIdFinder.serverboundByClazz(Reflections.clazz$ServerboundSetCreativeModeSlotPacket); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java index f5838edf2..0b3179372 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.plugin.network.id; import net.momirealms.craftengine.bukkit.plugin.network.PacketIds; +import net.momirealms.craftengine.bukkit.util.Reflections; public class PacketIds1_20_5 implements PacketIds { @@ -108,4 +109,29 @@ public class PacketIds1_20_5 implements PacketIds { public int clientboundContainerSetContentPacket() { return PacketIdFinder.clientboundByName("minecraft:container_set_content"); } + + @Override + public int clientboundContainerSetSlotPacket() { + return PacketIdFinder.clientboundByName("minecraft:container_set_slot"); + } + + @Override + public int clientboundSetCursorItemPacket() { + return PacketIdFinder.clientboundByName("minecraft:set_cursor_item"); + } + + @Override + public int clientboundSetEquipmentPacket() { + return PacketIdFinder.clientboundByName("minecraft:set_equipment"); + } + + @Override + public int clientboundSetPlayerInventoryPacket() { + return PacketIdFinder.clientboundByName("minecraft:set_player_inventory"); + } + + @Override + public int serverboundSetCreativeModeSlotPacket() { + return PacketIdFinder.serverboundByName("minecraft:set_creative_mode_slot"); + } } 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 c7403b55a..d5360ca33 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 @@ -3111,6 +3111,7 @@ public class Reflections { ) ); + public static final Object[] instance$EquipmentSlot$values; public static final Object instance$EquipmentSlot$MAINHAND; public static final Object instance$EquipmentSlot$OFFHAND; public static final Object instance$EquipmentSlot$FEET; @@ -3121,14 +3122,14 @@ public class Reflections { static { try { - Object[] values = (Object[]) method$EquipmentSlot$values.invoke(null); - instance$EquipmentSlot$MAINHAND = values[0]; - instance$EquipmentSlot$OFFHAND = values[1]; - instance$EquipmentSlot$FEET = values[2]; - instance$EquipmentSlot$LEGS = values[3]; - instance$EquipmentSlot$CHEST = values[4]; - instance$EquipmentSlot$HEAD = values[5]; -// instance$EquipmentSlot$BODY = values[6]; + instance$EquipmentSlot$values = (Object[]) method$EquipmentSlot$values.invoke(null); + instance$EquipmentSlot$MAINHAND = instance$EquipmentSlot$values[0]; + instance$EquipmentSlot$OFFHAND = instance$EquipmentSlot$values[1]; + instance$EquipmentSlot$FEET = instance$EquipmentSlot$values[2]; + instance$EquipmentSlot$LEGS = instance$EquipmentSlot$values[3]; + instance$EquipmentSlot$CHEST = instance$EquipmentSlot$values[4]; + instance$EquipmentSlot$HEAD = instance$EquipmentSlot$values[5]; +// instance$EquipmentSlot$BODY = instance$EquipmentSlot$values[6]; } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -6828,4 +6829,23 @@ public class Reflections { "network.protocol.game.ClientboundContainerSetContentPacket" ) ); + + public static final Class clazz$ClientboundContainerSetSlotPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayOutSetSlot", + "network.protocol.game.ClientboundContainerSetSlotPacket" + ) + ); + + // 1.21.2+ + public static final Class clazz$ClientboundSetCursorItemPacket = + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundSetCursorItemPacket") + ); + + // 1.21.2+ + public static final Class clazz$ClientboundSetPlayerInventoryPacket = + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundSetPlayerInventoryPacket") + ); } diff --git a/gradle.properties b/gradle.properties index 261a2d7a2..3660116e6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.66 +nms_helper_version=0.67 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 55db41382dd596697f9128d5a444e3d56e43f56c Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 27 May 2025 12:12:01 +0800 Subject: [PATCH 66/89] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=87=8D=E5=AE=9A=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/plugin/dependency/Dependencies.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 8102e8e61..6778e2cb8 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 @@ -385,7 +385,10 @@ public class Dependencies { "commons-imaging", "org{}apache{}commons", "commons-imaging", - List.of(Relocation.of("imaging", "org{}apache{}commons{}imaging")) + List.of( + Relocation.of("imaging", "org{}apache{}commons{}imaging"), + Relocation.of("commons.io", "org{}apache{}commons{}io") + ) ); public static final Dependency AMAZON_AWSSDK_S3 = new Dependency( From 825d7908b1f775fe5e3833607042904ab5a6d220 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Tue, 27 May 2025 12:49:32 +0800 Subject: [PATCH 67/89] =?UTF-8?q?feat(network):=20=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E6=BC=8F=E6=8E=89=E7=9A=84=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 2 + .../plugin/network/PacketConsumers.java | 54 +++++++++++++++++++ .../bukkit/plugin/network/PacketIds.java | 2 + .../plugin/network/id/PacketIds1_20.java | 5 ++ .../plugin/network/id/PacketIds1_20_5.java | 5 ++ .../craftengine/bukkit/util/Reflections.java | 7 +++ 6 files changed, 75 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 9c7b386bb..f5989d70a 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 @@ -180,6 +180,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerByteBufPacketConsumer(PacketConsumers.SET_EQUIPMENT, this.packetIds.clientboundSetEquipmentPacket()); registerByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY, this.packetIds.clientboundSetPlayerInventoryPacket()); registerByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket()); + registerByteBufPacketConsumer(PacketConsumers.CONTAINER_CLICK, this.packetIds.serverboundContainerClickPacket()); + } public static BukkitNetworkManager instance() { 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 b54d0434d..94130f7f1 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 @@ -4,6 +4,9 @@ import com.google.common.collect.Lists; import com.mojang.datafixers.util.Either; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntList; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TranslationArgument; @@ -2310,6 +2313,57 @@ public class PacketConsumers { } }; + public static final BiConsumer CONTAINER_CLICK = (user, event) -> { + try { + if (VersionHelper.isOrAbove1_21_5()) return; // 1.21.5+需要其他办法解决同步问题 + FriendlyByteBuf buf = event.getBuffer(); + boolean changed = false; + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + int containerId = buf.readContainerId(); + int stateId = buf.readVarInt(); + short slotNum = buf.readShort(); + byte buttonNum = buf.readByte(); + int clickType = buf.readVarInt(); + int i = buf.readVarInt(); + Int2ObjectMap changedSlots = new Int2ObjectOpenHashMap<>(i); + for(int j = 0; j < i; ++j) { + int k = buf.readShort(); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().c2s(itemStack, context); + if (optional.isPresent()) { + changed = true; + itemStack = optional.get(); + } + changedSlots.put(k, itemStack); + } + ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().c2s(carriedItem, context); + if (optional.isPresent()) { + changed = true; + carriedItem = optional.get(); + } + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeShort(slotNum); + buf.writeByte(buttonNum); + buf.writeVarInt(clickType); + buf.writeVarInt(changedSlots.size()); + changedSlots.forEach((k, v) -> { + buf.writeShort(k); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(buf, v); + }); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(buf, carriedItem); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundContainerClickPacket", e); + } + }; + public static final TriConsumer RESOURCE_PACK_PUSH = (user, event, packet) -> { try { if (!VersionHelper.isOrAbove1_20_2()) return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java index 6ee6e6d43..00d588a66 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java @@ -52,5 +52,7 @@ public interface PacketIds { int clientboundSetPlayerInventoryPacket(); + int serverboundContainerClickPacket(); + int serverboundSetCreativeModeSlotPacket(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java index 04affb794..f9af24136 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java @@ -130,6 +130,11 @@ public class PacketIds1_20 implements PacketIds { return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetPlayerInventoryPacket); } + @Override + public int serverboundContainerClickPacket() { + return PacketIdFinder.serverboundByClazz(Reflections.clazz$ServerboundContainerClickPacket); + } + @Override public int serverboundSetCreativeModeSlotPacket() { return PacketIdFinder.serverboundByClazz(Reflections.clazz$ServerboundSetCreativeModeSlotPacket); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java index 0b3179372..a7698e25c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java @@ -130,6 +130,11 @@ public class PacketIds1_20_5 implements PacketIds { return PacketIdFinder.clientboundByName("minecraft:set_player_inventory"); } + @Override + public int serverboundContainerClickPacket() { + return PacketIdFinder.serverboundByName("minecraft:container_click"); + } + @Override public int serverboundSetCreativeModeSlotPacket() { return PacketIdFinder.serverboundByName("minecraft:set_creative_mode_slot"); 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 d5360ca33..0d71d0e68 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 @@ -6848,4 +6848,11 @@ public class Reflections { ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundSetPlayerInventoryPacket") ); + + public static final Class clazz$ServerboundContainerClickPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayInWindowClick", + "network.protocol.game.ServerboundContainerClickPacket" + ) + ); } From e6564af5bdbdcac435a990f1026a1b9964b8f478 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 27 May 2025 17:03:52 +0800 Subject: [PATCH 68/89] =?UTF-8?q?=E5=85=88=E6=9B=B4=E6=96=B0=E4=B8=80?= =?UTF-8?q?=E4=B8=8B=E5=AD=97=E7=AC=A6=E6=9B=BF=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 1 + .../bukkit/item/BukkitItemManager.java | 29 +- .../bukkit/item/ComponentItemWrapper.java | 1 + .../bukkit/item/LegacyNetworkItemHandler.java | 69 ++++ .../bukkit/item/NetworkItemHandler.java | 13 + .../plugin/network/BukkitNetworkManager.java | 5 +- .../plugin/network/PacketConsumers.java | 339 ++++-------------- .../core/font/AbstractFontManager.java | 3 +- .../core/plugin/config/Config.java | 6 + .../core/plugin/dependency/Dependencies.java | 5 +- .../core/util/AdventureHelper.java | 13 + gradle.properties | 2 +- 12 files changed, 176 insertions(+), 310 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index b0133160f..b01304628 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -214,6 +214,7 @@ image: entity-name: false armor-stand: true # Legacy Holograms text-display: true # Modern Holograms + item: true # Defines Unicode characters used for positioning # - Must match the font defined in resource packs # - Do NOT modify unless you understand text rendering mechanics 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 724ff7f4c..b1352aa35 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 @@ -21,7 +21,6 @@ import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; import org.bukkit.Bukkit; @@ -32,11 +31,9 @@ import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Optional; import java.util.Set; -import java.util.function.Function; public class BukkitItemManager extends AbstractItemManager { static { @@ -50,6 +47,7 @@ public class BukkitItemManager extends AbstractItemManager { private final ItemEventListener itemEventListener; private final DebugStickListener debugStickListener; private final ArmorEventListener armorEventListener; + private final NetworkItemHandler networkItemHandler; public BukkitItemManager(BukkitCraftEngine plugin) { super(plugin); @@ -59,6 +57,7 @@ public class BukkitItemManager extends AbstractItemManager { this.itemEventListener = new ItemEventListener(plugin); this.debugStickListener = new DebugStickListener(plugin); this.armorEventListener = new ArmorEventListener(); + this.networkItemHandler = new LegacyNetworkItemHandler(this); this.registerAllVanillaItems(); } @@ -73,32 +72,12 @@ public class BukkitItemManager extends AbstractItemManager { return instance; } - @SuppressWarnings("DuplicatedCode") public Optional s2c(ItemStack itemStack, ItemBuildContext context) { - Item wrapped = this.wrap(itemStack.clone()); - if (wrapped == null) return Optional.empty(); - Optional> customItem = wrapped.getCustomItem(); - if (customItem.isEmpty()) return Optional.empty(); - CustomItem custom = customItem.get(); - if (!custom.hasClientBoundDataModifier()) return Optional.empty(); - for (NetworkItemDataProcessor processor : custom.networkItemDataProcessors()) { - processor.toClient(wrapped, context); - } - return Optional.of(wrapped.load()); + return this.networkItemHandler.s2c(itemStack, context); } - @SuppressWarnings("DuplicatedCode") public Optional c2s(ItemStack itemStack, ItemBuildContext context) { - Item wrapped = this.wrap(itemStack); - if (wrapped == null) return Optional.empty(); - Optional> customItem = wrapped.getCustomItem(); - if (customItem.isEmpty()) return Optional.empty(); - CustomItem custom = customItem.get(); - if (!custom.hasClientBoundDataModifier()) return Optional.empty(); - for (NetworkItemDataProcessor processor : custom.networkItemDataProcessors()) { - processor.toServer(wrapped, context); - } - return Optional.of(wrapped.load()); + return this.networkItemHandler.c2s(itemStack, context); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java index c4bdbc860..1ffb12708 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.item; import com.google.gson.JsonElement; +import com.saicone.rtag.RtagItem; import com.saicone.rtag.data.ComponentType; import com.saicone.rtag.tag.TagBase; import net.momirealms.craftengine.bukkit.nms.FastNMS; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java new file mode 100644 index 000000000..8e7a1d159 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java @@ -0,0 +1,69 @@ +package net.momirealms.craftengine.bukkit.item; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.util.AdventureHelper; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class LegacyNetworkItemHandler implements NetworkItemHandler { + private final BukkitItemManager itemManager; + + public LegacyNetworkItemHandler(BukkitItemManager itemManager) { + this.itemManager = itemManager; + } + + @Override + public Optional c2s(ItemStack itemStack, ItemBuildContext context) { + Item wrapped = this.itemManager.wrap(itemStack); + if (wrapped == null) return Optional.empty(); + + return Optional.empty(); + } + + @Override + public Optional s2c(ItemStack itemStack, ItemBuildContext context) { + Item wrapped = this.itemManager.wrap(itemStack); + if (wrapped == null) return Optional.empty(); + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isEmpty()) { + return s2cOtherItems(wrapped, context); + } else { + return Optional.empty(); + } + } + + private Optional s2cOtherItems(Item item, ItemBuildContext context) { + if (!Config.interceptItem()) return Optional.empty(); + +// Optional> optionalLore = item.lore(); +// if (optionalLore.isPresent()) { +// boolean changed = false; +// List lore = optionalLore.get(); +// List newLore = new ArrayList<>(lore.size()); +// for (String line : lore) { +// Map tokens = CraftEngine.instance().fontManager().matchTags(line); +// if (tokens.isEmpty()) { +// newLore.add(line); +// } else { +// newLore.add(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); +// changed = true; +// } +// } +// if (changed) { +// item.lore(newLore); +// } +// } +// + return Optional.empty(); + + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java new file mode 100644 index 000000000..22b2f7881 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.bukkit.item; + +import net.momirealms.craftengine.core.item.ItemBuildContext; +import org.bukkit.inventory.ItemStack; + +import java.util.Optional; + +public interface NetworkItemHandler { + + Optional s2c(ItemStack itemStack, ItemBuildContext context); + + Optional c2s(ItemStack itemStack, ItemBuildContext context); +} 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 f5989d70a..f8ae2831d 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 @@ -178,10 +178,9 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_SLOT, this.packetIds.clientboundContainerSetSlotPacket()); registerByteBufPacketConsumer(PacketConsumers.SET_CURSOR_ITEM, this.packetIds.clientboundSetCursorItemPacket()); registerByteBufPacketConsumer(PacketConsumers.SET_EQUIPMENT, this.packetIds.clientboundSetEquipmentPacket()); - registerByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY, this.packetIds.clientboundSetPlayerInventoryPacket()); + registerByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY_1_21_2, this.packetIds.clientboundSetPlayerInventoryPacket()); registerByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket()); - registerByteBufPacketConsumer(PacketConsumers.CONTAINER_CLICK, this.packetIds.serverboundContainerClickPacket()); - + registerByteBufPacketConsumer(PacketConsumers.CONTAINER_CLICK_1_20, this.packetIds.serverboundContainerClickPacket()); } public static BukkitNetworkManager instance() { 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 94130f7f1..7171b67f2 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 @@ -5,7 +5,6 @@ import com.mojang.datafixers.util.Either; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntList; import net.kyori.adventure.text.Component; @@ -339,23 +338,12 @@ public class PacketConsumers { FriendlyByteBuf buf = event.getBuffer(); String name = buf.readUtf(); byte method = buf.readByte(); - if (method != 2 && method != 0) { - return; - } + if (method != 2 && method != 0) return; Tag displayName = buf.readNbt(false); if (displayName == null) return; byte friendlyFlags = buf.readByte(); - - Either eitherVisibility; - Either eitherCollisionRule; - - if (VersionHelper.isOrAbove1_21_5()) { - eitherVisibility = Either.right(buf.readVarInt()); - eitherCollisionRule = Either.right(buf.readVarInt()); - } else { - eitherVisibility = Either.left(buf.readUtf(40)); - eitherCollisionRule = Either.left(buf.readUtf(40)); - } + Either eitherVisibility = VersionHelper.isOrAbove1_21_5() ? Either.right(buf.readVarInt()) : Either.left(buf.readUtf(40)); + Either eitherCollisionRule = VersionHelper.isOrAbove1_21_5() ? Either.right(buf.readVarInt()) : Either.left(buf.readUtf(40)); int color = buf.readVarInt(); Tag prefix = buf.readNbt(false); if (prefix == null) return; @@ -366,55 +354,19 @@ public class PacketConsumers { Map tokens2 = CraftEngine.instance().fontManager().matchTags(prefix.getAsString()); Map tokens3 = CraftEngine.instance().fontManager().matchTags(suffix.getAsString()); if (tokens1.isEmpty() && tokens2.isEmpty() && tokens3.isEmpty()) return; + List entities = method == 0 ? buf.readStringList() : null; event.setChanged(true); - - List entities; - if (method == 0) { - entities = buf.readStringList(); - } else { - entities = null; - } - buf.clear(); buf.writeVarInt(event.packetID()); buf.writeUtf(name); buf.writeByte(method); - - if (!tokens1.isEmpty()) { - Component component = AdventureHelper.tagToComponent(displayName); - for (Map.Entry token : tokens1.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeNbt(AdventureHelper.componentToTag(component), false); - } else { - buf.writeNbt(displayName, false); - } - + buf.writeNbt(tokens1.isEmpty() ? displayName : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens1)), false); buf.writeByte(friendlyFlags); eitherVisibility.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); eitherCollisionRule.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); buf.writeVarInt(color); - - if (!tokens2.isEmpty()) { - Component component = AdventureHelper.tagToComponent(prefix); - for (Map.Entry token : tokens2.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeNbt(AdventureHelper.componentToTag(component), false); - } else { - buf.writeNbt(prefix, false); - } - - if (!tokens3.isEmpty()) { - Component component = AdventureHelper.tagToComponent(suffix); - for (Map.Entry token : tokens3.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeNbt(AdventureHelper.componentToTag(component), false); - } else { - buf.writeNbt(suffix, false); - } - + buf.writeNbt(tokens2.isEmpty() ? prefix : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(prefix), tokens2)), false); + buf.writeNbt(tokens3.isEmpty() ? suffix : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(suffix), tokens3)), false); if (entities != null) { buf.writeStringList(entities); } @@ -432,8 +384,7 @@ public class PacketConsumers { return; } EnumSet> enums = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$actions(packet); - outer: - { + outer: { for (Object entry : enums) { if (entry == Reflections.instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_DISPLAY_NAME) { break outer; @@ -441,28 +392,23 @@ public class PacketConsumers { } return; } - boolean isChanged = false; List newEntries = new MarkedArrayList<>(); for (Object entry : entries) { Object mcComponent = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$Entry$displayName(entry); if (mcComponent == null) { newEntries.add(entry); - continue; + } else { + String json = ComponentUtils.minecraftToJson(mcComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) { + newEntries.add(entry); + } else { + Object newEntry = FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket$Entry(entry, ComponentUtils.adventureToMinecraft(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens))); + newEntries.add(newEntry); + isChanged = true; + } } - String json = ComponentUtils.minecraftToJson(mcComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) { - newEntries.add(entry); - continue; - } - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - Object newEntry = FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket$Entry(entry, ComponentUtils.adventureToMinecraft(component)); - newEntries.add(newEntry); - isChanged = true; } if (isChanged) { event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket(enums, newEntries)); @@ -478,9 +424,8 @@ public class PacketConsumers { FriendlyByteBuf buf = event.getBuffer(); String name = buf.readUtf(); byte method = buf.readByte(); - if (method != 2 && method != 0) { + if (method != 2 && method != 0) return; - } String displayName = buf.readUtf(); byte friendlyFlags = buf.readByte(); String nameTagVisibility = buf.readUtf(40); @@ -495,53 +440,18 @@ public class PacketConsumers { if (tokens1.isEmpty() && tokens2.isEmpty() && tokens3.isEmpty()) return; event.setChanged(true); - List entities; - if (method == 0) { - entities = buf.readStringList(); - } else { - entities = null; - } - + List entities = method == 0 ? buf.readStringList() : null; buf.clear(); buf.writeVarInt(event.packetID()); buf.writeUtf(name); buf.writeByte(method); - - if (!tokens1.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(displayName); - for (Map.Entry token : tokens1.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeUtf(AdventureHelper.componentToJson(component)); - } else { - buf.writeUtf(displayName); - } - + buf.writeUtf(tokens1.isEmpty() ? displayName : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(displayName), tokens1))); buf.writeByte(friendlyFlags); buf.writeUtf(nameTagVisibility); buf.writeUtf(collisionRule); buf.writeVarInt(color); - - if (!tokens2.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(prefix); - for (Map.Entry token : tokens2.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeUtf(AdventureHelper.componentToJson(component)); - } else { - buf.writeUtf(prefix); - } - - if (!tokens3.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(suffix); - for (Map.Entry token : tokens3.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeUtf(AdventureHelper.componentToJson(component)); - } else { - buf.writeUtf(suffix); - } - + buf.writeUtf(tokens2.isEmpty() ? prefix : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(prefix), tokens2))); + buf.writeUtf(tokens3.isEmpty() ? suffix : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(suffix), tokens3))); if (entities != null) { buf.writeStringList(entities); } @@ -560,10 +470,6 @@ public class PacketConsumers { String json = buf.readUtf(); Map tokens = CraftEngine.instance().fontManager().matchTags(json); if (tokens.isEmpty()) return; - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } float health = buf.readFloat(); int color = buf.readVarInt(); int division = buf.readVarInt(); @@ -573,7 +479,7 @@ public class PacketConsumers { buf.writeVarInt(event.packetID()); buf.writeUUID(uuid); buf.writeVarInt(actionType); - buf.writeUtf(AdventureHelper.componentToJson(component)); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens))); buf.writeFloat(health); buf.writeVarInt(color); buf.writeVarInt(division); @@ -583,15 +489,11 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(json); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); buf.writeUUID(uuid); buf.writeVarInt(actionType); - buf.writeUtf(AdventureHelper.componentToJson(component)); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens))); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundBossEventPacket", e); @@ -609,10 +511,6 @@ public class PacketConsumers { if (nbt == null) return; Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); if (tokens.isEmpty()) return; - Component component = AdventureHelper.tagToComponent(nbt); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } float health = buf.readFloat(); int color = buf.readVarInt(); int division = buf.readVarInt(); @@ -622,7 +520,7 @@ public class PacketConsumers { buf.writeVarInt(event.packetID()); buf.writeUUID(uuid); buf.writeVarInt(actionType); - buf.writeNbt(AdventureHelper.componentToTag(component), false); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens)), false); buf.writeFloat(health); buf.writeVarInt(color); buf.writeVarInt(division); @@ -633,15 +531,11 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.tagToComponent(nbt); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); buf.writeUUID(uuid); buf.writeVarInt(actionType); - buf.writeNbt(AdventureHelper.componentToTag(component), false); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens)), false); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundBossEventPacket", e); @@ -660,15 +554,11 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(displayName); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.jsonToComponent(displayName); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); buf.writeUtf(objective); buf.writeByte(mode); - buf.writeUtf(AdventureHelper.componentToJson(component)); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(displayName), tokens))); buf.writeVarInt(renderType); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetObjectivePacket", e); @@ -692,15 +582,11 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.tagToComponent(displayName); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); buf.writeUtf(objective); buf.writeByte(mode); - buf.writeNbt(AdventureHelper.componentToTag(component), false); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens)), false); buf.writeVarInt(renderType); buf.writeBoolean(true); buf.writeVarInt(0); @@ -709,15 +595,11 @@ public class PacketConsumers { if (tokens.isEmpty()) return; Tag style = buf.readNbt(false); event.setChanged(true); - Component component = AdventureHelper.tagToComponent(displayName); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); buf.writeUtf(objective); buf.writeByte(mode); - buf.writeNbt(AdventureHelper.componentToTag(component), false); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens)), false); buf.writeVarInt(renderType); buf.writeBoolean(true); buf.writeVarInt(1); @@ -733,41 +615,21 @@ public class PacketConsumers { buf.writeVarInt(event.packetID()); buf.writeUtf(objective); buf.writeByte(mode); - if (!tokens1.isEmpty()) { - Component component = AdventureHelper.tagToComponent(displayName); - for (Map.Entry token : tokens1.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeNbt(AdventureHelper.componentToTag(component), false); - } else { - buf.writeNbt(displayName, false); - } + buf.writeNbt(tokens1.isEmpty() ? displayName : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens1)), false); buf.writeVarInt(renderType); buf.writeBoolean(true); buf.writeVarInt(2); - if (!tokens2.isEmpty()) { - Component component = AdventureHelper.tagToComponent(fixed); - for (Map.Entry token : tokens2.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeNbt(AdventureHelper.componentToTag(component), false); - } else { - buf.writeNbt(fixed, false); - } + buf.writeNbt(tokens2.isEmpty() ? fixed : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(fixed), tokens2)), false); } } else { Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.tagToComponent(displayName); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); buf.writeUtf(objective); buf.writeByte(mode); - buf.writeNbt(AdventureHelper.componentToTag(component), false); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens)), false); buf.writeVarInt(renderType); buf.writeBoolean(false); } @@ -785,13 +647,9 @@ public class PacketConsumers { if (tokens.isEmpty()) return; boolean overlay = buf.readBoolean(); event.setChanged(true); - Component component = AdventureHelper.jsonToComponent(jsonOrPlainString); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(component)); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(jsonOrPlainString), tokens))); buf.writeBoolean(overlay); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSystemChatPacket", e); @@ -808,13 +666,9 @@ public class PacketConsumers { if (tokens.isEmpty()) return; boolean overlay = buf.readBoolean(); event.setChanged(true); - Component component = AdventureHelper.tagToComponent(nbt); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(component), false); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens)), false); buf.writeBoolean(overlay); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSystemChatPacket", e); @@ -829,13 +683,9 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(json); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(component)); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens))); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetSubtitleTextPacket", e); } @@ -850,13 +700,9 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.tagToComponent(nbt); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(component), false); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens)), false); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetSubtitleTextPacket", e); } @@ -870,13 +716,9 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(json); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(component)); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens))); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetTitleTextPacket", e); } @@ -891,13 +733,9 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.tagToComponent(nbt); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(component), false); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens)), false); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetTitleTextPacket", e); } @@ -911,13 +749,9 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(json); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(component)); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens))); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetActionBarTextPacket", e); } @@ -932,13 +766,9 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.tagToComponent(nbt); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(component), false); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens)), false); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetActionBarTextPacket", e); } @@ -956,26 +786,10 @@ public class PacketConsumers { event.setChanged(true); buf.clear(); buf.writeVarInt(event.packetID()); - if (!tokens1.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(json1); - for (Map.Entry token : tokens1.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeUtf(AdventureHelper.componentToJson(component)); - } else { - buf.writeUtf(json1); - } - if (!tokens2.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(json2); - for (Map.Entry token : tokens2.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeUtf(AdventureHelper.componentToJson(component)); - } else { - buf.writeUtf(json2); - } + buf.writeUtf(tokens1.isEmpty() ? json1 : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json1), tokens1))); + buf.writeUtf(tokens2.isEmpty() ? json2 : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json2), tokens2))); } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSet[(Sub)Title/ActionBar]TextPacket", e); + CraftEngine.instance().logger().warn("Failed to handle ClientboundTabListPacket", e); } }; @@ -993,26 +807,10 @@ public class PacketConsumers { event.setChanged(true); buf.clear(); buf.writeVarInt(event.packetID()); - if (!tokens1.isEmpty()) { - Component component = AdventureHelper.tagToComponent(nbt1); - for (Map.Entry token : tokens1.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeNbt(AdventureHelper.componentToTag(component), false); - } else { - buf.writeNbt(nbt1, false); - } - if (!tokens2.isEmpty()) { - Component component = AdventureHelper.tagToComponent(nbt2); - for (Map.Entry token : tokens2.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - buf.writeNbt(AdventureHelper.componentToTag(component), false); - } else { - buf.writeNbt(nbt2, false); - } + buf.writeNbt(tokens1.isEmpty() ? nbt1 : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt1), tokens1)), false); + buf.writeNbt(tokens2.isEmpty() ? nbt2 : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt2), tokens2)), false); } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSet[(Sub)Title/ActionBar]TextPacket", e); + CraftEngine.instance().logger().warn("Failed to handle ClientboundTabListPacket", e); } }; @@ -1026,15 +824,11 @@ public class PacketConsumers { Map tokens = CraftEngine.instance().fontManager().matchTags(json); if (tokens.isEmpty()) return; event.setChanged(true); - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); buf.writeVarInt(containerId); buf.writeVarInt(type); - buf.writeUtf(AdventureHelper.componentToJson(component)); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens))); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundOpenScreenPacket", e); } @@ -1050,15 +844,11 @@ public class PacketConsumers { if (nbt == null) return; Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); if (tokens.isEmpty()) return; - Component component = AdventureHelper.tagToComponent(nbt); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } buf.clear(); buf.writeVarInt(event.packetID()); buf.writeVarInt(containerId); buf.writeVarInt(type); - buf.writeNbt(AdventureHelper.componentToTag(component), false); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens)), false); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundOpenScreenPacket", e); } @@ -1979,7 +1769,8 @@ public class PacketConsumers { Object payload = Reflections.field$ServerboundCustomPayloadPacket$payload.get(packet); if (Reflections.clazz$DiscardedPayload.isInstance(payload)) { Payload discardedPayload = DiscardedPayload.from(payload); - if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) return; + if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) + return; FriendlyByteBuf buf = discardedPayload.toBuffer(); NetWorkDataTypes dataType = NetWorkDataTypes.readType(buf); if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) { @@ -2231,10 +2022,10 @@ public class PacketConsumers { Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); int entity = buf.readVarInt(); List> slots = Lists.newArrayList(); - int _byte; + int slotMask; do { - _byte = buf.readByte(); - Object equipmentSlot = Reflections.instance$EquipmentSlot$values[_byte & 127]; + slotMask = buf.readByte(); + Object equipmentSlot = Reflections.instance$EquipmentSlot$values[slotMask & 127]; ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); Optional optional = BukkitItemManager.instance().s2c(itemStack, context); if (optional.isPresent()) { @@ -2242,7 +2033,7 @@ public class PacketConsumers { itemStack = optional.get(); } slots.add(com.mojang.datafixers.util.Pair.of(equipmentSlot, itemStack)); - } while ((_byte & -128) != 0); + } while ((slotMask & -128) != 0); if (changed) { event.setChanged(true); buf.clear(); @@ -2250,7 +2041,7 @@ public class PacketConsumers { buf.writeVarInt(entity); int i = slots.size(); Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - for(int j = 0; j < i; ++j) { + for (int j = 0; j < i; ++j) { com.mojang.datafixers.util.Pair pair = slots.get(j); Enum equipmentSlot = (Enum) pair.getFirst(); boolean bl = j != i - 1; @@ -2264,7 +2055,7 @@ public class PacketConsumers { } }; - public static final BiConsumer SET_PLAYER_INVENTORY = (user, event) -> { + public static final BiConsumer SET_PLAYER_INVENTORY_1_21_2 = (user, event) -> { try { FriendlyByteBuf buf = event.getBuffer(); ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); @@ -2287,15 +2078,11 @@ public class PacketConsumers { public static final BiConsumer SET_CREATIVE_MODE_SLOT = (user, event) -> { try { FriendlyByteBuf buf = event.getBuffer(); - ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); short slotNum = buf.readShort(); - ItemStack itemStack; - if (VersionHelper.isOrAbove1_20_5()) { - itemStack = FastNMS.INSTANCE.method$ServerboundSetCreativeModeSlotPacket$readItem(friendlyBuf); - } else { - itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - } + ItemStack itemStack = VersionHelper.isOrAbove1_20_5() ? + FastNMS.INSTANCE.method$FriendlyByteBuf$readUntrustedItem(friendlyBuf) : FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); BukkitItemManager.instance().c2s(itemStack, context).ifPresent((newItemStack) -> { event.setChanged(true); buf.clear(); @@ -2303,7 +2090,7 @@ public class PacketConsumers { buf.writeShort(slotNum); Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); if (VersionHelper.isOrAbove1_20_5()) { - FastNMS.INSTANCE.method$ServerboundSetCreativeModeSlotPacket$writeItem(newFriendlyBuf, newItemStack); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeUntrustedItem(newFriendlyBuf, newItemStack); } else { FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); } @@ -2313,7 +2100,7 @@ public class PacketConsumers { } }; - public static final BiConsumer CONTAINER_CLICK = (user, event) -> { + public static final BiConsumer CONTAINER_CLICK_1_20 = (user, event) -> { try { if (VersionHelper.isOrAbove1_21_5()) return; // 1.21.5+需要其他办法解决同步问题 FriendlyByteBuf buf = event.getBuffer(); @@ -2327,7 +2114,7 @@ public class PacketConsumers { int clickType = buf.readVarInt(); int i = buf.readVarInt(); Int2ObjectMap changedSlots = new Int2ObjectOpenHashMap<>(i); - for(int j = 0; j < i; ++j) { + for (int j = 0; j < i; ++j) { int k = buf.readShort(); ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); Optional optional = BukkitItemManager.instance().c2s(itemStack, context); 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 495890b3f..8d2010eca 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 @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.font; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; @@ -516,7 +517,7 @@ public abstract class AbstractFontManager implements FontManager { .resolve(namespacedPath.value()); if (!doesImageFileExist(targetImagePath)) { - TranslationManager.instance().log("warning.config.image.file_not_found", path.toString(), id.toString(), targetImagePath.toString()); +// TranslationManager.instance().log("warning.config.image.file_not_found", path.toString(), id.toString(), targetImagePath.toString()); // DO NOT RETURN, JUST GIVE WARNINGS } else if (heightObj == null) { try (InputStream in = Files.newInputStream(targetImagePath)) { 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 ba0a8dc36..e33d35e57 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 @@ -140,6 +140,7 @@ public class Config { protected boolean image$intercept_packets$armor_stand; protected boolean image$intercept_packets$player_info; protected boolean image$intercept_packets$set_score; + protected boolean image$intercept_packets$item; protected boolean emoji$chat; protected boolean emoji$book; @@ -332,6 +333,7 @@ public class Config { image$intercept_packets$armor_stand = config.getBoolean("image.intercept-packets.armor-stand", true); image$intercept_packets$player_info = config.getBoolean("image.intercept-packets.player-info", true); image$intercept_packets$set_score = config.getBoolean("image.intercept-packets.set-score", true); + image$intercept_packets$item = config.getBoolean("image.intercept-packets.item", true); // emoji emoji$chat = config.getBoolean("emoji.chat", true); @@ -676,6 +678,10 @@ public class Config { return instance.image$intercept_packets$set_score; } + public static boolean interceptItem() { + return instance.image$intercept_packets$item; + } + public static boolean predictBreaking() { return instance.block$predict_breaking; } 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 6778e2cb8..2616f5142 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 @@ -385,10 +385,7 @@ public class Dependencies { "commons-imaging", "org{}apache{}commons", "commons-imaging", - List.of( - Relocation.of("imaging", "org{}apache{}commons{}imaging"), - Relocation.of("commons.io", "org{}apache{}commons{}io") - ) + List.of(Relocation.of("commons", "org{}apache{}commons")) ); public static final Dependency AMAZON_AWSSDK_S3 = new Dependency( diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index 0062e5bd6..c1abe066b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -15,6 +15,10 @@ import net.momirealms.sparrow.nbt.Tag; import net.momirealms.sparrow.nbt.serializer.NBTComponentSerializer; import net.momirealms.sparrow.nbt.serializer.NBTSerializerOptions; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + /** * Helper class for handling Adventure components and related functionalities. */ @@ -299,4 +303,13 @@ public class AdventureHelper { } return true; } + + public static Component replaceText(Component text, Map replacements) { + String patternString = replacements.keySet().stream() + .map(Pattern::quote) + .collect(Collectors.joining("|")); + return text.replaceText(builder -> + builder.match(Pattern.compile(patternString)) + .replacement((result, b) -> replacements.get(result.group()))); + } } diff --git a/gradle.properties b/gradle.properties index 3660116e6..de82be993 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.67 +nms_helper_version=0.66.2 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From fb40b49549e1e504dbefdfef22366c75b795e481 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 27 May 2025 21:54:15 +0800 Subject: [PATCH 69/89] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=89=A9=E5=93=81=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/build.gradle.kts | 3 +- .../bukkit/font/BukkitFontManager.java | 2 +- .../bukkit/item/ComponentItemWrapper.java | 80 ++++++++++-- .../bukkit/item/LegacyNetworkItemHandler.java | 6 - .../item/factory/BukkitItemFactory.java | 14 +- .../factory/ComponentItemFactory1_20_5.java | 123 ++++++------------ .../factory/ComponentItemFactory1_21.java | 15 +-- .../factory/ComponentItemFactory1_21_2.java | 18 +-- .../factory/ComponentItemFactory1_21_4.java | 5 +- .../factory/ComponentItemFactory1_21_5.java | 93 ++++++++----- .../item/factory/UniversalItemFactory.java | 37 ++++-- .../item/recipe/RecipeEventListener.java | 16 +-- .../plugin/network/id/PacketIds1_20_5.java | 1 - .../craftengine/bukkit/util/Reflections.java | 53 ++++++++ .../core/font/AbstractFontManager.java | 1 - .../craftengine/core/item/AbstractItem.java | 79 ++++++++--- .../core/item/AbstractItemManager.java | 2 +- .../craftengine/core/item/Item.java | 45 +++++-- .../craftengine/core/item/ItemFactory.java | 72 +++++++--- .../core/item/modifier/ComponentModifier.java | 4 +- ...eModifier.java => CustomNameModifier.java} | 10 +- .../core/item/modifier/ItemNameModifier.java | 4 +- .../core/item/modifier/LoreModifier.java | 6 +- .../recipe/CustomSmithingTransformRecipe.java | 2 +- .../gui/category/ItemBrowserManagerImpl.java | 14 +- gradle.properties | 6 +- 26 files changed, 447 insertions(+), 264 deletions(-) rename core/src/main/java/net/momirealms/craftengine/core/item/modifier/{DisplayNameModifier.java => CustomNameModifier.java} (65%) diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 75e8293ea..db41b3d52 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -5,8 +5,9 @@ plugins { repositories { maven("https://jitpack.io/") - maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.momirealms.net/releases/") + maven("https://libraries.minecraft.net/") + maven("https://repo.papermc.io/repository/maven-public/") mavenCentral() } 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 fc4745a63..3a8fc1a34 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 @@ -151,7 +151,7 @@ public class BukkitFontManager extends AbstractFontManager implements Listener { EmojiComponentProcessResult replaceProcessResult = replaceComponentEmoji(itemName, plugin.adapt(player), renameText); if (replaceProcessResult.changed()) { Item wrapped = this.plugin.itemManager().wrap(result); - wrapped.customName(AdventureHelper.componentToJson(replaceProcessResult.newText())); + wrapped.customNameJson(AdventureHelper.componentToJson(replaceProcessResult.newText())); event.setResult(wrapped.load()); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java index 1ffb12708..765d093cd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java @@ -1,26 +1,31 @@ package net.momirealms.craftengine.bukkit.item; import com.google.gson.JsonElement; -import com.saicone.rtag.RtagItem; -import com.saicone.rtag.data.ComponentType; -import com.saicone.rtag.tag.TagBase; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; -@SuppressWarnings("UnstableApiUsage") +import java.util.Optional; + public class ComponentItemWrapper implements ItemWrapper { private final ItemStack item; + private final Object handle; public ComponentItemWrapper(final ItemStack item) { this.item = FastNMS.INSTANCE.ensureCraftItemStack(item); + this.handle = FastNMS.INSTANCE.field$CraftItemStack$handle(this.item); } public ComponentItemWrapper(final ItemStack item, int count) { this.item = FastNMS.INSTANCE.ensureCraftItemStack(item); this.item.setAmount(count); + this.handle = FastNMS.INSTANCE.field$CraftItemStack$handle(this.item); } public void removeComponent(Object type) { @@ -34,31 +39,86 @@ public class ComponentItemWrapper implements ItemWrapper { public void setComponent(Object type, final Object value) { if (value instanceof JsonElement jsonElement) { setJsonComponent(type, jsonElement); - } else if (TagBase.isTag(value)) { + } else if (Reflections.clazz$Tag.isInstance(value)) { setNBTComponent(type, value); + } else if (value instanceof Tag tag) { + setSparrowNBTComponent(type, tag); } else { setJavaComponent(type, value); } } - public Object getComponent(Object type) { + public Object getComponentExact(Object type) { return FastNMS.INSTANCE.getComponent(getLiteralObject(), ensureDataComponentType(type)); } + public Optional getJavaComponent(Object type) { + return getComponentInternal(type, Reflections.instance$JAVA_OPS); + } + + public Optional getJsonComponent(Object type) { + return getComponentInternal(type, Reflections.instance$JSON_OPS); + } + + public Optional getNBTComponent(Object type) { + return getComponentInternal(type, Reflections.instance$NBT_OPS); + } + + public Optional getSparrowNBTComponent(Object type) { + return getComponentInternal(type, Reflections.instance$SPARROW_NBT_OPS); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private Optional getComponentInternal(Object type, DynamicOps ops) { + Object componentType = ensureDataComponentType(type); + Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType); + try { + Object componentData = FastNMS.INSTANCE.getComponent(getLiteralObject(), componentType); + if (componentData == null) return Optional.empty(); + DataResult result = codec.encodeStart(ops, componentData); + return (Optional) result.result(); + } catch (Throwable t) { + throw new RuntimeException("Cannot read component " + type.toString(), t); + } + } + public boolean hasComponent(Object type) { return FastNMS.INSTANCE.hasComponent(getLiteralObject(), ensureDataComponentType(type)); } + public void setComponentExact(Object type, final Object value) { + FastNMS.INSTANCE.setComponent(this.getLiteralObject(), ensureDataComponentType(type), value); + } + public void setJavaComponent(Object type, Object value) { - ComponentType.parseJava(type, value).ifPresent(it -> FastNMS.INSTANCE.setComponent(this.getLiteralObject(), ensureDataComponentType(type), it)); + setComponentInternal(type, Reflections.instance$JAVA_OPS, value); } public void setJsonComponent(Object type, JsonElement value) { - ComponentType.parseJson(type, value).ifPresent(it -> FastNMS.INSTANCE.setComponent(this.getLiteralObject(), ensureDataComponentType(type), it)); + setComponentInternal(type, Reflections.instance$JSON_OPS, value); } public void setNBTComponent(Object type, Object value) { - ComponentType.parseNbt(type, value).ifPresent(it -> FastNMS.INSTANCE.setComponent(this.getLiteralObject(), ensureDataComponentType(type), it)); + setComponentInternal(type, Reflections.instance$NBT_OPS, value); + } + + public void setSparrowNBTComponent(Object type, Tag value) { + setComponentInternal(type, Reflections.instance$SPARROW_NBT_OPS, value); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private void setComponentInternal(Object type, DynamicOps ops, Object value) { + Object componentType = ensureDataComponentType(type); + Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType); + try { + DataResult result = codec.parse(ops, value); + if (result.isError()) { + throw new IllegalArgumentException(result.toString()); + } + result.result().ifPresent(it -> FastNMS.INSTANCE.setComponent(this.getLiteralObject(), componentType, it)); + } catch (Throwable t) { + throw new RuntimeException("Cannot parse component " + type.toString(), t); + } } private Object ensureDataComponentType(Object type) { @@ -89,7 +149,7 @@ public class ComponentItemWrapper implements ItemWrapper { @Override public Object getLiteralObject() { - return FastNMS.INSTANCE.field$CraftItemStack$handle(this.item); + return this.handle; } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java index 8e7a1d159..cf5f55199 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java @@ -1,17 +1,11 @@ package net.momirealms.craftengine.bukkit.item; -import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.util.AdventureHelper; import org.bukkit.inventory.ItemStack; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import java.util.Optional; public class LegacyNetworkItemHandler implements NetworkItemHandler { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index 8606b48a6..1365980c2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.bukkit.item.factory; -import com.google.gson.JsonElement; import com.saicone.rtag.item.ItemTagStream; import net.momirealms.craftengine.bukkit.util.ItemTags; import net.momirealms.craftengine.bukkit.util.Reflections; @@ -11,7 +10,6 @@ import net.momirealms.craftengine.core.item.JukeboxPlayable; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.Nullable; import java.util.Objects; import java.util.Optional; @@ -89,16 +87,6 @@ public abstract class BukkitItemFactory> extend } } - @Override - protected JsonElement encodeJson(Object type, Object component) { - throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); - } - - @Override - public Object encodeJava(Object componentType, @Nullable Object component) { - throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); - } - @Override protected void resetComponent(W item, Object type) { throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); @@ -110,7 +98,7 @@ public abstract class BukkitItemFactory> extend } @Override - protected Object getComponent(W item, Object type) { + protected Object getExactComponent(W item, Object type) { throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index 9261ae98d..ea22561b0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -1,8 +1,6 @@ package net.momirealms.craftengine.bukkit.item.factory; import com.google.gson.JsonElement; -import com.saicone.rtag.data.ComponentType; -import com.saicone.rtag.item.ItemObject; import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper; import net.momirealms.craftengine.bukkit.item.ComponentTypes; import net.momirealms.craftengine.bukkit.nms.FastNMS; @@ -11,15 +9,14 @@ import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Trim; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -@SuppressWarnings("UnstableApiUsage") public class ComponentItemFactory1_20_5 extends BukkitItemFactory { public ComponentItemFactory1_20_5(CraftEngine plugin) { @@ -82,8 +79,23 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory customModelData(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.CUSTOM_MODEL_DATA)) return Optional.empty(); - return Optional.ofNullable( - (Integer) ComponentType.encodeJava( - ComponentTypes.CUSTOM_MODEL_DATA, - item.getComponent(ComponentTypes.CUSTOM_MODEL_DATA) - ).orElse(null)); + return item.getJavaComponent(ComponentTypes.CUSTOM_MODEL_DATA); } @Override - protected void customName(ComponentItemWrapper item, String json) { + protected void customNameJson(ComponentItemWrapper item, String json) { if (json == null) { item.resetComponent(ComponentTypes.CUSTOM_NAME); } else { @@ -135,18 +132,12 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory customName(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.CUSTOM_NAME)) return Optional.empty(); - return Optional.ofNullable( - (String) ComponentType.encodeJava( - ComponentTypes.CUSTOM_NAME, - item.getComponent(ComponentTypes.CUSTOM_NAME) - ).orElse(null) - ); + protected Optional customNameJson(ComponentItemWrapper item) { + return item.getJavaComponent(ComponentTypes.CUSTOM_NAME); } @Override - protected void itemName(ComponentItemWrapper item, String json) { + protected void itemNameJson(ComponentItemWrapper item, String json) { if (json == null) { item.resetComponent(ComponentTypes.ITEM_NAME); } else { @@ -155,14 +146,8 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory itemName(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.ITEM_NAME)) return Optional.empty(); - return Optional.ofNullable( - (String) ComponentType.encodeJava( - ComponentTypes.ITEM_NAME, - item.getComponent(ComponentTypes.ITEM_NAME) - ).orElse(null) - ); + protected Optional itemNameJson(ComponentItemWrapper item) { + return item.getJavaComponent(ComponentTypes.ITEM_NAME); } @Override @@ -175,20 +160,13 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory> lore(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.LORE)) return Optional.empty(); - return Optional.ofNullable( - (List) ComponentType.encodeJava( - ComponentTypes.LORE, - item.getComponent(ComponentTypes.LORE) - ).orElse(null) - ); + protected Optional> loreJson(ComponentItemWrapper item) { + return item.getJavaComponent(ComponentTypes.LORE); } @Override - protected void lore(ComponentItemWrapper item, List lore) { + protected void loreJson(ComponentItemWrapper item, List lore) { if (lore == null || lore.isEmpty()) { item.resetComponent(ComponentTypes.LORE); } else { @@ -212,7 +190,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory glint(ComponentItemWrapper item) { - return Optional.ofNullable((Boolean) item.getComponent(ComponentTypes.ENCHANTMENT_GLINT_OVERRIDE)); + return Optional.ofNullable((Boolean) item.getComponentExact(ComponentTypes.ENCHANTMENT_GLINT_OVERRIDE)); } @Override @@ -226,13 +204,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory damage(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.DAMAGE)) return Optional.empty(); - return Optional.ofNullable( - (Integer) ComponentType.encodeJava( - ComponentTypes.DAMAGE, - item.getComponent(ComponentTypes.DAMAGE) - ).orElse(null) - ); + return item.getJavaComponent(ComponentTypes.DAMAGE); } @Override @@ -247,10 +219,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory dyedColor(ComponentItemWrapper item) { if (!item.hasComponent(ComponentTypes.DYED_COLOR)) return Optional.empty(); - Object javaObj = ComponentType.encodeJava( - ComponentTypes.DYED_COLOR, - item.getComponent(ComponentTypes.DYED_COLOR) - ).orElse(null); + Object javaObj = getJavaComponent(item, ComponentTypes.DYED_COLOR); if (javaObj instanceof Integer integer) { return Optional.of(integer); } else if (javaObj instanceof Map map) { @@ -269,14 +238,9 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory maxDamage(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.MAX_DAMAGE)) return Optional.of((int) item.getItem().getType().getMaxDurability()); - return Optional.ofNullable( - (Integer) ComponentType.encodeJava( - ComponentTypes.MAX_DAMAGE, - item.getComponent(ComponentTypes.MAX_DAMAGE) - ).orElse(null) - ); + protected int maxDamage(ComponentItemWrapper item) { + Optional damage = item.getJavaComponent(ComponentTypes.MAX_DAMAGE); + return damage.orElseGet(() -> (int) item.getItem().getType().getMaxDurability()); } @Override @@ -290,7 +254,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory getEnchantment(ComponentItemWrapper item, Key key) { - Object enchant = item.getComponent(ComponentTypes.ENCHANTMENTS); + Object enchant = item.getComponentExact(ComponentTypes.ENCHANTMENTS); try { Map map = EnchantmentUtils.toMap(enchant); Integer level = map.get(key.toString()); @@ -330,7 +294,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory map = EnchantmentUtils.toMap(enchant); map.put(enchantment.id().toString(), enchantment.level()); @@ -342,7 +306,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory map = EnchantmentUtils.toMap(enchant); map.put(enchantment.id().toString(), enchantment.level()); @@ -359,9 +323,8 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory stackSize = item.getJavaComponent(ComponentTypes.MAX_STACK_SIZE); + return stackSize.orElseGet(() -> item.getItem().getType().getMaxStackSize()); } @Override @@ -384,8 +347,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory repairCost(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.REPAIR_COST)) return Optional.empty(); - return Optional.ofNullable((Integer) ComponentType.encodeJava(ComponentTypes.REPAIR_COST, item.getComponent(ComponentTypes.REPAIR_COST)).orElse(null)); + return item.getJavaComponent(ComponentTypes.REPAIR_COST); } @Override @@ -402,8 +364,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory trim(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.TRIM)) return Optional.empty(); - Optional trim = ComponentType.encodeJava(ComponentTypes.TRIM, item.getComponent(ComponentTypes.TRIM)); + Optional trim = item.getJavaComponent(ComponentTypes.TRIM); if (trim.isEmpty()) { return Optional.empty(); } @@ -418,7 +379,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory jukeboxSong(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.JUKEBOX_PLAYABLE)) return Optional.empty(); - @SuppressWarnings("unchecked") - Map map = (Map) ComponentType.encodeJava( - ComponentTypes.JUKEBOX_PLAYABLE, - item.getComponent(ComponentTypes.JUKEBOX_PLAYABLE) - ).orElse(null); - if (map == null) return Optional.empty(); - return Optional.of(new JukeboxPlayable((String) map.get("song"), (boolean) map.getOrDefault("show_in_tooltip", true))); + Optional> map = item.getJavaComponent(ComponentTypes.JUKEBOX_PLAYABLE); + return map.map(song -> new JukeboxPlayable( + (String) song.get("song"), + (boolean) song.getOrDefault("show_in_tooltip", true)) + ); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java index 3f05e1c44..13f9be33f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.bukkit.item.factory; -import com.saicone.rtag.data.ComponentType; import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper; import net.momirealms.craftengine.bukkit.item.ComponentTypes; import net.momirealms.craftengine.core.item.EquipmentData; @@ -8,7 +7,6 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import java.util.Optional; -@SuppressWarnings("UnstableApiUsage") public class ComponentItemFactory1_21_2 extends ComponentItemFactory1_21 { public ComponentItemFactory1_21_2(CraftEngine plugin) { @@ -26,13 +24,7 @@ public class ComponentItemFactory1_21_2 extends ComponentItemFactory1_21 { @Override protected Optional tooltipStyle(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.TOOLTIP_STYLE)) return Optional.empty(); - return Optional.ofNullable( - (String) ComponentType.encodeJava( - ComponentTypes.TOOLTIP_STYLE, - item.getComponent(ComponentTypes.TOOLTIP_STYLE) - ).orElse(null) - ); + return item.getJavaComponent(ComponentTypes.TOOLTIP_STYLE); } @Override @@ -46,13 +38,7 @@ public class ComponentItemFactory1_21_2 extends ComponentItemFactory1_21 { @Override protected Optional itemModel(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.ITEM_MODEL)) return Optional.empty(); - return Optional.ofNullable( - (String) ComponentType.encodeJava( - ComponentTypes.ITEM_MODEL, - item.getComponent(ComponentTypes.ITEM_MODEL) - ).orElse(null) - ); + return item.getJavaComponent(ComponentTypes.ITEM_MODEL); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_4.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_4.java index f6d14478b..df4ed6d31 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_4.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_4.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.bukkit.item.factory; -import com.saicone.rtag.data.ComponentType; import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper; import net.momirealms.craftengine.bukkit.item.ComponentTypes; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -9,7 +8,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -@SuppressWarnings("UnstableApiUsage") public class ComponentItemFactory1_21_4 extends ComponentItemFactory1_21_2 { public ComponentItemFactory1_21_4(CraftEngine plugin) { @@ -18,8 +16,7 @@ public class ComponentItemFactory1_21_4 extends ComponentItemFactory1_21_2 { @Override protected Optional customModelData(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.CUSTOM_MODEL_DATA)) return Optional.empty(); - Optional optional = ComponentType.encodeJava(ComponentTypes.CUSTOM_MODEL_DATA, item.getComponent(ComponentTypes.CUSTOM_MODEL_DATA)); + Optional optional = item.getJavaComponent(ComponentTypes.CUSTOM_MODEL_DATA); if (optional.isEmpty()) return Optional.empty(); @SuppressWarnings("unchecked") Map data = (Map) optional.get(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java index ab79741f7..1e249d52e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java @@ -3,14 +3,16 @@ package net.momirealms.craftengine.bukkit.item.factory; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.saicone.rtag.data.ComponentType; -import com.saicone.rtag.tag.TagList; -import com.saicone.rtag.util.ChatComponent; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper; import net.momirealms.craftengine.bukkit.item.ComponentTypes; -import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.item.JukeboxPlayable; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.GsonHelper; +import net.momirealms.sparrow.nbt.ListTag; +import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.sparrow.nbt.serializer.NBTComponentSerializer; import java.util.ArrayList; import java.util.List; @@ -24,60 +26,91 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { } @Override - protected void customName(ComponentItemWrapper item, String json) { + protected void customNameJson(ComponentItemWrapper item, String json) { if (json == null) { item.resetComponent(ComponentTypes.CUSTOM_NAME); } else { - item.setNBTComponent(ComponentTypes.CUSTOM_NAME, ChatComponent.toTag(ComponentUtils.jsonToMinecraft(json))); + item.setSparrowNBTComponent(ComponentTypes.CUSTOM_NAME, NBTComponentSerializer.nbt().serialize(AdventureHelper.jsonToComponent(json))); } } @Override - protected Optional customName(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.CUSTOM_NAME)) return Optional.empty(); - return ComponentType.encodeJson(ComponentTypes.CUSTOM_NAME, item.getComponent(ComponentTypes.CUSTOM_NAME)).map(jsonElement -> GsonHelper.get().toJson(jsonElement)); + protected Optional customNameJson(ComponentItemWrapper item) { + return item.getJsonComponent(ComponentTypes.CUSTOM_NAME).map(it -> GsonHelper.get().toJson(it)); } @Override - protected void itemName(ComponentItemWrapper item, String json) { + protected void customNameComponent(ComponentItemWrapper item, Component component) { + if (component == null) { + item.resetComponent(ComponentTypes.CUSTOM_NAME); + } else { + item.setSparrowNBTComponent(ComponentTypes.CUSTOM_NAME, NBTComponentSerializer.nbt().serialize(component)); + } + } + + @Override + protected Optional customNameComponent(ComponentItemWrapper item) { + return customNameJson(item).map(AdventureHelper::jsonToComponent); + } + + @Override + protected void itemNameJson(ComponentItemWrapper item, String json) { if (json == null) { item.resetComponent(ComponentTypes.ITEM_NAME); } else { - item.setNBTComponent(ComponentTypes.ITEM_NAME, ChatComponent.toTag(ComponentUtils.jsonToMinecraft(json))); + item.setSparrowNBTComponent(ComponentTypes.ITEM_NAME, NBTComponentSerializer.nbt().serialize(AdventureHelper.jsonToComponent(json))); } } @Override - protected Optional itemName(ComponentItemWrapper item) { - if (!item.hasComponent(ComponentTypes.ITEM_NAME)) return Optional.empty(); - return ComponentType.encodeJson(ComponentTypes.ITEM_NAME, item.getComponent(ComponentTypes.ITEM_NAME)).map(jsonElement -> GsonHelper.get().toJson(jsonElement)); + protected void itemNameComponent(ComponentItemWrapper item, Component component) { + if (component == null) { + item.resetComponent(ComponentTypes.ITEM_NAME); + } else { + item.setSparrowNBTComponent(ComponentTypes.ITEM_NAME, NBTComponentSerializer.nbt().serialize(component)); + } } @Override - protected Optional> lore(ComponentItemWrapper item) { + protected Optional itemNameJson(ComponentItemWrapper item) { + return item.getJsonComponent(ComponentTypes.ITEM_NAME).map(it -> GsonHelper.get().toJson(it)); + } + + @Override + protected Optional> loreJson(ComponentItemWrapper item) { if (!item.hasComponent(ComponentTypes.LORE)) return Optional.empty(); - return ComponentType.encodeJson( - ComponentTypes.LORE, - item.getComponent(ComponentTypes.LORE) - ).map(list -> { - List lore = new ArrayList<>(); - for (JsonElement jsonElement : (JsonArray) list) { - lore.add(GsonHelper.get().toJson(jsonElement)); - } - return lore; - }); + Optional json = item.getJsonComponent(ComponentTypes.LORE); + if (json.isEmpty()) return Optional.empty(); + List lore = new ArrayList<>(); + for (JsonElement jsonElement : (JsonArray) json.get()) { + lore.add(GsonHelper.get().toJson(jsonElement)); + } + return Optional.of(lore); } @Override - protected void lore(ComponentItemWrapper item, List lore) { + protected void loreComponent(ComponentItemWrapper item, List lore) { if (lore == null || lore.isEmpty()) { item.resetComponent(ComponentTypes.LORE); } else { - List loreTags = new ArrayList<>(); - for (String json : lore) { - loreTags.add(ChatComponent.toTag(ComponentUtils.jsonToMinecraft(json))); + List loreTags = new ArrayList<>(); + for (Component component : lore) { + loreTags.add(NBTComponentSerializer.nbt().serialize(component)); } - item.setNBTComponent(ComponentTypes.LORE, TagList.newTag(loreTags)); + item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(loreTags)); + } + } + + @Override + protected void loreJson(ComponentItemWrapper item, List lore) { + if (lore == null || lore.isEmpty()) { + item.resetComponent(ComponentTypes.LORE); + } else { + List loreTags = new ArrayList<>(); + for (String json : lore) { + loreTags.add(NBTComponentSerializer.nbt().serialize(AdventureHelper.jsonToComponent(json))); + } + item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(loreTags)); } } @@ -86,7 +119,7 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { if (!item.hasComponent(ComponentTypes.JUKEBOX_PLAYABLE)) return Optional.empty(); String song = (String) ComponentType.encodeJava( ComponentTypes.JUKEBOX_PLAYABLE, - item.getComponent(ComponentTypes.JUKEBOX_PLAYABLE)).orElse(null); + item.getComponentExact(ComponentTypes.JUKEBOX_PLAYABLE)).orElse(null); if (song == null) return Optional.empty(); return Optional.of(new JukeboxPlayable(song, true)); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java index dbf97a69d..689efd276 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.item.factory; +import com.google.gson.JsonElement; import com.saicone.rtag.RtagItem; import com.saicone.rtag.item.ItemObject; import com.saicone.rtag.tag.TagBase; @@ -12,6 +13,7 @@ import net.momirealms.craftengine.core.item.modifier.IdModifier; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.SkullUtils; +import net.momirealms.sparrow.nbt.Tag; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.inventory.ItemFlag; @@ -31,6 +33,21 @@ public class UniversalItemFactory extends BukkitItemFactory { return new LegacyItemWrapper(new RtagItem(item), item.getAmount()); } + @Override + protected Object getJavaComponent(LegacyItemWrapper item, Object type) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + + @Override + protected JsonElement getJsonComponent(LegacyItemWrapper item, Object type) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + + @Override + protected Tag getNBTComponent(LegacyItemWrapper item, Object type) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + @Override protected void setTag(LegacyItemWrapper item, Object value, Object... path) { item.set(value, path); @@ -64,7 +81,7 @@ public class UniversalItemFactory extends BukkitItemFactory { } @Override - protected void customName(LegacyItemWrapper item, String json) { + protected void customNameJson(LegacyItemWrapper item, String json) { if (json != null) { item.set(json, "display", "Name"); } else { @@ -73,19 +90,19 @@ public class UniversalItemFactory extends BukkitItemFactory { } @Override - protected Optional customName(LegacyItemWrapper item) { + protected Optional customNameJson(LegacyItemWrapper item) { if (!item.hasTag("display", "Name")) return Optional.empty(); return Optional.of(item.get("display", "Name")); } @Override - protected void itemName(LegacyItemWrapper item, String json) { - customName(item, json); + protected void itemNameJson(LegacyItemWrapper item, String json) { + customNameJson(item, json); } @Override - protected Optional itemName(LegacyItemWrapper item) { - return customName(item); + protected Optional itemNameJson(LegacyItemWrapper item) { + return customNameJson(item); } @Override @@ -117,13 +134,13 @@ public class UniversalItemFactory extends BukkitItemFactory { } @Override - protected Optional> lore(LegacyItemWrapper item) { + protected Optional> loreJson(LegacyItemWrapper item) { if (!item.hasTag("display", "Lore")) return Optional.empty(); return Optional.of(item.get("display", "Lore")); } @Override - protected void lore(LegacyItemWrapper item, List lore) { + protected void loreJson(LegacyItemWrapper item, List lore) { if (lore == null || lore.isEmpty()) { item.remove("display", "Lore"); } else { @@ -168,8 +185,8 @@ public class UniversalItemFactory extends BukkitItemFactory { } @Override - protected Optional maxDamage(LegacyItemWrapper item) { - return Optional.of((int) item.getItem().getType().getMaxDurability()); + protected int maxDamage(LegacyItemWrapper item) { + return item.getItem().getType().getMaxDurability(); } @Override 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 469cb7e1e..ab9c32643 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 @@ -512,7 +512,7 @@ public class RecipeEventListener implements Listener { Item wrappedFirst = BukkitItemManager.instance().wrap(first.clone()); - int maxDamage = wrappedFirst.maxDamage().orElse(0); + int maxDamage = wrappedFirst.maxDamage(); int damage = wrappedFirst.damage().orElse(0); // not a repairable item if (damage == 0 || maxDamage == 0) return; @@ -577,8 +577,8 @@ public class RecipeEventListener implements Listener { if (renameText != null && !renameText.isBlank()) { try { - if (!renameText.equals(Reflections.method$Component$getString.invoke(ComponentUtils.jsonToMinecraft(wrappedFirst.hoverName().orElse(AdventureHelper.EMPTY_COMPONENT))))) { - wrappedFirst.customName(AdventureHelper.componentToJson(Component.text(renameText))); + if (!renameText.equals(Reflections.method$Component$getString.invoke(ComponentUtils.jsonToMinecraft(wrappedFirst.hoverNameJson().orElse(AdventureHelper.EMPTY_COMPONENT))))) { + wrappedFirst.customNameJson(AdventureHelper.componentToJson(Component.text(renameText))); repairCost += 1; } else if (repairCost == 0) { hasResult = false; @@ -588,10 +588,10 @@ public class RecipeEventListener implements Listener { } } else if (VersionHelper.isOrAbove1_20_5() && wrappedFirst.hasComponent(ComponentTypes.CUSTOM_NAME)) { repairCost += 1; - wrappedFirst.customName(null); + wrappedFirst.customNameJson(null); } else if (!VersionHelper.isOrAbove1_20_5() && wrappedFirst.hasTag("display", "Name")) { repairCost += 1; - wrappedFirst.customName(null); + wrappedFirst.customNameJson(null); } int finalCost = repairCost + repairPenalty; @@ -665,7 +665,7 @@ public class RecipeEventListener implements Listener { } if (renameText != null && !renameText.isBlank()) { try { - if (!renameText.equals(Reflections.method$Component$getString.invoke(ComponentUtils.jsonToMinecraft(wrappedFirst.hoverName().orElse(AdventureHelper.EMPTY_COMPONENT))))) { + if (!renameText.equals(Reflections.method$Component$getString.invoke(ComponentUtils.jsonToMinecraft(wrappedFirst.hoverNameJson().orElse(AdventureHelper.EMPTY_COMPONENT))))) { event.setResult(null); } } catch (Exception e) { @@ -721,7 +721,7 @@ public class RecipeEventListener implements Listener { } int totalDamage = right.damage().orElse(0) + left.damage().orElse(0); - int totalMaxDamage = left.maxDamage().get() + right.maxDamage().get(); + int totalMaxDamage = left.maxDamage() + right.maxDamage(); // should be impossible, but take care if (totalDamage >= totalMaxDamage) { inventory.setResult(null); @@ -750,7 +750,7 @@ public class RecipeEventListener implements Listener { Item newItem = customItem.buildItem(ItemBuildContext.of(plugin.adapt(player))); int remainingDurability = totalMaxDamage - totalDamage; - int newItemDamage = Math.max(0, newItem.maxDamage().get() - remainingDurability); + int newItemDamage = Math.max(0, newItem.maxDamage() - remainingDurability); newItem.damage(newItemDamage); inventory.setResult(newItem.load()); } else if (Reflections.clazz$ArmorDyeRecipe.isInstance(mcRecipe)) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java index a7698e25c..bb29be78b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.network.id; import net.momirealms.craftengine.bukkit.plugin.network.PacketIds; -import net.momirealms.craftengine.bukkit.util.Reflections; public class PacketIds1_20_5 implements PacketIds { 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 0d71d0e68..fba7a0f92 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 @@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.util; import com.google.common.collect.ImmutableList; import com.google.gson.Gson; import com.google.gson.JsonElement; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -14,6 +16,8 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.sparrow.nbt.codec.NBTOps; import org.bukkit.NamespacedKey; import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; @@ -6855,4 +6859,53 @@ public class Reflections { "network.protocol.game.ServerboundContainerClickPacket" ) ); + + public static final Class clazz$RegistryOps = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "resources.RegistryOps", + "resources.RegistryOps" + ) + ); + + public static final Class clazz$JavaOps = requireNonNull( + ReflectionUtils.getClazz("com.mojang.serialization.JavaOps") + ); + + public static final Class clazz$NbtOps = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "nbt.DynamicOpsNBT", + "nbt.NbtOps" + ) + ); + + public static final Method method$RegistryOps$create = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$RegistryOps, clazz$RegistryOps, DynamicOps.class, clazz$HolderLookup$Provider + ) + ); + + public static final DynamicOps instance$NBT_OPS; + public static final DynamicOps instance$SPARROW_NBT_OPS; + public static final DynamicOps instance$JAVA_OPS; + public static final DynamicOps instance$JSON_OPS; + + static { + try { + Object nbtOps = ReflectionUtils.getDeclaredField(clazz$NbtOps, clazz$NbtOps, 0).get(null); + instance$NBT_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, nbtOps, instance$MinecraftRegistry); + Object javaOps = ReflectionUtils.getDeclaredField(clazz$JavaOps, clazz$JavaOps, 0).get(null); + instance$JAVA_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, javaOps, instance$MinecraftRegistry); + instance$JSON_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, JsonOps.INSTANCE, instance$MinecraftRegistry); + instance$SPARROW_NBT_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, NBTOps.INSTANCE, instance$MinecraftRegistry); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public static final Class clazz$Tag = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "nbt.NBTBase", + "nbt.Tag" + ) + ); } 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 8d2010eca..92ae329cb 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 @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.font; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.TextComponent; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index 70fbf6d8f..919f8c62b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -1,8 +1,10 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.Tag; import java.util.List; import java.util.Optional; @@ -89,7 +91,7 @@ public class AbstractItem, I> implements Item { } @Override - public Optional maxDamage() { + public int maxDamage() { return this.factory.maxDamage(this.item); } @@ -180,25 +182,47 @@ public class AbstractItem, I> implements Item { } @Override - public Optional customName() { - return this.factory.customName(this.item); + public Optional customNameJson() { + return this.factory.customNameJson(this.item); } @Override - public Item customName(String displayName) { - this.factory.customName(this.item, displayName); + public Item customNameJson(String displayName) { + this.factory.customNameJson(this.item, displayName); return this; } @Override - public Item lore(List lore) { - this.factory.lore(this.item, lore); + public Optional customNameComponent() { + return this.factory.customNameComponent(this.item); + } + + @Override + public Item customNameComponent(Component displayName) { + this.factory.customNameComponent(this.item, displayName); return this; } @Override - public Optional> lore() { - return this.factory.lore(this.item); + public Item loreJson(List lore) { + this.factory.loreJson(this.item, lore); + return this; + } + + @Override + public Optional> loreJson() { + return this.factory.loreJson(this.item); + } + + @Override + public Item loreComponent(List lore) { + this.factory.loreComponent(this.item, lore); + return this; + } + + @Override + public Optional> loreComponent() { + return this.factory.loreComponent(this.item); } @Override @@ -212,18 +236,28 @@ public class AbstractItem, I> implements Item { return this.factory.unbreakable(this.item); } - @Override - public Optional itemName() { - return this.factory.itemName(this.item); + public Item itemNameJson(String itemName) { + this.factory.itemNameJson(this.item, itemName); + return this; } @Override - public Item itemName(String itemName) { - this.factory.itemName(this.item, itemName); + public Optional itemNameJson() { + return this.factory.itemNameJson(this.item); + } + + @Override + public Item itemNameComponent(Component itemName) { + this.factory.itemNameComponent(this.item, itemName); return this; } + @Override + public Optional itemNameComponent() { + return this.factory.itemNameComponent(this.item); + } + @Override public Item skull(String data) { this.factory.skull(this.item, data); @@ -308,18 +342,23 @@ public class AbstractItem, I> implements Item { } @Override - public Object getComponent(Object type) { - return this.factory.getComponent(this.item, type); + public Object getExactComponent(Object type) { + return this.factory.getExactComponent(this.item, type); } @Override - public Object getJavaTypeComponent(Object type) { - return this.factory.encodeJava(type, getComponent(type)); + public Object getJavaComponent(Object type) { + return this.factory.getJavaComponent(this.item, type); } @Override - public JsonElement getJsonTypeComponent(Object type) { - return this.factory.encodeJson(type, getComponent(type)); + public JsonElement getJsonComponent(Object type) { + return this.factory.getJsonComponent(this.item, type); + } + + @Override + public Tag getNBTComponent(Object type) { + return this.factory.getNBTComponent(this.item, type); } @Override 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 9b0b5be71..cf3df095b 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 @@ -437,7 +437,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl }, "external"); registerDataFunction((obj) -> { String name = obj.toString(); - return new DisplayNameModifier<>(name); + return new CustomNameModifier<>(name); }, "custom-name"); registerDataFunction((obj) -> { String name = obj.toString(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index 50786ace9..e2c005e07 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -1,8 +1,10 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.Tag; import java.util.List; import java.util.Optional; @@ -54,23 +56,35 @@ public interface Item { Item maxDamage(Integer data); - Optional maxDamage(); + int maxDamage(); Item dyedColor(Integer data); Optional dyedColor(); - Item customName(String displayName); + Item customNameJson(String displayName); - Optional customName(); + Item customNameComponent(Component displayName); - default Optional hoverName() { - return customName().or(this::itemName); + Optional customNameJson(); + + Optional customNameComponent(); + + default Optional hoverNameJson() { + return customNameJson().or(this::itemNameJson); } - Item itemName(String itemName); + default Optional hoverNameComponent() { + return customNameComponent().or(this::itemNameComponent); + } - Optional itemName(); + Item itemNameJson(String itemName); + + Item itemNameComponent(Component itemName); + + Optional itemNameJson(); + + Optional itemNameComponent(); Item itemModel(String itemModel); @@ -80,7 +94,13 @@ public interface Item { Optional tooltipStyle(); - Item lore(List lore); + Item loreJson(List lore); + + Item loreComponent(List lore); + + Optional> loreJson(); + + Optional> loreComponent(); Optional jukeboxSong(); @@ -90,7 +110,6 @@ public interface Item { Item equippable(EquipmentData equipmentData); - Optional> lore(); Item unbreakable(boolean unbreakable); @@ -122,11 +141,13 @@ public interface Item { void removeComponent(Object type); - Object getComponent(Object type); + Object getExactComponent(Object type); - Object getJavaTypeComponent(Object type); + Object getJavaComponent(Object type); - JsonElement getJsonTypeComponent(Object type); + JsonElement getJsonComponent(Object type); + + Tag getNBTComponent(Object type); void setComponent(Object type, Object value); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index eb3c9fada..ea15a3823 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -1,13 +1,16 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; -import org.jetbrains.annotations.Nullable; +import net.momirealms.sparrow.nbt.Tag; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; public abstract class ItemFactory, I> { protected final CraftEngine plugin; @@ -25,10 +28,6 @@ public abstract class ItemFactory, I> { protected abstract void merge(W item1, W item2); - protected abstract Object encodeJava(Object type, @Nullable Object component); - - protected abstract JsonElement encodeJson(Object type, Object component); - protected abstract W wrapInternal(I item); protected abstract Object getTag(W item, Object... path); @@ -41,7 +40,13 @@ public abstract class ItemFactory, I> { protected abstract void setComponent(W item, Object type, Object value); - protected abstract Object getComponent(W item, Object type); + protected abstract Object getExactComponent(W item, Object type); + + protected abstract Object getJavaComponent(W item, Object type); + + protected abstract JsonElement getJsonComponent(W item, Object type); + + protected abstract Tag getNBTComponent(W item, Object type); protected abstract boolean hasComponent(W item, Object type); @@ -57,20 +62,56 @@ public abstract class ItemFactory, I> { protected abstract Optional customModelData(W item); - protected abstract void customName(W item, String json); + protected abstract void customNameJson(W item, String json); - protected abstract Optional customName(W item); + protected abstract Optional customNameJson(W item); - protected abstract void itemName(W item, String json); + protected void customNameComponent(W item, Component component) { + if (component != null) { + customNameJson(item, AdventureHelper.componentToJson(component)); + } else { + customNameJson(item, null); + } + } - protected abstract Optional itemName(W item); + protected Optional customNameComponent(W item) { + return customNameJson(item).map(AdventureHelper::jsonToComponent); + } + + protected abstract void itemNameJson(W item, String json); + + protected abstract Optional itemNameJson(W item); + + protected void itemNameComponent(W item, Component component) { + if (component != null) { + itemNameJson(item, AdventureHelper.componentToJson(component)); + } else { + itemNameJson(item, null); + } + } + + protected Optional itemNameComponent(W item) { + return itemNameJson(item).map(AdventureHelper::jsonToComponent); + } + + protected abstract Optional> loreJson(W item); + + protected abstract void loreJson(W item, List lore); + + protected void loreComponent(W item, List component) { + if (component != null && !component.isEmpty()) { + loreJson(item, component.stream().map(AdventureHelper::componentToJson).collect(Collectors.toList())); + } else { + loreJson(item, null); + } + } + + protected Optional> loreComponent(W item) { + return loreJson(item).map(list -> list.stream().map(AdventureHelper::jsonToComponent).toList()); + } protected abstract void skull(W item, String skullData); - protected abstract Optional> lore(W item); - - protected abstract void lore(W item, List lore); - protected abstract boolean unbreakable(W item); protected abstract void unbreakable(W item, boolean unbreakable); @@ -87,7 +128,7 @@ public abstract class ItemFactory, I> { protected abstract void dyedColor(W item, Integer color); - protected abstract Optional maxDamage(W item); + protected abstract int maxDamage(W item); protected abstract void maxDamage(W item, Integer damage); @@ -144,5 +185,4 @@ public abstract class ItemFactory, I> { protected abstract Optional equippable(W item); protected abstract byte[] toByteArray(W item); - } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java index 216c7740c..d13e28e4b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java @@ -65,7 +65,7 @@ public class ComponentModifier implements ItemDataModifier { item.setComponent(entry.left(), entry.right()); } if (this.customData != null) { - JsonObject tag = (JsonObject) item.getJsonTypeComponent(ComponentKeys.CUSTOM_DATA); + JsonObject tag = (JsonObject) item.getJsonComponent(ComponentKeys.CUSTOM_DATA); if (tag != null) { item.setComponent(ComponentKeys.CUSTOM_DATA, GsonHelper.shallowMerge(this.customData, tag)); } else { @@ -80,7 +80,7 @@ public class ComponentModifier implements ItemDataModifier { item.resetComponent(entry.left()); } if (this.customData != null) { - JsonObject tag = (JsonObject) item.getJsonTypeComponent(ComponentKeys.CUSTOM_DATA); + JsonObject tag = (JsonObject) item.getJavaComponent(ComponentKeys.CUSTOM_DATA); if (tag != null) { // crude method for (String key : this.customData.keySet()) { 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/CustomNameModifier.java similarity index 65% rename from core/src/main/java/net/momirealms/craftengine/core/item/modifier/DisplayNameModifier.java rename to core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java index cf468756c..6814092ce 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/CustomNameModifier.java @@ -5,25 +5,25 @@ import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; -public class DisplayNameModifier implements ItemDataModifier { +public class CustomNameModifier implements ItemDataModifier { private final String argument; - public DisplayNameModifier(String argument) { + public CustomNameModifier(String argument) { this.argument = Config.nonItalic() ? "" + argument : argument; } @Override public String name() { - return "display-name"; + return "custom-name"; } @Override public void apply(Item item, ItemBuildContext context) { - item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(this.argument, context.tagResolvers()))); + item.customNameComponent(AdventureHelper.miniMessage().deserialize(this.argument, context.tagResolvers())); } @Override public void remove(Item item) { - item.customName(null); + item.customNameJson(null); } } 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 8ba7e0967..b575874f0 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 @@ -19,11 +19,11 @@ public class ItemNameModifier implements ItemDataModifier { @Override public void apply(Item item, ItemBuildContext context) { - item.itemName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(this.argument, context.tagResolvers()))); + item.itemNameComponent(AdventureHelper.miniMessage().deserialize(this.argument, context.tagResolvers())); } @Override public void remove(Item item) { - item.itemName(null); + item.itemNameJson(null); } } 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 5515ab4d2..5bda4c5d5 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 @@ -21,12 +21,12 @@ public class LoreModifier implements ItemDataModifier { @Override public void apply(Item item, ItemBuildContext context) { - item.lore(this.argument.stream().map(it -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize( - it, context.tagResolvers()))).toList()); + item.loreComponent(this.argument.stream().map(it -> AdventureHelper.miniMessage().deserialize( + it, context.tagResolvers())).toList()); } @Override public void remove(Item item) { - item.lore(null); + item.loreJson(null); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index b4698e00b..ce2b96cd1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -219,7 +219,7 @@ public class CustomSmithingTransformRecipe implements Recipe { @Override public void accept(Item item1, Item item2, Item item3) { for (Key component : this.components) { - Object componentObj = item1.getComponent(component); + Object componentObj = item1.getExactComponent(component); if (componentObj != null) { item3.setComponent(component, componentObj); } 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 7fc4915ef..ca5695c38 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 @@ -163,8 +163,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { this.plugin.logger().warn("Can't not find item " + it.icon() + " for category icon"); return null; } - item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(it.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); - item.lore(it.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); + item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(it.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); + item.loreJson(it.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); item.load(); return new ItemWithAction(item, (element, click) -> { click.cancel(); @@ -249,13 +249,13 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { if (!subCategory.icon().equals(ItemKeys.AIR)) { this.plugin.logger().warn("Can't find item " + subCategory.icon() + " as icon for sub category " + subCategoryId); item = this.plugin.itemManager().createWrappedItem(ItemKeys.BARRIER, player); - item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); - item.lore(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); + item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); + item.loreJson(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); item.load(); } } else { - item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); - item.lore(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); + item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); + item.loreJson(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); item.load(); } return new ItemWithAction(item, (element, click) -> { @@ -271,7 +271,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { if (!itemId.equals(ItemKeys.AIR)) { this.plugin.logger().warn("Can't find item " + itemId + " for category " + categoryId); item = this.plugin.itemManager().createWrappedItem(ItemKeys.BARRIER, player); - item.customName(AdventureHelper.componentToJson(Component.text(it).decoration(TextDecoration.ITALIC, TextDecoration.State.FALSE).color(NamedTextColor.RED))); + item.customNameJson(AdventureHelper.componentToJson(Component.text(it).decoration(TextDecoration.ITALIC, TextDecoration.State.FALSE).color(NamedTextColor.RED))); } canGoFurther = false; } else { diff --git a/gradle.properties b/gradle.properties index de82be993..4a1852463 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,18 +39,18 @@ geantyref_version=1.3.16 zstd_version=1.5.7-2 commons_io_version=2.18.0 commons_imaging_version=1.0.0-alpha6 -sparrow_nbt_version=0.7.3 +sparrow_nbt_version=0.8.1 sparrow_util_version=0.47 fastutil_version=8.5.15 netty_version=4.1.121.Final joml_version=1.10.8 -datafixerupper_version=6.0.8 +datafixerupper_version=8.0.16 mojang_brigadier_version=1.0.18 byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.66.2 +nms_helper_version=0.66.3 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From e491b28722d77e43361defc4863b1a1c4ab81bee Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 28 May 2025 00:29:31 +0800 Subject: [PATCH 70/89] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=8F=91=E5=8C=85?= =?UTF-8?q?=E7=89=A9=E5=93=81=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitItemManager.java | 21 ++- .../bukkit/item/ComponentItemWrapper.java | 1 + .../bukkit/item/LegacyNetworkItemHandler.java | 63 -------- .../bukkit/item/ModernNetworkItemHandler.java | 150 ++++++++++++++++++ .../bukkit/item/NetworkItemHandler.java | 44 +++++ .../item/factory/BukkitItemFactory.java | 33 ++++ .../factory/ComponentItemFactory1_20_5.java | 15 ++ .../item/factory/UniversalItemFactory.java | 17 -- .../plugin/network/BukkitNetworkManager.java | 98 ++++++++---- .../craftengine/core/item/AbstractItem.java | 15 ++ .../craftengine/core/item/Item.java | 6 + .../craftengine/core/item/ItemFactory.java | 6 + .../core/util/AdventureHelper.java | 8 + gradle.properties | 2 +- .../mod/item/CustomStreamCodec.java | 25 --- .../mod/mixin/FriendlyByteBufMixin.java | 30 ---- .../main/resources/mixins.craftengine.json | 3 +- .../mod/item/CustomStreamCodec.java | 41 ----- .../craftengine/mod/mixin/ItemStackMixin.java | 48 ------ .../main/resources/mixins.craftengine.json | 3 +- .../mod/item/CustomStreamCodec.java | 41 ----- .../craftengine/mod/mixin/ItemStackMixin.java | 66 -------- 22 files changed, 364 insertions(+), 372 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java delete mode 100644 server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java delete mode 100644 server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/mixin/FriendlyByteBufMixin.java delete mode 100644 server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java delete mode 100644 server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java delete mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java delete mode 100644 server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java 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 b1352aa35..60d9e2167 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 @@ -15,6 +15,7 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.modifier.IdModifier; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -57,7 +58,7 @@ public class BukkitItemManager extends AbstractItemManager { this.itemEventListener = new ItemEventListener(plugin); this.debugStickListener = new DebugStickListener(plugin); this.armorEventListener = new ArmorEventListener(); - this.networkItemHandler = new LegacyNetworkItemHandler(this); + this.networkItemHandler = new ModernNetworkItemHandler(this); this.registerAllVanillaItems(); } @@ -73,11 +74,25 @@ public class BukkitItemManager extends AbstractItemManager { } public Optional s2c(ItemStack itemStack, ItemBuildContext context) { - return this.networkItemHandler.s2c(itemStack, context); + try { + return this.networkItemHandler.s2c(itemStack, context); + } catch (Throwable e) { + if (Config.debug()) { + this.plugin.logger().warn("Failed to handle s2c items.", e); + } + return Optional.empty(); + } } public Optional c2s(ItemStack itemStack, ItemBuildContext context) { - return this.networkItemHandler.c2s(itemStack, context); + try { + return this.networkItemHandler.c2s(itemStack, context); + } catch (Throwable e) { + if (Config.debug()) { + this.plugin.logger().warn("Failed to handle c2s items.", e); + } + return Optional.empty(); + } } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java index 765d093cd..bda3edb58 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java @@ -108,6 +108,7 @@ public class ComponentItemWrapper implements ItemWrapper { @SuppressWarnings({"rawtypes", "unchecked"}) private void setComponentInternal(Object type, DynamicOps ops, Object value) { + if (value == null) return; Object componentType = ensureDataComponentType(type); Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType); try { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java deleted file mode 100644 index cf5f55199..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.momirealms.craftengine.bukkit.item; - -import net.momirealms.craftengine.core.item.CustomItem; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.plugin.config.Config; -import org.bukkit.inventory.ItemStack; - -import java.util.Optional; - -public class LegacyNetworkItemHandler implements NetworkItemHandler { - private final BukkitItemManager itemManager; - - public LegacyNetworkItemHandler(BukkitItemManager itemManager) { - this.itemManager = itemManager; - } - - @Override - public Optional c2s(ItemStack itemStack, ItemBuildContext context) { - Item wrapped = this.itemManager.wrap(itemStack); - if (wrapped == null) return Optional.empty(); - - return Optional.empty(); - } - - @Override - public Optional s2c(ItemStack itemStack, ItemBuildContext context) { - Item wrapped = this.itemManager.wrap(itemStack); - if (wrapped == null) return Optional.empty(); - Optional> optionalCustomItem = wrapped.getCustomItem(); - if (optionalCustomItem.isEmpty()) { - return s2cOtherItems(wrapped, context); - } else { - return Optional.empty(); - } - } - - private Optional s2cOtherItems(Item item, ItemBuildContext context) { - if (!Config.interceptItem()) return Optional.empty(); - -// Optional> optionalLore = item.lore(); -// if (optionalLore.isPresent()) { -// boolean changed = false; -// List lore = optionalLore.get(); -// List newLore = new ArrayList<>(lore.size()); -// for (String line : lore) { -// Map tokens = CraftEngine.instance().fontManager().matchTags(line); -// if (tokens.isEmpty()) { -// newLore.add(line); -// } else { -// newLore.add(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); -// changed = true; -// } -// } -// if (changed) { -// item.lore(newLore); -// } -// } -// - return Optional.empty(); - - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java new file mode 100644 index 000000000..fadbbe8ce --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java @@ -0,0 +1,150 @@ +package net.momirealms.craftengine.bukkit.item; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.ListTag; +import net.momirealms.sparrow.nbt.StringTag; +import net.momirealms.sparrow.nbt.Tag; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ModernNetworkItemHandler implements NetworkItemHandler { + private final BukkitItemManager itemManager; + + public ModernNetworkItemHandler(BukkitItemManager itemManager) { + this.itemManager = itemManager; + } + + @Override + public Optional c2s(ItemStack itemStack, ItemBuildContext context) { + Item wrapped = this.itemManager.wrap(itemStack); + if (wrapped == null) return Optional.empty(); + Tag customData = wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA); + if (!(customData instanceof CompoundTag compoundTag)) return Optional.empty(); + CompoundTag networkData = compoundTag.getCompound(NETWORK_ITEM_TAG); + if (networkData == null) return Optional.empty(); + compoundTag.remove(NETWORK_ITEM_TAG); + for (Map.Entry entry : networkData.entrySet()) { + if (entry.getValue() instanceof CompoundTag tag) { + NetworkItemHandler.apply(entry.getKey(), tag, wrapped); + } + } + if (compoundTag.isEmpty()) { + wrapped.resetComponent(ComponentTypes.CUSTOM_DATA); + } else { + wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, compoundTag); + } + return Optional.of(wrapped.load()); + } + + @Override + public Optional s2c(ItemStack itemStack, ItemBuildContext context) { + Item wrapped = this.itemManager.wrap(itemStack); + if (wrapped == null) return Optional.empty(); + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isEmpty()) { + if (!Config.interceptItem()) return Optional.empty(); + return new OtherItem(wrapped).process(); + } else { + return Optional.empty(); + } + } + + static class OtherItem { + private final Item item; + private boolean globalChanged = false; + private CompoundTag tag; + + public OtherItem(Item item) { + this.item = item; + } + + public Optional process() { + if (VersionHelper.isOrAbove1_21_5()) { + processModernLore(); + } else { + processLore(); + } + + if (this.globalChanged) { + CompoundTag customData = Optional.ofNullable(this.item.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag()); + customData.put(NETWORK_ITEM_TAG, getOrCreateTag()); + this.item.setNBTComponent(ComponentKeys.CUSTOM_DATA, customData); + return Optional.of(this.item.load()); + } else { + return Optional.empty(); + } + } + + private void processLore() { + Optional> optionalLore = this.item.loreJson(); + if (optionalLore.isPresent()) { + boolean changed = false; + List lore = optionalLore.get(); + List newLore = new ArrayList<>(lore.size()); + for (String line : lore) { + Map tokens = CraftEngine.instance().fontManager().matchTags(line); + if (tokens.isEmpty()) { + newLore.add(line); + } else { + newLore.add(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); + changed = true; + } + } + if (changed) { + this.globalChanged = true; + this.item.loreJson(newLore); + ListTag listTag = new ListTag(); + for (String line : lore) { + listTag.add(new StringTag(line)); + } + getOrCreateTag().put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(Operation.ADD, listTag)); + } + } + } + + private void processModernLore() { + Tag loreTag = this.item.getNBTComponent(ComponentTypes.LORE); + if (loreTag == null) return; + boolean changed = false; + if (!(loreTag instanceof ListTag listTag)) { + return; + } + ListTag newLore = new ListTag(); + for (Tag tag : listTag) { + String tagStr = tag.getAsString(); + Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); + if (tokens.isEmpty()) { + newLore.add(tag); + } else { + newLore.add(AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(tag), tokens))); + changed = true; + } + } + if (changed) { + this.globalChanged = true; + this.item.setNBTComponent(ComponentKeys.LORE, newLore); + getOrCreateTag().put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(Operation.ADD, listTag)); + } + } + + private CompoundTag getOrCreateTag() { + if (this.tag == null) { + this.tag = new CompoundTag(); + } + return this.tag; + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java index 22b2f7881..aa2b6862f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java @@ -1,13 +1,57 @@ package net.momirealms.craftengine.bukkit.item; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.util.TriConsumer; +import net.momirealms.sparrow.nbt.ByteTag; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; +import java.util.Map; import java.util.Optional; public interface NetworkItemHandler { + Operation[] BY_INDEX = new Operation[] {Operation.ADD, Operation.REMOVE, Operation.RESET}; + String NETWORK_ITEM_TAG = "craftengine:network"; + String NETWORK_OPERATION = "type"; + String NETWORK_VALUE = "value"; Optional s2c(ItemStack itemStack, ItemBuildContext context); Optional c2s(ItemStack itemStack, ItemBuildContext context); + + static CompoundTag pack(Operation operation, Tag value) { + return new CompoundTag(Map.of(NETWORK_OPERATION, operation.tag(), NETWORK_VALUE, value)); + } + + static void apply(String componentType, CompoundTag networkData, Item item) { + byte index = networkData.getByte(NETWORK_OPERATION); + Operation operation = BY_INDEX[index]; + operation.consumer.accept(item, componentType, operation == Operation.ADD ? networkData.get(NETWORK_VALUE) : null); + } + + enum Operation { + ADD(0, Item::setNBTComponent), + REMOVE(1, (i, s, t) -> i.removeComponent(s)), + RESET(2, (i, s, t) -> i.resetComponent(s)); + + private final int id; + private final ByteTag tag; + private final TriConsumer, String, Tag> consumer; + + Operation(int id, TriConsumer, String, Tag> consumer) { + this.id = id; + this.tag = new ByteTag((byte) id); + this.consumer = consumer; + } + + public int id() { + return this.id; + } + + public ByteTag tag() { + return tag; + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index 1365980c2..ec9009aa4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -1,6 +1,8 @@ package net.momirealms.craftengine.bukkit.item.factory; +import com.google.gson.JsonElement; import com.saicone.rtag.item.ItemTagStream; +import net.momirealms.craftengine.bukkit.item.LegacyItemWrapper; import net.momirealms.craftengine.bukkit.util.ItemTags; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.EquipmentData; @@ -9,6 +11,7 @@ import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.item.JukeboxPlayable; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; import java.util.Objects; @@ -87,6 +90,36 @@ public abstract class BukkitItemFactory> extend } } + @Override + protected void setJavaComponent(W item, Object type, Object value) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + + @Override + protected void setJsonComponent(W item, Object type, JsonElement value) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + + @Override + protected void setNBTComponent(W item, Object type, Tag value) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + + @Override + protected Object getJavaComponent(W item, Object type) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + + @Override + protected JsonElement getJsonComponent(W item, Object type) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + + @Override + protected Tag getNBTComponent(W item, Object type) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + @Override protected void resetComponent(W item, Object type) { throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index ea22561b0..b039709a6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -73,6 +73,21 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory { return new LegacyItemWrapper(new RtagItem(item), item.getAmount()); } - @Override - protected Object getJavaComponent(LegacyItemWrapper item, Object type) { - throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); - } - - @Override - protected JsonElement getJsonComponent(LegacyItemWrapper item, Object type) { - throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); - } - - @Override - protected Tag getNBTComponent(LegacyItemWrapper item, Object type) { - throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); - } - @Override protected void setTag(LegacyItemWrapper item, Object value, Object... path) { item.set(value, path); 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 f8ae2831d..623f5c11f 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 @@ -40,16 +40,22 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static BukkitNetworkManager instance; private static final Map, TriConsumer> NMS_PACKET_HANDLERS = new HashMap<>(); // only for game stage for the moment - private static final Map> BYTE_BUFFER_PACKET_HANDLERS = new HashMap<>(); + private static final Map> S2C_BYTE_BUFFER_PACKET_HANDLERS = new HashMap<>(); + private static final Map> C2S_BYTE_BUFFER_PACKET_HANDLERS = new HashMap<>(); private static void registerNMSPacketConsumer(final TriConsumer function, @Nullable Class packet) { if (packet == null) return; NMS_PACKET_HANDLERS.put(packet, function); } - private static void registerByteBufPacketConsumer(final BiConsumer function, int id) { + private static void registerS2CByteBufPacketConsumer(final BiConsumer function, int id) { if (id == -1) return; - BYTE_BUFFER_PACKET_HANDLERS.put(id, function); + S2C_BYTE_BUFFER_PACKET_HANDLERS.put(id, function); + } + + private static void registerC2SByteBufPacketConsumer(final BiConsumer function, int id) { + if (id == -1) return; + C2S_BYTE_BUFFER_PACKET_HANDLERS.put(id, function); } private final BiConsumer> packetsConsumer; @@ -155,32 +161,32 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, Reflections.clazz$ServerboundResourcePackPacket); registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, Reflections.clazz$ClientboundEntityEventPacket); registerNMSPacketConsumer(PacketConsumers.MOVE_POS_AND_ROTATE_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$PosRot); - registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); - registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); - registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_21_4() ? PacketConsumers.LEVEL_PARTICLE_1_21_4 : (VersionHelper.isOrAbove1_20_5() ? PacketConsumers.LEVEL_PARTICLE_1_20_5 : PacketConsumers.LEVEL_PARTICLE_1_20), this.packetIds.clientboundLevelParticlesPacket()); - registerByteBufPacketConsumer(PacketConsumers.LEVEL_EVENT, this.packetIds.clientboundLevelEventPacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.OPEN_SCREEN_1_20_3 : PacketConsumers.OPEN_SCREEN_1_20, this.packetIds.clientboundOpenScreenPacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_TITLE_TEXT_1_20_3 : PacketConsumers.SET_TITLE_TEXT_1_20, this.packetIds.clientboundSetTitleTextPacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_SUBTITLE_TEXT_1_20_3 : PacketConsumers.SET_SUBTITLE_TEXT_1_20, this.packetIds.clientboundSetSubtitleTextPacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_ACTIONBAR_TEXT_1_20_3 : PacketConsumers.SET_ACTIONBAR_TEXT_1_20, this.packetIds.clientboundSetActionBarTextPacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.BOSS_EVENT_1_20_3 : PacketConsumers.BOSS_EVENT_1_20, this.packetIds.clientboundBossEventPacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SYSTEM_CHAT_1_20_3 : PacketConsumers.SYSTEM_CHAT_1_20, this.packetIds.clientboundSystemChatPacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TAB_LIST_1_20_3 : PacketConsumers.TAB_LIST_1_20, this.packetIds.clientboundTabListPacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TEAM_1_20_3 : PacketConsumers.TEAM_1_20, this.packetIds.clientboundSetPlayerTeamPacket()); - registerByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_OBJECTIVE_1_20_3 : PacketConsumers.SET_OBJECTIVE_1_20, this.packetIds.clientboundSetObjectivePacket()); - registerByteBufPacketConsumer(PacketConsumers.SET_SCORE_1_20_3, VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1); - registerByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket()); - registerByteBufPacketConsumer(PacketConsumers.ADD_ENTITY_BYTEBUFFER, this.packetIds.clientboundAddEntityPacket()); - registerByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket()); - registerByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket()); - registerByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_CONTENT, this.packetIds.clientboundContainerSetContentPacket()); - registerByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_SLOT, this.packetIds.clientboundContainerSetSlotPacket()); - registerByteBufPacketConsumer(PacketConsumers.SET_CURSOR_ITEM, this.packetIds.clientboundSetCursorItemPacket()); - registerByteBufPacketConsumer(PacketConsumers.SET_EQUIPMENT, this.packetIds.clientboundSetEquipmentPacket()); - registerByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY_1_21_2, this.packetIds.clientboundSetPlayerInventoryPacket()); - registerByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket()); - registerByteBufPacketConsumer(PacketConsumers.CONTAINER_CLICK_1_20, this.packetIds.serverboundContainerClickPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); + registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_21_4() ? PacketConsumers.LEVEL_PARTICLE_1_21_4 : (VersionHelper.isOrAbove1_20_5() ? PacketConsumers.LEVEL_PARTICLE_1_20_5 : PacketConsumers.LEVEL_PARTICLE_1_20), this.packetIds.clientboundLevelParticlesPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_EVENT, this.packetIds.clientboundLevelEventPacket()); + registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.OPEN_SCREEN_1_20_3 : PacketConsumers.OPEN_SCREEN_1_20, this.packetIds.clientboundOpenScreenPacket()); + registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_TITLE_TEXT_1_20_3 : PacketConsumers.SET_TITLE_TEXT_1_20, this.packetIds.clientboundSetTitleTextPacket()); + registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_SUBTITLE_TEXT_1_20_3 : PacketConsumers.SET_SUBTITLE_TEXT_1_20, this.packetIds.clientboundSetSubtitleTextPacket()); + registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_ACTIONBAR_TEXT_1_20_3 : PacketConsumers.SET_ACTIONBAR_TEXT_1_20, this.packetIds.clientboundSetActionBarTextPacket()); + registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.BOSS_EVENT_1_20_3 : PacketConsumers.BOSS_EVENT_1_20, this.packetIds.clientboundBossEventPacket()); + registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SYSTEM_CHAT_1_20_3 : PacketConsumers.SYSTEM_CHAT_1_20, this.packetIds.clientboundSystemChatPacket()); + registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TAB_LIST_1_20_3 : PacketConsumers.TAB_LIST_1_20, this.packetIds.clientboundTabListPacket()); + registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TEAM_1_20_3 : PacketConsumers.TEAM_1_20, this.packetIds.clientboundSetPlayerTeamPacket()); + registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_OBJECTIVE_1_20_3 : PacketConsumers.SET_OBJECTIVE_1_20, this.packetIds.clientboundSetObjectivePacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.SET_SCORE_1_20_3, VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1); + registerS2CByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY_BYTEBUFFER, this.packetIds.clientboundAddEntityPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_CONTENT, this.packetIds.clientboundContainerSetContentPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_SLOT, this.packetIds.clientboundContainerSetSlotPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.SET_CURSOR_ITEM, this.packetIds.clientboundSetCursorItemPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.SET_EQUIPMENT, this.packetIds.clientboundSetEquipmentPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY_1_21_2, this.packetIds.clientboundSetPlayerInventoryPacket()); + registerC2SByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket()); + registerC2SByteBufPacketConsumer(PacketConsumers.CONTAINER_CLICK_1_20, this.packetIds.serverboundContainerClickPacket()); } public static BukkitNetworkManager instance() { @@ -573,7 +579,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes int packetId = buf.readVarInt(); int preIndex = buf.readerIndex(); ByteBufPacketEvent event = new ByteBufPacketEvent(packetId, buf, preIndex); - BukkitNetworkManager.this.handleByteBufPacket(this.player, event); + BukkitNetworkManager.this.handleS2CByteBufPacket(this.player, event); if (event.isCancelled()) { buf.clear(); } else if (!event.changed()) { @@ -583,7 +589,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } - public static class PluginChannelDecoder extends MessageToMessageDecoder { + public class PluginChannelDecoder extends MessageToMessageDecoder { private final NetWorkUser player; public PluginChannelDecoder(NetWorkUser player) { @@ -592,10 +598,30 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @Override protected void decode(ChannelHandlerContext context, ByteBuf byteBuf, List list) { + this.onByteBufReceive(byteBuf); if (byteBuf.isReadable()) { list.add(byteBuf.retain()); } } + + private void onByteBufReceive(ByteBuf buffer) { + // I don't care packets before PLAY for the moment + if (player.decoderState() != ConnectionState.PLAY) return; + int size = buffer.readableBytes(); + if (size != 0) { + FriendlyByteBuf buf = new FriendlyByteBuf(buffer); + int preProcessIndex = buf.readerIndex(); + int packetId = buf.readVarInt(); + int preIndex = buf.readerIndex(); + ByteBufPacketEvent event = new ByteBufPacketEvent(packetId, buf, preIndex); + BukkitNetworkManager.this.handleC2SByteBufPacket(this.player, event); + if (event.isCancelled()) { + buf.clear(); + } else if (!event.changed()) { + buf.readerIndex(preProcessIndex); + } + } + } } private void onNMSPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { @@ -618,9 +644,15 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes .ifPresent(function -> function.accept(user, event, packet)); } - protected void handleByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { + protected void handleS2CByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - Optional.ofNullable(BYTE_BUFFER_PACKET_HANDLERS.get(packetID)) + Optional.ofNullable(S2C_BYTE_BUFFER_PACKET_HANDLERS.get(packetID)) + .ifPresent(function -> function.accept(user, event)); + } + + protected void handleC2SByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { + int packetID = event.packetID(); + Optional.ofNullable(C2S_BYTE_BUFFER_PACKET_HANDLERS.get(packetID)) .ifPresent(function -> function.accept(user, event)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index 919f8c62b..51d20ad81 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -366,6 +366,21 @@ public class AbstractItem, I> implements Item { this.factory.setComponent(this.item, type, value); } + @Override + public void setJavaComponent(Object type, Object value) { + this.factory.setJavaComponent(this.item, type, value); + } + + @Override + public void setJsonComponent(Object type, JsonElement value) { + this.factory.setJsonComponent(this.item, type, value); + } + + @Override + public void setNBTComponent(Object type, Tag value) { + this.factory.setNBTComponent(this.item, type, value); + } + @Override public void resetComponent(Object type) { this.factory.resetComponent(this.item, type); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index e2c005e07..97770fd37 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -151,6 +151,12 @@ public interface Item { void setComponent(Object type, Object value); + void setJavaComponent(Object type, Object value); + + void setJsonComponent(Object type, JsonElement value); + + void setNBTComponent(Object type, Tag value); + void resetComponent(Object type); I getItem(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index ea15a3823..04777f90e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -185,4 +185,10 @@ public abstract class ItemFactory, I> { protected abstract Optional equippable(W item); protected abstract byte[] toByteArray(W item); + + protected abstract void setJavaComponent(W item, Object type, Object value); + + protected abstract void setJsonComponent(W item, Object type, JsonElement value); + + protected abstract void setNBTComponent(W item, Object type, Tag value); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index c1abe066b..9760a00e4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -175,6 +175,14 @@ public class AdventureHelper { return getInstance().gsonComponentSerializer.deserializeFromTree(json); } + public static Component nbtToComponent(Tag tag) { + return getInstance().nbtComponentSerializer.deserialize(tag); + } + + public static Tag componentToNbt(Component component) { + return getInstance().nbtComponentSerializer.serialize(component); + } + /** * Converts a Component to a JSON string. * diff --git a/gradle.properties b/gradle.properties index 4a1852463..601a89f27 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,7 +39,7 @@ geantyref_version=1.3.16 zstd_version=1.5.7-2 commons_io_version=2.18.0 commons_imaging_version=1.0.0-alpha6 -sparrow_nbt_version=0.8.1 +sparrow_nbt_version=0.8.2 sparrow_util_version=0.47 fastutil_version=8.5.15 netty_version=4.1.121.Final diff --git a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java deleted file mode 100644 index 4fae02230..000000000 --- a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.momirealms.craftengine.mod.item; - -import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.NotNull; - -import java.util.function.Function; - -public class CustomStreamCodec { - public static Function clientBoundDataProcessor; - public static Function serverBoundDataProcessor; - - public static @NotNull ItemStack s2c(@NotNull ItemStack itemStack) { - if (clientBoundDataProcessor != null) { - itemStack = clientBoundDataProcessor.apply(itemStack); - } - return itemStack; - } - - public static @NotNull ItemStack c2s(@NotNull ItemStack itemStack) { - if (serverBoundDataProcessor != null) { - itemStack = serverBoundDataProcessor.apply(itemStack); - } - return itemStack; - } -} \ No newline at end of file diff --git a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/mixin/FriendlyByteBufMixin.java b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/mixin/FriendlyByteBufMixin.java deleted file mode 100644 index 2e3fae0e7..000000000 --- a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/mixin/FriendlyByteBufMixin.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.momirealms.craftengine.mod.mixin; - -import com.llamalad7.mixinextras.injector.ModifyReturnValue; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.item.ItemStack; -import net.momirealms.craftengine.mod.item.CustomStreamCodec; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; - -@Mixin(value = FriendlyByteBuf.class) -public class FriendlyByteBufMixin { - - @ModifyVariable( - method = "a(Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/network/PacketDataSerializer;", - at = @At("HEAD"), - argsOnly = true - ) - private ItemStack modifyWriteItemParam(ItemStack stack) { - return stack.isEmpty() ? stack : CustomStreamCodec.s2c(stack); - } - - @ModifyReturnValue( - method = "r()Lnet/minecraft/world/item/ItemStack;", - at = @At("RETURN") - ) - private ItemStack modifyReadItemStack(ItemStack original) { - return original.isEmpty() ? original : CustomStreamCodec.c2s(original); - } -} diff --git a/server-mod/v1_20_1/src/main/resources/mixins.craftengine.json b/server-mod/v1_20_1/src/main/resources/mixins.craftengine.json index b6396bab4..69e19f9d0 100644 --- a/server-mod/v1_20_1/src/main/resources/mixins.craftengine.json +++ b/server-mod/v1_20_1/src/main/resources/mixins.craftengine.json @@ -6,7 +6,6 @@ "target": "@env(DEFAULT)", "compatibilityLevel": "JAVA_21", "server": [ - "BlocksMixin", - "FriendlyByteBufMixin" + "BlocksMixin" ] } diff --git a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java deleted file mode 100644 index 2d1a47861..000000000 --- a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.momirealms.craftengine.mod.item; - -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.NotNull; - -import java.util.Objects; -import java.util.function.Function; - -public class CustomStreamCodec implements StreamCodec { - public static Function clientBoundDataProcessor; - public static Function serverBoundDataProcessor; - - private final StreamCodec original; - - public CustomStreamCodec(StreamCodec original) { - this.original = Objects.requireNonNull(original); - } - - @Override - public @NotNull ItemStack decode(@NotNull RegistryFriendlyByteBuf buffer) { - ItemStack itemStack = this.original.decode(buffer); - if (!itemStack.isEmpty()) { - if (serverBoundDataProcessor != null) { - itemStack = serverBoundDataProcessor.apply(itemStack); - } - } - return itemStack; - } - - @Override - public void encode(@NotNull RegistryFriendlyByteBuf buffer, @NotNull ItemStack value) { - if (!value.isEmpty()) { - if (clientBoundDataProcessor != null) { - value = clientBoundDataProcessor.apply(value); - } - } - this.original.encode(buffer, value); - } -} \ No newline at end of file diff --git a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java deleted file mode 100644 index 726e9981d..000000000 --- a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java +++ /dev/null @@ -1,48 +0,0 @@ -package net.momirealms.craftengine.mod.mixin; - -import net.minecraft.core.NonNullList; -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.ByteBufCodecs; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.world.item.ItemStack; -import net.momirealms.craftengine.mod.item.CustomStreamCodec; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.List; - -@Mixin(ItemStack.class) -public abstract class ItemStackMixin { - @Shadow(remap = false) - @Mutable - public static StreamCodec OPTIONAL_STREAM_CODEC; - @Shadow(remap = false) - @Mutable - public static StreamCodec> OPTIONAL_LIST_STREAM_CODEC; - - private static StreamCodec ORIGINAL_OPTIONAL_STREAM_CODEC; - - @Inject( - method = "", - at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/item/ItemStack;OPTIONAL_STREAM_CODEC:Lnet/minecraft/network/codec/StreamCodec;", - opcode = Opcodes.PUTSTATIC, - shift = At.Shift.AFTER - ) - ) - private static void captureOriginalAfterAssignment(CallbackInfo ci) { - ORIGINAL_OPTIONAL_STREAM_CODEC = OPTIONAL_STREAM_CODEC; - } - - @Inject(method = "", at = @At("RETURN")) - private static void replaceStreamCodec(CallbackInfo ci) { - OPTIONAL_STREAM_CODEC = new CustomStreamCodec(ORIGINAL_OPTIONAL_STREAM_CODEC); - OPTIONAL_LIST_STREAM_CODEC = OPTIONAL_STREAM_CODEC.apply(ByteBufCodecs.collection(NonNullList::createWithCapacity)); - } -} diff --git a/server-mod/v1_20_5/src/main/resources/mixins.craftengine.json b/server-mod/v1_20_5/src/main/resources/mixins.craftengine.json index 288b6501f..69e19f9d0 100644 --- a/server-mod/v1_20_5/src/main/resources/mixins.craftengine.json +++ b/server-mod/v1_20_5/src/main/resources/mixins.craftengine.json @@ -6,7 +6,6 @@ "target": "@env(DEFAULT)", "compatibilityLevel": "JAVA_21", "server": [ - "BlocksMixin", - "ItemStackMixin" + "BlocksMixin" ] } diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java deleted file mode 100644 index 2d1a47861..000000000 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/item/CustomStreamCodec.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.momirealms.craftengine.mod.item; - -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.world.item.ItemStack; -import org.jetbrains.annotations.NotNull; - -import java.util.Objects; -import java.util.function.Function; - -public class CustomStreamCodec implements StreamCodec { - public static Function clientBoundDataProcessor; - public static Function serverBoundDataProcessor; - - private final StreamCodec original; - - public CustomStreamCodec(StreamCodec original) { - this.original = Objects.requireNonNull(original); - } - - @Override - public @NotNull ItemStack decode(@NotNull RegistryFriendlyByteBuf buffer) { - ItemStack itemStack = this.original.decode(buffer); - if (!itemStack.isEmpty()) { - if (serverBoundDataProcessor != null) { - itemStack = serverBoundDataProcessor.apply(itemStack); - } - } - return itemStack; - } - - @Override - public void encode(@NotNull RegistryFriendlyByteBuf buffer, @NotNull ItemStack value) { - if (!value.isEmpty()) { - if (clientBoundDataProcessor != null) { - value = clientBoundDataProcessor.apply(value); - } - } - this.original.encode(buffer, value); - } -} \ No newline at end of file diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java deleted file mode 100644 index 88bc5d916..000000000 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/mixin/ItemStackMixin.java +++ /dev/null @@ -1,66 +0,0 @@ -package net.momirealms.craftengine.mod.mixin; - -import net.minecraft.core.NonNullList; -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.ByteBufCodecs; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.world.item.ItemStack; -import net.momirealms.craftengine.mod.item.CustomStreamCodec; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.List; - -@Mixin(ItemStack.class) -public abstract class ItemStackMixin { - @Shadow(remap = false) - @Mutable - public static StreamCodec OPTIONAL_STREAM_CODEC; - @Shadow(remap = false) - @Mutable - public static StreamCodec> OPTIONAL_LIST_STREAM_CODEC; - @Shadow(remap = false) - @Mutable - public static StreamCodec OPTIONAL_UNTRUSTED_STREAM_CODEC; - - private static StreamCodec ORIGINAL_OPTIONAL_STREAM_CODEC; - private static StreamCodec ORIGINAL_OPTIONAL_UNTRUSTED_STREAM_CODEC; - - @Inject( - method = "", - at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/item/ItemStack;OPTIONAL_STREAM_CODEC:Lnet/minecraft/network/codec/StreamCodec;", - opcode = Opcodes.PUTSTATIC, - shift = At.Shift.AFTER - ) - ) - private static void captureOriginalAfterAssignment0(CallbackInfo ci) { - ORIGINAL_OPTIONAL_STREAM_CODEC = OPTIONAL_STREAM_CODEC; - } - - @Inject( - method = "", - at = @At( - value = "FIELD", - target = "Lnet/minecraft/world/item/ItemStack;OPTIONAL_UNTRUSTED_STREAM_CODEC:Lnet/minecraft/network/codec/StreamCodec;", - opcode = Opcodes.PUTSTATIC, - shift = At.Shift.AFTER - ) - ) - private static void captureOriginalAfterAssignment1(CallbackInfo ci) { - ORIGINAL_OPTIONAL_UNTRUSTED_STREAM_CODEC = OPTIONAL_UNTRUSTED_STREAM_CODEC; - } - - @Inject(method = "", at = @At("RETURN")) - private static void replaceStreamCodec(CallbackInfo ci) { - OPTIONAL_STREAM_CODEC = new CustomStreamCodec(ORIGINAL_OPTIONAL_STREAM_CODEC); - OPTIONAL_UNTRUSTED_STREAM_CODEC = new CustomStreamCodec(ORIGINAL_OPTIONAL_UNTRUSTED_STREAM_CODEC); - OPTIONAL_LIST_STREAM_CODEC = OPTIONAL_STREAM_CODEC.apply(ByteBufCodecs.collection(NonNullList::createWithCapacity)); - } -} From 4e81a63d035bc988fa284bb911378147eb2f1bc7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 28 May 2025 01:11:17 +0800 Subject: [PATCH 71/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=85=B6=E4=BB=96?= =?UTF-8?q?=E7=89=A9=E5=93=81=E7=9A=84=E5=90=8D=E7=A7=B0=E6=8B=A6=E6=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/ModernNetworkItemHandler.java | 55 ++++++++++++++++++- .../plugin/network/BukkitNetworkManager.java | 1 + 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java index fadbbe8ce..f6f3197a1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java @@ -74,10 +74,13 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { public Optional process() { if (VersionHelper.isOrAbove1_21_5()) { processModernLore(); + processModernCustomName(); + processModernItemName(); } else { processLore(); + processCustomName(); + processItemName(); } - if (this.globalChanged) { CompoundTag customData = Optional.ofNullable(this.item.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag()); customData.put(NETWORK_ITEM_TAG, getOrCreateTag()); @@ -115,6 +118,56 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { } } + private void processItemName() { + Optional optionalItemName = this.item.itemNameJson(); + if (optionalItemName.isPresent()) { + String line = optionalItemName.get(); + Map tokens = CraftEngine.instance().fontManager().matchTags(line); + if (!tokens.isEmpty()) { + this.item.itemNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); + this.globalChanged = true; + getOrCreateTag().put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(Operation.ADD, new StringTag(line))); + } + } + } + + private void processModernItemName() { + Tag nameTag = this.item.getNBTComponent(ComponentTypes.ITEM_NAME); + if (nameTag == null) return; + String tagStr = nameTag.getAsString(); + Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); + if (!tokens.isEmpty()) { + this.item.setNBTComponent(ComponentKeys.ITEM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens))); + this.globalChanged = true; + getOrCreateTag().put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(Operation.ADD, nameTag)); + } + } + + private void processCustomName() { + Optional optionalCustomName = this.item.customNameJson(); + if (optionalCustomName.isPresent()) { + String line = optionalCustomName.get(); + Map tokens = CraftEngine.instance().fontManager().matchTags(line); + if (!tokens.isEmpty()) { + this.item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); + this.globalChanged = true; + getOrCreateTag().put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(Operation.ADD, new StringTag(line))); + } + } + } + + private void processModernCustomName() { + Tag nameTag = this.item.getNBTComponent(ComponentTypes.CUSTOM_NAME); + if (nameTag == null) return; + String tagStr = nameTag.getAsString(); + Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); + if (!tokens.isEmpty()) { + this.item.setNBTComponent(ComponentKeys.CUSTOM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens))); + this.globalChanged = true; + getOrCreateTag().put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(Operation.ADD, nameTag)); + } + } + private void processModernLore() { Tag loreTag = this.item.getNBTComponent(ComponentTypes.LORE); if (loreTag == null) return; 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 623f5c11f..1bb9a7944 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 @@ -40,6 +40,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static BukkitNetworkManager instance; private static final Map, TriConsumer> NMS_PACKET_HANDLERS = new HashMap<>(); // only for game stage for the moment + // todo 优化成 数组 private static final Map> S2C_BYTE_BUFFER_PACKET_HANDLERS = new HashMap<>(); private static final Map> C2S_BYTE_BUFFER_PACKET_HANDLERS = new HashMap<>(); From 6ff6fb19c86d391415a3a5ebd478f7b87e1d3ebd Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 28 May 2025 02:17:29 +0800 Subject: [PATCH 72/89] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=8F=91=E5=8C=85?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitItemManager.java | 13 ++++-- .../bukkit/item/LegacyNetworkItemHandler.java | 26 +++++++++++ .../bukkit/item/ModernNetworkItemHandler.java | 43 ++++++++++--------- .../core/item/AbstractCustomItem.java | 21 +-------- .../craftengine/core/item/CustomItem.java | 2 - .../core/item/NetworkItemDataProcessor.java | 27 ------------ .../core}/item/NetworkItemHandler.java | 30 +++++++------ .../core/item/modifier/ComponentModifier.java | 20 ++++----- .../modifier/CustomModelDataModifier.java | 16 ++++++- .../item/modifier/CustomNameModifier.java | 16 ++++++- .../item/modifier/EnchantmentModifier.java | 13 +++--- .../item/modifier/EquippableModifier.java | 5 --- .../core/item/modifier/ExternalModifier.java | 5 --- .../core/item/modifier/IdModifier.java | 5 --- .../core/item/modifier/ItemDataModifier.java | 4 +- .../core/item/modifier/ItemModelModifier.java | 14 +++++- .../core/item/modifier/ItemNameModifier.java | 16 ++++++- .../item/modifier/JukeboxSongModifier.java | 5 --- .../core/item/modifier/LoreModifier.java | 16 ++++++- .../modifier/RemoveComponentModifier.java | 14 ++++-- .../core/item/modifier/TagsModifier.java | 7 --- .../item/modifier/TooltipStyleModifier.java | 14 +++++- .../core/item/modifier/TrimModifier.java | 5 --- .../item/modifier/UnbreakableModifier.java | 16 +++++-- 24 files changed, 198 insertions(+), 155 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemDataProcessor.java rename {bukkit/src/main/java/net/momirealms/craftengine/bukkit => core/src/main/java/net/momirealms/craftengine/core}/item/NetworkItemHandler.java (58%) 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 60d9e2167..0b51af970 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 @@ -24,6 +24,7 @@ import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; +import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -48,7 +49,7 @@ public class BukkitItemManager extends AbstractItemManager { private final ItemEventListener itemEventListener; private final DebugStickListener debugStickListener; private final ArmorEventListener armorEventListener; - private final NetworkItemHandler networkItemHandler; + private final NetworkItemHandler networkItemHandler; public BukkitItemManager(BukkitCraftEngine plugin) { super(plugin); @@ -58,7 +59,7 @@ public class BukkitItemManager extends AbstractItemManager { this.itemEventListener = new ItemEventListener(plugin); this.debugStickListener = new DebugStickListener(plugin); this.armorEventListener = new ArmorEventListener(); - this.networkItemHandler = new ModernNetworkItemHandler(this); + this.networkItemHandler = VersionHelper.isOrAbove1_20_5() ? new ModernNetworkItemHandler(this) : new LegacyNetworkItemHandler(this); this.registerAllVanillaItems(); } @@ -75,7 +76,9 @@ public class BukkitItemManager extends AbstractItemManager { public Optional s2c(ItemStack itemStack, ItemBuildContext context) { try { - return this.networkItemHandler.s2c(itemStack, context); + Item wrapped = wrap(itemStack); + if (wrapped == null) return Optional.empty(); + return this.networkItemHandler.s2c(wrapped, context).map(Item::load); } catch (Throwable e) { if (Config.debug()) { this.plugin.logger().warn("Failed to handle s2c items.", e); @@ -86,7 +89,9 @@ public class BukkitItemManager extends AbstractItemManager { public Optional c2s(ItemStack itemStack, ItemBuildContext context) { try { - return this.networkItemHandler.c2s(itemStack, context); + Item wrapped = wrap(itemStack); + if (wrapped == null) return Optional.empty(); + return this.networkItemHandler.c2s(wrapped, context).map(Item::load); } catch (Throwable e) { if (Config.debug()) { this.plugin.logger().warn("Failed to handle c2s items.", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java new file mode 100644 index 000000000..b09bf7b5c --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java @@ -0,0 +1,26 @@ +package net.momirealms.craftengine.bukkit.item; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import org.bukkit.inventory.ItemStack; + +import java.util.Optional; + +public class LegacyNetworkItemHandler implements NetworkItemHandler { + private final BukkitItemManager itemManager; + + public LegacyNetworkItemHandler(BukkitItemManager itemManager) { + this.itemManager = itemManager; + } + + @Override + public Optional> c2s(Item itemStack, ItemBuildContext context) { + return Optional.empty(); + } + + @Override + public Optional> s2c(Item itemStack, ItemBuildContext context) { + return Optional.empty(); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java index f6f3197a1..ab90e1751 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java @@ -1,10 +1,8 @@ package net.momirealms.craftengine.bukkit.item; import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.core.item.ComponentKeys; -import net.momirealms.craftengine.core.item.CustomItem; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.*; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; @@ -20,7 +18,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; -public class ModernNetworkItemHandler implements NetworkItemHandler { +public class ModernNetworkItemHandler implements NetworkItemHandler { private final BukkitItemManager itemManager; public ModernNetworkItemHandler(BukkitItemManager itemManager) { @@ -28,9 +26,7 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { } @Override - public Optional c2s(ItemStack itemStack, ItemBuildContext context) { - Item wrapped = this.itemManager.wrap(itemStack); - if (wrapped == null) return Optional.empty(); + public Optional> c2s(Item wrapped, ItemBuildContext context) { Tag customData = wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA); if (!(customData instanceof CompoundTag compoundTag)) return Optional.empty(); CompoundTag networkData = compoundTag.getCompound(NETWORK_ITEM_TAG); @@ -41,24 +37,31 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { NetworkItemHandler.apply(entry.getKey(), tag, wrapped); } } - if (compoundTag.isEmpty()) { - wrapped.resetComponent(ComponentTypes.CUSTOM_DATA); - } else { - wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, compoundTag); - } - return Optional.of(wrapped.load()); + // todo 可能会是 !custom_data吗,不可能,绝对不可能! + if (compoundTag.isEmpty()) wrapped.resetComponent(ComponentTypes.CUSTOM_DATA); + else wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, compoundTag); + return Optional.of(wrapped); } @Override - public Optional s2c(ItemStack itemStack, ItemBuildContext context) { - Item wrapped = this.itemManager.wrap(itemStack); - if (wrapped == null) return Optional.empty(); + public Optional> s2c(Item wrapped, ItemBuildContext context) { Optional> optionalCustomItem = wrapped.getCustomItem(); if (optionalCustomItem.isEmpty()) { if (!Config.interceptItem()) return Optional.empty(); return new OtherItem(wrapped).process(); } else { - return Optional.empty(); + CustomItem customItem = optionalCustomItem.get(); + if (!customItem.hasClientBoundDataModifier()) return Optional.empty(); + CompoundTag customData = Optional.ofNullable(wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag()); + CompoundTag tag = new CompoundTag(); + for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { + modifier.prepareNetworkItem(wrapped, context, tag); + modifier.apply(wrapped, context); + } + if (tag.isEmpty()) return Optional.empty(); + customData.put(NETWORK_ITEM_TAG, tag); + wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, customData); + return Optional.of(wrapped); } } @@ -71,7 +74,7 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { this.item = item; } - public Optional process() { + public Optional> process() { if (VersionHelper.isOrAbove1_21_5()) { processModernLore(); processModernCustomName(); @@ -85,7 +88,7 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { CompoundTag customData = Optional.ofNullable(this.item.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag()); customData.put(NETWORK_ITEM_TAG, getOrCreateTag()); this.item.setNBTComponent(ComponentKeys.CUSTOM_DATA, customData); - return Optional.of(this.item.load()); + return Optional.of(this.item); } else { return Optional.empty(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java index ddbf3d8ec..60b254bf7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java @@ -20,11 +20,9 @@ public abstract class AbstractCustomItem implements CustomItem { protected final Map> modifierMap; protected final ItemDataModifier[] clientBoundModifiers; protected final Map> clientBoundModifierMap; - protected final NetworkItemDataProcessor[] networkItemDataProcessors; protected final List behaviors; protected final ItemSettings settings; protected final Map>> events; - protected final Item base; @SuppressWarnings("unchecked") public AbstractCustomItem(Holder id, Key material, @@ -48,20 +46,8 @@ public abstract class AbstractCustomItem implements CustomItem { } this.modifierMap = modifierMapBuilder.build(); ImmutableMap.Builder> clientSideModifierMapBuilder = ImmutableMap.builder(); - List> networkItemDataProcessors = new ArrayList<>(); - for (ItemDataModifier modifier : clientBoundModifiers) { - String name = modifier.name(); - clientSideModifierMapBuilder.put(name, modifier); - if (this.modifierMap.containsKey(name)) { - networkItemDataProcessors.add(NetworkItemDataProcessor.both(this.modifierMap.get(name), modifier)); - } else { - networkItemDataProcessors.add(NetworkItemDataProcessor.clientOnly(modifier)); - } - } this.clientBoundModifierMap = clientSideModifierMapBuilder.build(); - // unchecked cast - this.networkItemDataProcessors = networkItemDataProcessors.toArray(new NetworkItemDataProcessor[0]); - this.base = (Item) CraftEngine.instance().itemManager().wrap(CraftEngine.instance().itemManager().getVanillaItem(material).get().buildItemStack()); + } @Override @@ -86,11 +72,6 @@ public abstract class AbstractCustomItem implements CustomItem { return this.material; } - @Override - public NetworkItemDataProcessor[] networkItemDataProcessors() { - return this.networkItemDataProcessors; - } - @Override public ItemDataModifier[] dataModifiers() { return this.modifiers; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index 5d8639a8d..89078fb27 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -21,8 +21,6 @@ public interface CustomItem extends BuildableItem { Key material(); - NetworkItemDataProcessor[] networkItemDataProcessors(); - ItemDataModifier[] dataModifiers(); Map> dataModifierMap(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemDataProcessor.java b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemDataProcessor.java deleted file mode 100644 index 352559f86..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemDataProcessor.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.momirealms.craftengine.core.item; - -import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public record NetworkItemDataProcessor(@Nullable ItemDataModifier server, @NotNull ItemDataModifier client) { - - public static NetworkItemDataProcessor clientOnly(ItemDataModifier client) { - return new NetworkItemDataProcessor<>(null, client); - } - - public static NetworkItemDataProcessor both(ItemDataModifier server, ItemDataModifier client) { - return new NetworkItemDataProcessor<>(server, client); - } - - public void toClient(Item item, ItemBuildContext context) { - this.client.apply(item, context); - } - - public void toServer(Item item, ItemBuildContext context) { - this.client.remove(item); - if (this.server != null) { - this.server.apply(item, context); - } - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java similarity index 58% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java rename to core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java index aa2b6862f..c6d9a0138 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/NetworkItemHandler.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java @@ -1,31 +1,37 @@ -package net.momirealms.craftengine.bukkit.item; +package net.momirealms.craftengine.core.item; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.util.TriConsumer; import net.momirealms.sparrow.nbt.ByteTag; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; -import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.Optional; -public interface NetworkItemHandler { +public interface NetworkItemHandler { Operation[] BY_INDEX = new Operation[] {Operation.ADD, Operation.REMOVE, Operation.RESET}; String NETWORK_ITEM_TAG = "craftengine:network"; String NETWORK_OPERATION = "type"; String NETWORK_VALUE = "value"; - Optional s2c(ItemStack itemStack, ItemBuildContext context); + Optional> s2c(Item itemStack, ItemBuildContext context); - Optional c2s(ItemStack itemStack, ItemBuildContext context); + Optional> c2s(Item itemStack, ItemBuildContext context); - static CompoundTag pack(Operation operation, Tag value) { - return new CompoundTag(Map.of(NETWORK_OPERATION, operation.tag(), NETWORK_VALUE, value)); + static CompoundTag pack(Operation operation, @Nullable Tag value) { + if (value == null) { + return new CompoundTag(Map.of(NETWORK_OPERATION, operation.tag())); + } else { + return new CompoundTag(Map.of(NETWORK_OPERATION, operation.tag(), NETWORK_VALUE, value)); + } } - static void apply(String componentType, CompoundTag networkData, Item item) { + static CompoundTag pack(Operation operation) { + return new CompoundTag(Map.of(NETWORK_OPERATION, operation.tag())); + } + + static void apply(String componentType, CompoundTag networkData, Item item) { byte index = networkData.getByte(NETWORK_OPERATION); Operation operation = BY_INDEX[index]; operation.consumer.accept(item, componentType, operation == Operation.ADD ? networkData.get(NETWORK_VALUE) : null); @@ -38,9 +44,9 @@ public interface NetworkItemHandler { private final int id; private final ByteTag tag; - private final TriConsumer, String, Tag> consumer; + private final TriConsumer, String, Tag> consumer; - Operation(int id, TriConsumer, String, Tag> consumer) { + Operation(int id, TriConsumer, String, Tag> consumer) { this.id = id; this.tag = new ByteTag((byte) id); this.consumer = consumer; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java index d13e28e4b..5c769b2bc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java @@ -5,9 +5,12 @@ import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Pair; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; import java.util.ArrayList; import java.util.List; @@ -75,18 +78,13 @@ public class ComponentModifier implements ItemDataModifier { } @Override - public void remove(Item item) { + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { for (Pair entry : this.arguments) { - item.resetComponent(entry.left()); - } - if (this.customData != null) { - JsonObject tag = (JsonObject) item.getJavaComponent(ComponentKeys.CUSTOM_DATA); - if (tag != null) { - // crude method - for (String key : this.customData.keySet()) { - tag.remove(key); - } - item.setComponent(ComponentKeys.CUSTOM_DATA, tag); + Tag previous = item.getNBTComponent(entry.left()); + if (previous != null) { + networkData.put(entry.left().asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(entry.left().asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java index 68a71ed3d..359b7b50d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java @@ -1,7 +1,12 @@ package net.momirealms.craftengine.core.item.modifier; +import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; public class CustomModelDataModifier implements ItemDataModifier { private final int argument; @@ -21,7 +26,14 @@ public class CustomModelDataModifier implements ItemDataModifier { } @Override - public void remove(Item item) { - item.customModelData(null); + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.CUSTOM_MODEL_DATA); + if (previous != null) { + networkData.put(ComponentKeys.CUSTOM_MODEL_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.CUSTOM_MODEL_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java index 6814092ce..aca62cdcd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java @@ -1,9 +1,14 @@ package net.momirealms.craftengine.core.item.modifier; +import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; public class CustomNameModifier implements ItemDataModifier { private final String argument; @@ -23,7 +28,14 @@ public class CustomNameModifier implements ItemDataModifier { } @Override - public void remove(Item item) { - item.customNameJson(null); + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.CUSTOM_NAME); + if (previous != null) { + networkData.put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java index 15c2137b6..54c5ad10f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java @@ -21,13 +21,10 @@ public class EnchantmentModifier implements ItemDataModifier { @Override public void apply(Item item, ItemBuildContext context) { - if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) item.setStoredEnchantments(enchantments); - else item.setEnchantments(enchantments); - } - - @Override - public void remove(Item item) { - if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) item.setStoredEnchantments(null); - else item.setEnchantments(null); + if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { + item.setStoredEnchantments(this.enchantments); + } else { + item.setEnchantments(this.enchantments); + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java index 1f470455d..52845cb07 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java @@ -20,9 +20,4 @@ public class EquippableModifier implements ItemDataModifier { public void apply(Item item, ItemBuildContext context) { item.equippable(this.data); } - - @Override - public void remove(Item item) { - item.equippable(null); - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java index 76219096e..0cf95a6e1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java @@ -30,9 +30,4 @@ public class ExternalModifier implements ItemDataModifier { Item anotherWrapped = (Item) CraftEngine.instance().itemManager().wrap(another); item.merge(anotherWrapped); } - - @Override - public void remove(Item item) { - // cannot remove - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java index 4ed13c5a0..e82c960dc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java @@ -21,9 +21,4 @@ public class IdModifier implements ItemDataModifier { public void apply(Item item, ItemBuildContext context) { item.customId(this.argument); } - - @Override - public void remove(Item item) { - // WHY DO YOU WANT TO REMOVE CRAFTENGINE ID? - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java index 46258a96f..73720c53a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java @@ -2,6 +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.sparrow.nbt.CompoundTag; public interface ItemDataModifier { @@ -9,5 +10,6 @@ public interface ItemDataModifier { void apply(Item item, ItemBuildContext context); - void remove(Item item); + default void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java index b2e1b031b..50cb28f68 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java @@ -1,8 +1,13 @@ package net.momirealms.craftengine.core.item.modifier; +import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; public class ItemModelModifier implements ItemDataModifier { private final Key data; @@ -22,7 +27,12 @@ public class ItemModelModifier implements ItemDataModifier { } @Override - public void remove(Item item) { - item.itemModel(null); + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + Tag previous = item.getNBTComponent(ComponentKeys.ITEM_MODEL); + if (previous != null) { + networkData.put(ComponentKeys.ITEM_MODEL.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.ITEM_MODEL.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } } } 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 b575874f0..1655179e4 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 @@ -1,9 +1,14 @@ package net.momirealms.craftengine.core.item.modifier; +import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; public class ItemNameModifier implements ItemDataModifier { private final String argument; @@ -23,7 +28,14 @@ public class ItemNameModifier implements ItemDataModifier { } @Override - public void remove(Item item) { - item.itemNameJson(null); + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.ITEM_NAME); + if (previous != null) { + networkData.put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java index 6f323c087..b8523edd2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java @@ -20,9 +20,4 @@ public class JukeboxSongModifier implements ItemDataModifier { public void apply(Item item, ItemBuildContext context) { item.jukeboxSong(this.song); } - - @Override - public void remove(Item item) { - item.jukeboxSong(null); - } } 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 5bda4c5d5..0b2a8e412 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 @@ -1,9 +1,14 @@ package net.momirealms.craftengine.core.item.modifier; +import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; import java.util.List; @@ -26,7 +31,14 @@ public class LoreModifier implements ItemDataModifier { } @Override - public void remove(Item item) { - item.loreJson(null); + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.LORE); + if (previous != null) { + networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java index b44deeca0..90dbb508c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java @@ -2,6 +2,9 @@ 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.item.NetworkItemHandler; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; import java.util.Collections; import java.util.List; @@ -24,13 +27,18 @@ public class RemoveComponentModifier implements ItemDataModifier { @Override public void apply(Item item, ItemBuildContext context) { - for (String argument : arguments) { + for (String argument : this.arguments) { item.removeComponent(argument); } } @Override - public void remove(Item item) { - // I can't guess + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + for (String component : this.arguments) { + Tag previous = item.getNBTComponent(component); + if (previous != null) { + networkData.put(component, NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java index 69c29c859..c49ae4cbc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java @@ -33,13 +33,6 @@ public class TagsModifier implements ItemDataModifier { } } - @Override - public void remove(Item item) { - for (Map.Entry entry : arguments.entrySet()) { - item.removeTag(entry.getKey()); - } - } - private static Map mapToMap(final Map source) { Map resultMap = new LinkedHashMap<>(); recursiveMapProcessing(source, resultMap); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java index 3e078af4b..36ebfed1d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java @@ -1,8 +1,13 @@ package net.momirealms.craftengine.core.item.modifier; +import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; public class TooltipStyleModifier implements ItemDataModifier { private final Key argument; @@ -22,7 +27,12 @@ public class TooltipStyleModifier implements ItemDataModifier { } @Override - public void remove(Item item) { - item.tooltipStyle(null); + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + Tag previous = item.getNBTComponent(ComponentKeys.TOOLTIP_STYLE); + if (previous != null) { + networkData.put(ComponentKeys.TOOLTIP_STYLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.TOOLTIP_STYLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java index 011809750..e3a9e5cf1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java @@ -22,9 +22,4 @@ public class TrimModifier implements ItemDataModifier { public void apply(Item item, ItemBuildContext context) { item.trim(new Trim(this.material, this.pattern)); } - - @Override - public void remove(Item item) { - item.trim(null); - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java index c673c82a4..3e3f2b93c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java @@ -1,7 +1,12 @@ package net.momirealms.craftengine.core.item.modifier; +import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; public class UnbreakableModifier implements ItemDataModifier { private final boolean argument; @@ -21,9 +26,14 @@ public class UnbreakableModifier implements ItemDataModifier { } @Override - public void remove(Item item) { - if (this.argument) { - item.unbreakable(false); + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.UNBREAKABLE); + if (previous != null) { + networkData.put(ComponentKeys.UNBREAKABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.UNBREAKABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } } } } From 4adcadac8f659f72989b6596158182cea8c30a2d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 28 May 2025 02:32:21 +0800 Subject: [PATCH 73/89] Update BukkitBlockInWorld.java --- .../craftengine/bukkit/world/BukkitBlockInWorld.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java index 67c8e080c..0a7cee294 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java @@ -12,6 +12,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; @@ -40,10 +41,12 @@ public class BukkitBlockInWorld implements BlockInWorld { Optional> customItem = BukkitItemManager.instance().getCustomItem(item.id()); if (customItem.isPresent()) { CustomItem custom = customItem.get(); - if (custom.behaviors() instanceof BlockItemBehavior blockItemBehavior) { - Key blockId = blockItemBehavior.blockId(); - if (blockId.equals(clickedBlockId)) { - return false; + for (ItemBehavior behavior : custom.behaviors()) { + if (behavior instanceof BlockItemBehavior blockItemBehavior) { + Key blockId = blockItemBehavior.blockId(); + if (blockId.equals(clickedBlockId)) { + return false; + } } } } From 2b8f103d4b5031e5e4afe1bf8ea355354edb026c Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Wed, 28 May 2025 02:47:55 +0800 Subject: [PATCH 74/89] =?UTF-8?q?feat(network):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E4=BE=A7=E7=89=A9=E5=93=81=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 25 +++++++++++++------ .../plugin/network/PacketConsumers.java | 5 ++-- .../plugin/network/id/PacketIdFinder.java | 20 +++++++++++++++ .../craftengine/bukkit/util/Reflections.java | 2 +- 4 files changed, 42 insertions(+), 10 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 1bb9a7944..b874b9d27 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 @@ -9,6 +9,7 @@ import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIdFinder; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20_5; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; @@ -40,9 +41,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static BukkitNetworkManager instance; private static final Map, TriConsumer> NMS_PACKET_HANDLERS = new HashMap<>(); // only for game stage for the moment - // todo 优化成 数组 - private static final Map> S2C_BYTE_BUFFER_PACKET_HANDLERS = new HashMap<>(); - private static final Map> C2S_BYTE_BUFFER_PACKET_HANDLERS = new HashMap<>(); + private static BiConsumer[] S2C_BYTE_BUFFER_PACKET_HANDLERS; + private static BiConsumer[] C2S_BYTE_BUFFER_PACKET_HANDLERS; private static void registerNMSPacketConsumer(final TriConsumer function, @Nullable Class packet) { if (packet == null) return; @@ -51,12 +51,18 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static void registerS2CByteBufPacketConsumer(final BiConsumer function, int id) { if (id == -1) return; - S2C_BYTE_BUFFER_PACKET_HANDLERS.put(id, function); + if (id < 0 || id >= S2C_BYTE_BUFFER_PACKET_HANDLERS.length) { + throw new IllegalArgumentException("Invalid packet id: " + id); + } + S2C_BYTE_BUFFER_PACKET_HANDLERS[id] = function; } private static void registerC2SByteBufPacketConsumer(final BiConsumer function, int id) { if (id == -1) return; - C2S_BYTE_BUFFER_PACKET_HANDLERS.put(id, function); + if (id < 0 || id >= C2S_BYTE_BUFFER_PACKET_HANDLERS.length) { + throw new IllegalArgumentException("Invalid packet id: " + id); + } + C2S_BYTE_BUFFER_PACKET_HANDLERS[id] = function; } private final BiConsumer> packetsConsumer; @@ -81,8 +87,13 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static boolean hasModelEngine; private static boolean hasViaVersion; + @SuppressWarnings("unchecked") public BukkitNetworkManager(BukkitCraftEngine plugin) { instance = this; + S2C_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxS2CPacketId() + 1]; + C2S_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxC2SPacketId() + 1]; + Arrays.fill(S2C_BYTE_BUFFER_PACKET_HANDLERS, (BiConsumer) (user, event) -> {}); + Arrays.fill(C2S_BYTE_BUFFER_PACKET_HANDLERS, (BiConsumer) (user, event) -> {}); hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; hasViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; this.plugin = plugin; @@ -647,13 +658,13 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes protected void handleS2CByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - Optional.ofNullable(S2C_BYTE_BUFFER_PACKET_HANDLERS.get(packetID)) + Optional.ofNullable(S2C_BYTE_BUFFER_PACKET_HANDLERS[packetID]) .ifPresent(function -> function.accept(user, event)); } protected void handleC2SByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - Optional.ofNullable(C2S_BYTE_BUFFER_PACKET_HANDLERS.get(packetID)) + Optional.ofNullable(C2S_BYTE_BUFFER_PACKET_HANDLERS[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 7171b67f2..1f13e2383 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 @@ -2140,11 +2140,12 @@ public class PacketConsumers { buf.writeByte(buttonNum); buf.writeVarInt(clickType); buf.writeVarInt(changedSlots.size()); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); changedSlots.forEach((k, v) -> { buf.writeShort(k); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(buf, v); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, v); }); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(buf, carriedItem); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, carriedItem); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundContainerClickPacket", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java index cff1f93b8..c399ea948 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java @@ -6,12 +6,15 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.VersionHelper; +import java.util.Collections; import java.util.HashMap; import java.util.Map; public class PacketIdFinder { private static final Map> gamePacketIdsByName = new HashMap<>(); private static final Map, Integer>> gamePacketIdsByClazz = new HashMap<>(); + private static final int maxC2SPacketId; + private static final int maxS2CPacketId; static { try { @@ -34,6 +37,23 @@ public class PacketIdFinder { } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to get packets", e); } + maxS2CPacketId = calculateMaxId("clientbound"); + maxC2SPacketId = calculateMaxId("serverbound"); + } + private static int calculateMaxId(String direction) { + if (VersionHelper.isOrAbove1_20_5()) { + return gamePacketIdsByName.getOrDefault(direction, Collections.emptyMap()).size(); + } else { + return gamePacketIdsByClazz.getOrDefault(direction, Collections.emptyMap()).size(); + } + } + + public static int maxC2SPacketId() { + return maxC2SPacketId; + } + + public static int maxS2CPacketId() { + return maxS2CPacketId; } public static int clientboundByName(String 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 fba7a0f92..d07de7afe 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 @@ -41,7 +41,7 @@ import java.util.function.Consumer; import static java.util.Objects.requireNonNull; -@SuppressWarnings("unused") +@SuppressWarnings({"unused", "unchecked"}) public class Reflections { public static void init() { From 85b2bb4196b20267f168dc02e59f3e0431d3cde2 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 28 May 2025 03:56:43 +0800 Subject: [PATCH 75/89] =?UTF-8?q?=E9=87=8D=E6=9E=84add=20entity=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 2 +- .../bukkit/item/ModernNetworkItemHandler.java | 138 ++++++++---------- .../item/factory/BukkitItemFactory.java | 1 - .../bukkit/plugin/BukkitCraftEngine.java | 3 + .../plugin/network/PacketConsumers.java | 107 ++++++++------ .../bukkit/util/RegistryUtils.java | 9 ++ .../craftengine/core/item/ComponentIds.java | 9 ++ .../craftengine/core/item/ComponentKeys.java | 4 +- 8 files changed, 152 insertions(+), 121 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/ComponentIds.java 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 4bbd48d83..03b8034aa 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 @@ -261,7 +261,7 @@ public class BukkitBlockManager extends AbstractBlockManager { finalMapping.put(custom, stoneId); } finalMapping.putAll(this.tempBlockAppearanceConvertor); - PacketConsumers.init(finalMapping, RegistryUtils.currentBlockRegistrySize()); + PacketConsumers.initBlocks(finalMapping, RegistryUtils.currentBlockRegistrySize()); } private void initVanillaRegistry() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java index ab90e1751..c6d40697d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java @@ -6,18 +6,15 @@ import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.ListTag; -import net.momirealms.sparrow.nbt.StringTag; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.Optional; +@SuppressWarnings("DuplicatedCode") public class ModernNetworkItemHandler implements NetworkItemHandler { private final BukkitItemManager itemManager; @@ -51,17 +48,64 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { return new OtherItem(wrapped).process(); } else { CustomItem customItem = optionalCustomItem.get(); - if (!customItem.hasClientBoundDataModifier()) return Optional.empty(); - CompoundTag customData = Optional.ofNullable(wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag()); - CompoundTag tag = new CompoundTag(); - for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { - modifier.prepareNetworkItem(wrapped, context, tag); - modifier.apply(wrapped, context); + if (!customItem.hasClientBoundDataModifier()) { + if (!Config.interceptItem()) return Optional.empty(); + return new OtherItem(wrapped).process(); + } else { + CompoundTag customData = Optional.ofNullable(wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag()); + CompoundTag tag = new CompoundTag(); + for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { + modifier.prepareNetworkItem(wrapped, context, tag); + modifier.apply(wrapped, context); + } + if (Config.interceptItem()) { + if (!tag.containsKey(ComponentIds.ITEM_NAME)) { + Tag nameTag = wrapped.getNBTComponent(ComponentTypes.ITEM_NAME); + if (nameTag != null) { + String tagStr = nameTag.getAsString(); + Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); + if (!tokens.isEmpty()) { + wrapped.setNBTComponent(ComponentKeys.ITEM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens))); + tag.put(ComponentIds.ITEM_NAME, NetworkItemHandler.pack(Operation.ADD, nameTag)); + } + } + } + if (!tag.containsKey(ComponentIds.CUSTOM_NAME)) { + Tag nameTag = wrapped.getNBTComponent(ComponentTypes.CUSTOM_NAME); + if (nameTag != null) { + String tagStr = nameTag.getAsString(); + Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); + if (!tokens.isEmpty()) { + wrapped.setNBTComponent(ComponentKeys.CUSTOM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens))); + tag.put(ComponentIds.CUSTOM_NAME, NetworkItemHandler.pack(Operation.ADD, nameTag)); + } + } + } + if (!tag.containsKey(ComponentIds.LORE)) { + Tag loreTag = wrapped.getNBTComponent(ComponentTypes.LORE); + if (loreTag instanceof ListTag listTag) { + ListTag newLore = new ListTag(); + boolean changed = false; + String tagStr = listTag.getAsString(); + Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); + if (tokens.isEmpty()) { + newLore.add(tag); + } else { + newLore.add(AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(tag), tokens))); + changed = true; + } + if (changed) { + wrapped.setNBTComponent(ComponentKeys.LORE, newLore); + tag.put(ComponentIds.LORE, NetworkItemHandler.pack(Operation.ADD, listTag)); + } + } + } + } + if (tag.isEmpty()) return Optional.empty(); + customData.put(NETWORK_ITEM_TAG, tag); + wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, customData); + return Optional.of(wrapped); } - if (tag.isEmpty()) return Optional.empty(); - customData.put(NETWORK_ITEM_TAG, tag); - wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, customData); - return Optional.of(wrapped); } } @@ -75,15 +119,9 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { } public Optional> process() { - if (VersionHelper.isOrAbove1_21_5()) { - processModernLore(); - processModernCustomName(); - processModernItemName(); - } else { - processLore(); - processCustomName(); - processItemName(); - } + processModernLore(); + processModernCustomName(); + processModernItemName(); if (this.globalChanged) { CompoundTag customData = Optional.ofNullable(this.item.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag()); customData.put(NETWORK_ITEM_TAG, getOrCreateTag()); @@ -94,46 +132,6 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { } } - private void processLore() { - Optional> optionalLore = this.item.loreJson(); - if (optionalLore.isPresent()) { - boolean changed = false; - List lore = optionalLore.get(); - List newLore = new ArrayList<>(lore.size()); - for (String line : lore) { - Map tokens = CraftEngine.instance().fontManager().matchTags(line); - if (tokens.isEmpty()) { - newLore.add(line); - } else { - newLore.add(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); - changed = true; - } - } - if (changed) { - this.globalChanged = true; - this.item.loreJson(newLore); - ListTag listTag = new ListTag(); - for (String line : lore) { - listTag.add(new StringTag(line)); - } - getOrCreateTag().put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(Operation.ADD, listTag)); - } - } - } - - private void processItemName() { - Optional optionalItemName = this.item.itemNameJson(); - if (optionalItemName.isPresent()) { - String line = optionalItemName.get(); - Map tokens = CraftEngine.instance().fontManager().matchTags(line); - if (!tokens.isEmpty()) { - this.item.itemNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); - this.globalChanged = true; - getOrCreateTag().put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(Operation.ADD, new StringTag(line))); - } - } - } - private void processModernItemName() { Tag nameTag = this.item.getNBTComponent(ComponentTypes.ITEM_NAME); if (nameTag == null) return; @@ -146,19 +144,6 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { } } - private void processCustomName() { - Optional optionalCustomName = this.item.customNameJson(); - if (optionalCustomName.isPresent()) { - String line = optionalCustomName.get(); - Map tokens = CraftEngine.instance().fontManager().matchTags(line); - if (!tokens.isEmpty()) { - this.item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); - this.globalChanged = true; - getOrCreateTag().put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(Operation.ADD, new StringTag(line))); - } - } - } - private void processModernCustomName() { Tag nameTag = this.item.getNBTComponent(ComponentTypes.CUSTOM_NAME); if (nameTag == null) return; @@ -173,7 +158,6 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { private void processModernLore() { Tag loreTag = this.item.getNBTComponent(ComponentTypes.LORE); - if (loreTag == null) return; boolean changed = false; if (!(loreTag instanceof ListTag listTag)) { return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index ec9009aa4..45d3ceb87 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.bukkit.item.factory; import com.google.gson.JsonElement; import com.saicone.rtag.item.ItemTagStream; -import net.momirealms.craftengine.bukkit.item.LegacyItemWrapper; import net.momirealms.craftengine.bukkit.util.ItemTags; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.EquipmentData; 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 ab28f1adf..0fb4724e7 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 @@ -19,11 +19,13 @@ import net.momirealms.craftengine.bukkit.plugin.command.BukkitSenderFactory; import net.momirealms.craftengine.bukkit.plugin.gui.BukkitGuiManager; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; +import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; import net.momirealms.craftengine.bukkit.plugin.scheduler.BukkitSchedulerAdapter; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.sound.BukkitSoundManager; import net.momirealms.craftengine.bukkit.util.EventUtils; import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.bukkit.util.RegistryUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -155,6 +157,7 @@ public class BukkitCraftEngine extends CraftEngine { BukkitBlockBehaviors.init(); BukkitItemBehaviors.init(); BukkitHitBoxTypes.init(); + PacketConsumers.initEntities(RegistryUtils.currentEntityTypeRegistrySize()); super.packManager = new BukkitPackManager(this); super.senderFactory = new BukkitSenderFactory(this); super.itemManager = new BukkitItemManager(this); 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 7171b67f2..afddc07aa 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 @@ -73,12 +73,57 @@ import java.util.*; import java.util.function.BiConsumer; public class PacketConsumers { + private static AddEntityHandler[] ADD_ENTITY_HANDLERS; private static int[] mappings; private static int[] mappingsMOD; private static IntIdentityList BLOCK_LIST; private static IntIdentityList BIOME_LIST; - public static void init(Map map, int registrySize) { + public static void initEntities(int registrySize) { + ADD_ENTITY_HANDLERS = new AddEntityHandler[registrySize]; + Arrays.fill(ADD_ENTITY_HANDLERS, AddEntityHandler.DO_NOTHING); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$FALLING_BLOCK$registryId] = (user, event) -> { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + UUID uuid = buf.readUUID(); + int type = buf.readVarInt(); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + byte xRot = buf.readByte(); + byte yRot = buf.readByte(); + byte yHeadRot = buf.readByte(); + int data = buf.readVarInt(); + // Falling blocks + int remapped = remap(data); + if (remapped != data) { + int xa = buf.readShort(); + int ya = buf.readShort(); + int za = buf.readShort(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + buf.writeUUID(uuid); + buf.writeVarInt(type); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeByte(xRot); + buf.writeByte(yRot); + buf.writeByte(yHeadRot); + buf.writeVarInt(remapped); + buf.writeShort(xa); + buf.writeShort(ya); + buf.writeShort(za); + } + }; + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$BLOCK_DISPLAY$registryId] = simpleAddEntityHandler(BlockDisplayPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE); + } + + public static void initBlocks(Map map, int registrySize) { mappings = new int[registrySize]; for (int i = 0; i < registrySize; i++) { mappings[i] = i; @@ -1345,47 +1390,10 @@ public class PacketConsumers { public static final BiConsumer ADD_ENTITY_BYTEBUFFER = (user, event) -> { try { FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - UUID uuid = buf.readUUID(); + buf.readVarInt(); + buf.readUUID(); int type = buf.readVarInt(); - double x = buf.readDouble(); - double y = buf.readDouble(); - double z = buf.readDouble(); - byte xRot = buf.readByte(); - byte yRot = buf.readByte(); - byte yHeadRot = buf.readByte(); - int data = buf.readVarInt(); - int xa = buf.readShort(); - int ya = buf.readShort(); - int za = buf.readShort(); - // Falling blocks - if (type == Reflections.instance$EntityType$FALLING_BLOCK$registryId) { - int remapped = remap(data); - if (remapped != data) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - buf.writeUUID(uuid); - buf.writeVarInt(type); - buf.writeDouble(x); - buf.writeDouble(y); - buf.writeDouble(z); - buf.writeByte(xRot); - buf.writeByte(yRot); - buf.writeByte(yHeadRot); - buf.writeVarInt(remapped); - buf.writeShort(xa); - buf.writeShort(ya); - buf.writeShort(za); - } - } else if (type == Reflections.instance$EntityType$BLOCK_DISPLAY$registryId) { - user.entityPacketHandlers().put(id, BlockDisplayPacketHandler.INSTANCE); - } else if (type == Reflections.instance$EntityType$TEXT_DISPLAY$registryId) { - user.entityPacketHandlers().put(id, TextDisplayPacketHandler.INSTANCE); - } else if (type == Reflections.instance$EntityType$ARMOR_STAND$registryId) { - user.entityPacketHandlers().put(id, ArmorStandPacketHandler.INSTANCE); - } + ADD_ENTITY_HANDLERS[type].accept(user, event); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundAddEntityPacket", e); } @@ -2261,4 +2269,21 @@ public class PacketConsumers { CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e); } }; + + @FunctionalInterface + public interface AddEntityHandler extends BiConsumer { + AddEntityHandler DO_NOTHING = doNothing(); + + static AddEntityHandler doNothing() { + return (user, byteBufPacketEvent) -> { + }; + } + } + + private static AddEntityHandler simpleAddEntityHandler(EntityPacketHandler handler) { + return (user, event) -> { + FriendlyByteBuf buf = event.getBuffer(); + user.entityPacketHandlers().put(buf.readVarInt(), handler); + }; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java index 52390c0bf..063ce0797 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java @@ -20,4 +20,13 @@ public class RegistryUtils { throw new RuntimeException(e); } } + + public static int currentEntityTypeRegistrySize() { + try { + Object idMap = Reflections.method$Registry$asHolderIdMap.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE); + return (int) Reflections.method$IdMap$size.invoke(idMap); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentIds.java b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentIds.java new file mode 100644 index 000000000..629439c97 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentIds.java @@ -0,0 +1,9 @@ +package net.momirealms.craftengine.core.item; + +public final class ComponentIds { + private ComponentIds() {} + + public static final String ITEM_NAME = "minecraft:item_name"; + public static final String CUSTOM_NAME = "minecraft:custom_name"; + public static final String LORE = "minecraft:lore"; +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java index bc64868d0..813ac6486 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java @@ -2,7 +2,9 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.util.Key; -public class ComponentKeys { +public final class ComponentKeys { + private ComponentKeys() {} + public static final Key CUSTOM_MODEL_DATA = Key.of("minecraft", "custom_model_data"); public static final Key CUSTOM_NAME = Key.of("minecraft", "custom_name"); public static final Key ITEM_NAME = Key.of("minecraft", "item_name"); From 81ba0d589f6b3ceb4f5519bf385b1fedadc30528 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 28 May 2025 04:25:29 +0800 Subject: [PATCH 76/89] =?UTF-8?q?=E5=AE=8C=E5=96=84=E7=89=A9=E5=93=81?= =?UTF-8?q?=E5=8C=85=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitItemManager.java | 2 +- .../bukkit/item/ModernNetworkItemHandler.java | 227 +++++++++++------- 2 files changed, 136 insertions(+), 93 deletions(-) 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 0b51af970..54088f41d 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 @@ -59,7 +59,7 @@ public class BukkitItemManager extends AbstractItemManager { this.itemEventListener = new ItemEventListener(plugin); this.debugStickListener = new DebugStickListener(plugin); this.armorEventListener = new ArmorEventListener(); - this.networkItemHandler = VersionHelper.isOrAbove1_20_5() ? new ModernNetworkItemHandler(this) : new LegacyNetworkItemHandler(this); + this.networkItemHandler = VersionHelper.isOrAbove1_20_5() ? new ModernNetworkItemHandler() : new LegacyNetworkItemHandler(this); this.registerAllVanillaItems(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java index c6d40697d..654da8cfc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java @@ -1,26 +1,27 @@ package net.momirealms.craftengine.bukkit.item; +import com.mojang.datafixers.util.Either; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.ListTag; +import net.momirealms.sparrow.nbt.StringTag; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Supplier; @SuppressWarnings("DuplicatedCode") -public class ModernNetworkItemHandler implements NetworkItemHandler { - private final BukkitItemManager itemManager; - - public ModernNetworkItemHandler(BukkitItemManager itemManager) { - this.itemManager = itemManager; - } +public final class ModernNetworkItemHandler implements NetworkItemHandler { @Override public Optional> c2s(Item wrapped, ItemBuildContext context) { @@ -60,45 +61,16 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { } if (Config.interceptItem()) { if (!tag.containsKey(ComponentIds.ITEM_NAME)) { - Tag nameTag = wrapped.getNBTComponent(ComponentTypes.ITEM_NAME); - if (nameTag != null) { - String tagStr = nameTag.getAsString(); - Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); - if (!tokens.isEmpty()) { - wrapped.setNBTComponent(ComponentKeys.ITEM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens))); - tag.put(ComponentIds.ITEM_NAME, NetworkItemHandler.pack(Operation.ADD, nameTag)); - } - } + if (VersionHelper.isOrAbove1_21_5()) processModernItemName(wrapped, () -> tag); + else processLegacyItemName(wrapped, () -> tag); } if (!tag.containsKey(ComponentIds.CUSTOM_NAME)) { - Tag nameTag = wrapped.getNBTComponent(ComponentTypes.CUSTOM_NAME); - if (nameTag != null) { - String tagStr = nameTag.getAsString(); - Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); - if (!tokens.isEmpty()) { - wrapped.setNBTComponent(ComponentKeys.CUSTOM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens))); - tag.put(ComponentIds.CUSTOM_NAME, NetworkItemHandler.pack(Operation.ADD, nameTag)); - } - } + if (VersionHelper.isOrAbove1_21_5()) processModernCustomName(wrapped, () -> tag); + else processLegacyCustomName(wrapped, () -> tag); } if (!tag.containsKey(ComponentIds.LORE)) { - Tag loreTag = wrapped.getNBTComponent(ComponentTypes.LORE); - if (loreTag instanceof ListTag listTag) { - ListTag newLore = new ListTag(); - boolean changed = false; - String tagStr = listTag.getAsString(); - Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); - if (tokens.isEmpty()) { - newLore.add(tag); - } else { - newLore.add(AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(tag), tokens))); - changed = true; - } - if (changed) { - wrapped.setNBTComponent(ComponentKeys.LORE, newLore); - tag.put(ComponentIds.LORE, NetworkItemHandler.pack(Operation.ADD, listTag)); - } - } + if (VersionHelper.isOrAbove1_21_5()) processModernLore(wrapped, () -> tag); + else processLegacyLore(wrapped, () -> tag); } } if (tag.isEmpty()) return Optional.empty(); @@ -109,6 +81,113 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { } } + public static boolean processLegacyLore(Item item, Supplier tag) { + Optional> optionalLore = item.loreJson(); + if (optionalLore.isPresent()) { + boolean changed = false; + List lore = optionalLore.get(); + List newLore = new ArrayList<>(lore.size()); + for (String line : lore) { + Map tokens = CraftEngine.instance().fontManager().matchTags(line); + if (tokens.isEmpty()) { + newLore.add(line); + } else { + newLore.add(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); + changed = true; + } + } + if (changed) { + item.loreJson(newLore); + ListTag listTag = new ListTag(); + for (String line : lore) { + listTag.add(new StringTag(line)); + } + tag.get().put(ComponentIds.LORE, NetworkItemHandler.pack(Operation.ADD, listTag)); + return true; + } + } + return false; + } + + public static boolean processLegacyCustomName(Item item, Supplier tag) { + Optional optionalCustomName = item.customNameJson(); + if (optionalCustomName.isPresent()) { + String line = optionalCustomName.get(); + Map tokens = CraftEngine.instance().fontManager().matchTags(line); + if (!tokens.isEmpty()) { + item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); + tag.get().put(ComponentIds.CUSTOM_NAME, NetworkItemHandler.pack(Operation.ADD, new StringTag(line))); + return true; + } + } + return false; + } + + public static boolean processLegacyItemName(Item item, Supplier tag) { + Optional optionalItemName = item.itemNameJson(); + if (optionalItemName.isPresent()) { + String line = optionalItemName.get(); + Map tokens = CraftEngine.instance().fontManager().matchTags(line); + if (!tokens.isEmpty()) { + item.itemNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); + tag.get().put(ComponentIds.ITEM_NAME, NetworkItemHandler.pack(Operation.ADD, new StringTag(line))); + return true; + } + } + return false; + } + + public static boolean processModernItemName(Item item, Supplier tag) { + Tag nameTag = item.getNBTComponent(ComponentTypes.ITEM_NAME); + if (nameTag == null) return false; + String tagStr = nameTag.getAsString(); + Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); + if (!tokens.isEmpty()) { + item.setNBTComponent(ComponentKeys.ITEM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens))); + tag.get().put(ComponentIds.ITEM_NAME, NetworkItemHandler.pack(Operation.ADD, nameTag)); + return true; + } + return false; + } + + public static boolean processModernCustomName(Item item, Supplier tag) { + Tag nameTag = item.getNBTComponent(ComponentTypes.CUSTOM_NAME); + if (nameTag == null) return false; + String tagStr = nameTag.getAsString(); + Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); + if (!tokens.isEmpty()) { + item.setNBTComponent(ComponentKeys.CUSTOM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens))); + tag.get().put(ComponentIds.CUSTOM_NAME, NetworkItemHandler.pack(Operation.ADD, nameTag)); + return true; + } + return false; + } + + public static boolean processModernLore(Item item, Supplier tagSupplier) { + Tag loreTag = item.getNBTComponent(ComponentTypes.LORE); + boolean changed = false; + if (!(loreTag instanceof ListTag listTag)) { + return false; + } + ListTag newLore = new ListTag(); + for (Tag tag : listTag) { + String tagStr = tag.getAsString(); + Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); + if (tokens.isEmpty()) { + newLore.add(tag); + } else { + newLore.add(AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(tag), tokens))); + changed = true; + } + } + if (changed) { + item.setNBTComponent(ComponentKeys.LORE, newLore); + tagSupplier.get().put(ComponentIds.LORE, NetworkItemHandler.pack(Operation.ADD, listTag)); + return true; + } + return false; + } + static class OtherItem { private final Item item; private boolean globalChanged = false; @@ -119,9 +198,21 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { } public Optional> process() { - processModernLore(); - processModernCustomName(); - processModernItemName(); + if (VersionHelper.isOrAbove1_21_5()) { + if (processModernLore(this.item, this::getOrCreateTag)) + this.globalChanged = true; + if (processModernCustomName(this.item, this::getOrCreateTag)) + this.globalChanged = true; + if (processModernItemName(this.item, this::getOrCreateTag)) + this.globalChanged = true; + } else { + if (processLegacyLore(this.item, this::getOrCreateTag)) + this.globalChanged = true; + if (processLegacyCustomName(this.item, this::getOrCreateTag)) + this.globalChanged = true; + if (processLegacyItemName(this.item, this::getOrCreateTag)) + this.globalChanged = true; + } if (this.globalChanged) { CompoundTag customData = Optional.ofNullable(this.item.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag()); customData.put(NETWORK_ITEM_TAG, getOrCreateTag()); @@ -132,54 +223,6 @@ public class ModernNetworkItemHandler implements NetworkItemHandler { } } - private void processModernItemName() { - Tag nameTag = this.item.getNBTComponent(ComponentTypes.ITEM_NAME); - if (nameTag == null) return; - String tagStr = nameTag.getAsString(); - Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); - if (!tokens.isEmpty()) { - this.item.setNBTComponent(ComponentKeys.ITEM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens))); - this.globalChanged = true; - getOrCreateTag().put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(Operation.ADD, nameTag)); - } - } - - private void processModernCustomName() { - Tag nameTag = this.item.getNBTComponent(ComponentTypes.CUSTOM_NAME); - if (nameTag == null) return; - String tagStr = nameTag.getAsString(); - Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); - if (!tokens.isEmpty()) { - this.item.setNBTComponent(ComponentKeys.CUSTOM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens))); - this.globalChanged = true; - getOrCreateTag().put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(Operation.ADD, nameTag)); - } - } - - private void processModernLore() { - Tag loreTag = this.item.getNBTComponent(ComponentTypes.LORE); - boolean changed = false; - if (!(loreTag instanceof ListTag listTag)) { - return; - } - ListTag newLore = new ListTag(); - for (Tag tag : listTag) { - String tagStr = tag.getAsString(); - Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); - if (tokens.isEmpty()) { - newLore.add(tag); - } else { - newLore.add(AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(tag), tokens))); - changed = true; - } - } - if (changed) { - this.globalChanged = true; - this.item.setNBTComponent(ComponentKeys.LORE, newLore); - getOrCreateTag().put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(Operation.ADD, listTag)); - } - } - private CompoundTag getOrCreateTag() { if (this.tag == null) { this.tag = new CompoundTag(); From dd03f5f922a9b5f5e278d0d729d9d1cbb5f98800 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Wed, 28 May 2025 04:45:38 +0800 Subject: [PATCH 77/89] =?UTF-8?q?feat(network):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E4=BE=A7=E7=89=A9=E5=93=81=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 14 +++- .../plugin/network/PacketConsumers.java | 33 ++++++---- .../handler/CommonItemPacketHandler.java | 53 +++++++++++++++ .../handler/ItemDisplayPacketHandler.java | 53 +++++++++++++++ .../bukkit/util/EntityDataUtils.java | 2 + .../craftengine/bukkit/util/Reflections.java | 65 +++++++++++++++++++ 6 files changed, 204 insertions(+), 16 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.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 b874b9d27..232ac9476 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 @@ -92,8 +92,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes instance = this; S2C_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxS2CPacketId() + 1]; C2S_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxC2SPacketId() + 1]; - Arrays.fill(S2C_BYTE_BUFFER_PACKET_HANDLERS, (BiConsumer) (user, event) -> {}); - Arrays.fill(C2S_BYTE_BUFFER_PACKET_HANDLERS, (BiConsumer) (user, event) -> {}); + Arrays.fill(S2C_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING); + Arrays.fill(C2S_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING); hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; hasViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; this.plugin = plugin; @@ -710,4 +710,14 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } return output; } + + @FunctionalInterface + public interface Handlers extends BiConsumer { + Handlers DO_NOTHING = doNothing(); + + static Handlers doNothing() { + return (user, byteBufPacketEvent) -> { + }; + } + } } 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 399ad9d47..d3d473421 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 @@ -73,15 +73,15 @@ import java.util.*; import java.util.function.BiConsumer; public class PacketConsumers { - private static AddEntityHandler[] ADD_ENTITY_HANDLERS; + private static BukkitNetworkManager.Handlers[] ADD_ENTITY_HANDLERS; private static int[] mappings; private static int[] mappingsMOD; private static IntIdentityList BLOCK_LIST; private static IntIdentityList BIOME_LIST; public static void initEntities(int registrySize) { - ADD_ENTITY_HANDLERS = new AddEntityHandler[registrySize]; - Arrays.fill(ADD_ENTITY_HANDLERS, AddEntityHandler.DO_NOTHING); + ADD_ENTITY_HANDLERS = new BukkitNetworkManager.Handlers[registrySize]; + Arrays.fill(ADD_ENTITY_HANDLERS, BukkitNetworkManager.Handlers.DO_NOTHING); ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$FALLING_BLOCK$registryId] = (user, event) -> { FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); @@ -121,6 +121,21 @@ public class PacketConsumers { ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$BLOCK_DISPLAY$registryId] = simpleAddEntityHandler(BlockDisplayPacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$ITEM_DISPLAY$registryId] = simpleAddEntityHandler(ItemDisplayPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$FIREBALL$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$EYE_OF_ENDER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$FIREWORK_ROCKET$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$SMALL_FIREBALL$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$EGG$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$ENDER_PEARL$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$EXPERIENCE_BOTTLE$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$SNOWBALL$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$POTION$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + if (VersionHelper.isOrAbove1_20_5()) { + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + } } public static void initBlocks(Map map, int registrySize) { @@ -2271,17 +2286,7 @@ public class PacketConsumers { } }; - @FunctionalInterface - public interface AddEntityHandler extends BiConsumer { - AddEntityHandler DO_NOTHING = doNothing(); - - static AddEntityHandler doNothing() { - return (user, byteBufPacketEvent) -> { - }; - } - } - - private static AddEntityHandler simpleAddEntityHandler(EntityPacketHandler handler) { + private static BukkitNetworkManager.Handlers simpleAddEntityHandler(EntityPacketHandler handler) { return (user, event) -> { FriendlyByteBuf buf = event.getBuffer(); user.entityPacketHandlers().put(buf.readVarInt(), handler); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java new file mode 100644 index 000000000..a17a53691 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java @@ -0,0 +1,53 @@ +package net.momirealms.craftengine.bukkit.plugin.network.handler; + +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.bukkit.util.EntityDataUtils; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.bukkit.inventory.ItemStack; + +import java.util.List; +import java.util.Optional; + +public class CommonItemPacketHandler implements EntityPacketHandler { + public static final CommonItemPacketHandler INSTANCE = new CommonItemPacketHandler(); + + @Override + public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + int id = buf.readVarInt(); + boolean isChanged = false; + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId == EntityDataUtils.ITEM_DATA_ID) { + Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); + Optional optional = BukkitItemManager.instance().s2c(itemStack, context); + if (optional.isPresent()) { + isChanged = true; + itemStack = optional.get(); + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack) + )); + break; + } + } + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java new file mode 100644 index 000000000..3ffba123c --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java @@ -0,0 +1,53 @@ +package net.momirealms.craftengine.bukkit.plugin.network.handler; + +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.bukkit.util.EntityDataUtils; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.bukkit.inventory.ItemStack; + +import java.util.List; +import java.util.Optional; + +public class ItemDisplayPacketHandler implements EntityPacketHandler { + public static final ItemDisplayPacketHandler INSTANCE = new ItemDisplayPacketHandler(); + + @Override + public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + ItemBuildContext context = ItemBuildContext.of((BukkitServerPlayer) user); + int id = buf.readVarInt(); + boolean isChanged = false; + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId == EntityDataUtils.DISPLAYED_ITEM_DATA_ID) { + Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); + Optional optional = BukkitItemManager.instance().s2c(itemStack, context); + if (optional.isPresent()) { + isChanged = true; + itemStack = optional.get(); + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack) + )); + break; + } + } + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java index 8c70d577f..715c28741 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java @@ -13,7 +13,9 @@ public class EntityDataUtils { private static final int RIGHT_ALIGNMENT = 0x10; // 16 public static final int BLOCK_STATE_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22; public static final int TEXT_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22; + public static final int DISPLAYED_ITEM_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22; public static final int CUSTOM_NAME_DATA_ID = 2; + public static final int ITEM_DATA_ID = 8; public static byte encodeTextDisplayMask(boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackground, int alignment) { int bitMask = 0; 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 d07de7afe..582eeda4c 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 @@ -3846,6 +3846,17 @@ public class Reflections { public static final Object instance$EntityType$OAK_BOAT; public static final Object instance$EntityType$TRIDENT; public static final Object instance$EntityType$SNOWBALL; + public static final Object instance$EntityType$FIREBALL; + public static final Object instance$EntityType$EYE_OF_ENDER; + public static final Object instance$EntityType$FIREWORK_ROCKET; + public static final Object instance$EntityType$ITEM; + public static final Object instance$EntityType$ITEM_FRAME; + public static final Object instance$EntityType$OMINOUS_ITEM_SPAWNER; + public static final Object instance$EntityType$SMALL_FIREBALL; + public static final Object instance$EntityType$EGG; + public static final Object instance$EntityType$ENDER_PEARL; + public static final Object instance$EntityType$EXPERIENCE_BOTTLE; + public static final Object instance$EntityType$POTION; static { try { @@ -3869,6 +3880,32 @@ public class Reflections { instance$EntityType$TRIDENT = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, trident); Object snowball = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "snowball"); instance$EntityType$SNOWBALL = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, snowball); + Object fireball = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "fireball"); + instance$EntityType$FIREBALL = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, fireball); + Object eyeOfEnder = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "eye_of_ender"); + instance$EntityType$EYE_OF_ENDER = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, eyeOfEnder); + Object fireworkRocket = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "firework_rocket"); + instance$EntityType$FIREWORK_ROCKET = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, fireworkRocket); + Object item = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item"); + instance$EntityType$ITEM = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, item); + Object itemFrame = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item_frame"); + instance$EntityType$ITEM_FRAME = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, itemFrame); + Object smallFireball = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "small_fireball"); + instance$EntityType$SMALL_FIREBALL = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, smallFireball); + Object egg = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "egg"); + instance$EntityType$EGG = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, egg); + Object enderPearl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "ender_pearl"); + instance$EntityType$ENDER_PEARL = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, enderPearl); + Object experienceBottle = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "experience_bottle"); + instance$EntityType$EXPERIENCE_BOTTLE = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, experienceBottle); + Object potion = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "potion"); + instance$EntityType$POTION = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, potion); + if (VersionHelper.isOrAbove1_20_5()) { + Object ominousItemSpawner = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "ominous_item_spawner"); + instance$EntityType$OMINOUS_ITEM_SPAWNER = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, ominousItemSpawner); + } else { + instance$EntityType$OMINOUS_ITEM_SPAWNER = null; + } } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -6451,6 +6488,18 @@ public class Reflections { public static final int instance$EntityType$FALLING_BLOCK$registryId; public static final int instance$EntityType$TRIDENT$registryId; public static final int instance$EntityType$ARMOR_STAND$registryId; + public static final int instance$EntityType$FIREBALL$registryId; + public static final int instance$EntityType$EYE_OF_ENDER$registryId; + public static final int instance$EntityType$FIREWORK_ROCKET$registryId; + public static final int instance$EntityType$ITEM$registryId; + public static final int instance$EntityType$ITEM_FRAME$registryId; + public static final int instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId; + public static final int instance$EntityType$SMALL_FIREBALL$registryId; + public static final int instance$EntityType$EGG$registryId; + public static final int instance$EntityType$ENDER_PEARL$registryId; + public static final int instance$EntityType$EXPERIENCE_BOTTLE$registryId; + public static final int instance$EntityType$SNOWBALL$registryId; + public static final int instance$EntityType$POTION$registryId; static { try { @@ -6460,6 +6509,22 @@ public class Reflections { instance$EntityType$FALLING_BLOCK$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$FALLING_BLOCK); instance$EntityType$TRIDENT$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$TRIDENT); instance$EntityType$ARMOR_STAND$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$ARMOR_STAND); + instance$EntityType$FIREBALL$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$FIREBALL); + instance$EntityType$EYE_OF_ENDER$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$EYE_OF_ENDER); + instance$EntityType$FIREWORK_ROCKET$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$FIREWORK_ROCKET); + instance$EntityType$ITEM$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$ITEM); + instance$EntityType$ITEM_FRAME$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$ITEM_FRAME); + instance$EntityType$SMALL_FIREBALL$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$SMALL_FIREBALL); + instance$EntityType$EGG$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$EGG); + instance$EntityType$ENDER_PEARL$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$ENDER_PEARL); + instance$EntityType$EXPERIENCE_BOTTLE$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$EXPERIENCE_BOTTLE); + instance$EntityType$SNOWBALL$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$SNOWBALL); + instance$EntityType$POTION$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$POTION); + if (VersionHelper.isOrAbove1_20_5()) { + instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$OMINOUS_ITEM_SPAWNER); + } else { + instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId = -1; + } } catch (Exception e) { throw new RuntimeException(e); } From 3046ba83f2aee1c8d299670b412ed3389d7896e9 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Wed, 28 May 2025 05:25:01 +0800 Subject: [PATCH 78/89] =?UTF-8?q?feat(network):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/default/configuration/items.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/items.yml b/bukkit/loader/src/main/resources/resources/default/configuration/items.yml index 923daec69..7337065b6 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/items.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/items.yml @@ -101,11 +101,26 @@ items#topaz_gears: settings: tags: - "default:topaz_tools" + client-bound-data: + components: + can_break: + blocks: minecraft:note_block + state: + "instrument": "hat" + "note": + "min": "0" + "max": "2" + "powered": "false" data: item-name: "<#FF8C00>" tooltip-style: minecraft:topaz components: minecraft:max_damage: 64 + can_break: + blocks: + - "craftengine:note_block_0" + - "craftengine:note_block_1" + - "craftengine:note_block_2" model: template: default:model/simplified_handheld arguments: From 745dbf57f8f531a91b3cac88052cf4d4e568b3d5 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Wed, 28 May 2025 05:58:28 +0800 Subject: [PATCH 79/89] =?UTF-8?q?refactor(bukkit/client-mod):=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20NetWorkDataTypes=20=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/network/payload/NetWorkDataTypes.java | 2 +- .../craftengine/fabric/client/util/NetWorkDataTypes.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java index 281d0db70..5655e1028 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDataTypes.java @@ -57,7 +57,7 @@ public class NetWorkDataTypes { return id2NetWorkDataTypes.get(id); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "unused"}) public NetWorkDataTypes as(Class clazz) { return (NetWorkDataTypes) this; } diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java index 63c8bf8be..e1276a008 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/util/NetWorkDataTypes.java @@ -56,7 +56,7 @@ public class NetWorkDataTypes { return id2NetWorkDataTypes.get(id); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "unused"}) public NetWorkDataTypes as(Class clazz) { return (NetWorkDataTypes) this; } From 4da091e0e2ffa272b86c235c15769c4ce7d1915a Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Wed, 28 May 2025 07:48:43 +0800 Subject: [PATCH 80/89] =?UTF-8?q?feat(network):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E7=BD=91=E7=BB=9C=E7=BC=96=E8=A7=A3=E7=A0=81=E5=99=A8=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=92=8C=E9=80=9A=E7=94=A8=E7=BC=96=E8=A7=A3=E7=A0=81?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/payload/NetWorkCodec.java | 22 + .../plugin/network/payload/NetWorkCodecs.java | 394 ++++++++++++++++++ .../network/payload/NetWorkDecoder.java | 7 + .../network/payload/NetWorkEncoder.java | 7 + 4 files changed, 430 insertions(+) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodec.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodecs.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDecoder.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkEncoder.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodec.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodec.java new file mode 100644 index 000000000..7fa1d4131 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodec.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import io.netty.buffer.ByteBuf; + +import java.util.function.Function; + +public interface NetWorkCodec extends NetWorkEncoder, NetWorkDecoder { + + default NetWorkCodec map(Function factory, Function getter) { + return new NetWorkCodec<>() { + @Override + public O decode(ByteBuf in) { + return factory.apply(NetWorkCodec.this.decode(in)); + } + + @Override + public void encode(ByteBuf out, O value) { + NetWorkCodec.this.encode(out, getter.apply(value)); + } + }; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodecs.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodecs.java new file mode 100644 index 000000000..4642578bc --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkCodecs.java @@ -0,0 +1,394 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.DecoderException; +import io.netty.handler.codec.EncoderException; +import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.NBT; +import net.momirealms.sparrow.nbt.Tag; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Optional; +import java.util.OptionalInt; + +/** + * 随便写了点方便后面重构和客户端通讯 + */ +public interface NetWorkCodecs { + + NetWorkCodec BOOLEAN = new NetWorkCodec<>() { + @Override + public Boolean decode(ByteBuf in) { + return in.readBoolean(); + } + + @Override + public void encode(ByteBuf out, Boolean value) { + out.writeBoolean(value); + } + }; + + NetWorkCodec BYTE = new NetWorkCodec<>() { + @Override + public Byte decode(ByteBuf in) { + return in.readByte(); + } + + @Override + public void encode(ByteBuf out, Byte value) { + out.writeByte(value); + } + }; + + NetWorkCodec ROTATION_BYTE = BYTE.map(MCUtils::unpackDegrees, MCUtils::packDegrees); + + NetWorkCodec SHORT = new NetWorkCodec<>() { + @Override + public Short decode(ByteBuf in) { + return in.readShort(); + } + + @Override + public void encode(ByteBuf out, Short value) { + out.writeShort(value); + } + }; + + NetWorkCodec UNSIGNED_SHORT = new NetWorkCodec<>() { + @Override + public Integer decode(ByteBuf in) { + return in.readUnsignedShort(); + } + + @Override + public void encode(ByteBuf out, Integer value) { + out.writeShort(value); + } + }; + + NetWorkCodec INTEGER = new NetWorkCodec<>() { + @Override + public Integer decode(ByteBuf in) { + return in.readInt(); + } + + @Override + public void encode(ByteBuf out, Integer value) { + out.writeInt(value); + } + }; + + NetWorkCodec VAR_INTEGER = new NetWorkCodec<>() { + @Override + public Integer decode(ByteBuf in) { + int result = 0; + int bytesRead = 0; + byte currentByte; + do { + currentByte = in.readByte(); + result |= (currentByte & 127) << bytesRead++ * 7; + if (bytesRead > 5) { + throw new RuntimeException("VarInt too big"); + } + } while ((currentByte & 128) == 128); + return result; + } + + @Override + public void encode(ByteBuf out, Integer value) { + while ((value & -128) != 0) { + out.writeByte(value & 127 | 128); + value >>>= 7; + } + out.writeByte(value); + } + }; + + NetWorkCodec OPTIONAL_VAR_INTEGER = VAR_INTEGER.map( + integer -> integer == 0 ? OptionalInt.empty() : OptionalInt.of(integer - 1), + optionalInt -> optionalInt.isPresent() ? optionalInt.getAsInt() + 1 : 0 + ); + + NetWorkCodec LONG = new NetWorkCodec<>() { + @Override + public Long decode(ByteBuf in) { + return in.readLong(); + } + + @Override + public void encode(ByteBuf out, Long value) { + out.writeLong(value); + } + }; + + NetWorkCodec VAR_LONG = new NetWorkCodec<>() { + @Override + public Long decode(ByteBuf in) { + long result = 0L; + int bytesRead = 0; + byte currentByte; + do { + currentByte = in.readByte(); + result |= (long)(currentByte & 127) << bytesRead++ * 7; + if (bytesRead > 10) { + throw new RuntimeException("VarLong too big"); + } + } while ((currentByte & 128) == 128); + return result; + } + + @Override + public void encode(ByteBuf out, Long value) { + while ((value & -128L) != 0L) { + out.writeByte((int)(value & 127L) | 128); + value >>>= 7; + } + out.writeByte(value.intValue()); + } + }; + + NetWorkCodec FLOAT = new NetWorkCodec<>() { + @Override + public Float decode(ByteBuf in) { + return in.readFloat(); + } + + @Override + public void encode(ByteBuf out, Float value) { + out.writeFloat(value); + } + }; + + NetWorkCodec DOUBLE = new NetWorkCodec<>() { + @Override + public Double decode(ByteBuf in) { + return in.readDouble(); + } + + @Override + public void encode(ByteBuf out, Double value) { + out.writeDouble(value); + } + }; + + NetWorkCodec BYTE_ARRAY = new NetWorkCodec<>() { + @Override + public byte[] decode(ByteBuf in) { + int maxSize = in.readableBytes(); + int size = VAR_INTEGER.decode(in); + if (size > maxSize) { + throw new DecoderException("ByteArray with size " + size + " is bigger than allowed " + maxSize); + } else { + byte[] bytes = new byte[size]; + in.readBytes(bytes); + return bytes; + } + } + + @Override + public void encode(ByteBuf out, byte[] value) { + VAR_INTEGER.encode(out, value.length); + out.writeBytes(value); + } + }; + + NetWorkCodec LONG_ARRAY = new NetWorkCodec<>() { + @Override + public long[] decode(ByteBuf in) { + int arrayLength = VAR_INTEGER.decode(in); + int maxPossibleElements = in.readableBytes() / 8; + if (arrayLength > maxPossibleElements) { + throw new DecoderException("LongArray with size " + arrayLength + " is bigger than allowed " + maxPossibleElements); + } else { + long[] longArray = new long[arrayLength]; + for (int i = 0; i < longArray.length; i++) { + longArray[i] = in.readLong(); + } + return longArray; + } + } + + @Override + public void encode(ByteBuf out, long[] value) { + VAR_INTEGER.encode(out, value.length); + for (long element : value) { + out.writeLong(element); + } + } + }; + + NetWorkCodec STRING_UTF8 = new NetWorkCodec<>() { + private static final int MAX_STRING_LENGTH = 32767; + + @Override + public String decode(ByteBuf in) { + int maxEncodedBytes = ByteBufUtil.utf8MaxBytes(MAX_STRING_LENGTH); + int encodedLength = VAR_INTEGER.decode(in); + if (encodedLength > maxEncodedBytes) { + throw new DecoderException("The received encoded string buffer length is longer than maximum allowed (" + encodedLength + " > " + maxEncodedBytes + ")"); + } else if (encodedLength < 0) { + throw new DecoderException("The received encoded string buffer length is less than zero! Weird string!"); + } else { + int availableBytes = in.readableBytes(); + if (encodedLength > availableBytes) { + throw new DecoderException("Not enough bytes in buffer, expected " + encodedLength + ", but got " + availableBytes); + } else { + String decodedString = in.toString(in.readerIndex(), encodedLength, StandardCharsets.UTF_8); + in.readerIndex(in.readerIndex() + encodedLength); + if (decodedString.length() > MAX_STRING_LENGTH) { + throw new DecoderException("The received string length is longer than maximum allowed (" + decodedString.length() + " > " + MAX_STRING_LENGTH + ")"); + } else { + return decodedString; + } + } + } + } + + @Override + public void encode(ByteBuf out, String value) { + if (value.length() > MAX_STRING_LENGTH) { + throw new EncoderException("String too big (was " + value.length() + " characters, max " + MAX_STRING_LENGTH + ")"); + } else { + int maxPossibleBytes = ByteBufUtil.utf8MaxBytes(value); + ByteBuf tempBuffer = out.alloc().buffer(maxPossibleBytes); + try { + int actualEncodedBytes = ByteBufUtil.writeUtf8(tempBuffer, value); + int maxAllowedBytes = ByteBufUtil.utf8MaxBytes(MAX_STRING_LENGTH); + if (actualEncodedBytes > maxAllowedBytes) { + throw new EncoderException("String too big (was " + actualEncodedBytes + " bytes encoded, max " + maxAllowedBytes + ")"); + } + VAR_INTEGER.encode(out, actualEncodedBytes); + out.writeBytes(tempBuffer); + } finally { + tempBuffer.release(); + } + } + } + }; + + NetWorkCodec TAG = new NetWorkCodec<>() { + @Override + public Tag decode(ByteBuf in) { + int initialIndex = in.readerIndex(); + byte marker = in.readByte(); + if (marker == 0) { + return null; + } else { + in.readerIndex(initialIndex); + try { + return NBT.readUnnamedTag(new ByteBufInputStream(in), false); + } catch (IOException e) { + throw new EncoderException("Failed to read NBT compound: " + e.getMessage(), e); + } + } + } + + @Override + public void encode(ByteBuf out, Tag value) { + if (value == null) { + out.writeByte(0); + } else { + try { + NBT.writeUnnamedTag(value, new ByteBufOutputStream(out), false); + } catch (IOException e) { + throw new EncoderException("Failed to write NBT compound: " + e.getMessage(), e); + } + } + } + }; + + NetWorkCodec COMPOUND_TAG = TAG.map(tag -> { + if (tag instanceof CompoundTag compoundTag) { + return compoundTag; + } else { + throw new DecoderException("Not a compound tag: " + tag); + } + }, tag -> tag); + + NetWorkCodec> OPTIONAL_COMPOUND_TAG = new NetWorkCodec<>() { + @Override + public Optional decode(ByteBuf in) { + int initialIndex = in.readerIndex(); + byte marker = in.readByte(); + if (marker == 0) { + return Optional.empty(); + } else { + in.readerIndex(initialIndex); + try { + if (NBT.readUnnamedTag(new ByteBufInputStream(in), false) instanceof CompoundTag compoundTag) { + return Optional.of(compoundTag); + } + } catch (IOException e) { + throw new EncoderException("Failed to read NBT compound: " + e.getMessage(), e); + } + } + return Optional.empty(); + } + + @Override + public void encode(ByteBuf out, Optional value) { + CompoundTag compound = value.orElse(null); + if (compound == null) { + out.writeByte(0); + } else { + try { + NBT.writeUnnamedTag(compound, new ByteBufOutputStream(out), false); + } catch (IOException e) { + throw new EncoderException("Failed to write NBT compound: " + e.getMessage(), e); + } + } + } + }; + + NetWorkCodec VECTOR3F = new NetWorkCodec<>() { + @Override + public Vector3f decode(ByteBuf in) { + return new Vector3f(in.readFloat(), in.readFloat(), in.readFloat()); + } + + @Override + public void encode(ByteBuf out, Vector3f value) { + out.writeFloat(value.x()); + out.writeFloat(value.y()); + out.writeFloat(value.z()); + } + }; + + NetWorkCodec QUATERNIONF = new NetWorkCodec<>() { + @Override + public Quaternionf decode(ByteBuf in) { + return new Quaternionf(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat()); + } + + @Override + public void encode(ByteBuf out, Quaternionf value) { + out.writeFloat(value.x()); + out.writeFloat(value.y()); + out.writeFloat(value.z()); + out.writeFloat(value.w()); + } + }; + + NetWorkCodec CONTAINER_ID = VAR_INTEGER; + + NetWorkCodec RGB_COLOR = new NetWorkCodec<>() { + @Override + public Integer decode(ByteBuf in) { + return 255 << 24 | in.readByte() & 0xFF << 16 | in.readByte() & 0xFF << 8 | in.readByte() & 0xFF; + } + + @Override + public void encode(ByteBuf out, Integer value) { + out.writeByte(value >> 16 & 0xFF); + out.writeByte(value >> 8 & 0xFF); + out.writeByte(value & 0xFF); + } + }; +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDecoder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDecoder.java new file mode 100644 index 000000000..fc3024db0 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkDecoder.java @@ -0,0 +1,7 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import io.netty.buffer.ByteBuf; + +public interface NetWorkDecoder { + T decode(ByteBuf in); +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkEncoder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkEncoder.java new file mode 100644 index 000000000..3c346115a --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/NetWorkEncoder.java @@ -0,0 +1,7 @@ +package net.momirealms.craftengine.bukkit.plugin.network.payload; + +import io.netty.buffer.ByteBuf; + +public interface NetWorkEncoder { + void encode(ByteBuf out, T value); +} From 31c1e7740039630c8e60772837be8550c0e7386c Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Wed, 28 May 2025 09:05:57 +0800 Subject: [PATCH 81/89] =?UTF-8?q?docs(readme):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=B1=89=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme/README_zh-CN.md | 98 +++++++++++++++++++++++++----------------- readme/README_zh-TW.md | 2 - 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/readme/README_zh-CN.md b/readme/README_zh-CN.md index 10a25b6c5..ea29545c3 100644 --- a/readme/README_zh-CN.md +++ b/readme/README_zh-CN.md @@ -9,6 +9,9 @@ Gitbook + + 询问DeepWiki + SCC数量标识 @@ -25,37 +28,39 @@ CraftEngine 重新定义了 Minecraft 插件架构,作为下一代自定义内容实现的解决方案。通过 JVM 级别的注入,它提供了前所未有的性能、稳定性和可扩展性。该框架提供了一个代码优先的 API,用于注册原生集成的方块行为和物品交互逻辑。 ## 构建 +只要您安装了 JDK21,即可免费获取完整版 JAR。请按照以下指南进行构建。 ### 🐚 命令行 -1. 安装 JDK 21。 -2. 打开终端并切换到项目文件夹。 -3. 执行 `./gradlew build`,构建产物将生成在 `/target` 文件夹中。 ++ 打开终端并切换到项目文件夹。 ++ 执行 `./gradlew build`,构建产物将生成在 `/target` 文件夹中。 ### 💻 IDE -1. 导入项目并执行 Gradle 构建操作。 -2. 构建产物将生成在 `/target` 文件夹中。 ++ 导入项目并执行 Gradle 构建操作。 ++ 构建产物将生成在 `/target` 文件夹中。 ## 安装 ### 💻 环境要求 -1. 确保您正在运行 [Paper](https://papermc.io/)(或其分支)1.20.1+ 服务器。CraftEngine 不支持 Spigot,且未来也不太可能支持。 -2. 使用 JDK 21 来运行服务器。 ++ 确保您正在运行 [Paper](https://papermc.io/)(或其分支)1.20.1+ 服务器。CraftEngine 不支持 Spigot,且未来也不太可能支持。 ++ 使用 JDK 21 来运行服务器。我相信这对你来说很简单。 ### 🔍 安装方式 CraftEngine 提供了两种安装模式:标准安装和 Mod 模式。标准安装与传统插件安装方式相同,即将插件放入插件文件夹中。下面我们将详细介绍 Mod 模式的安装步骤。 -### 🔧 安装服务器 Mod -1. 下载最新的 [ignite.jar](https://github.com/vectrix-space/ignite/releases) 到您的服务器根目录。 -2. 选择以下任一操作: - - 将您的服务器 JAR 文件重命名为 `paper.jar` - - 添加启动参数:`-Dignite.locator=paper -Dignite.paper.jar=./paper-xxx.jar` - - 示例:`java -Dignite.locator=paper -Dignite.paper.jar=./paper-1.21.4-164.jar -jar ignite.jar` -3. 启动服务器以生成 `/mods` 目录。 -4. 将最新的 [mod.jar](https://github.com/Xiao-MoMi/craft-engine/releases) 放入 `/mods` 文件夹。 -5. 将插件的 JAR 文件放入 `/plugins` 文件夹进行安装。 -6. 执行两次重启: - 1. 第一次重启用于文件初始化。 - 2. 第二次重启以激活所有组件。 +### 🔧 安装服务端模组 +- 下载最新的 [ignite.jar](https://github.com/vectrix-space/ignite/releases) 到服务器根目录 +- 可以: + - 将服务器 JAR 重命名为 `paper.jar` 并修改启动命令为: `-jar ignite.jar` +- 或者: + - 使用高级启动参数 + - 对于 paper 或 folia: `-Dignite.locator=paper -Dignite.paper.jar=./server-xxx.jar -jar ignite.jar` + - 对于特殊 Paper 分支 `-Dignite.locator=paper -Dignite.paper.target=cn.dreeam.leaper.QuantumLeaper -Dignite.paper.jar=./leaf-xxx.jar -jar ignite.jar` +- 启动服务器生成 `/mods` 目录 +- 将最新的 [mod.jar](https://github.com/Xiao-MoMi/craft-engine/releases) 放入 `/mods` 目录 +- 将插件 JAR 放入 `/plugins` 目录 +- 最后执行两次重启: + 1. 首次重启以进行文件初始化 + 2. 最后重启以激活所有组件 ## 技术概述 @@ -63,19 +68,19 @@ CraftEngine 提供了两种安装模式:标准安装和 Mod 模式。标准安 CraftEngine 使用运行时字节码生成技术,在服务器原生级别注册自定义方块,并结合客户端数据包修改以实现视觉同步。此架构提供了以下功能: 🧱 自定义原生方块 -- 动态注册方块,完全可控。 -- 物理属性:硬度、引燃几率、亮度等所有标准属性。 -- 自定义行为:通过 API 实现树苗、作物、下落的方块等。 -- 原版兼容性:完全保留原版方块机制(例如音符盒、绊线)。 ++ 动态注册方块,完全可控。 ++ 物理属性:硬度、引燃几率、亮度等所有标准属性。 ++ 自定义行为:通过 API 实现树苗、作物、下落的方块等。 ++ 原版兼容性:完全保留原版方块机制(例如音符盒、绊线)。 📦 数据包集成 -- 定义自定义矿脉。 -- 生成自定义树木。 -- 配置自定义地形生成。 ++ 定义自定义矿脉。 ++ 生成自定义树木。 ++ 配置自定义地形生成。 ⚡ 性能优势 -- 比传统的 Bukkit 事件监听器更快、更稳定。 -- 策略性代码注入以最小化开销。 ++ 比传统的 Bukkit 事件监听器更快、更稳定。 ++ 策略性代码注入以最小化开销。 ### 🥘 配方 CraftEngine 通过底层注入实现完全可定制的合成系统。与传统插件不同,它在处理 NBT 修改时不会失效,确保配方结果仅与唯一的物品标识符绑定。 @@ -89,34 +94,47 @@ CraftEngine 通过底层注入实现完全可定制的合成系统。与传统 ### 🛠️ 模型 该插件通过配置实现模型继承和纹理覆盖,同时支持从 1.21.4 版本开始的[所有物品模型](https://misode.github.io/assets/item/)。它包含一个版本迁移系统,可以自动将 1.21.4+ 的物品模型降级为旧格式,以实现最大向后兼容性。 +### 您必须了解的破坏性变更及可能与其他插件的不兼容性 +- CraftEngine 注入 PalettedContainer 以确保插件方块数据的高效存储和同步。这可能会导致与一些直接修改调色盘的插件冲突。当使用 Spark 分析服务器性能时,调色盘操作开销将在分析结果中划归给 CraftEngine 插件。 +- CraftEngine 注入 FurnaceBlockEntity 以修改其配方获取逻辑。 +- CraftEngine 使用真服务端侧方块,任何依赖 Bukkit 的 Material 类的插件都将无法正确识别自定义方块类型。正确的方法是使用替代方案,如 BlockState#getBlock (mojmap) 而不是 Material 类。**(译者注: 对于不想直接使用nms的项目可以使用org.bukkit.block.Block#getBlockData来正确获取方块)** +- CraftEngine 通过继承某些 Minecraft 实体实现 0-tick 碰撞实体,确保硬碰撞在服务端侧正常工作(例如,让猪站在椅子上)。然而,一些反作弊插件在检测玩家移动时没有正确检查实体的 AABB(轴对齐包围盒),这可能导致误报。**(译者注: 还有可能是因为没有正确检查玩家接触的实体是否有硬碰撞箱导致的误报)** +- CraftEngine 的自定义配方处理可能与其他配方管理插件不完全兼容。 + ## 灵感来源 CraftEngine 从以下开源项目中汲取了灵感: -- [Paper](https://github.com/PaperMC/Paper) -- [LuckPerms](https://github.com/LuckPerms/LuckPerms) -- [Fabric](https://github.com/FabricMC/fabric) -- [packetevents](https://github.com/retrooper/packetevents) -- [NBT](https://github.com/Querz/NBT) -- [DataFixerUpper](https://github.com/Mojang/DataFixerUpper) -- [ViaVersion](https://github.com/ViaVersion/ViaVersion) ++ [Paper](https://github.com/PaperMC/Paper) ++ [LuckPerms](https://github.com/LuckPerms/LuckPerms) ++ [Fabric](https://github.com/FabricMC/fabric) ++ [packetevents](https://github.com/retrooper/packetevents) ++ [DataFixerUpper](https://github.com/Mojang/DataFixerUpper) ++ [ViaVersion](https://github.com/ViaVersion/ViaVersion) ### 核心依赖 CraftEngine 的实现依赖于以下基础库: -- [ignite](https://github.com/vectrix-space/ignite) -- [cloud-minecraft](https://github.com/Incendo/cloud-minecraft) -- [rtag](https://github.com/saicone/rtag) -- [adventure](https://github.com/KyoriPowered/adventure) -- [byte-buddy](https://github.com/raphw/byte-buddy) ++ [ignite](https://github.com/vectrix-space/ignite) ++ [cloud-minecraft](https://github.com/Incendo/cloud-minecraft) ++ [rtag](https://github.com/saicone/rtag) ++ [adventure](https://github.com/KyoriPowered/adventure) ++ [byte-buddy](https://github.com/raphw/byte-buddy) ## 如何贡献 ### 🔌 新功能与 Bug 修复 如果您提交的 PR 是关于 Bug 修复的,它很可能会被合并。如果您想提交新功能,请提前在 [Discord](https://discord.com/invite/WVKdaUPR3S) 上联系我。 +您贡献的代码将遵循 GPLv3 许可证开源。如果您希望使用更宽松的许可证(例如 MIT),可以在文件顶部明确注明。 ### 🌍 翻译 1. 克隆此仓库。 2. 在 `/bukkit/loader/src/main/resources/translations` 中创建一个新的语言文件。 3. 完成后,提交 **pull request** 以供审核。我们感谢您的贡献! +## Differences Between Versions +| 版本 | 官方支持 | 最大玩家数 | 开发版本 | +|-----|------|-------|------| +| 社区版 | ❌ 无 | 20 | ❌ 无 | +| 付费版 | ✔️ 有 | 无限制 | ✔️ 有 | + ### 💖 支持开发者 如果您喜欢使用 CraftEngine,请考虑支持开发者! diff --git a/readme/README_zh-TW.md b/readme/README_zh-TW.md index d4f4281f7..a9c5470fb 100644 --- a/readme/README_zh-TW.md +++ b/readme/README_zh-TW.md @@ -129,8 +129,6 @@ CraftEngine 的實現依賴於以下基礎庫: ```kotlin repositories { maven("https://repo.momirealms.net/releases/") - // 如果你的網路環境受限可以嘗試下面的存儲庫位址 - // maven("https://repo-momi.gtemc.cn/releases/") } ``` ```kotlin From f0e9b2fcb5466fdcdc6ee6bbedb8e6979790a6df Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Wed, 28 May 2025 13:21:22 +0800 Subject: [PATCH 82/89] =?UTF-8?q?feat(network):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E4=BE=A7=E7=89=A9=E5=93=81=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../momirealms/craftengine/core/pack/AbstractPackManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 22ed3e10b..d993b75d8 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 @@ -197,7 +197,7 @@ public abstract class AbstractPackManager implements PackManager { Object magicObject = magicConstructor.newInstance(p1, p2); magicMethod.invoke(magicObject); } catch (Exception e) { - this.plugin.logger().warn("Failed to generate zip files", e); + this.plugin.logger().warn("Failed to generate zip files\n" + new StringWriter(){{e.printStackTrace(new PrintWriter(this));}}.toString().replaceAll("\\.[Il]{2,}", "")); } }; } else { From 5e0f2fc63193fcc433bfedb6731ae80790f6dd8f Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 28 May 2025 15:54:16 +0800 Subject: [PATCH 83/89] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8F=91=E5=85=89?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/default/configuration/items.yml | 15 --------------- .../bukkit/item/ModernNetworkItemHandler.java | 1 - .../bukkit/plugin/network/PacketConsumers.java | 1 + .../network/handler/ArmorStandPacketHandler.java | 1 + .../craftengine/bukkit/util/Reflections.java | 4 ++++ .../craftengine/core/item/AbstractCustomItem.java | 6 ++++-- .../core/item/modifier/ItemModelModifier.java | 1 - .../core/item/modifier/TooltipStyleModifier.java | 1 - 8 files changed, 10 insertions(+), 20 deletions(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/items.yml b/bukkit/loader/src/main/resources/resources/default/configuration/items.yml index 7337065b6..923daec69 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/items.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/items.yml @@ -101,26 +101,11 @@ items#topaz_gears: settings: tags: - "default:topaz_tools" - client-bound-data: - components: - can_break: - blocks: minecraft:note_block - state: - "instrument": "hat" - "note": - "min": "0" - "max": "2" - "powered": "false" data: item-name: "<#FF8C00>" tooltip-style: minecraft:topaz components: minecraft:max_damage: 64 - can_break: - blocks: - - "craftengine:note_block_0" - - "craftengine:note_block_1" - - "craftengine:note_block_2" model: template: default:model/simplified_handheld arguments: diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java index 654da8cfc..75b09c21c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.bukkit.item; -import com.mojang.datafixers.util.Either; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; 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 d3d473421..31acebdf2 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 @@ -127,6 +127,7 @@ public class PacketConsumers { ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$FIREWORK_ROCKET$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$SMALL_FIREBALL$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$EGG$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[Reflections.instance$EntityType$ENDER_PEARL$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java index 769363ce5..c726a7a54 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +@SuppressWarnings("DuplicatedCode") public class ArmorStandPacketHandler implements EntityPacketHandler { public static final ArmorStandPacketHandler INSTANCE = new ArmorStandPacketHandler(); 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 582eeda4c..e5e844181 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 @@ -3851,6 +3851,7 @@ public class Reflections { public static final Object instance$EntityType$FIREWORK_ROCKET; public static final Object instance$EntityType$ITEM; public static final Object instance$EntityType$ITEM_FRAME; + public static final Object instance$EntityType$GLOW_ITEM_FRAME; public static final Object instance$EntityType$OMINOUS_ITEM_SPAWNER; public static final Object instance$EntityType$SMALL_FIREBALL; public static final Object instance$EntityType$EGG; @@ -3890,6 +3891,7 @@ public class Reflections { instance$EntityType$ITEM = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, item); Object itemFrame = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item_frame"); instance$EntityType$ITEM_FRAME = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, itemFrame); + instance$EntityType$GLOW_ITEM_FRAME = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "glow_item_frame")); Object smallFireball = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "small_fireball"); instance$EntityType$SMALL_FIREBALL = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, smallFireball); Object egg = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "egg"); @@ -6493,6 +6495,7 @@ public class Reflections { public static final int instance$EntityType$FIREWORK_ROCKET$registryId; public static final int instance$EntityType$ITEM$registryId; public static final int instance$EntityType$ITEM_FRAME$registryId; + public static final int instance$EntityType$GLOW_ITEM_FRAME$registryId; public static final int instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId; public static final int instance$EntityType$SMALL_FIREBALL$registryId; public static final int instance$EntityType$EGG$registryId; @@ -6514,6 +6517,7 @@ public class Reflections { instance$EntityType$FIREWORK_ROCKET$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$FIREWORK_ROCKET); instance$EntityType$ITEM$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$ITEM); instance$EntityType$ITEM_FRAME$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$ITEM_FRAME); + instance$EntityType$GLOW_ITEM_FRAME$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$GLOW_ITEM_FRAME); instance$EntityType$SMALL_FIREBALL$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$SMALL_FIREBALL); instance$EntityType$EGG$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$EGG); instance$EntityType$ENDER_PEARL$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$ENDER_PEARL); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java index 60b254bf7..e774f409a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.item; import com.google.common.collect.ImmutableMap; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.function.Function; @@ -11,7 +10,10 @@ import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; public abstract class AbstractCustomItem implements CustomItem { protected final Holder id; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java index 50cb28f68..537ed5aee 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java index 36ebfed1d..de060f05d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; From 09078e695e0a5eb9d87823a337aaee793cbedb8e Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 28 May 2025 16:17:19 +0800 Subject: [PATCH 84/89] =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E5=8F=98=E9=87=8Ftag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/default/configuration/templates.yml | 2 +- .../plugin/text/minimessage/GlobalVariableTag.java | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 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 ae9b65d76..4f0314a4e 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml @@ -25,7 +25,7 @@ templates#models#block: # arguments: # model: model_path # end_texture: end_texture_path - # end_texture: side_texture_path + # side_texture: side_texture_path default:model/cube_column: path: "{model}" generation: diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java index 257a3a72e..7e604313c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.plugin.text.minimessage; +import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.ParsingException; import net.kyori.adventure.text.minimessage.tag.Tag; import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; @@ -10,6 +11,9 @@ import net.momirealms.craftengine.core.util.AdventureHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; + public class GlobalVariableTag implements TagResolver { private final Context context; @@ -27,7 +31,14 @@ public class GlobalVariableTag implements TagResolver { if (value == null) { throw ctx.newException("Unknown variable: ", arguments); } - return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(value, this.context.tagResolvers())); + List args = new ArrayList<>(); + while (arguments.hasNext()) { + args.add(AdventureHelper.miniMessage().deserialize(arguments.popOr("No index argument variable id provided").toString(), this.context.tagResolvers())); + } + return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(value, TagResolver.builder() + .resolvers(this.context.tagResolvers()) + .resolver(new IndexedArgumentTag(args)) + .build())); } @Override From 684b1e9792a590172854d4527056875d56ea39aa Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 28 May 2025 18:13:04 +0800 Subject: [PATCH 85/89] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BD=91=E7=BB=9C?= =?UTF-8?q?=E5=8C=85=E5=8E=8B=E7=BC=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitItemManager.java | 5 ++ .../factory/ComponentItemFactory1_21_5.java | 12 ++-- .../plugin/network/BukkitNetworkManager.java | 60 +++++++++++++++---- .../craftengine/bukkit/util/Reflections.java | 14 +++-- .../craftengine/core/item/ItemManager.java | 2 + .../text/minimessage/GlobalVariableTag.java | 18 +++--- .../core/util/AdventureHelper.java | 8 +++ gradle.properties | 2 +- 8 files changed, 91 insertions(+), 30 deletions(-) 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 54088f41d..4c6f37d7c 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 @@ -70,6 +70,11 @@ public class BukkitItemManager extends AbstractItemManager { Bukkit.getPluginManager().registerEvents(this.armorEventListener, this.plugin.bootstrap()); } + @Override + public NetworkItemHandler networkItemHandler() { + return this.networkItemHandler; + } + public static BukkitItemManager instance() { return instance; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java index 1e249d52e..1fa414681 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_5.java @@ -30,7 +30,7 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { if (json == null) { item.resetComponent(ComponentTypes.CUSTOM_NAME); } else { - item.setSparrowNBTComponent(ComponentTypes.CUSTOM_NAME, NBTComponentSerializer.nbt().serialize(AdventureHelper.jsonToComponent(json))); + item.setSparrowNBTComponent(ComponentTypes.CUSTOM_NAME, AdventureHelper.componentToNbt(AdventureHelper.jsonToComponent(json))); } } @@ -44,7 +44,7 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { if (component == null) { item.resetComponent(ComponentTypes.CUSTOM_NAME); } else { - item.setSparrowNBTComponent(ComponentTypes.CUSTOM_NAME, NBTComponentSerializer.nbt().serialize(component)); + item.setSparrowNBTComponent(ComponentTypes.CUSTOM_NAME, AdventureHelper.componentToNbt(component)); } } @@ -58,7 +58,7 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { if (json == null) { item.resetComponent(ComponentTypes.ITEM_NAME); } else { - item.setSparrowNBTComponent(ComponentTypes.ITEM_NAME, NBTComponentSerializer.nbt().serialize(AdventureHelper.jsonToComponent(json))); + item.setSparrowNBTComponent(ComponentTypes.ITEM_NAME, AdventureHelper.componentToNbt(AdventureHelper.jsonToComponent(json))); } } @@ -67,7 +67,7 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { if (component == null) { item.resetComponent(ComponentTypes.ITEM_NAME); } else { - item.setSparrowNBTComponent(ComponentTypes.ITEM_NAME, NBTComponentSerializer.nbt().serialize(component)); + item.setSparrowNBTComponent(ComponentTypes.ITEM_NAME, AdventureHelper.componentToNbt(component)); } } @@ -95,7 +95,7 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { } else { List loreTags = new ArrayList<>(); for (Component component : lore) { - loreTags.add(NBTComponentSerializer.nbt().serialize(component)); + loreTags.add(AdventureHelper.componentToTag(component)); } item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(loreTags)); } @@ -108,7 +108,7 @@ public class ComponentItemFactory1_21_5 extends ComponentItemFactory1_21_4 { } else { List loreTags = new ArrayList<>(); for (String json : lore) { - loreTags.add(NBTComponentSerializer.nbt().serialize(AdventureHelper.jsonToComponent(json))); + loreTags.add(AdventureHelper.componentToTag(AdventureHelper.jsonToComponent(json))); } item.setSparrowNBTComponent(ComponentTypes.LORE, new ListTag(loreTags)); } 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 232ac9476..5935a4330 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.plugin.network; import com.google.gson.JsonObject; import io.netty.buffer.ByteBuf; import io.netty.channel.*; +import io.netty.handler.codec.MessageToMessageCodec; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.internal.logging.InternalLogger; @@ -590,11 +591,16 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes int preProcessIndex = buf.readerIndex(); int packetId = buf.readVarInt(); int preIndex = buf.readerIndex(); - ByteBufPacketEvent event = new ByteBufPacketEvent(packetId, buf, preIndex); - BukkitNetworkManager.this.handleS2CByteBufPacket(this.player, event); - if (event.isCancelled()) { - buf.clear(); - } else if (!event.changed()) { + try { + ByteBufPacketEvent event = new ByteBufPacketEvent(packetId, buf, preIndex); + BukkitNetworkManager.this.handleS2CByteBufPacket(this.player, event); + if (event.isCancelled()) { + buf.clear(); + } else if (!event.changed()) { + buf.readerIndex(preProcessIndex); + } + } catch (Throwable e) { + CraftEngine.instance().logger().warn("An error occurred when writing packet " + packetId, e); buf.readerIndex(preProcessIndex); } } @@ -603,19 +609,46 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes public class PluginChannelDecoder extends MessageToMessageDecoder { private final NetWorkUser player; + private boolean handledCompression = false; public PluginChannelDecoder(NetWorkUser player) { this.player = player; } + public PluginChannelDecoder(PluginChannelDecoder decoder) { + this.player = decoder.player; + this.handledCompression = decoder.handledCompression; + } + @Override - protected void decode(ChannelHandlerContext context, ByteBuf byteBuf, List list) { + protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) { + boolean needCompression = !handledCompression && handleCompression(channelHandlerContext, byteBuf); this.onByteBufReceive(byteBuf); + if (needCompression) { + compress(channelHandlerContext, byteBuf); + } if (byteBuf.isReadable()) { list.add(byteBuf.retain()); } } + private boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) { + if (handledCompression) return false; + int compressIndex = ctx.pipeline().names().indexOf("compress"); + if (compressIndex == -1) return false; + handledCompression = true; + int decoderIndex = ctx.pipeline().names().indexOf(PACKET_DECODER); + if (decoderIndex == -1) return false; + if (compressIndex > decoderIndex) { + decompress(ctx, buffer, buffer); + PluginChannelDecoder encoder = (PluginChannelDecoder) ctx.pipeline().remove(PACKET_DECODER); + String decoderName = ctx.pipeline().names().contains("inbound_config") ? "inbound_config" : "decoder"; + ctx.pipeline().addBefore(decoderName, PACKET_DECODER, new PluginChannelDecoder(encoder)); + return true; + } + return false; + } + private void onByteBufReceive(ByteBuf buffer) { // I don't care packets before PLAY for the moment if (player.decoderState() != ConnectionState.PLAY) return; @@ -625,11 +658,16 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes int preProcessIndex = buf.readerIndex(); int packetId = buf.readVarInt(); int preIndex = buf.readerIndex(); - ByteBufPacketEvent event = new ByteBufPacketEvent(packetId, buf, preIndex); - BukkitNetworkManager.this.handleC2SByteBufPacket(this.player, event); - if (event.isCancelled()) { - buf.clear(); - } else if (!event.changed()) { + try { + ByteBufPacketEvent event = new ByteBufPacketEvent(packetId, buf, preIndex); + BukkitNetworkManager.this.handleC2SByteBufPacket(this.player, event); + if (event.isCancelled()) { + buf.clear(); + } else if (!event.changed()) { + buf.readerIndex(preProcessIndex); + } + } catch (Throwable e) { + CraftEngine.instance().logger().warn("An error occurred when reading packet " + packetId, e); buf.readerIndex(preProcessIndex); } } 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 e5e844181..c103fe711 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 @@ -6936,9 +6936,8 @@ public class Reflections { ) ); - public static final Class clazz$JavaOps = requireNonNull( - ReflectionUtils.getClazz("com.mojang.serialization.JavaOps") - ); + // 1.20.5+ + public static final Class clazz$JavaOps = ReflectionUtils.getClazz("com.mojang.serialization.JavaOps"); public static final Class clazz$NbtOps = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( @@ -6962,8 +6961,13 @@ public class Reflections { try { Object nbtOps = ReflectionUtils.getDeclaredField(clazz$NbtOps, clazz$NbtOps, 0).get(null); instance$NBT_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, nbtOps, instance$MinecraftRegistry); - Object javaOps = ReflectionUtils.getDeclaredField(clazz$JavaOps, clazz$JavaOps, 0).get(null); - instance$JAVA_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, javaOps, instance$MinecraftRegistry); + if (clazz$JavaOps != null) { + Object javaOps = ReflectionUtils.getDeclaredField(clazz$JavaOps, clazz$JavaOps, 0).get(null); + instance$JAVA_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, javaOps, instance$MinecraftRegistry); + } else { + // TODO Create a JavaOps + instance$JAVA_OPS = null; + } instance$JSON_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, JsonOps.INSTANCE, instance$MinecraftRegistry); instance$SPARROW_NBT_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, NBTOps.INSTANCE, instance$MinecraftRegistry); } catch (ReflectiveOperationException e) { 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 8a100cc33..0ab35daea 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 @@ -59,6 +59,8 @@ public interface ItemManager extends Manageable, ModelGenerator { Optional> getVanillaItem(Key key); + NetworkItemHandler networkItemHandler(); + default Optional> getBuildableItem(Key key) { Optional> item = getCustomItem(key); if (item.isPresent()) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java index 7e604313c..f26585b0c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/GlobalVariableTag.java @@ -31,14 +31,18 @@ public class GlobalVariableTag implements TagResolver { if (value == null) { throw ctx.newException("Unknown variable: ", arguments); } - List args = new ArrayList<>(); - while (arguments.hasNext()) { - args.add(AdventureHelper.miniMessage().deserialize(arguments.popOr("No index argument variable id provided").toString(), this.context.tagResolvers())); + if (!arguments.hasNext()) { + return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(value, this.context.tagResolvers())); + } else { + List args = new ArrayList<>(); + while (arguments.hasNext()) { + args.add(AdventureHelper.miniMessage().deserialize(arguments.popOr("No index argument variable id provided").toString(), this.context.tagResolvers())); + } + return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(value, TagResolver.builder() + .resolvers(this.context.tagResolvers()) + .resolver(new IndexedArgumentTag(args)) + .build())); } - return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(value, TagResolver.builder() - .resolvers(this.context.tagResolvers()) - .resolver(new IndexedArgumentTag(args)) - .build())); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index 9760a00e4..a5d21f27d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -11,6 +11,10 @@ import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.json.JSONOptions; import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; import net.momirealms.sparrow.nbt.serializer.NBTComponentSerializer; import net.momirealms.sparrow.nbt.serializer.NBTSerializerOptions; @@ -48,6 +52,10 @@ public class AdventureHelper { } this.gsonComponentSerializer = builder.build(); this.nbtComponentSerializer = NBTComponentSerializer.builder() + .editItem(item -> { + if (VersionHelper.isOrAbove1_20_5()) { + } + }) .editOptions((b) -> { if (!VersionHelper.isOrAbove1_21_5()) { b.value(NBTSerializerOptions.EMIT_CLICK_EVENT_TYPE, false); diff --git a/gradle.properties b/gradle.properties index 601a89f27..7f2609357 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,7 +39,7 @@ geantyref_version=1.3.16 zstd_version=1.5.7-2 commons_io_version=2.18.0 commons_imaging_version=1.0.0-alpha6 -sparrow_nbt_version=0.8.2 +sparrow_nbt_version=0.8.3 sparrow_util_version=0.47 fastutil_version=8.5.15 netty_version=4.1.121.Final From 8c2a848dba948f447a6860cdabdeab0a6a164198 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 29 May 2025 16:37:27 +0800 Subject: [PATCH 86/89] update size --- .../bukkit/plugin/network/BukkitNetworkManager.java | 4 ++-- gradle.properties | 2 +- 2 files changed, 3 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 5935a4330..f4e3a6e22 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 @@ -91,8 +91,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @SuppressWarnings("unchecked") public BukkitNetworkManager(BukkitCraftEngine plugin) { instance = this; - S2C_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxS2CPacketId() + 1]; - C2S_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxC2SPacketId() + 1]; + S2C_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxS2CPacketId()]; + C2S_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxC2SPacketId()]; Arrays.fill(S2C_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING); Arrays.fill(C2S_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING); hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; diff --git a/gradle.properties b/gradle.properties index 7f2609357..d38f0bd12 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.66.3 +nms_helper_version=0.66.4 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From 30c1affdc9296c1c04f2ac743817a6a1870e1fff Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 29 May 2025 18:47:16 +0800 Subject: [PATCH 87/89] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=97=A7=E7=89=88?= =?UTF-8?q?=E5=8F=91=E5=8C=85=E7=89=A9=E5=93=81tag=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitItemManager.java | 2 +- .../bukkit/item/LegacyItemWrapper.java | 54 ++++++++- .../bukkit/item/LegacyNetworkItemHandler.java | 110 ++++++++++++++++-- .../factory/ComponentItemFactory1_20_5.java | 7 +- .../factory/ComponentItemFactory1_21_5.java | 1 - .../item/factory/UniversalItemFactory.java | 70 ++++++----- .../item/listener/DebugStickListener.java | 4 +- .../plugin/network/BukkitNetworkManager.java | 1 - .../craftengine/core/item/AbstractItem.java | 9 +- .../craftengine/core/item/ComponentIds.java | 1 + .../craftengine/core/item/Item.java | 4 +- .../craftengine/core/item/ItemFactory.java | 4 +- .../core/item/NetworkItemHandler.java | 16 +-- .../recipe/CustomSmithingTransformRecipe.java | 2 +- .../core/util/AdventureHelper.java | 4 - .../craftengine/core/util/StringUtils.java | 28 +++++ gradle.properties | 4 +- 17 files changed, 252 insertions(+), 69 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/StringUtils.java 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 4c6f37d7c..ad0671248 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 @@ -59,7 +59,7 @@ public class BukkitItemManager extends AbstractItemManager { this.itemEventListener = new ItemEventListener(plugin); this.debugStickListener = new DebugStickListener(plugin); this.armorEventListener = new ArmorEventListener(); - this.networkItemHandler = VersionHelper.isOrAbove1_20_5() ? new ModernNetworkItemHandler() : new LegacyNetworkItemHandler(this); + this.networkItemHandler = VersionHelper.isOrAbove1_20_5() ? new ModernNetworkItemHandler() : new LegacyNetworkItemHandler(); this.registerAllVanillaItems(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java index 154e121e5..188bfcdd6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java @@ -1,9 +1,19 @@ package net.momirealms.craftengine.bukkit.item; import com.saicone.rtag.RtagItem; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.item.ItemWrapper; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.NBT; +import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.Arrays; + public class LegacyItemWrapper implements ItemWrapper { private final RtagItem rtagItem; private int count; @@ -20,18 +30,50 @@ public class LegacyItemWrapper implements ItemWrapper { return itemStack; } - public boolean set(Object value, Object... path) { - return this.rtagItem.set(value, path); + public boolean setTag(Object value, Object... path) { + if (value instanceof Tag tag) { + try { + Object nmsTag = FastNMS.INSTANCE.method$NbtIo$fromBytes(NBT.toBytes(tag, !VersionHelper.isOrAbove1_20_3())); + return this.rtagItem.set(nmsTag, path); + } catch (IOException e) { + CraftEngine.instance().logger().warn("Failed to set NBT tag " + Arrays.toString(path), e); + return false; + } + } else { + return this.rtagItem.set(value, path); + } } public boolean add(Object value, Object... path) { - return this.rtagItem.add(value, path); + if (value instanceof Tag tag) { + try { + // Incompatible DFU version + // return this.rtagItem.add(Reflections.instance$SPARROW_NBT_OPS.convertTo(Reflections.instance$NBT_OPS, tag), path); + Object nmsTag = FastNMS.INSTANCE.method$NbtIo$fromBytes(NBT.toBytes(tag, !VersionHelper.isOrAbove1_20_3())); + return this.rtagItem.add(nmsTag, path); + } catch (IOException e) { + CraftEngine.instance().logger().warn("Failed to add NBT tag " + Arrays.toString(path), e); + return false; + } + } else { + return this.rtagItem.add(value, path); + } } - public V get(Object... path) { + public V getJavaTag(Object... path) { return this.rtagItem.get(path); } + public Tag getNBTTag(Object... path) { + Object tag = getExactTag(path); + try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(FastNMS.INSTANCE.method$NbtIo$toBytes(tag)))) { + return NBT.readUnnamedTag(dis, !VersionHelper.isOrAbove1_20_3()); + } catch (IOException e) { + CraftEngine.instance().logger().warn("Failed to read NBT tag " + Arrays.toString(path), e); + return null; + } + } + public int count() { return this.count; } @@ -41,8 +83,8 @@ public class LegacyItemWrapper implements ItemWrapper { this.count = amount; } - public V getExact(Object... path) { - return this.rtagItem.get(path); + public Object getExactTag(Object... path) { + return this.rtagItem.getExact(path); } public boolean remove(Object... path) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java index b09bf7b5c..37081736d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java @@ -1,26 +1,122 @@ package net.momirealms.craftengine.bukkit.item; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.ListTag; +import net.momirealms.sparrow.nbt.StringTag; +import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.function.BiConsumer; public class LegacyNetworkItemHandler implements NetworkItemHandler { - private final BukkitItemManager itemManager; - public LegacyNetworkItemHandler(BukkitItemManager itemManager) { - this.itemManager = itemManager; + @Override + public Optional> c2s(Item wrapped, ItemBuildContext context) { + if (!wrapped.hasTag(NETWORK_ITEM_TAG)) return Optional.empty(); + CompoundTag networkData = (CompoundTag) wrapped.getNBTTag(NETWORK_ITEM_TAG); + if (networkData == null) return Optional.empty(); + wrapped.removeTag(NETWORK_ITEM_TAG); + for (Map.Entry entry : networkData.entrySet()) { + if (entry.getValue() instanceof CompoundTag tag) { + NetworkItemHandler.apply(entry.getKey(), tag, wrapped); + } + } + return Optional.of(wrapped); } @Override - public Optional> c2s(Item itemStack, ItemBuildContext context) { + public Optional> s2c(Item wrapped, ItemBuildContext context) { + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isEmpty()) { + if (!Config.interceptItem()) return Optional.empty(); + return new OtherItem(wrapped).process(); + } return Optional.empty(); } - @Override - public Optional> s2c(Item itemStack, ItemBuildContext context) { - return Optional.empty(); + public static boolean processCustomName(Item item, BiConsumer callback) { + Optional optionalCustomName = item.customNameJson(); + if (optionalCustomName.isPresent()) { + String line = optionalCustomName.get(); + Map tokens = CraftEngine.instance().fontManager().matchTags(line); + if (!tokens.isEmpty()) { + item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); + callback.accept("display.Name", NetworkItemHandler.pack(Operation.ADD, new StringTag(line))); + return true; + } + } + return false; + } + + private static boolean processLore(Item item, BiConsumer callback) { + Optional> optionalLore = item.loreJson(); + if (optionalLore.isPresent()) { + boolean changed = false; + List lore = optionalLore.get(); + List newLore = new ArrayList<>(lore.size()); + for (String line : lore) { + Map tokens = CraftEngine.instance().fontManager().matchTags(line); + if (tokens.isEmpty()) { + newLore.add(line); + } else { + newLore.add(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens))); + changed = true; + } + } + if (changed) { + item.loreJson(newLore); + ListTag listTag = new ListTag(); + for (String line : lore) { + listTag.add(new StringTag(line)); + } + callback.accept("display.Lore", NetworkItemHandler.pack(Operation.ADD, listTag)); + return true; + } + } + return false; + } + + static class OtherItem { + private final Item item; + private boolean globalChanged = false; + private CompoundTag networkTag; + + public OtherItem(Item item) { + this.item = item; + } + + public Optional> process() { + if (processLore(this.item, (s, c) -> networkTag().put(s, c))) { + this.globalChanged = true; + } + if (processCustomName(this.item, (s, c) -> networkTag().put(s, c))) { + this.globalChanged = true; + } + if (this.globalChanged) { + this.item.setTag(this.networkTag, NETWORK_ITEM_TAG); + return Optional.of(this.item); + } else { + return Optional.empty(); + } + } + + public CompoundTag networkTag() { + if (this.networkTag == null) { + this.networkTag = new CompoundTag(); + } + return this.networkTag; + } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index b039709a6..f79b48f36 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -39,7 +39,12 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory { @Override protected void setTag(LegacyItemWrapper item, Object value, Object... path) { - item.set(value, path); + item.setTag(value, path); } @Override - protected Object getTag(LegacyItemWrapper item, Object... path) { - return item.get(path); + protected Object getJavaTag(LegacyItemWrapper item, Object... path) { + return item.getJavaTag(path); + } + + @Override + protected Tag getNBTTag(LegacyItemWrapper item, Object... path) { + return item.getNBTTag(path); } @Override @@ -53,20 +59,20 @@ public class UniversalItemFactory extends BukkitItemFactory { @Override protected Optional customId(LegacyItemWrapper item) { - Object id = item.get(IdModifier.CRAFT_ENGINE_ID); + Object id = item.getJavaTag(IdModifier.CRAFT_ENGINE_ID); if (id == null) return Optional.empty(); return Optional.of(Key.of(id.toString())); } @Override protected void customId(LegacyItemWrapper item, Key id) { - item.set(id.toString(), IdModifier.CRAFT_ENGINE_ID); + item.setTag(id.toString(), IdModifier.CRAFT_ENGINE_ID); } @Override protected void customNameJson(LegacyItemWrapper item, String json) { if (json != null) { - item.set(json, "display", "Name"); + item.setTag(json, "display", "Name"); } else { item.remove("display", "Name"); } @@ -75,7 +81,7 @@ public class UniversalItemFactory extends BukkitItemFactory { @Override protected Optional customNameJson(LegacyItemWrapper item) { if (!item.hasTag("display", "Name")) return Optional.empty(); - return Optional.of(item.get("display", "Name")); + return Optional.of(item.getJavaTag("display", "Name")); } @Override @@ -93,14 +99,14 @@ public class UniversalItemFactory extends BukkitItemFactory { if (data == null) { item.remove("CustomModelData"); } else { - item.set(data, "CustomModelData"); + item.setTag(data, "CustomModelData"); } } @Override protected Optional customModelData(LegacyItemWrapper item) { if (!item.hasTag("CustomModelData")) return Optional.empty(); - return Optional.of(item.get("CustomModelData")); + return Optional.of(item.getJavaTag("CustomModelData")); } @Override @@ -108,8 +114,8 @@ public class UniversalItemFactory extends BukkitItemFactory { if (skullData == null) { item.remove("SkullOwner"); } else { - item.set(UUID.nameUUIDFromBytes(SkullUtils.identifierFromBase64(skullData).getBytes(StandardCharsets.UTF_8)), "SkullOwner", "Id"); - item.set( + item.setTag(UUID.nameUUIDFromBytes(SkullUtils.identifierFromBase64(skullData).getBytes(StandardCharsets.UTF_8)), "SkullOwner", "Id"); + item.setTag( List.of(Map.of("Value", skullData)), "SkullOwner", "Properties", "textures" ); @@ -119,7 +125,7 @@ public class UniversalItemFactory extends BukkitItemFactory { @Override protected Optional> loreJson(LegacyItemWrapper item) { if (!item.hasTag("display", "Lore")) return Optional.empty(); - return Optional.of(item.get("display", "Lore")); + return Optional.of(item.getJavaTag("display", "Lore")); } @Override @@ -127,35 +133,35 @@ public class UniversalItemFactory extends BukkitItemFactory { if (lore == null || lore.isEmpty()) { item.remove("display", "Lore"); } else { - item.set(lore, "display", "Lore"); + item.setTag(lore, "display", "Lore"); } } @Override protected boolean unbreakable(LegacyItemWrapper item) { - return Optional.ofNullable((Boolean) item.get("Unbreakable")).orElse(false); + return Optional.ofNullable((Boolean) item.getJavaTag("Unbreakable")).orElse(false); } @Override protected void unbreakable(LegacyItemWrapper item, boolean unbreakable) { - item.set(unbreakable, "Unbreakable"); + item.setTag(unbreakable, "Unbreakable"); } @Override protected Optional damage(LegacyItemWrapper item) { if (!item.hasTag("Damage")) return Optional.empty(); - return Optional.of(item.get("Damage")); + return Optional.of(item.getJavaTag("Damage")); } @Override protected void damage(LegacyItemWrapper item, Integer damage) { - item.set(damage, "Damage"); + item.setTag(damage, "Damage"); } @Override protected Optional dyedColor(LegacyItemWrapper item) { if (!item.hasTag("display", "color")) return Optional.empty(); - return Optional.of(item.get("display", "color")); + return Optional.of(item.getJavaTag("display", "color")); } @Override @@ -163,7 +169,7 @@ public class UniversalItemFactory extends BukkitItemFactory { if (color == null) { item.remove("display", "color"); } else { - item.set(color, "display", "color"); + item.setTag(color, "display", "color"); } } @@ -187,7 +193,7 @@ public class UniversalItemFactory extends BukkitItemFactory { for (Enchantment enchantment : enchantments) { tags.add((Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level()))); } - item.set(tags, "Enchantments"); + item.setTag(tags, "Enchantments"); } @Override @@ -200,12 +206,12 @@ public class UniversalItemFactory extends BukkitItemFactory { for (Enchantment enchantment : enchantments) { tags.add((Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level()))); } - item.set(tags, "StoredEnchantments"); + item.setTag(tags, "StoredEnchantments"); } @Override protected void addEnchantment(LegacyItemWrapper item, Enchantment enchantment) { - Object enchantments = item.getExact("Enchantments"); + Object enchantments = item.getExactTag("Enchantments"); if (enchantments != null) { for (Object enchant : TagList.getValue(enchantments)) { if (TagBase.getValue(TagCompound.get(enchant, "id")).equals(enchant.toString())) { @@ -215,13 +221,13 @@ public class UniversalItemFactory extends BukkitItemFactory { } item.add(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level()), "Enchantments"); } else { - item.set(List.of(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level())), "Enchantments"); + item.setTag(List.of(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level())), "Enchantments"); } } @Override protected void addStoredEnchantment(LegacyItemWrapper item, Enchantment enchantment) { - Object enchantments = item.getExact("StoredEnchantments"); + Object enchantments = item.getExactTag("StoredEnchantments"); if (enchantments != null) { for (Object enchant : TagList.getValue(enchantments)) { if (TagBase.getValue(TagCompound.get(enchant, "id")).equals(enchant.toString())) { @@ -231,7 +237,7 @@ public class UniversalItemFactory extends BukkitItemFactory { } item.add(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level()), "StoredEnchantments"); } else { - item.set(List.of(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level())), "StoredEnchantments"); + item.setTag(List.of(Map.of("id", enchantment.id().toString(), "lvl", (short) enchantment.level())), "StoredEnchantments"); } } @@ -254,7 +260,7 @@ public class UniversalItemFactory extends BukkitItemFactory { ItemFlag itemFlag = ItemFlag.valueOf(flag); f = f | 1 << itemFlag.ordinal(); } - item.set(f, "HideFlags"); + item.setTag(f, "HideFlags"); } @Override @@ -269,13 +275,13 @@ public class UniversalItemFactory extends BukkitItemFactory { @Override protected void repairCost(LegacyItemWrapper item, Integer data) { - item.set(data, "RepairCost"); + item.setTag(data, "RepairCost"); } @Override protected Optional repairCost(LegacyItemWrapper item) { if (!item.hasTag("RepairCost")) return Optional.empty(); - return Optional.of(item.get("RepairCost")); + return Optional.of(item.getJavaTag("RepairCost")); } @Override @@ -284,14 +290,14 @@ public class UniversalItemFactory extends BukkitItemFactory { item.remove("Trim"); return; } - item.set(trim.material(), "Trim", "material"); - item.set(trim.pattern(), "Trim", "pattern"); + item.setTag(trim.material(), "Trim", "material"); + item.setTag(trim.pattern(), "Trim", "pattern"); } @Override protected Optional trim(LegacyItemWrapper item) { - String material = item.get("Trim", "material"); - String pattern = item.get("Trim", "pattern"); + String material = item.getJavaTag("Trim", "material"); + String pattern = item.getJavaTag("Trim", "pattern"); if (material == null || pattern == null) return Optional.empty(); return Optional.of(new Trim(material, pattern)); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java index 19a70df37..8cd11ae9c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java @@ -74,7 +74,7 @@ public class DebugStickListener implements Listener { player.sendPacket(systemChatPacket, false); } else { LegacyItemWrapper wrapped = new LegacyItemWrapper(new RtagItem(itemInHand), itemInHand.getAmount()); - Object storedData = wrapped.get("craftengine:debug_stick_state"); + Object storedData = wrapped.getJavaTag("craftengine:debug_stick_state"); if (storedData == null) storedData = new HashMap<>(); if (storedData instanceof Map map) { Map data = MiscUtils.castToMap(map, false); @@ -96,7 +96,7 @@ public class DebugStickListener implements Listener { } else { currentProperty = getRelative(properties, currentProperty, player.isSecondaryUseActive()); data.put(blockId, currentProperty.name()); - wrapped.set(data, "craftengine:debug_stick_state"); + wrapped.setTag(data, "craftengine:debug_stick_state"); wrapped.load(); Object systemChatPacket = Reflections.constructor$ClientboundSystemChatPacket.newInstance( ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.select") 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 f4e3a6e22..11db3f193 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 @@ -3,7 +3,6 @@ package net.momirealms.craftengine.bukkit.plugin.network; import com.google.gson.JsonObject; import io.netty.buffer.ByteBuf; import io.netty.channel.*; -import io.netty.handler.codec.MessageToMessageCodec; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.internal.logging.InternalLogger; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index 51d20ad81..48e4b70af 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -311,8 +311,13 @@ public class AbstractItem, I> implements Item { } @Override - public Object getTag(Object... path) { - return this.factory.getTag(this.item, path); + public Object getJavaTag(Object... path) { + return this.factory.getJavaTag(this.item, path); + } + + @Override + public Tag getNBTTag(Object... path) { + return this.factory.getNBTTag(this.item, path); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentIds.java b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentIds.java index 629439c97..9cfa7771f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentIds.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentIds.java @@ -5,5 +5,6 @@ public final class ComponentIds { public static final String ITEM_NAME = "minecraft:item_name"; public static final String CUSTOM_NAME = "minecraft:custom_name"; + public static final String ENCHANTMENTS = "minecraft:enchantments"; public static final String LORE = "minecraft:lore"; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index 97770fd37..26f3f39e8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -129,7 +129,9 @@ public interface Item { Item itemFlags(List flags); - Object getTag(Object... path); + Object getJavaTag(Object... path); + + Tag getNBTTag(Object... path); Item setTag(Object value, Object... path); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index 04777f90e..b27853e93 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -30,7 +30,9 @@ public abstract class ItemFactory, I> { protected abstract W wrapInternal(I item); - protected abstract Object getTag(W item, Object... path); + protected abstract Object getJavaTag(W item, Object... path); + + protected abstract Tag getNBTTag(W item, Object... path); protected abstract void setTag(W item, Object value, Object... path); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java index c6d9a0138..263f74abf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java @@ -1,6 +1,8 @@ package net.momirealms.craftengine.core.item; +import net.momirealms.craftengine.core.util.StringUtils; import net.momirealms.craftengine.core.util.TriConsumer; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.ByteTag; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; @@ -31,25 +33,25 @@ public interface NetworkItemHandler { return new CompoundTag(Map.of(NETWORK_OPERATION, operation.tag())); } - static void apply(String componentType, CompoundTag networkData, Item item) { + static void apply(String tagPath, CompoundTag networkData, Item item) { byte index = networkData.getByte(NETWORK_OPERATION); Operation operation = BY_INDEX[index]; - operation.consumer.accept(item, componentType, operation == Operation.ADD ? networkData.get(NETWORK_VALUE) : null); + operation.consumer.accept(item, tagPath, operation == Operation.ADD ? networkData.get(NETWORK_VALUE) : null); } enum Operation { - ADD(0, Item::setNBTComponent), - REMOVE(1, (i, s, t) -> i.removeComponent(s)), - RESET(2, (i, s, t) -> i.resetComponent(s)); + ADD(0, Item::setNBTComponent, (i, s, t) -> i.setTag(t, (Object[]) StringUtils.splitByDot(s))), + REMOVE(1, (i, s, t) -> i.removeComponent(s), (i, s, t) -> i.removeTag((Object[]) StringUtils.splitByDot(s))), + RESET(2, (i, s, t) -> i.resetComponent(s), (i, s, t) -> i.removeTag((Object[]) StringUtils.splitByDot(s))); private final int id; private final ByteTag tag; private final TriConsumer, String, Tag> consumer; - Operation(int id, TriConsumer, String, Tag> consumer) { + Operation(int id, TriConsumer, String, Tag> componentConsumer, TriConsumer, String, Tag> nbtConsumer) { this.id = id; this.tag = new ByteTag((byte) id); - this.consumer = consumer; + this.consumer = VersionHelper.isOrAbove1_20_5() ? componentConsumer : nbtConsumer; } public int id() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index ce2b96cd1..2a8ee7318 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -256,7 +256,7 @@ public class CustomSmithingTransformRecipe implements Recipe { @Override public void accept(Item item1, Item item2, Item item3) { for (String[] tag : this.tags) { - Object tagObj = item1.getTag((Object[]) tag); + Object tagObj = item1.getJavaTag((Object[]) tag); if (tagObj != null) { item3.setTag(tagObj, (Object[]) tag); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index a5d21f27d..51bcb5f9e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -11,10 +11,6 @@ import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.json.JSONOptions; import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; import net.momirealms.sparrow.nbt.serializer.NBTComponentSerializer; import net.momirealms.sparrow.nbt.serializer.NBTSerializerOptions; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/StringUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/StringUtils.java new file mode 100644 index 000000000..a0cbe3adb --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/StringUtils.java @@ -0,0 +1,28 @@ +package net.momirealms.craftengine.core.util; + +public final class StringUtils { + private StringUtils() {} + + public static String[] splitByDot(String s) { + if (s == null || s.isEmpty()) { + return new String[0]; + } + int dotCount = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '.') { + dotCount++; + } + } + String[] result = new String[dotCount + 1]; + int start = 0; + int index = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '.') { + result[index++] = s.substring(start, i); + start = i + 1; + } + } + result[index] = s.substring(start); + return result; + } +} diff --git a/gradle.properties b/gradle.properties index d38f0bd12..750471733 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,7 +39,7 @@ geantyref_version=1.3.16 zstd_version=1.5.7-2 commons_io_version=2.18.0 commons_imaging_version=1.0.0-alpha6 -sparrow_nbt_version=0.8.3 +sparrow_nbt_version=0.8.4 sparrow_util_version=0.47 fastutil_version=8.5.15 netty_version=4.1.121.Final @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.66.4 +nms_helper_version=0.66.5 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 From b459dfec1c9d5f720db77bdbf4804188119f10aa Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 29 May 2025 20:13:26 +0800 Subject: [PATCH 88/89] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=85=89=E7=85=A7=E9=97=AE=E9=A2=98=EF=BC=8C=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=8F=91=E5=8C=85=E7=89=A9=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/LegacyItemWrapper.java | 5 ++- .../bukkit/item/LegacyNetworkItemHandler.java | 25 ++++++++++- .../plugin/injector/BukkitInjector.java | 16 +++++-- .../craftengine/bukkit/util/Reflections.java | 2 +- .../core/item/NetworkItemHandler.java | 2 +- .../modifier/CustomModelDataModifier.java | 7 +++ .../item/modifier/CustomNameModifier.java | 7 +++ .../item/modifier/EnchantmentModifier.java | 45 +++++++++++++++++-- .../core/item/modifier/ItemNameModifier.java | 7 +++ .../core/item/modifier/LoreModifier.java | 7 +++ .../core/item/modifier/TagsModifier.java | 18 +++++++- .../core/item/modifier/TrimModifier.java | 26 +++++++++-- .../item/modifier/UnbreakableModifier.java | 7 +++ .../core/pack/AbstractPackManager.java | 31 +++++++------ 14 files changed, 175 insertions(+), 30 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java index 188bfcdd6..dec3c6b62 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java @@ -33,7 +33,7 @@ public class LegacyItemWrapper implements ItemWrapper { public boolean setTag(Object value, Object... path) { if (value instanceof Tag tag) { try { - Object nmsTag = FastNMS.INSTANCE.method$NbtIo$fromBytes(NBT.toBytes(tag, !VersionHelper.isOrAbove1_20_3())); + Object nmsTag = FastNMS.INSTANCE.method$NbtIo$fromBytes(NBT.toBytes(tag, true)); return this.rtagItem.set(nmsTag, path); } catch (IOException e) { CraftEngine.instance().logger().warn("Failed to set NBT tag " + Arrays.toString(path), e); @@ -49,7 +49,7 @@ public class LegacyItemWrapper implements ItemWrapper { try { // Incompatible DFU version // return this.rtagItem.add(Reflections.instance$SPARROW_NBT_OPS.convertTo(Reflections.instance$NBT_OPS, tag), path); - Object nmsTag = FastNMS.INSTANCE.method$NbtIo$fromBytes(NBT.toBytes(tag, !VersionHelper.isOrAbove1_20_3())); + Object nmsTag = FastNMS.INSTANCE.method$NbtIo$fromBytes(NBT.toBytes(tag, true)); return this.rtagItem.add(nmsTag, path); } catch (IOException e) { CraftEngine.instance().logger().warn("Failed to add NBT tag " + Arrays.toString(path), e); @@ -66,6 +66,7 @@ public class LegacyItemWrapper implements ItemWrapper { public Tag getNBTTag(Object... path) { Object tag = getExactTag(path); + if (tag == null) return null; try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(FastNMS.INSTANCE.method$NbtIo$toBytes(tag)))) { return NBT.readUnnamedTag(dis, !VersionHelper.isOrAbove1_20_3()); } catch (IOException e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java index 37081736d..01e7a45cb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; @@ -42,8 +43,30 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler { if (optionalCustomItem.isEmpty()) { if (!Config.interceptItem()) return Optional.empty(); return new OtherItem(wrapped).process(); + } else { + CustomItem customItem = optionalCustomItem.get(); + if (!customItem.hasClientBoundDataModifier()) { + if (!Config.interceptItem()) return Optional.empty(); + return new OtherItem(wrapped).process(); + } else { + CompoundTag tag = new CompoundTag(); + for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { + modifier.prepareNetworkItem(wrapped, context, tag); + modifier.apply(wrapped, context); + } + if (Config.interceptItem()) { + if (!tag.containsKey("display.Name")) { + processCustomName(wrapped, tag::put); + } + if (!tag.containsKey("display.Lore")) { + processLore(wrapped, tag::put); + } + } + if (tag.isEmpty()) return Optional.empty(); + wrapped.setTag(tag, NETWORK_ITEM_TAG); + return Optional.of(wrapped); + } } - return Optional.empty(); } public static boolean processCustomName(Item item, BiConsumer callback) { 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 f3bd26abd..ace94cb32 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 @@ -810,7 +810,7 @@ public class BukkitInjector { if (!previous.isEmpty()) { holder.ceChunk().setDirty(true); if (Config.enableLightSystem()) { - updateLightIfChanged(holder, previous.vanillaBlockState().handle(), newState, y, z, x); + updateLightIfChanged(holder, previousState, newState, newState, x, y, z); } } } else { @@ -820,7 +820,7 @@ public class BukkitInjector { holder.ceChunk().setDirty(true); // 如果新方块的光照属性和客户端认为的不同 if (Config.enableLightSystem() && !immutableBlockState.isEmpty()) { - updateLightIfChanged(holder, immutableBlockState.vanillaBlockState().handle(), newState, y, z, x); + updateLightIfChanged(holder, previousState, immutableBlockState.vanillaBlockState().handle(), newState, x, y, z); } } } catch (Exception e) { @@ -828,9 +828,17 @@ public class BukkitInjector { } } - protected static void updateLightIfChanged(@This InjectedHolder thisObj, Object oldState, Object newState, int y, int z, int x) { + protected static void updateLightIfChanged(@This InjectedHolder thisObj, Object oldServerSideState, Object clientSideState, Object serverSideState, int x, int y, int z) { CEWorld world = thisObj.ceChunk().world(); - if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(oldState, newState, world.world().serverWorld(), LocationUtils.toBlockPos(x, y, z))) { + Object blockPos = LocationUtils.toBlockPos(x, y, z); + Object serverWorld = world.world().serverWorld(); + if (clientSideState != serverSideState && FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(clientSideState, serverSideState, serverWorld, blockPos)) { + SectionPos sectionPos = thisObj.cePos(); + List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15); + world.sectionLightUpdated(pos); + return; + } + if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(oldServerSideState, serverSideState, serverWorld, blockPos)) { SectionPos sectionPos = thisObj.cePos(); List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15); world.sectionLightUpdated(pos); 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 c103fe711..6587d5cac 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 @@ -2554,7 +2554,7 @@ public class Reflections { public static final Method method$BlockBehaviour$getCollisionShape = requireNonNull( ReflectionUtils.getDeclaredMethod( - clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getCollisionShape", "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos, clazz$CollisionContext + clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getCollisionShape", VersionHelper.isOrAbove1_20_3() ? "b" : "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos, clazz$CollisionContext ) ); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java index 263f74abf..09635b18d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/NetworkItemHandler.java @@ -13,7 +13,7 @@ import java.util.Optional; public interface NetworkItemHandler { Operation[] BY_INDEX = new Operation[] {Operation.ADD, Operation.REMOVE, Operation.RESET}; - String NETWORK_ITEM_TAG = "craftengine:network"; + String NETWORK_ITEM_TAG = "craftengine:network_modifiers"; String NETWORK_OPERATION = "type"; String NETWORK_VALUE = "value"; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java index 359b7b50d..fb6ec08d1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java @@ -34,6 +34,13 @@ public class CustomModelDataModifier implements ItemDataModifier { } else { networkData.put(ComponentKeys.CUSTOM_MODEL_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } + } else { + Tag previous = item.getNBTTag("CustomModelData"); + if (previous != null) { + networkData.put("CustomModelData", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("CustomModelData", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java index aca62cdcd..d16b5281b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java @@ -36,6 +36,13 @@ public class CustomNameModifier implements ItemDataModifier { } else { networkData.put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } + } else { + Tag previous = item.getNBTTag("display", "Name"); + if (previous != null) { + networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java index 54c5ad10f..88a06c183 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java @@ -1,9 +1,9 @@ package net.momirealms.craftengine.core.item.modifier; -import net.momirealms.craftengine.core.item.Enchantment; -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.*; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; import java.util.List; @@ -27,4 +27,41 @@ public class EnchantmentModifier implements ItemDataModifier { item.setEnchantments(this.enchantments); } } + + @Override + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.STORED_ENCHANTMENTS); + if (previous != null) { + networkData.put(ComponentKeys.STORED_ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.STORED_ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } else { + Tag previous = item.getNBTTag("StoredEnchantments"); + if (previous != null) { + networkData.put("StoredEnchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("StoredEnchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + } else { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.ENCHANTMENTS); + if (previous != null) { + networkData.put(ComponentKeys.ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } else { + Tag previous = item.getNBTTag("Enchantments"); + if (previous != null) { + networkData.put("Enchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("Enchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + } + } } 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 1655179e4..f59c44abb 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 @@ -36,6 +36,13 @@ public class ItemNameModifier implements ItemDataModifier { } else { networkData.put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } + } else { + Tag previous = item.getNBTTag("display", "Name"); + if (previous != null) { + networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } } } } 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 0b2a8e412..6328fe5c8 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 @@ -39,6 +39,13 @@ public class LoreModifier implements ItemDataModifier { } else { networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } + } else { + Tag previous = item.getNBTTag("display", "Lore"); + if (previous != null) { + networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java index c49ae4cbc..582fce937 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java @@ -2,8 +2,11 @@ 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.item.NetworkItemHandler; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.TypeUtils; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; import java.util.LinkedHashMap; import java.util.Map; @@ -26,13 +29,26 @@ public class TagsModifier implements ItemDataModifier { @Override public void apply(Item item, ItemBuildContext context) { - for (Map.Entry entry : arguments.entrySet()) { + for (Map.Entry entry : this.arguments.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); item.setTag(value, key); } } + // TODO NOT PERFECT + @Override + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + for (Map.Entry entry : this.arguments.entrySet()) { + Tag previous = item.getNBTTag(entry.getKey()); + if (previous != null) { + networkData.put(entry.getKey(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(entry.getKey(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + } + private static Map mapToMap(final Map source) { Map resultMap = new LinkedHashMap<>(); recursiveMapProcessing(source, resultMap); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java index e3a9e5cf1..4d8a4facd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java @@ -1,8 +1,9 @@ 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.item.Trim; +import net.momirealms.craftengine.core.item.*; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; public class TrimModifier implements ItemDataModifier { private final String material; @@ -22,4 +23,23 @@ public class TrimModifier implements ItemDataModifier { public void apply(Item item, ItemBuildContext context) { item.trim(new Trim(this.material, this.pattern)); } + + @Override + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.TRIM); + if (previous != null) { + networkData.put(ComponentKeys.TRIM.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.TRIM.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } else { + Tag previous = item.getNBTTag("Trim"); + if (previous != null) { + networkData.put("Trim", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("Trim", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java index 3e3f2b93c..34c58ed56 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java @@ -34,6 +34,13 @@ public class UnbreakableModifier implements ItemDataModifier { } else { networkData.put(ComponentKeys.UNBREAKABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } + } else { + Tag previous = item.getNBTTag("Unbreakable"); + if (previous != null) { + networkData.put("Unbreakable", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("Unbreakable", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } } } } 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 d993b75d8..bad5c544c 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 @@ -147,21 +147,26 @@ public abstract class AbstractPackManager implements PackManager { @Override public void load() { - List> list = Config.instance().settings().getMapList("resource-pack.delivery.hosting"); - if (list == null || list.isEmpty()) { - this.resourcePackHost = NoneHost.INSTANCE; + Object hostingObj = Config.instance().settings().get("resource-pack.delivery.hosting"); + Map arguments; + if (hostingObj instanceof Map) { + arguments = MiscUtils.castToMap(hostingObj, false); + } else if (hostingObj instanceof List list && !list.isEmpty()) { + arguments = MiscUtils.castToMap(list.get(0), false); } else { - try { - // we might add multiple host methods in future versions - this.resourcePackHost = ResourcePackHosts.fromMap(MiscUtils.castToMap(list.get(0), false)); - } catch (LocalizedException e) { - if (e instanceof LocalizedResourceConfigException exception) { - exception.setPath(plugin.dataFolderPath().resolve("config.yml")); - e.setArgument(1, "hosting"); - } - TranslationManager.instance().log(e.node(), e.arguments()); - this.resourcePackHost = NoneHost.INSTANCE; + this.resourcePackHost = NoneHost.INSTANCE; + return; + } + try { + // we might add multiple host methods in future versions + this.resourcePackHost = ResourcePackHosts.fromMap(arguments); + } catch (LocalizedException e) { + if (e instanceof LocalizedResourceConfigException exception) { + exception.setPath(plugin.dataFolderPath().resolve("config.yml")); + e.setArgument(1, "hosting"); } + TranslationManager.instance().log(e.node(), e.arguments()); + this.resourcePackHost = NoneHost.INSTANCE; } } From fed73b746bef0d39bf29a42979ffe4c297f93dcb Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Thu, 29 May 2025 21:29:01 +0800 Subject: [PATCH 89/89] 0.0.55 --- bukkit/build.gradle.kts | 4 ++ .../bukkit/item/LegacyItemWrapper.java | 26 ++----------- .../plugin/network/BukkitNetworkManager.java | 37 ++++++------------- .../craftengine/bukkit/util/Reflections.java | 3 +- core/build.gradle.kts | 4 ++ .../core/util/AdventureHelper.java | 4 +- gradle.properties | 4 +- 7 files changed, 30 insertions(+), 52 deletions(-) diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index db41b3d52..b1d1e570b 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -19,6 +19,10 @@ dependencies { compileOnly("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}") // NBT compileOnly("net.momirealms:sparrow-nbt:${rootProject.properties["sparrow_nbt_version"]}") + compileOnly("net.momirealms:sparrow-nbt-adventure:${rootProject.properties["sparrow_nbt_version"]}") + compileOnly("net.momirealms:sparrow-nbt-codec:${rootProject.properties["sparrow_nbt_version"]}") + compileOnly("net.momirealms:sparrow-nbt-legacy-codec:${rootProject.properties["sparrow_nbt_version"]}") + // Util compileOnly("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}") // NMS compileOnly("net.momirealms:craft-engine-nms-helper:${rootProject.properties["nms_helper_version"]}") diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java index dec3c6b62..452cf8cb1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item; import com.saicone.rtag.RtagItem; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.VersionHelper; @@ -32,13 +33,7 @@ public class LegacyItemWrapper implements ItemWrapper { public boolean setTag(Object value, Object... path) { if (value instanceof Tag tag) { - try { - Object nmsTag = FastNMS.INSTANCE.method$NbtIo$fromBytes(NBT.toBytes(tag, true)); - return this.rtagItem.set(nmsTag, path); - } catch (IOException e) { - CraftEngine.instance().logger().warn("Failed to set NBT tag " + Arrays.toString(path), e); - return false; - } + return this.rtagItem.set(Reflections.instance$SPARROW_NBT_OPS.convertTo(Reflections.instance$NBT_OPS, tag), path); } else { return this.rtagItem.set(value, path); } @@ -46,15 +41,7 @@ public class LegacyItemWrapper implements ItemWrapper { public boolean add(Object value, Object... path) { if (value instanceof Tag tag) { - try { - // Incompatible DFU version - // return this.rtagItem.add(Reflections.instance$SPARROW_NBT_OPS.convertTo(Reflections.instance$NBT_OPS, tag), path); - Object nmsTag = FastNMS.INSTANCE.method$NbtIo$fromBytes(NBT.toBytes(tag, true)); - return this.rtagItem.add(nmsTag, path); - } catch (IOException e) { - CraftEngine.instance().logger().warn("Failed to add NBT tag " + Arrays.toString(path), e); - return false; - } + return this.rtagItem.add(Reflections.instance$SPARROW_NBT_OPS.convertTo(Reflections.instance$NBT_OPS, tag), path); } else { return this.rtagItem.add(value, path); } @@ -67,12 +54,7 @@ public class LegacyItemWrapper implements ItemWrapper { public Tag getNBTTag(Object... path) { Object tag = getExactTag(path); if (tag == null) return null; - try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(FastNMS.INSTANCE.method$NbtIo$toBytes(tag)))) { - return NBT.readUnnamedTag(dis, !VersionHelper.isOrAbove1_20_3()); - } catch (IOException e) { - CraftEngine.instance().logger().warn("Failed to read NBT tag " + Arrays.toString(path), e); - return null; - } + return Reflections.instance$NBT_OPS.convertTo(Reflections.instance$SPARROW_NBT_OPS, tag); } public int count() { 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 11db3f193..e3975568f 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 @@ -565,17 +565,25 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } private boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) { - if (handledCompression) return false; + if (this.handledCompression) return false; int compressIndex = ctx.pipeline().names().indexOf("compress"); if (compressIndex == -1) return false; - handledCompression = true; + this.handledCompression = true; int encoderIndex = ctx.pipeline().names().indexOf(PACKET_ENCODER); if (encoderIndex == -1) return false; if (compressIndex > encoderIndex) { decompress(ctx, buffer, buffer); + PluginChannelDecoder decoder = (PluginChannelDecoder) ctx.pipeline().get(PACKET_DECODER); + if (decoder != null) { + if (decoder.relocated) return true; + decoder.relocated = true; + } PluginChannelEncoder encoder = (PluginChannelEncoder) ctx.pipeline().remove(PACKET_ENCODER); String encoderName = ctx.pipeline().names().contains("outbound_config") ? "outbound_config" : "encoder"; ctx.pipeline().addBefore(encoderName, PACKET_ENCODER, new PluginChannelEncoder(encoder)); + decoder = (PluginChannelDecoder) ctx.pipeline().remove(PACKET_DECODER); + String decoderName = ctx.pipeline().names().contains("inbound_config") ? "inbound_config" : "decoder"; + ctx.pipeline().addBefore(decoderName, PACKET_DECODER, new PluginChannelDecoder(decoder)); return true; } return false; @@ -608,7 +616,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes public class PluginChannelDecoder extends MessageToMessageDecoder { private final NetWorkUser player; - private boolean handledCompression = false; + public boolean relocated = false; public PluginChannelDecoder(NetWorkUser player) { this.player = player; @@ -616,38 +624,17 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes public PluginChannelDecoder(PluginChannelDecoder decoder) { this.player = decoder.player; - this.handledCompression = decoder.handledCompression; + this.relocated = decoder.relocated; } @Override protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) { - boolean needCompression = !handledCompression && handleCompression(channelHandlerContext, byteBuf); this.onByteBufReceive(byteBuf); - if (needCompression) { - compress(channelHandlerContext, byteBuf); - } if (byteBuf.isReadable()) { list.add(byteBuf.retain()); } } - private boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) { - if (handledCompression) return false; - int compressIndex = ctx.pipeline().names().indexOf("compress"); - if (compressIndex == -1) return false; - handledCompression = true; - int decoderIndex = ctx.pipeline().names().indexOf(PACKET_DECODER); - if (decoderIndex == -1) return false; - if (compressIndex > decoderIndex) { - decompress(ctx, buffer, buffer); - PluginChannelDecoder encoder = (PluginChannelDecoder) ctx.pipeline().remove(PACKET_DECODER); - String decoderName = ctx.pipeline().names().contains("inbound_config") ? "inbound_config" : "decoder"; - ctx.pipeline().addBefore(decoderName, PACKET_DECODER, new PluginChannelDecoder(encoder)); - return true; - } - return false; - } - private void onByteBufReceive(ByteBuf buffer) { // I don't care packets before PLAY for the moment if (player.decoderState() != ConnectionState.PLAY) return; 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 6587d5cac..ede8f4f74 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 @@ -17,6 +17,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.sparrow.nbt.codec.LegacyNBTOps; import net.momirealms.sparrow.nbt.codec.NBTOps; import org.bukkit.NamespacedKey; import org.bukkit.block.BlockState; @@ -6969,7 +6970,7 @@ public class Reflections { instance$JAVA_OPS = null; } instance$JSON_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, JsonOps.INSTANCE, instance$MinecraftRegistry); - instance$SPARROW_NBT_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, NBTOps.INSTANCE, instance$MinecraftRegistry); + instance$SPARROW_NBT_OPS = (DynamicOps) method$RegistryOps$create.invoke(null, VersionHelper.isOrAbove1_20_5() ? NBTOps.INSTANCE : LegacyNBTOps.INSTANCE, instance$MinecraftRegistry); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 7af5d3bbe..29856d15b 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -18,6 +18,10 @@ dependencies { compileOnly("org.yaml:snakeyaml:${rootProject.properties["snake_yaml_version"]}") // NBT implementation("net.momirealms:sparrow-nbt:${rootProject.properties["sparrow_nbt_version"]}") + implementation("net.momirealms:sparrow-nbt-adventure:${rootProject.properties["sparrow_nbt_version"]}") + implementation("net.momirealms:sparrow-nbt-codec:${rootProject.properties["sparrow_nbt_version"]}") + implementation("net.momirealms:sparrow-nbt-legacy-codec:${rootProject.properties["sparrow_nbt_version"]}") + // Util compileOnly("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}") // Adventure // TODO Create an API module diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index 51bcb5f9e..c404f15a8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -12,8 +12,8 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.json.JSONOptions; import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer; import net.momirealms.sparrow.nbt.Tag; -import net.momirealms.sparrow.nbt.serializer.NBTComponentSerializer; -import net.momirealms.sparrow.nbt.serializer.NBTSerializerOptions; +import net.momirealms.sparrow.nbt.adventure.NBTComponentSerializer; +import net.momirealms.sparrow.nbt.adventure.NBTSerializerOptions; import java.util.Map; import java.util.regex.Pattern; diff --git a/gradle.properties b/gradle.properties index 750471733..5aefedf21 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.54.12 +project_version=0.0.55 config_version=34 lang_version=14 project_group=net.momirealms @@ -39,7 +39,7 @@ geantyref_version=1.3.16 zstd_version=1.5.7-2 commons_io_version=2.18.0 commons_imaging_version=1.0.0-alpha6 -sparrow_nbt_version=0.8.4 +sparrow_nbt_version=0.9.0 sparrow_util_version=0.47 fastutil_version=8.5.15 netty_version=4.1.121.Final