Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
personthecat.catlib.command.DefaultLibCommands Maven / Gradle / Ivy
package personthecat.catlib.command;
import com.google.common.collect.Lists;
import com.mojang.brigadier.arguments.StringArgumentType;
import lombok.experimental.UtilityClass;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.class_1041;
import net.minecraft.class_124;
import net.minecraft.class_1291;
import net.minecraft.class_1293;
import net.minecraft.class_1294;
import net.minecraft.class_156;
import net.minecraft.class_1657;
import net.minecraft.class_1934;
import net.minecraft.class_2170;
import net.minecraft.class_2558;
import net.minecraft.class_2561;
import net.minecraft.class_2568;
import net.minecraft.class_2583;
import net.minecraft.class_2585;
import net.minecraft.class_310;
import net.minecraft.class_315;
import net.minecraft.network.chat.*;
import net.minecraft.server.MinecraftServer;
import personthecat.catlib.client.gui.SimpleTextPage;
import personthecat.catlib.command.arguments.JsonArgument;
import personthecat.catlib.config.LibConfig;
import personthecat.catlib.serialization.json.JsonPath;
import personthecat.catlib.data.ModDescriptor;
import personthecat.catlib.io.FileIO;
import personthecat.catlib.serialization.json.XjsUtils;
import personthecat.catlib.serialization.json.JsonCombiner;
import personthecat.catlib.util.McUtils;
import personthecat.catlib.util.PathUtils;
import xjs.core.Json;
import xjs.core.JsonObject;
import xjs.core.JsonValue;
import java.io.File;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import static net.minecraft.class_2170.method_9247;
import static personthecat.catlib.command.CommandSuggestions.CURRENT_JSON;
import static personthecat.catlib.command.CommandUtils.arg;
import static personthecat.catlib.command.CommandUtils.fileArg;
import static personthecat.catlib.command.CommandUtils.greedyArg;
import static personthecat.catlib.command.CommandUtils.jsonFileArg;
import static personthecat.catlib.command.CommandUtils.jsonPathArg;
import static personthecat.catlib.util.PathUtils.extension;
import static personthecat.catlib.util.PathUtils.noExtension;
@UtilityClass
public class DefaultLibCommands {
public static final String FILE_ARGUMENT = "file";
public static final String TO_ARGUMENT = "to";
public static final String PATH_ARGUMENT = "path";
public static final String VALUE_ARGUMENT = "value";
public static final String DIRECTORY_ARGUMENT = "dir";
public static final String NAME_ARGUMENT = "name";
public static final String MAX_ARGUMENT = "max";
public static final String SCALE_ARGUMENT = "scale";
/** The header displayed whenever the /display command runs. */
private static final String DISPLAY_HEADER = "--- {} ---";
/** The text formatting to be used for the display message header. */
private static final class_2583 DISPLAY_HEADER_STYLE = class_2583.field_24360
.method_10977(class_124.field_1060)
.method_10982(true);
/** The text formatting used to indicate values being deleted. */
private static final class_2583 DELETED_VALUE_STYLE = class_2583.field_24360
.method_10977(class_124.field_1061);
/** The text formatting used to indicate values being replaced. */
private static final class_2583 REPLACED_VALUE_STYLE = class_2583.field_24360
.method_10977(class_124.field_1060);
/** The text formatting used for the undo button. */
private static final class_2583 UNDO_STYLE = class_2583.field_24360
.method_10977(class_124.field_1080)
.method_10949(new class_2568(class_2568.class_5247.field_24342, new class_2585("Click to undo.")))
.method_27706(class_124.field_1073)
.method_10982(true);
/** The number of backups before a warning is displayed. */
private static final int BACKUP_COUNT_WARNING = 10;
public static List createAll(final ModDescriptor mod, final boolean global) {
return Lists.newArrayList(
createDisplay(mod, global),
createUpdate(mod, global),
createBackup(mod, global),
createCopy(mod, global),
createMove(mod, global),
createDelete(mod, global),
createClean(mod, global),
createRename(mod, global),
createOpen(mod, global),
createCombine(mod, global),
createTest(mod, global),
createUnTest(mod, global),
createCh(mod, global),
createCw(mod, global),
createToJson(mod, global),
createToXjs(mod, global)
);
}
public static LibCommandBuilder createDisplay(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("display")
.arguments(" []")
.append("Outputs the contents of any JSON file to the chat.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(jsonFileArg(FILE_ARGUMENT, mod)
.executes(utl.wrap(DefaultLibCommands::display))
.then(jsonPathArg(PATH_ARGUMENT)
.executes(utl.wrap(DefaultLibCommands::display))))
);
}
public static LibCommandBuilder createUpdate(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("update")
.arguments(" [] []")
.append("Manually update a JSON value. Omit the value or")
.append("path to display the current contents.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(jsonFileArg(FILE_ARGUMENT, mod)
.executes(utl.wrap(DefaultLibCommands::display))
.then(jsonPathArg(PATH_ARGUMENT)
.executes(utl.wrap(DefaultLibCommands::display))
.then(greedyArg(VALUE_ARGUMENT, CURRENT_JSON)
.executes(utl.wrap(DefaultLibCommands::update)))))
);
}
public static LibCommandBuilder createBackup(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("backup")
.arguments("")
.append("Copies a file to the current mod's backup folder.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(fileArg(FILE_ARGUMENT, mod)
.executes(utl.wrap(DefaultLibCommands::backup)))
);
}
public static LibCommandBuilder createCopy(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("copy")
.arguments(" ")
.append("Copies a file from one location to another.")
.append("Accepts either a directory or a file as .")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(fileArg(FILE_ARGUMENT, mod)
.then(fileArg(DIRECTORY_ARGUMENT, mod)
.executes(utl.wrap(DefaultLibCommands::copy))))
);
}
public static LibCommandBuilder createMove(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("move")
.arguments(" ")
.append("Moves a file from one location to another.")
.append("Accepts either a directory or a file as .")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(fileArg(FILE_ARGUMENT, mod)
.then(fileArg(DIRECTORY_ARGUMENT, mod)
.executes(utl.wrap( DefaultLibCommands::move))))
);
}
public static LibCommandBuilder createDelete(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("delete")
.arguments("")
.append("Moves a file to the current mod's backup folder.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(fileArg(FILE_ARGUMENT, mod)
.executes(utl.wrap(DefaultLibCommands::delete)))
);
}
public static LibCommandBuilder createClean(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("clean")
.arguments("")
.append("Moves all files in the given directory to the mod's")
.append("backup folder. Else, deletes the contents of the")
.append("mod's backup folder.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder.executes(utl.wrap(DefaultLibCommands::clean))
.then(fileArg(DIRECTORY_ARGUMENT, mod)
.executes(utl.wrap(DefaultLibCommands::clean)))
);
}
public static LibCommandBuilder createRename(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("rename")
.arguments(" ")
.append("Renames a file without needing a path or extension.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(fileArg(FILE_ARGUMENT, mod)
.then(class_2170.method_9244(NAME_ARGUMENT, StringArgumentType.word())
.executes(utl.wrap(DefaultLibCommands::rename))))
);
}
public static LibCommandBuilder createOpen(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("open")
.arguments("[]")
.append("Opens a file or directory in your default editor.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(fileArg(FILE_ARGUMENT, mod)
.executes(utl.wrap(DefaultLibCommands::open)))
);
}
public static LibCommandBuilder createCombine(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("combine")
.arguments(" ")
.append("Copies the given path from the first preset into the second preset.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(jsonFileArg(FILE_ARGUMENT, mod)
.then(jsonPathArg(PATH_ARGUMENT)
.then(jsonFileArg(TO_ARGUMENT, mod)
.executes(utl.wrap(DefaultLibCommands::combine)))))
);
}
public static LibCommandBuilder createTest(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("test")
.append("Applies night vision and spectator mode for easy cave viewing.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) ->
builder.executes(utl.wrap(DefaultLibCommands::test)));
}
public static LibCommandBuilder createUnTest(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("untest")
.append("Removes night vision and puts you in the default game mode.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) ->
builder.executes(utl.wrap(DefaultLibCommands::unTest)));
}
public static LibCommandBuilder createCh(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("ch")
.arguments("[]")
.append("Allows you to expand your chat height beyond the")
.append("default limit of 1.0.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.side(CommandSide.CLIENT)
.generate((builder, utl) -> builder.executes(utl.wrap(ctx -> ch(ctx, false)))
.then(method_9247(MAX_ARGUMENT).executes(utl.wrap(ctx -> ch(ctx, true))))
.then(arg(SCALE_ARGUMENT, 0.25, 5.0).executes(utl.wrap(ctx -> ch(ctx, false))))
);
}
public static LibCommandBuilder createCw(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("cw")
.arguments("[]")
.append("Allows you to expand your chat width beyond the")
.append("default limit of 1.0.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.side(CommandSide.CLIENT)
.generate((builder, utl) -> builder.executes(utl.wrap(ctx -> cw(ctx, false)))
.then(method_9247(MAX_ARGUMENT).executes(utl.wrap(ctx -> cw(ctx, true))))
.then(arg(SCALE_ARGUMENT, 0.25, 3.0).executes(utl.wrap(ctx -> cw(ctx, false))))
);
}
public static LibCommandBuilder createToJson(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("tojson")
.arguments("")
.append("Converts an XJS file to a regular JSON file.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(fileArg(FILE_ARGUMENT, mod)
.executes(utl.wrap(ctx -> convert(ctx, true)))));
}
public static LibCommandBuilder createToXjs(final ModDescriptor mod, final boolean global) {
return LibCommandBuilder.named("toxjs")
.arguments("")
.append("Converts a regular JSON into an XJS file.")
.type(global ? CommandType.GLOBAL : CommandType.MOD)
.generate((builder, utl) -> builder
.then(fileArg(FILE_ARGUMENT, mod)
.executes(utl.wrap(ctx -> convert(ctx, false)))));
}
private static void display(final CommandContextWrapper wrapper) {
final JsonArgument.Result file = wrapper.getJsonFile(FILE_ARGUMENT);
final JsonValue json = wrapper.getOptional(PATH_ARGUMENT, JsonPath.class)
.flatMap(result -> XjsUtils.getValueFromPath(file.json.get(), result))
.orElseGet(file.json);
final String header = file.file.getParentFile().getName() + "/" + file.file.getName();
final class_2561 headerComponent =
wrapper.createText(DISPLAY_HEADER, header).method_10862(DISPLAY_HEADER_STYLE);
final String details = json.trim().toString(XjsUtils.noCr());
final class_2561 detailsComponent = wrapper.lintMessage(details);
final long numLines = details.chars().filter(c -> c == '\n').count();
if (McUtils.isClientSide() && numLines >= LibConfig.displayLength()) {
loadTextPage(wrapper, headerComponent, detailsComponent);
return;
}
wrapper.generateMessage("")
.append(headerComponent)
.append("\n")
.append(detailsComponent)
.sendMessage();
}
@Environment(EnvType.CLIENT)
private static void loadTextPage(
final CommandContextWrapper wrapper, final class_2561 header, final class_2561 details) {
wrapper.setScreen(new SimpleTextPage(null, header, details));
}
private static void update(final CommandContextWrapper wrapper) {
final JsonArgument.Result file = wrapper.getJsonFile(FILE_ARGUMENT);
final JsonPath path = wrapper.getJsonPath(PATH_ARGUMENT);
// Read the old and new values.
final String toEscaped = wrapper.getString(VALUE_ARGUMENT);
final String toLiteral = unEscape(toEscaped);
final JsonValue toValue = Json.parse(toLiteral).trim();
final JsonValue fromValue = XjsUtils.getValueFromPath(file.json.get(), path)
.orElseGet(() -> Json.value(null));
final String fromLiteral = fromValue.unformatted().toString(XjsUtils.noCr());
final String fromEscaped = escape(fromLiteral);
// Write the new value.
XjsUtils.setValueFromPath(file.json.get(), path, toValue.isNull() ? null : toValue);
XjsUtils.writeJson(file.json.get(), file.file)
.expect("Error writing to file: {}", file.file.getName());
// Send feedback.
wrapper.generateMessage("Successfully updated {}.\n", file.file.getName())
.append(fromLiteral.replace("\r", ""), DELETED_VALUE_STYLE)
.append(" -> ")
.append(toLiteral, REPLACED_VALUE_STYLE)
.append(" ")
.append(generateUndo(wrapper.getInput(), fromEscaped, toEscaped))
.sendMessage();
}
private static class_2585 generateUndo(final String input, final String from, final String to) {
final int index = input.lastIndexOf(to);
final String command = (input.substring(0, index) + from).replace("\"\"", "\"");
final class_2558 undo = new class_2558(class_2558.class_2559.field_11750, command);
return (class_2585) new class_2585("[UNDO]").method_10862(UNDO_STYLE.method_10958(undo));
}
private static String escape(final String literal) {
return literal.replaceAll("\r?\n", "\\\\n") // newline -> \n
.replace("\"", "\\\""); // " -> \"
}
private static String unEscape(final String escaped) {
return escaped.replace("\\n", "\n")
.replace("\\\"", "\"");
}
private static void backup(final CommandContextWrapper wrapper) {
if (BACKUP_COUNT_WARNING < FileIO.backup(wrapper.getBackupsFolder(), wrapper.getFile(FILE_ARGUMENT), true)) {
wrapper.sendError("{} backups detected. Consider cleaning these out.", BACKUP_COUNT_WARNING);
}
wrapper.sendMessage("Backup created successfully.");
}
private static void copy(final CommandContextWrapper wrapper) {
FileIO.copy(wrapper.getFile(FILE_ARGUMENT), wrapper.getFile(DIRECTORY_ARGUMENT))
.expect("The file could not be copied.");
wrapper.sendMessage("File copied successfully.");
}
private static void move(final CommandContextWrapper wrapper) {
FileIO.move(wrapper.getFile(FILE_ARGUMENT), wrapper.getFile(DIRECTORY_ARGUMENT))
.expect("The file could not be moved.");
wrapper.sendMessage("File moved successfully.");
}
private static void delete(final CommandContextWrapper wrapper) {
final File file = wrapper.getFile(FILE_ARGUMENT);
if (PathUtils.isIn(wrapper.getMod().getBackupFolder(), file)) {
FileIO.delete(file);
wrapper.sendMessage("File deleted successfully.");
} else if (BACKUP_COUNT_WARNING < FileIO.backup(wrapper.getBackupsFolder(), wrapper.getFile(FILE_ARGUMENT), false)) {
wrapper.sendError("{} backups have been created. Consider cleaning these out.", BACKUP_COUNT_WARNING);
}
wrapper.sendMessage("File moved to backups.");
}
private static void clean(final CommandContextWrapper wrapper) {
final Optional directory = wrapper.getOptional(DIRECTORY_ARGUMENT, File.class)
.filter(dir -> !dir.equals(wrapper.getBackupsFolder()));
if (directory.isPresent()) {
final File dir = directory.get();
if (dir.isFile()) {
if (!dir.delete()) {
wrapper.sendError("Error deleting {}", dir.getName());
} else {
wrapper.sendMessage("Deleted {}", dir.getName());
}
} else {
cleanFiles(wrapper, dir);
}
} else {
cleanFiles(wrapper, wrapper.getBackupsFolder());
}
}
private static void cleanFiles(final CommandContextWrapper wrapper, final File dir) {
final int deleted = deleteNotRecursive(dir);
if (deleted < 0) {
wrapper.sendError("Some files could not be deleted.");
} else {
wrapper.sendMessage("Deleted {} files.", deleted);
}
}
private static int deleteNotRecursive(final File dir) {
int deleted = 0;
for (final File f : FileIO.listFiles(dir)) {
if (f.isFile() && !f.delete()) {
return -1;
}
deleted++;
}
return deleted;
}
private static void rename(final CommandContextWrapper wrapper) {
FileIO.rename(wrapper.getFile(FILE_ARGUMENT), wrapper.getString(NAME_ARGUMENT))
.expect("Error renaming file.");
wrapper.sendMessage("File renamed successfully.");
}
private static void open(final CommandContextWrapper wrapper) {
class_156.method_668().method_672(wrapper.getFile(FILE_ARGUMENT));
}
private static void combine(final CommandContextWrapper wrapper) {
final JsonArgument.Result from = wrapper.getJsonFile(FILE_ARGUMENT);
final JsonPath path = wrapper.getJsonPath(PATH_ARGUMENT);
final JsonArgument.Result to = wrapper.getJsonFile(TO_ARGUMENT);
if (BACKUP_COUNT_WARNING < FileIO.backup(wrapper.getBackupsFolder(), to.file, true)) {
wrapper.sendError("Created > {} backups. Consider cleaning these out.", BACKUP_COUNT_WARNING);
}
JsonCombiner.combine(from, to, path);
wrapper.sendMessage("Finished combining file. The original was moved to the backups directory.");
}
private static void test(final CommandContextWrapper wrapper) {
final class_1657 player = wrapper.getPlayer();
if (player != null) {
wrapper.setGameMode(class_1934.field_9219);
final class_1291 nightVision = class_1294.field_5925;
player.method_6092(new class_1293(nightVision, 999999999, 1, true, false));
}
}
private static void unTest(final CommandContextWrapper wrapper) {
final class_1657 player = wrapper.getPlayer();
if (player != null) {
final class_1934 mode = Optional.ofNullable(wrapper.getServer())
.map(MinecraftServer::method_3790)
.orElse(class_1934.field_9220);
wrapper.setGameMode(mode);
player.method_6016(class_1294.field_5925);
}
}
private static void ch(final CommandContextWrapper wrapper, final boolean max) {
final class_310 mc = class_310.method_1551();
final class_315 cfg = mc.field_1690;
final class_1041 window = Objects.requireNonNull(mc.method_22683(), "Not running client side");
final Optional scaleArgument = wrapper.getOptional(SCALE_ARGUMENT, Double.class);
if (!max && scaleArgument.isEmpty()) {
wrapper.sendMessage("Current chat height: {}", cfg.field_1838);
return;
}
final double possible = (window.method_4502() - 20.0) / 180.0;
if (max) {
cfg.field_1838 = possible;
} else {
final double height = (scaleArgument.get() * 180.0 + 20.0) * window.method_4495();
if (height > window.method_4506()) {
wrapper.sendError("Max size is {} with your current window and scale.", possible);
return;
}
cfg.field_1838 = scaleArgument.get();
}
cfg.method_1640();
wrapper.sendMessage("Updated chat height: {}", cfg.field_1838);
}
private static void cw(final CommandContextWrapper wrapper, final boolean max) {
final class_310 mc = class_310.method_1551();
final class_315 cfg = mc.field_1690;
final class_1041 window = Objects.requireNonNull(mc.method_22683(), "Not running client side");
final Optional scaleArgument = wrapper.getOptional(SCALE_ARGUMENT, Double.class);
if (!max && scaleArgument.isEmpty()) {
wrapper.sendMessage("Current chat width: {}", cfg.field_1915);
return;
}
final double possible = (double) window.method_4486() / 320.0;
if (max) {
cfg.field_1915 = possible;
} else {
final double width = scaleArgument.get() * 320.0 * window.method_4495();
if (width > window.method_4489()) {
wrapper.sendError("Max size is {} with your current window and scale.", possible);
return;
}
cfg.field_1915 = scaleArgument.get();
}
cfg.method_1640();
wrapper.sendMessage("Updated chat width: {}", cfg.field_1915);
}
private static void convert(final CommandContextWrapper wrapper, final boolean toJson) {
final File source = wrapper.getFile(FILE_ARGUMENT);
if (!source.exists()) {
wrapper.sendError("Found not found.");
return;
}
if (toJson == "json".equals(extension(source))) {
wrapper.sendError("File is already in the desired format.");
return;
}
final Optional json = XjsUtils.readJson(source);
if (json.isEmpty()) {
wrapper.sendError("The file could not be read.");
return;
}
final String extension = toJson ? "json" : "xjs";
final File converted = new File(source.getParentFile(), noExtension(source) + extension);
XjsUtils.writeJson(json.get(), converted).expect("Error writing file.");
if (!PathUtils.isIn(wrapper.getBackupsFolder(), source)) {
FileIO.backup(wrapper.getBackupsFolder(), source, false);
wrapper.sendMessage("File converted successfully. The original was moved to the backups directory.");
} else {
wrapper.sendMessage("File converted successfully. The original could not be backed up.");
}
}
}