-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add the dump command #19
base: 1.19.4
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package xyz.nucleoid.creator_tools.command; | ||
|
||
import com.mojang.brigadier.Command; | ||
import com.mojang.brigadier.CommandDispatcher; | ||
import com.mojang.brigadier.context.CommandContext; | ||
import com.mojang.brigadier.exceptions.CommandSyntaxException; | ||
|
||
import net.minecraft.command.argument.IdentifierArgumentType; | ||
import net.minecraft.server.command.DataCommand; | ||
import net.minecraft.server.command.ServerCommandSource; | ||
import net.minecraft.server.command.DataCommand.ObjectType; | ||
import net.minecraft.text.Text; | ||
import xyz.nucleoid.creator_tools.CreatorTools; | ||
import xyz.nucleoid.creator_tools.exporter.DumpExporter; | ||
|
||
import static net.minecraft.server.command.CommandManager.argument; | ||
import static net.minecraft.server.command.CommandManager.literal; | ||
|
||
public final class DumpCommand { | ||
// @formatter:off | ||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) { | ||
var builder = literal("dump").requires(source -> source.hasPermissionLevel(4)); | ||
|
||
for (var objectType : DataCommand.TARGET_OBJECT_TYPES) { | ||
objectType.addArgumentsToBuilder(builder, builderx -> { | ||
return builderx | ||
.then(argument("path", IdentifierArgumentType.identifier()) | ||
.executes(context -> DumpCommand.dump(context, objectType))); | ||
}); | ||
} | ||
|
||
dispatcher.register(builder); | ||
} | ||
// @formatter:on | ||
|
||
private static int dump(CommandContext<ServerCommandSource> context, ObjectType objectType) throws CommandSyntaxException { | ||
var source = context.getSource(); | ||
|
||
var object = objectType.getObject(context); | ||
var nbt = object.getNbt(); | ||
|
||
var givenIdentifier = IdentifierArgumentType.getIdentifier(context, "path"); | ||
var identifier = CreatorTools.getSourceNameIdentifier(source, givenIdentifier); | ||
|
||
var future = DumpExporter.saveToExport(source.getServer(), nbt, identifier); | ||
|
||
future.handle((v, throwable) -> { | ||
if (throwable == null) { | ||
source.sendFeedback(Text.translatable("text.nucleoid_creator_tools.dump.success", identifier), false); | ||
} else { | ||
CreatorTools.LOGGER.error("Failed to export object to '{}'", identifier, throwable); | ||
source.sendError(Text.translatable("text.nucleoid_creator_tools.dump.error")); | ||
} | ||
return null; | ||
}); | ||
|
||
return Command.SINGLE_SUCCESS; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,84 @@ | ||||||||
package xyz.nucleoid.creator_tools.exporter; | ||||||||
|
||||||||
import net.minecraft.data.DataProvider; | ||||||||
import net.minecraft.nbt.NbtCompound; | ||||||||
import net.minecraft.nbt.NbtOps; | ||||||||
import net.minecraft.server.MinecraftServer; | ||||||||
import net.minecraft.util.Identifier; | ||||||||
import net.minecraft.util.InvalidIdentifierException; | ||||||||
import net.minecraft.util.JsonHelper; | ||||||||
import net.minecraft.util.PathUtil; | ||||||||
import net.minecraft.util.Util; | ||||||||
import net.minecraft.util.WorldSavePath; | ||||||||
|
||||||||
import java.io.IOException; | ||||||||
import java.io.OutputStreamWriter; | ||||||||
import java.nio.charset.StandardCharsets; | ||||||||
import java.nio.file.Files; | ||||||||
import java.nio.file.InvalidPathException; | ||||||||
import java.nio.file.Path; | ||||||||
import java.util.concurrent.CompletableFuture; | ||||||||
import java.util.concurrent.CompletionException; | ||||||||
|
||||||||
import com.google.gson.stream.JsonWriter; | ||||||||
import com.mojang.serialization.JsonOps; | ||||||||
|
||||||||
public final class DumpExporter { | ||||||||
private static final String DATA_DIRECTORY = "data"; | ||||||||
private static final String FILE_EXTENSION = ".json"; | ||||||||
|
||||||||
private DumpExporter() { | ||||||||
} | ||||||||
|
||||||||
public static CompletableFuture<Void> saveToExport(MinecraftServer server, NbtCompound nbt, Identifier identifier) { | ||||||||
return CompletableFuture.supplyAsync(() -> { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: |
||||||||
try { | ||||||||
var generatedPath = server.getSavePath(WorldSavePath.GENERATED); | ||||||||
var path = getAndCheckDataPath(generatedPath, identifier, FILE_EXTENSION); | ||||||||
|
||||||||
var json = NbtOps.INSTANCE.convertTo(JsonOps.INSTANCE, nbt); | ||||||||
System.out.println(json); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be removed? |
||||||||
|
||||||||
Files.createDirectories(path.getParent()); | ||||||||
|
||||||||
try (var output = Files.newOutputStream(path)) { | ||||||||
var jsonWriter = new JsonWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8)); | ||||||||
Comment on lines
+44
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
jsonWriter.setSerializeNulls(false); | ||||||||
jsonWriter.setIndent(" "); | ||||||||
|
||||||||
JsonHelper.writeSorted(jsonWriter, json, DataProvider.JSON_KEY_SORTING_COMPARATOR); | ||||||||
jsonWriter.flush(); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should not be needed if including the |
||||||||
} | ||||||||
|
||||||||
return null; | ||||||||
} catch (IOException | InvalidIdentifierException e) { | ||||||||
throw new CompletionException(e); | ||||||||
} | ||||||||
}, Util.getIoWorkerExecutor()); | ||||||||
} | ||||||||
|
||||||||
public static Path getDataPath(Path path, Identifier identifier, String extension) { | ||||||||
try { | ||||||||
Path namespacePath = path.resolve(identifier.getNamespace()); | ||||||||
Path dataPath = namespacePath.resolve(DATA_DIRECTORY); | ||||||||
|
||||||||
return PathUtil.getResourcePath(dataPath, identifier.getPath(), extension); | ||||||||
} catch (InvalidPathException e) { | ||||||||
throw new InvalidIdentifierException("Invalid resource path: " + identifier, e); | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
private static Path getAndCheckDataPath(Path path, Identifier identifier, String extension) { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, we should probably apply this to the map template exporter, too 😅 |
||||||||
if (identifier.getPath().contains("//")) { | ||||||||
throw new InvalidIdentifierException("Invalid resource path: " + identifier); | ||||||||
} | ||||||||
|
||||||||
Path dataPath = getDataPath(path, identifier, extension); | ||||||||
if (!(dataPath.startsWith(path) && PathUtil.isNormal(dataPath) && PathUtil.isAllowedName(dataPath))) { | ||||||||
throw new InvalidIdentifierException("Invalid resource path: " + dataPath); | ||||||||
} | ||||||||
|
||||||||
return dataPath; | ||||||||
} | ||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whenCompleteAsync(..., server)
? Sending messages off-thread has potential to explode 😅