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 {
|
plugins {
|
||||||
id("com.gradleup.shadow") version "9.2.2"
|
id("com.gradleup.shadow") version "9.3.0"
|
||||||
id("maven-publish")
|
id("maven-publish")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("com.gradleup.shadow") version "9.2.2"
|
id("com.gradleup.shadow") version "9.3.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
plugins {
|
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"
|
id("de.eldoria.plugin-yml.bukkit") version "0.7.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import xyz.jpenilla.runtask.pluginsapi.DownloadPluginsSpec
|
|||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
plugins {
|
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("de.eldoria.plugin-yml.paper") version "0.7.1"
|
||||||
id("xyz.jpenilla.run-paper") version "3.0.2"
|
id("xyz.jpenilla.run-paper") version "3.0.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
|
|||||||
new DebugIsSectionInjectedCommand(this, plugin),
|
new DebugIsSectionInjectedCommand(this, plugin),
|
||||||
new DebugMigrateTemplatesCommand(this, plugin),
|
new DebugMigrateTemplatesCommand(this, plugin),
|
||||||
new DebugIsChunkPersistentLoadedCommand(this, plugin),
|
new DebugIsChunkPersistentLoadedCommand(this, plugin),
|
||||||
|
new DebugOptimizeFurnitureStructureCommand(this, plugin),
|
||||||
new TotemAnimationCommand(this, plugin),
|
new TotemAnimationCommand(this, plugin),
|
||||||
new EnableResourceCommand(this, plugin),
|
new EnableResourceCommand(this, plugin),
|
||||||
new DisableResourceCommand(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
|
- /craftengine debug furniture
|
||||||
- /ce 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:
|
debug_test:
|
||||||
enable: true
|
enable: true
|
||||||
permission: ce.command.debug.test
|
permission: ce.command.debug.test
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("com.gradleup.shadow") version "9.2.2"
|
id("com.gradleup.shadow") version "9.3.0"
|
||||||
id("maven-publish")
|
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
|
zstd_version=1.5.7-6
|
||||||
commons_io_version=2.21.0
|
commons_io_version=2.21.0
|
||||||
commons_lang3_version=3.20.0
|
commons_lang3_version=3.20.0
|
||||||
sparrow_nbt_version=0.10.8
|
sparrow_nbt_version=0.10.9
|
||||||
sparrow_util_version=0.69
|
sparrow_util_version=0.69
|
||||||
fastutil_version=8.5.18
|
fastutil_version=8.5.18
|
||||||
netty_version=4.1.128.Final
|
netty_version=4.1.128.Final
|
||||||
@@ -48,7 +48,7 @@ byte_buddy_version=1.18.1
|
|||||||
ahocorasick_version=0.6.3
|
ahocorasick_version=0.6.3
|
||||||
snake_yaml_version=2.5
|
snake_yaml_version=2.5
|
||||||
anti_grief_version=1.0.5
|
anti_grief_version=1.0.5
|
||||||
nms_helper_version=1.0.148
|
nms_helper_version=1.0.149
|
||||||
evalex_version=3.5.0
|
evalex_version=3.5.0
|
||||||
reactive_streams_version=1.0.4
|
reactive_streams_version=1.0.4
|
||||||
amazon_awssdk_version=2.38.7
|
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
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
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
|
networkTimeout=10000
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
Reference in New Issue
Block a user