mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-19 15:09:15 +00:00
添加指令用于修改结构nbt文件
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("com.gradleup.shadow") version "9.2.2"
|
||||
id("com.gradleup.shadow") version "9.3.0"
|
||||
id("maven-publish")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("com.gradleup.shadow") version "9.2.2"
|
||||
id("com.gradleup.shadow") version "9.3.0"
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("com.gradleup.shadow") version "9.2.2"
|
||||
id("com.gradleup.shadow") version "9.3.0"
|
||||
id("de.eldoria.plugin-yml.bukkit") version "0.7.1"
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import xyz.jpenilla.runtask.pluginsapi.DownloadPluginsSpec
|
||||
import java.net.URI
|
||||
|
||||
plugins {
|
||||
id("com.gradleup.shadow") version "9.2.2"
|
||||
id("com.gradleup.shadow") version "9.3.0"
|
||||
id("de.eldoria.plugin-yml.paper") version "0.7.1"
|
||||
id("xyz.jpenilla.run-paper") version "3.0.2"
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
|
||||
new DebugIsSectionInjectedCommand(this, plugin),
|
||||
new DebugMigrateTemplatesCommand(this, plugin),
|
||||
new DebugIsChunkPersistentLoadedCommand(this, plugin),
|
||||
new DebugOptimizeFurnitureStructureCommand(this, plugin),
|
||||
new TotemAnimationCommand(this, plugin),
|
||||
new EnableResourceCommand(this, plugin),
|
||||
new DisableResourceCommand(this, plugin),
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.command.feature;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
|
||||
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 net.momirealms.craftengine.core.util.NBTUtils;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.DoubleTag;
|
||||
import net.momirealms.sparrow.nbt.ListTag;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.bukkit.parser.NamespacedKeyParser;
|
||||
import org.incendo.cloud.bukkit.parser.WorldParser;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.context.CommandInput;
|
||||
import org.incendo.cloud.parser.standard.DoubleParser;
|
||||
import org.incendo.cloud.suggestion.Suggestion;
|
||||
import org.incendo.cloud.suggestion.SuggestionProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class DebugOptimizeFurnitureStructureCommand extends BukkitCommandFeature<CommandSender> {
|
||||
|
||||
public DebugOptimizeFurnitureStructureCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
|
||||
super(commandManager, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
|
||||
return builder
|
||||
.required("world", WorldParser.worldParser())
|
||||
.required("file", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
|
||||
@Override
|
||||
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> context, @NonNull CommandInput input) {
|
||||
World world = context.get("world");
|
||||
Path generated = world.getWorldFolder().toPath().resolve("generated");
|
||||
if (!Files.exists(generated)) {
|
||||
return CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
try {
|
||||
return CompletableFuture.completedFuture(findStructures(generated).stream().map(Suggestion::suggestion).collect(Collectors.toList()));
|
||||
} catch (IOException e) {
|
||||
return CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
}))
|
||||
.optional("y-offset", DoubleParser.doubleParser())
|
||||
.handler(context -> {
|
||||
World world = context.get("world");
|
||||
NamespacedKey file = context.get("file");
|
||||
double offset = (double) context.optional("y-offset").orElse(0d);
|
||||
Path filePath = world.getWorldFolder().toPath().resolve("generated").resolve(file.getNamespace()).resolve("structures").resolve(file.getKey() + ".nbt");
|
||||
Sender sender = plugin().senderFactory().wrap(context.sender());
|
||||
if (!Files.exists(filePath)) {
|
||||
sender.sendMessage(Component.text("File not found", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
try (InputStream is = Files.newInputStream(filePath)) {
|
||||
CompoundTag structureTag = NBTUtils.readCompressed(is);
|
||||
ListTag entitiesTag = structureTag.getList("entities");
|
||||
if (entitiesTag == null) {
|
||||
sender.sendMessage(Component.text("Entities not found", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
int count = 0;
|
||||
ListTag toSave = new ListTag();
|
||||
for (Tag entityTag0 : entitiesTag) {
|
||||
CompoundTag entityTag = (CompoundTag) entityTag0;
|
||||
CompoundTag entityNBTTag = (CompoundTag) entityTag.get("nbt");
|
||||
if (entityNBTTag != null) {
|
||||
CompoundTag bukkitValuesTag = (CompoundTag) entityNBTTag.get("BukkitValues");
|
||||
if (bukkitValuesTag != null) {
|
||||
// 不保存碰撞实体
|
||||
if (bukkitValuesTag.containsKey("craftengine:collision")) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
if (bukkitValuesTag.containsKey("craftengine:furniture_id")) {
|
||||
if (offset != 0) {
|
||||
ListTag pos = (ListTag) entityTag.get("pos");
|
||||
double previousY = pos.getDouble(1);
|
||||
pos.set(1, new DoubleTag(previousY + offset));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
toSave.add(entityTag);
|
||||
}
|
||||
if (count == 0) {
|
||||
sender.sendMessage(Component.text("Nothing changed", NamedTextColor.WHITE));
|
||||
} else {
|
||||
structureTag.put("entities", toSave);
|
||||
try (OutputStream os = Files.newOutputStream(filePath)) {
|
||||
NBTUtils.writeCompressed(structureTag, os);
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(Component.text("Internal error", NamedTextColor.RED));
|
||||
plugin().logger().severe("Cannot write structure NBT file", e);
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(Component.text(count + " entities modified", NamedTextColor.WHITE));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(Component.text("Internal error", NamedTextColor.RED));
|
||||
plugin().logger().severe("Cannot read structure NBT file", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeatureID() {
|
||||
return "debug_optimize_furniture_structure";
|
||||
}
|
||||
|
||||
public static List<String> findStructures(Path startPath) throws IOException {
|
||||
// 并行遍历文件树,使用自定义的BiPredicate进行过滤
|
||||
try (Stream<Path> stream = Files.walk(startPath, FileVisitOption.FOLLOW_LINKS)) {
|
||||
return stream.filter(Files::isRegularFile)
|
||||
.filter(path -> {
|
||||
String filename = path.getFileName().toString();
|
||||
return filename.endsWith(".nbt") &&
|
||||
filename.length() > 4; // 确保有文件名(不只是.nbt)
|
||||
})
|
||||
.map(path -> {
|
||||
try {
|
||||
return extractPair(startPath, path);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private static String extractPair(Path basePath, Path nbtFile) {
|
||||
try {
|
||||
Path relativePath = basePath.relativize(nbtFile);
|
||||
List<String> parts = new ArrayList<>();
|
||||
for (Path part : relativePath) {
|
||||
parts.add(part.toString());
|
||||
}
|
||||
// 检查是否符合 xxx/structures/xxx.nbt 模式
|
||||
if (parts.size() >= 3 && "structures".equals(parts.get(parts.size() - 2))) {
|
||||
String firstXxx = parts.get(parts.size() - 3);
|
||||
String fileName = parts.getLast();
|
||||
if (fileName.endsWith(".nbt")) {
|
||||
String secondXxx = fileName.substring(0, fileName.length() - 4);
|
||||
return firstXxx + ":" + secondXxx;
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -283,6 +283,13 @@ debug_furniture:
|
||||
- /craftengine debug furniture
|
||||
- /ce debug furniture
|
||||
|
||||
debug_optimize_furniture_structure:
|
||||
enable: true
|
||||
permission: ce.command.debug.optimize_furniture_structure
|
||||
usage:
|
||||
- /craftengine debug optimize-furniture-structure
|
||||
- /ce debug optimize-furniture-structure
|
||||
|
||||
debug_test:
|
||||
enable: true
|
||||
permission: ce.command.debug.test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("com.gradleup.shadow") version "9.2.2"
|
||||
id("com.gradleup.shadow") version "9.3.0"
|
||||
id("maven-publish")
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.momirealms.craftengine.core.util;
|
||||
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.NBT;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public final class NBTUtils {
|
||||
|
||||
private NBTUtils() {
|
||||
}
|
||||
|
||||
public static void writeCompressed(CompoundTag nbt, OutputStream stream) throws IOException {
|
||||
try (DataOutputStream dataoutputstream = new DataOutputStream(new BufferedOutputStream(new GZIPOutputStream(stream)))) {
|
||||
NBT.writeCompound(nbt, dataoutputstream, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static CompoundTag readCompressed(InputStream stream) throws IOException {
|
||||
try (DataInputStream datainputstream = new DataInputStream(new BufferedInputStream(new GZIPInputStream(stream)))) {
|
||||
return NBT.readCompound(datainputstream, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ geantyref_version=1.3.16
|
||||
zstd_version=1.5.7-6
|
||||
commons_io_version=2.21.0
|
||||
commons_lang3_version=3.20.0
|
||||
sparrow_nbt_version=0.10.8
|
||||
sparrow_nbt_version=0.10.9
|
||||
sparrow_util_version=0.69
|
||||
fastutil_version=8.5.18
|
||||
netty_version=4.1.128.Final
|
||||
@@ -48,7 +48,7 @@ byte_buddy_version=1.18.1
|
||||
ahocorasick_version=0.6.3
|
||||
snake_yaml_version=2.5
|
||||
anti_grief_version=1.0.5
|
||||
nms_helper_version=1.0.148
|
||||
nms_helper_version=1.0.149
|
||||
evalex_version=3.5.0
|
||||
reactive_streams_version=1.0.4
|
||||
amazon_awssdk_version=2.38.7
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
Reference in New Issue
Block a user