- [FEAT] New APIs for Maintenance Mode and rewrite commands system
- [FEAT] Improved config system to fix old loading bugs and support JSON - [FEAT] LuckPerms support for commands
This commit is contained in:
@@ -1,53 +1,155 @@
|
||||
package com.hypherionmc.craterlib.api.commands;
|
||||
|
||||
import com.hypherionmc.craterlib.compat.LuckPermsCompat;
|
||||
import com.hypherionmc.craterlib.core.platform.ModloaderEnvironment;
|
||||
import com.hypherionmc.craterlib.nojang.authlib.BridgedGameProfile;
|
||||
import com.hypherionmc.craterlib.nojang.commands.BridgedCommandSourceStack;
|
||||
import com.hypherionmc.craterlib.nojang.world.entity.player.BridgedPlayer;
|
||||
import com.hypherionmc.craterlib.utils.TriConsumer;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import lombok.Getter;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.GameProfileArgument;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Getter
|
||||
public class CraterCommand {
|
||||
|
||||
private final HashMap<String, Pair<ArgumentType<?>, TriConsumer<?, ?, BridgedCommandSourceStack>>> arguments = new LinkedHashMap<>();
|
||||
private Consumer<BridgedCommandSourceStack> executor;
|
||||
private final LiteralArgumentBuilder<CommandSourceStack> mojangCommand;
|
||||
private int permLevel = 4;
|
||||
private String luckPermNode = "";
|
||||
|
||||
private final String commandName;
|
||||
private int permissionLevel = 4;
|
||||
|
||||
CraterCommand(String commandName) {
|
||||
this.commandName = commandName;
|
||||
CraterCommand(LiteralArgumentBuilder<CommandSourceStack> cmd) {
|
||||
this.mojangCommand = cmd;
|
||||
}
|
||||
|
||||
public static CraterCommand literal(String commandName) {
|
||||
return new CraterCommand(commandName);
|
||||
return new CraterCommand(Commands.literal(commandName));
|
||||
}
|
||||
|
||||
public CraterCommand requiresPermission(int perm) {
|
||||
this.permissionLevel = perm;
|
||||
this.permLevel = perm;
|
||||
this.mojangCommand.requires(this::checkPermission);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCommand withGameProfileArgument(String key, TriConsumer<BridgedPlayer, List<BridgedGameProfile>, BridgedCommandSourceStack> executor) {
|
||||
arguments.put(key, Pair.of(GameProfileArgument.gameProfile(), executor));
|
||||
public CraterCommand withNode(String key) {
|
||||
this.luckPermNode = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCommand then(CraterCommand child) {
|
||||
this.mojangCommand.then(child.mojangCommand);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCommand withGameProfilesArgument(String key, CommandExecutorWithArgs<List<BridgedGameProfile>> executor) {
|
||||
this.mojangCommand.then(Commands.argument(key, GameProfileArgument.gameProfile())
|
||||
.executes(context -> executor.run(
|
||||
BridgedPlayer.of(context.getSource().getPlayer()),
|
||||
GameProfileArgument.getGameProfiles(context, key).stream().map(BridgedGameProfile::of).toList(),
|
||||
BridgedCommandSourceStack.of(context.getSource()))
|
||||
));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCommand withBoolArgument(String key, CommandExecutorWithArgs<Boolean> executor) {
|
||||
this.mojangCommand.then(Commands.argument(key, BoolArgumentType.bool())
|
||||
.executes(context -> executor.run(
|
||||
BridgedPlayer.of(context.getSource().getPlayer()),
|
||||
BoolArgumentType.getBool(context, key),
|
||||
BridgedCommandSourceStack.of(context.getSource())
|
||||
)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCommand withWordArgument(String key, CommandExecutorWithArgs<String> executor) {
|
||||
this.mojangCommand.then(Commands.argument(key, StringArgumentType.word())
|
||||
.executes(context -> executor.run(
|
||||
BridgedPlayer.of(context.getSource().getPlayer()),
|
||||
StringArgumentType.getString(context, key),
|
||||
BridgedCommandSourceStack.of(context.getSource())
|
||||
)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCommand withStringArgument(String key, CommandExecutorWithArgs<String> executor) {
|
||||
this.mojangCommand.then(Commands.argument(key, StringArgumentType.string())
|
||||
.executes(context -> executor.run(
|
||||
BridgedPlayer.of(context.getSource().getPlayer()),
|
||||
StringArgumentType.getString(context, key),
|
||||
BridgedCommandSourceStack.of(context.getSource())
|
||||
)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCommand withPhraseArgument(String key, CommandExecutorWithArgs<String> executor) {
|
||||
this.mojangCommand.then(Commands.argument(key, StringArgumentType.greedyString())
|
||||
.executes(context -> executor.run(
|
||||
BridgedPlayer.of(context.getSource().getPlayer()),
|
||||
StringArgumentType.getString(context, key),
|
||||
BridgedCommandSourceStack.of(context.getSource())
|
||||
)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCommand withIntegerArgument(String key, CommandExecutorWithArgs<Integer> executor) {
|
||||
this.mojangCommand.then(Commands.argument(key, IntegerArgumentType.integer())
|
||||
.executes(context -> executor.run(
|
||||
BridgedPlayer.of(context.getSource().getPlayer()),
|
||||
IntegerArgumentType.getInteger(context, key),
|
||||
BridgedCommandSourceStack.of(context.getSource())
|
||||
)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CraterCommand execute(SingleCommandExecutor<BridgedCommandSourceStack> executor) {
|
||||
this.mojangCommand.executes(context -> executor.run(BridgedCommandSourceStack.of(context.getSource())));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
public CraterCommand executes(Consumer<BridgedCommandSourceStack> ctx) {
|
||||
executor = ctx;
|
||||
return this;
|
||||
return this.execute(stack -> {
|
||||
ctx.accept(stack);
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hasArguments() {
|
||||
return !arguments.isEmpty();
|
||||
@Deprecated(forRemoval = true)
|
||||
public CraterCommand withGameProfileArgument(String key, TriConsumer<BridgedPlayer, List<BridgedGameProfile>, BridgedCommandSourceStack> executor) {
|
||||
return this.withGameProfilesArgument(key, (player, argument, stack) -> {
|
||||
executor.accept(player, argument, stack);
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public void register(CommandDispatcher<CommandSourceStack> stack) {
|
||||
stack.register(this.mojangCommand);
|
||||
}
|
||||
|
||||
private boolean checkPermission(CommandSourceStack stack) {
|
||||
if (!ModloaderEnvironment.INSTANCE.isModLoaded("luckperms") || !stack.isPlayer() || luckPermNode.isEmpty())
|
||||
return stack.hasPermission(this.permLevel);
|
||||
|
||||
return LuckPermsCompat.INSTANCE.hasPermission(stack.getPlayer(), this.luckPermNode) || stack.hasPermission(this.permLevel);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CommandExecutorWithArgs<S> {
|
||||
int run(BridgedPlayer player, S argument, BridgedCommandSourceStack stack);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SingleCommandExecutor<S> {
|
||||
int run(S stack);
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@ import com.hypherionmc.craterlib.core.event.CraterEvent;
|
||||
import com.hypherionmc.craterlib.nojang.world.entity.player.BridgedPlayer;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
|
@@ -2,14 +2,17 @@ package com.hypherionmc.craterlib.api.events.server;
|
||||
|
||||
import com.hypherionmc.craterlib.api.commands.CraterCommand;
|
||||
import com.hypherionmc.craterlib.core.event.CraterEvent;
|
||||
import com.hypherionmc.craterlib.nojang.commands.CommandsRegistry;
|
||||
import lombok.NoArgsConstructor;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CraterRegisterCommandEvent extends CraterEvent {
|
||||
|
||||
private final CommandDispatcher<CommandSourceStack> stack;
|
||||
|
||||
public void registerCommand(CraterCommand cmd) {
|
||||
CommandsRegistry.INSTANCE.registerCommand(cmd);
|
||||
cmd.register(stack);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,35 @@
|
||||
package com.hypherionmc.craterlib.api.events.server;
|
||||
|
||||
import com.hypherionmc.craterlib.core.event.CraterEvent;
|
||||
import com.hypherionmc.craterlib.nojang.network.protocol.status.WrappedServerStatus;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class ServerStatusEvent {
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public static class StatusRequestEvent extends CraterEvent {
|
||||
|
||||
private final Component status;
|
||||
@Nullable
|
||||
private Component newStatus = null;
|
||||
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public static class FaviconRequestEvent extends CraterEvent {
|
||||
|
||||
private final Optional<WrappedServerStatus.WrappedFavicon> favicon;
|
||||
private Optional<WrappedServerStatus.WrappedFavicon> newIcon = Optional.empty();
|
||||
|
||||
}
|
||||
}
|
@@ -2,7 +2,7 @@ package com.hypherionmc.craterlib.client.gui.config;
|
||||
|
||||
import com.hypherionmc.craterlib.CraterConstants;
|
||||
import com.hypherionmc.craterlib.client.gui.config.widgets.*;
|
||||
import com.hypherionmc.craterlib.core.config.ModuleConfig;
|
||||
import com.hypherionmc.craterlib.core.config.AbstractConfig;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.HideFromScreen;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.SubConfig;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.Tooltip;
|
||||
@@ -44,11 +44,11 @@ public class CraterConfigScreen extends Screen {
|
||||
private static final int BOTTOM = 24;
|
||||
private final Screen parent;
|
||||
private final List<Option<?>> options = new ArrayList<>();
|
||||
private final ModuleConfig config;
|
||||
private final AbstractConfig config;
|
||||
public double scrollerAmount;
|
||||
private boolean dragging;
|
||||
|
||||
public CraterConfigScreen(ModuleConfig config, Screen parent, Object subConfig) {
|
||||
public CraterConfigScreen(AbstractConfig config, Screen parent, Object subConfig) {
|
||||
super(Component.translatable("cl." + config.getClass().getSimpleName().toLowerCase() + ".title"));
|
||||
this.parent = parent;
|
||||
this.config = config;
|
||||
@@ -59,7 +59,7 @@ public class CraterConfigScreen extends Screen {
|
||||
}
|
||||
}
|
||||
|
||||
public CraterConfigScreen(ModuleConfig config, Screen parent) {
|
||||
public CraterConfigScreen(AbstractConfig config, Screen parent) {
|
||||
this(config, parent, null);
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package com.hypherionmc.craterlib.client.gui.config.widgets;
|
||||
|
||||
import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen;
|
||||
import com.hypherionmc.craterlib.core.config.ModuleConfig;
|
||||
import com.hypherionmc.craterlib.core.config.AbstractConfig;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
@@ -15,10 +15,10 @@ import net.minecraft.network.chat.Component;
|
||||
public class SubConfigWidget<T> extends AbstractConfigWidget<T, Button> {
|
||||
|
||||
private final Object subConfig;
|
||||
private final ModuleConfig config;
|
||||
private final AbstractConfig config;
|
||||
private final Screen screen;
|
||||
|
||||
public SubConfigWidget(ModuleConfig config, Screen screen, Object subConfig) {
|
||||
public SubConfigWidget(AbstractConfig config, Screen screen, Object subConfig) {
|
||||
this.config = config;
|
||||
this.subConfig = subConfig;
|
||||
this.screen = screen;
|
||||
|
@@ -0,0 +1,20 @@
|
||||
package com.hypherionmc.craterlib.compat;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
public class LuckPermsCompat {
|
||||
|
||||
public static final LuckPermsCompat INSTANCE = new LuckPermsCompat();
|
||||
private final LuckPerms luckPerms = LuckPermsProvider.get();
|
||||
|
||||
LuckPermsCompat() {}
|
||||
|
||||
public boolean hasPermission(ServerPlayer player, String perm) {
|
||||
User luckPermsUser = luckPerms.getPlayerAdapter(ServerPlayer.class).getUser(player);
|
||||
return luckPermsUser.getCachedData().getPermissionData().checkPermission(perm).asBoolean();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
package com.hypherionmc.craterlib.core.config;
|
||||
|
||||
import com.hypherionmc.craterlib.core.config.formats.AbstractConfigFormat;
|
||||
import com.hypherionmc.craterlib.core.config.formats.JsonConfigFormat;
|
||||
import com.hypherionmc.craterlib.core.config.formats.TomlConfigFormat;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.hypherionmc.moonconfig.core.Config;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Getter
|
||||
public abstract class AbstractConfig<S> {
|
||||
|
||||
/* Final Variables */
|
||||
private final transient File configPath;
|
||||
private final transient String networkID;
|
||||
private final transient String configName;
|
||||
private final transient String modId;
|
||||
private transient boolean wasSaveCalled = false;
|
||||
|
||||
@Setter
|
||||
private transient AbstractConfigFormat<S> configFormat;
|
||||
|
||||
public AbstractConfig(String modId, String configName) {
|
||||
this(modId, null, configName);
|
||||
}
|
||||
|
||||
public AbstractConfig(String modId, @Nullable String subFolder, String configName) {
|
||||
Config.setInsertionOrderPreserved(true);
|
||||
|
||||
if (!configName.endsWith(".toml") && !configName.endsWith(".json"))
|
||||
configName = configName + ".toml";
|
||||
|
||||
File configDir = new File("config" + (subFolder == null ? "" : File.separator + subFolder));
|
||||
configPath = new File(configDir, configName);
|
||||
this.modId = modId;
|
||||
this.networkID = modId + ":conf_" + configName.replace(".toml", "").replace(".json", "").replace("-", "_").toLowerCase();
|
||||
this.configName = configName.replace(".toml", "").replace(".json", "");
|
||||
configDir.mkdirs();
|
||||
|
||||
configFormat = configName.endsWith(".json") ? new JsonConfigFormat<>(configPath, this::onSave) : new TomlConfigFormat<>(configPath, this::onSave);
|
||||
}
|
||||
|
||||
public void registerAndSetup(S config) {
|
||||
configFormat.register(config);
|
||||
ConfigController.register_config(this);
|
||||
this.configReloaded();
|
||||
}
|
||||
|
||||
public void saveConfig(S config) {
|
||||
this.wasSaveCalled = true;
|
||||
configFormat.saveConfig(config);
|
||||
}
|
||||
|
||||
private void onSave() {
|
||||
this.configReloaded();
|
||||
this.wasSaveCalled = false;
|
||||
}
|
||||
|
||||
public S readConfig(S config) {
|
||||
return configFormat.readConfig(config);
|
||||
}
|
||||
|
||||
public void migrateConfig(S config) {
|
||||
configFormat.migrateConfig(config);
|
||||
}
|
||||
|
||||
public abstract void configReloaded();
|
||||
}
|
@@ -3,6 +3,7 @@ package com.hypherionmc.craterlib.core.config;
|
||||
import com.hypherionmc.craterlib.CraterConstants;
|
||||
import lombok.Getter;
|
||||
import me.hypherionmc.moonconfig.core.file.FileWatcher;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -18,7 +19,7 @@ public final class ConfigController implements Serializable {
|
||||
* Cache of registered configs
|
||||
*/
|
||||
@Getter
|
||||
private static final HashMap<Object, FileWatcher> monitoredConfigs = new HashMap<>();
|
||||
private static final HashMap<String, Pair<AbstractConfig, FileWatcher>> watchedConfigs = new HashMap<>();
|
||||
|
||||
/**
|
||||
* INTERNAL METHOD - Register and watch the config
|
||||
@@ -26,23 +27,34 @@ public final class ConfigController implements Serializable {
|
||||
* @param config - The config class to register and watch
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@Deprecated
|
||||
public static void register_config(ModuleConfig config) {
|
||||
if (monitoredConfigs.containsKey(config)) {
|
||||
CraterConstants.LOG.error("Failed to register " + config.getConfigPath().getName() + ". Config already registered");
|
||||
register_config((AbstractConfig) config);
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL METHOD - Register and watch the config
|
||||
*
|
||||
* @param config - The config class to register and watch
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public static void register_config(AbstractConfig config) {
|
||||
if (watchedConfigs.containsKey(config.getConfigPath().toString())) {
|
||||
CraterConstants.LOG.error("Failed to register {}. Config already registered", config.getConfigPath().getName());
|
||||
} else {
|
||||
FileWatcher configWatcher = new FileWatcher();
|
||||
try {
|
||||
configWatcher.setWatch(config.getConfigPath(), () -> {
|
||||
if (!config.isSaveCalled()) {
|
||||
CraterConstants.LOG.info("Sending Reload Event for: " + config.getConfigPath().getName());
|
||||
if (!config.isWasSaveCalled()) {
|
||||
CraterConstants.LOG.info("Sending Reload Event for: {}", config.getConfigPath().getName());
|
||||
config.configReloaded();
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
CraterConstants.LOG.error("Failed to register " + config.getConfigPath().getName() + " for auto reloading. " + e.getMessage());
|
||||
CraterConstants.LOG.error("Failed to register {} for auto reloading. {}", config.getConfigPath().getName(), e.getMessage());
|
||||
}
|
||||
monitoredConfigs.put(config, configWatcher);
|
||||
CraterConstants.LOG.info("Registered " + config.getConfigPath().getName() + " successfully!");
|
||||
watchedConfigs.put(config.getConfigPath().toString(), Pair.of(config, configWatcher));
|
||||
CraterConstants.LOG.info("Registered {} successfully!", config.getConfigPath().getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,9 +1,7 @@
|
||||
package com.hypherionmc.craterlib.core.config;
|
||||
|
||||
import com.hypherionmc.craterlib.core.config.formats.TomlConfigFormat;
|
||||
import me.hypherionmc.moonconfig.core.CommentedConfig;
|
||||
import me.hypherionmc.moonconfig.core.Config;
|
||||
import me.hypherionmc.moonconfig.core.conversion.ObjectConverter;
|
||||
import me.hypherionmc.moonconfig.core.file.CommentedFileConfig;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -12,17 +10,8 @@ import java.io.File;
|
||||
* Base Config class containing the save, upgrading and loading logic.
|
||||
* All config classes must extend this class
|
||||
*/
|
||||
public class ModuleConfig {
|
||||
|
||||
/* Final Variables */
|
||||
private final transient File configPath;
|
||||
private final transient String networkID;
|
||||
|
||||
private final transient String configName;
|
||||
|
||||
private final transient String modId;
|
||||
|
||||
private transient boolean isSaveCalled = false;
|
||||
@Deprecated
|
||||
public class ModuleConfig extends AbstractConfig {
|
||||
|
||||
/**
|
||||
* Set up the config
|
||||
@@ -35,20 +24,7 @@ public class ModuleConfig {
|
||||
}
|
||||
|
||||
public ModuleConfig(String modId, String subFolder, String configName) {
|
||||
/* Preserve the order of the config values */
|
||||
Config.setInsertionOrderPreserved(true);
|
||||
|
||||
/* Configure Paths and Network SYNC ID */
|
||||
File configDir = new File("config" + (subFolder.isEmpty() ? "" : File.separator + subFolder));
|
||||
configPath = new File(configDir + File.separator + configName + ".toml");
|
||||
networkID = modId + ":conf_" + configName.replace("-", "_");
|
||||
this.modId = modId;
|
||||
this.configName = configName;
|
||||
|
||||
/* Check if the required directories exists, otherwise we create them */
|
||||
if (!configDir.exists()) {
|
||||
configDir.mkdirs();
|
||||
}
|
||||
super(modId, subFolder.isEmpty() ? null : subFolder, configName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,14 +33,7 @@ public class ModuleConfig {
|
||||
* @param config - The config class to use
|
||||
*/
|
||||
public void registerAndSetup(ModuleConfig config) {
|
||||
if (!configPath.exists() || configPath.length() < 2) {
|
||||
saveConfig(config);
|
||||
} else {
|
||||
migrateConfig(config);
|
||||
}
|
||||
/* Register the Config for Watching and events */
|
||||
ConfigController.register_config(this);
|
||||
this.configReloaded();
|
||||
super.registerAndSetup(config);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,16 +42,7 @@ public class ModuleConfig {
|
||||
* @param conf - The config class to serialize and save
|
||||
*/
|
||||
public void saveConfig(ModuleConfig conf) {
|
||||
this.isSaveCalled = true;
|
||||
/* Set up the Serializer and Config Object */
|
||||
ObjectConverter converter = new ObjectConverter();
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(configPath).build();
|
||||
|
||||
/* Save the config and fire the reload events */
|
||||
converter.toConfig(conf, config);
|
||||
config.save();
|
||||
configReloaded();
|
||||
this.isSaveCalled = false;
|
||||
super.registerAndSetup(conf);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,14 +52,7 @@ public class ModuleConfig {
|
||||
* @return - Returns the loaded version of the class
|
||||
*/
|
||||
public <T> T loadConfig(Object conf) {
|
||||
/* Set up the Serializer and Config Object */
|
||||
ObjectConverter converter = new ObjectConverter();
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(configPath).build();
|
||||
config.load();
|
||||
|
||||
/* Load the config and return the loaded config */
|
||||
converter.toObject(config, conf);
|
||||
return (T) conf;
|
||||
return (T) super.readConfig(conf);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,31 +61,13 @@ public class ModuleConfig {
|
||||
* @param conf - The config class to load
|
||||
*/
|
||||
public void migrateConfig(ModuleConfig conf) {
|
||||
/* Set up the Serializer and Config Objects */
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(configPath).build();
|
||||
CommentedFileConfig newConfig = CommentedFileConfig.builder(configPath).build();
|
||||
config.load();
|
||||
|
||||
/* Upgrade the config */
|
||||
new ObjectConverter().toConfig(conf, newConfig);
|
||||
updateConfigValues(config, newConfig, newConfig, "");
|
||||
newConfig.save();
|
||||
|
||||
config.close();
|
||||
newConfig.close();
|
||||
super.migrateConfig(conf);
|
||||
}
|
||||
|
||||
public void updateConfigValues(CommentedConfig oldConfig, CommentedConfig newConfig, CommentedConfig outputConfig, String subKey) {
|
||||
/* Loop over the config keys and check what has changed */
|
||||
newConfig.valueMap().forEach((key, value) -> {
|
||||
String finalKey = subKey + (subKey.isEmpty() ? "" : ".") + key;
|
||||
if (value instanceof CommentedConfig commentedConfig) {
|
||||
updateConfigValues(oldConfig, commentedConfig, outputConfig, finalKey);
|
||||
} else {
|
||||
outputConfig.set(finalKey,
|
||||
oldConfig.contains(finalKey) ? oldConfig.get(finalKey) : value);
|
||||
}
|
||||
});
|
||||
if (getConfigFormat() instanceof TomlConfigFormat<?> t) {
|
||||
t.updateConfigValues(oldConfig, newConfig, outputConfig, subKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +76,7 @@ public class ModuleConfig {
|
||||
* @return - The FILE object containing the config file
|
||||
*/
|
||||
public File getConfigPath() {
|
||||
return configPath;
|
||||
return super.getConfigPath();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,12 +85,13 @@ public class ModuleConfig {
|
||||
* @return - Returns the Sync ID in format modid:config_name
|
||||
*/
|
||||
public String getNetworkID() {
|
||||
return networkID;
|
||||
return super.getNetworkID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired whenever changes to the config are detected
|
||||
*/
|
||||
@Override
|
||||
public void configReloaded() {
|
||||
|
||||
}
|
||||
@@ -166,7 +102,7 @@ public class ModuleConfig {
|
||||
* @return
|
||||
*/
|
||||
public String getConfigName() {
|
||||
return configName;
|
||||
return super.getConfigName();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,10 +111,10 @@ public class ModuleConfig {
|
||||
* @return
|
||||
*/
|
||||
public String getModId() {
|
||||
return modId;
|
||||
return super.getModId();
|
||||
}
|
||||
|
||||
public boolean isSaveCalled() {
|
||||
return isSaveCalled;
|
||||
return super.isWasSaveCalled();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,32 @@
|
||||
package com.hypherionmc.craterlib.core.config.formats;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.hypherionmc.moonconfig.core.Config;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public abstract class AbstractConfigFormat<S> {
|
||||
|
||||
private final File configPath;
|
||||
private final Runnable onSave;
|
||||
|
||||
public void register(S conf) {
|
||||
if (!configPath.exists() || configPath.length() < 2) {
|
||||
saveConfig(conf);
|
||||
} else {
|
||||
migrateConfig(conf);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean wasConfigChanged(Config old, Config newConfig) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract void saveConfig(S config);
|
||||
public abstract S readConfig(S config);
|
||||
public abstract void migrateConfig(S config);
|
||||
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
package com.hypherionmc.craterlib.core.config.formats;
|
||||
|
||||
import me.hypherionmc.moonconfig.core.Config;
|
||||
import me.hypherionmc.moonconfig.core.conversion.ObjectConverter;
|
||||
import me.hypherionmc.moonconfig.core.file.FileConfig;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class JsonConfigFormat<S> extends AbstractConfigFormat<S> {
|
||||
|
||||
public JsonConfigFormat(File configPath, Runnable afterSave) {
|
||||
super(configPath, afterSave);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig(S conf) {
|
||||
ObjectConverter converter = new ObjectConverter();
|
||||
FileConfig config = FileConfig.builder(getConfigPath()).sync().build();
|
||||
|
||||
converter.toConfig(conf, config);
|
||||
config.save();
|
||||
getOnSave().run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public S readConfig(S conf) {
|
||||
/* Set up the Serializer and Config Object */
|
||||
ObjectConverter converter = new ObjectConverter();
|
||||
FileConfig config = FileConfig.builder(getConfigPath()).build();
|
||||
config.load();
|
||||
|
||||
/* Load the config and return the loaded config */
|
||||
converter.toObject(config, conf);
|
||||
return conf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrateConfig(S conf) {
|
||||
/* Set up the Serializer and Config Objects */
|
||||
FileConfig config = FileConfig.builder(getConfigPath()).build();
|
||||
FileConfig newConfig = FileConfig.builder(getConfigPath()).sync().build();
|
||||
config.load();
|
||||
|
||||
/* Upgrade the config */
|
||||
if (wasConfigChanged(config, newConfig)) {
|
||||
new ObjectConverter().toConfig(conf, newConfig);
|
||||
updateConfigValues(config, newConfig, newConfig, "");
|
||||
newConfig.save();
|
||||
}
|
||||
|
||||
config.close();
|
||||
newConfig.close();
|
||||
}
|
||||
|
||||
public void updateConfigValues(Config oldConfig, Config newConfig, Config outputConfig, String subKey) {
|
||||
/* Loop over the config keys and check what has changed */
|
||||
newConfig.valueMap().forEach((key, value) -> {
|
||||
String finalKey = subKey + (subKey.isEmpty() ? "" : ".") + key;
|
||||
if (value instanceof Config commentedConfig) {
|
||||
updateConfigValues(oldConfig, commentedConfig, outputConfig, finalKey);
|
||||
} else {
|
||||
outputConfig.set(finalKey,
|
||||
oldConfig.contains(finalKey) ? oldConfig.get(finalKey) : value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
package com.hypherionmc.craterlib.core.config.formats;
|
||||
|
||||
import me.hypherionmc.moonconfig.core.CommentedConfig;
|
||||
import me.hypherionmc.moonconfig.core.conversion.ObjectConverter;
|
||||
import me.hypherionmc.moonconfig.core.file.CommentedFileConfig;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class TomlConfigFormat<S> extends AbstractConfigFormat<S> {
|
||||
|
||||
public TomlConfigFormat(File configPath, Runnable onSave) {
|
||||
super(configPath, onSave);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig(S conf) {
|
||||
ObjectConverter converter = new ObjectConverter();
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(getConfigPath()).sync().build();
|
||||
|
||||
converter.toConfig(conf, config);
|
||||
config.save();
|
||||
getOnSave().run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public S readConfig(S conf) {
|
||||
/* Set up the Serializer and Config Object */
|
||||
ObjectConverter converter = new ObjectConverter();
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(getConfigPath()).build();
|
||||
config.load();
|
||||
|
||||
/* Load the config and return the loaded config */
|
||||
converter.toObject(config, conf);
|
||||
return conf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrateConfig(S conf) {
|
||||
/* Set up the Serializer and Config Objects */
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(getConfigPath()).build();
|
||||
CommentedFileConfig newConfig = CommentedFileConfig.builder(getConfigPath()).sync().build();
|
||||
config.load();
|
||||
|
||||
/* Upgrade the config */
|
||||
if (wasConfigChanged(config, newConfig)) {
|
||||
new ObjectConverter().toConfig(conf, newConfig);
|
||||
updateConfigValues(config, newConfig, newConfig, "");
|
||||
newConfig.save();
|
||||
}
|
||||
|
||||
config.close();
|
||||
newConfig.close();
|
||||
}
|
||||
|
||||
public void updateConfigValues(CommentedConfig oldConfig, CommentedConfig newConfig, CommentedConfig outputConfig, String subKey) {
|
||||
/* Loop over the config keys and check what has changed */
|
||||
newConfig.valueMap().forEach((key, value) -> {
|
||||
String finalKey = subKey + (subKey.isEmpty() ? "" : ".") + key;
|
||||
if (value instanceof CommentedConfig commentedConfig) {
|
||||
updateConfigValues(oldConfig, commentedConfig, outputConfig, finalKey);
|
||||
} else {
|
||||
outputConfig.set(finalKey,
|
||||
oldConfig.contains(finalKey) ? oldConfig.get(finalKey) : value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.hypherionmc.craterlib.mixin.events;
|
||||
|
||||
import com.hypherionmc.craterlib.api.events.server.ServerStatusEvent;
|
||||
import com.hypherionmc.craterlib.core.event.CraterEventBus;
|
||||
import com.hypherionmc.craterlib.nojang.network.protocol.status.WrappedServerStatus;
|
||||
import net.minecraft.network.protocol.status.ServerStatus;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(ServerStatus.class)
|
||||
public class ServerStatusMixin {
|
||||
|
||||
@Inject(method = "favicon", at = @At("RETURN"), cancellable = true)
|
||||
private void injectIconEvent(CallbackInfoReturnable<Optional<ServerStatus.Favicon>> cir) {
|
||||
ServerStatusEvent.FaviconRequestEvent event = new ServerStatusEvent.FaviconRequestEvent(cir.getReturnValue().isEmpty() ? Optional.empty() : Optional.of(new WrappedServerStatus.WrappedFavicon(cir.getReturnValue().get())));
|
||||
CraterEventBus.INSTANCE.postEvent(event);
|
||||
|
||||
if (event.getNewIcon().isPresent()) {
|
||||
cir.setReturnValue(Optional.of(event.getNewIcon().get().toMojang()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -16,6 +16,10 @@ public class BridgedCommandSourceStack {
|
||||
internal.sendSuccess(() -> ChatUtils.adventureToMojang(supplier.get()), bl);
|
||||
}
|
||||
|
||||
public void sendFailure(Component text) {
|
||||
internal.sendFailure(ChatUtils.adventureToMojang(text));
|
||||
}
|
||||
|
||||
public CommandSourceStack toMojang() {
|
||||
return internal;
|
||||
}
|
||||
|
@@ -1,85 +0,0 @@
|
||||
package com.hypherionmc.craterlib.nojang.commands;
|
||||
|
||||
import com.hypherionmc.craterlib.api.commands.CraterCommand;
|
||||
import com.hypherionmc.craterlib.nojang.authlib.BridgedGameProfile;
|
||||
import com.hypherionmc.craterlib.nojang.world.entity.player.BridgedPlayer;
|
||||
import com.hypherionmc.craterlib.utils.TriConsumer;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.GameProfileArgument;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CommandsRegistry {
|
||||
|
||||
public static final CommandsRegistry INSTANCE = new CommandsRegistry();
|
||||
|
||||
private final List<CraterCommand> commands = new ArrayList<>();
|
||||
|
||||
public void registerCommand(CraterCommand cmd) {
|
||||
commands.add(cmd);
|
||||
}
|
||||
|
||||
public void registerCommands(CommandDispatcher<CommandSourceStack> stack) {
|
||||
commands.forEach(cmd -> {
|
||||
if (cmd.hasArguments()) {
|
||||
CommandWithArguments.register(cmd, stack);
|
||||
} else {
|
||||
CommandWithoutArguments.register(cmd, stack);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static class CommandWithoutArguments {
|
||||
|
||||
public static void register(CraterCommand cmd, CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
LiteralArgumentBuilder<CommandSourceStack> command = Commands.literal(cmd.getCommandName())
|
||||
.requires(source -> source.hasPermission(cmd.getPermissionLevel()))
|
||||
.executes(context -> {
|
||||
cmd.getExecutor().accept(BridgedCommandSourceStack.of(context.getSource()));
|
||||
return 1;
|
||||
});
|
||||
|
||||
dispatcher.register(command);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static class CommandWithArguments {
|
||||
|
||||
public static void register(CraterCommand cmd, CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
LiteralArgumentBuilder<CommandSourceStack> command = Commands.literal(cmd.getCommandName())
|
||||
.requires(source -> source.hasPermission(cmd.getPermissionLevel()));
|
||||
|
||||
cmd.getArguments().forEach((key, pair) -> command.then(Commands.argument(key, pair.getLeft()).executes(context -> {
|
||||
|
||||
// This is FUCKING UGLY.... Need to improve this in the future
|
||||
if (pair.getLeft() instanceof GameProfileArgument) {
|
||||
Collection<GameProfile> profiles = GameProfileArgument.getGameProfiles(context, key);
|
||||
List<BridgedGameProfile> bridgedGameProfiles = new ArrayList<>();
|
||||
|
||||
profiles.forEach(p -> bridgedGameProfiles.add(BridgedGameProfile.of(p)));
|
||||
|
||||
((TriConsumer<BridgedPlayer, List<BridgedGameProfile>, BridgedCommandSourceStack>) pair.getRight())
|
||||
.accept(BridgedPlayer.of(context.getSource().getPlayer()), bridgedGameProfiles, BridgedCommandSourceStack.of(context.getSource()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
})));
|
||||
|
||||
dispatcher.register(command);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package com.hypherionmc.craterlib.nojang.network.protocol.status;
|
||||
|
||||
import net.minecraft.network.protocol.status.ServerStatus;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
public final class WrappedServerStatus {
|
||||
|
||||
public static final class WrappedFavicon {
|
||||
|
||||
private final ServerStatus.Favicon internal;
|
||||
|
||||
public WrappedFavicon(byte[] iconBytes) {
|
||||
internal = new ServerStatus.Favicon(iconBytes);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public WrappedFavicon(ServerStatus.Favicon internal) {
|
||||
this.internal = internal;
|
||||
}
|
||||
|
||||
public byte[] iconBytes() {
|
||||
return internal.iconBytes();
|
||||
}
|
||||
|
||||
public ServerStatus.Favicon toMojang() {
|
||||
return internal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -57,6 +57,11 @@ public class BridgedPlayer {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void disconnect(Component message) {
|
||||
if (isServerPlayer())
|
||||
toMojangServerPlayer().connection.disconnect(ChatUtils.adventureToMojang(message));
|
||||
}
|
||||
|
||||
public ServerPlayer toMojangServerPlayer() {
|
||||
return (ServerPlayer) internal;
|
||||
}
|
||||
|
@@ -108,4 +108,11 @@ public class ChatUtils {
|
||||
return mojangToAdventure(Component.translatable(Util.makeDescriptionId("biome", identifier.toMojang())));
|
||||
}
|
||||
|
||||
public static net.kyori.adventure.text.Component format(String value) {
|
||||
return net.kyori.adventure.text.Component.translatable(convertFormattingCodes(value));
|
||||
}
|
||||
|
||||
private static String convertFormattingCodes(String input) {
|
||||
return input.replaceAll("§([0-9a-fklmnor])", "\u00A7$1");
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,8 @@
|
||||
"events.CommandMixin",
|
||||
"events.PlayerAdvancementsMixin",
|
||||
"events.PlayerListMixin",
|
||||
"events.ServerPlayerMixin"
|
||||
"events.ServerPlayerMixin",
|
||||
"events.ServerStatusMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
Reference in New Issue
Block a user