- [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,156 @@
|
||||
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.server.level.ServerPlayer;
|
||||
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().getPlayerOrException()),
|
||||
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().getPlayerOrException()),
|
||||
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().getPlayerOrException()),
|
||||
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().getPlayerOrException()),
|
||||
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().getPlayerOrException()),
|
||||
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().getPlayerOrException()),
|
||||
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.getEntity() instanceof Player) || luckPermNode.isEmpty())
|
||||
return stack.hasPermission(this.permLevel);
|
||||
|
||||
return LuckPermsCompat.INSTANCE.hasPermission((ServerPlayer) stack.getEntity(), 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;
|
||||
@@ -45,11 +45,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(new TranslatableComponent("cl." + config.getClass().getSimpleName().toLowerCase() + ".title"));
|
||||
this.parent = parent;
|
||||
this.config = config;
|
||||
@@ -60,7 +60,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 com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
@@ -15,10 +15,10 @@ import net.minecraft.network.chat.TranslatableComponent;
|
||||
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 = "getFavicon", at = @At("RETURN"), cancellable = true)
|
||||
private void injectIconEvent(CallbackInfoReturnable<String> cir) {
|
||||
ServerStatusEvent.FaviconRequestEvent event = new ServerStatusEvent.FaviconRequestEvent(cir.getReturnValue().isEmpty() ? Optional.empty() : Optional.of(new WrappedServerStatus.WrappedFavicon(cir.getReturnValue())));
|
||||
CraterEventBus.INSTANCE.postEvent(event);
|
||||
|
||||
if (event.getNewIcon().isPresent()) {
|
||||
cir.setReturnValue(event.getNewIcon().get().toMojang());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
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.utils.ChatUtils;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
|
||||
import net.minecraft.network.protocol.status.ServerStatus;
|
||||
import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerStatusPacketListenerImpl;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerStatusPacketListenerImpl.class)
|
||||
public class ServerStatusPacketListenerMixin {
|
||||
|
||||
@Shadow @Final private Connection connection;
|
||||
|
||||
@Shadow @Final private MinecraftServer server;
|
||||
|
||||
@Inject(method = "handleStatusRequest",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/network/Connection;send(Lnet/minecraft/network/protocol/Packet;)V",
|
||||
shift = At.Shift.BEFORE),
|
||||
cancellable = true
|
||||
)
|
||||
private void injectHandleStatusRequest(ServerboundStatusRequestPacket arg, CallbackInfo ci) {
|
||||
ServerStatusEvent.StatusRequestEvent event = new ServerStatusEvent.StatusRequestEvent(ChatUtils.mojangToAdventure(server.getStatus().getDescription()));
|
||||
CraterEventBus.INSTANCE.postEvent(event);
|
||||
|
||||
if (event.getNewStatus() != null) {
|
||||
ci.cancel();
|
||||
ServerStatus serverStatus = this.server.getStatus();
|
||||
serverStatus.setDescription(ChatUtils.adventureToMojang(event.getNewStatus()));
|
||||
|
||||
this.connection.send(new ClientboundStatusResponsePacket(serverStatus));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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().getPlayerOrException()), bridgedGameProfiles, BridgedCommandSourceStack.of(context.getSource()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
})));
|
||||
|
||||
dispatcher.register(command);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package com.hypherionmc.craterlib.nojang.network.protocol.status;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
public final class WrappedServerStatus {
|
||||
|
||||
public static final class WrappedFavicon {
|
||||
|
||||
private final String internal;
|
||||
private final byte[] iconBytes;
|
||||
|
||||
public WrappedFavicon(byte[] iconBytes) {
|
||||
this.iconBytes = iconBytes;
|
||||
|
||||
if (iconBytes != null) {
|
||||
byte[] encoded = Base64.getEncoder().encode(iconBytes);
|
||||
internal = "data:image/png;base64," + new String(encoded, StandardCharsets.UTF_8);
|
||||
} else {
|
||||
internal = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public WrappedFavicon(String internal) {
|
||||
this.internal = internal;
|
||||
this.iconBytes = new byte[0];
|
||||
}
|
||||
|
||||
public byte[] iconBytes() {
|
||||
return iconBytes;
|
||||
}
|
||||
|
||||
public String 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;
|
||||
}
|
||||
|
@@ -95,4 +95,11 @@ public class ChatUtils {
|
||||
return mojangToAdventure(new TranslatableComponent(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,9 @@
|
||||
"events.CommandMixin",
|
||||
"events.PlayerAdvancementsMixin",
|
||||
"events.PlayerListMixin",
|
||||
"events.ServerPlayerMixin"
|
||||
"events.ServerPlayerMixin",
|
||||
"events.ServerStatusMixin",
|
||||
"events.ServerStatusPacketListenerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
@@ -9,7 +9,6 @@ import com.hypherionmc.craterlib.core.networking.CraterPacketNetwork;
|
||||
import com.hypherionmc.craterlib.core.networking.data.PacketSide;
|
||||
import com.hypherionmc.craterlib.core.platform.ModloaderEnvironment;
|
||||
import com.hypherionmc.craterlib.network.CraterFabricNetworkHandler;
|
||||
import com.hypherionmc.craterlib.nojang.commands.CommandsRegistry;
|
||||
import com.hypherionmc.craterlib.nojang.server.BridgedMinecraftServer;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||
@@ -21,8 +20,7 @@ public class CraterLibInitializer implements ModInitializer {
|
||||
public void onInitialize() {
|
||||
new CraterPacketNetwork(new CraterFabricNetworkHandler(PacketSide.SERVER));
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent());
|
||||
CommandsRegistry.INSTANCE.registerCommands(dispatcher);
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent(dispatcher));
|
||||
});
|
||||
|
||||
|
||||
|
@@ -2,7 +2,6 @@ package com.hypherionmc.craterlib;
|
||||
|
||||
import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen;
|
||||
import com.hypherionmc.craterlib.core.config.ConfigController;
|
||||
import com.hypherionmc.craterlib.core.config.ModuleConfig;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.NoConfigScreen;
|
||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
@@ -19,9 +18,9 @@ public class CraterLibModMenuIntegration implements ModMenuApi {
|
||||
public Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() {
|
||||
Map<String, ConfigScreenFactory<?>> configScreens = new HashMap<>();
|
||||
|
||||
ConfigController.getMonitoredConfigs().forEach((conf, watcher) -> {
|
||||
ConfigController.getWatchedConfigs().forEach((conf, watcher) -> {
|
||||
if (!conf.getClass().isAnnotationPresent(NoConfigScreen.class)) {
|
||||
configScreens.put(((ModuleConfig) conf).getModId(), screen -> new CraterConfigScreen((ModuleConfig) conf, screen));
|
||||
configScreens.put(watcher.getLeft().getModId(), screen -> new CraterConfigScreen(watcher.getLeft(), screen));
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -3,7 +3,6 @@ package com.hypherionmc.craterlib.common;
|
||||
import com.hypherionmc.craterlib.api.events.server.CraterRegisterCommandEvent;
|
||||
import com.hypherionmc.craterlib.api.events.server.CraterServerLifecycleEvent;
|
||||
import com.hypherionmc.craterlib.core.event.CraterEventBus;
|
||||
import com.hypherionmc.craterlib.nojang.commands.CommandsRegistry;
|
||||
import com.hypherionmc.craterlib.nojang.server.BridgedMinecraftServer;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import net.minecraftforge.event.server.ServerStartedEvent;
|
||||
@@ -36,8 +35,7 @@ public class ForgeServerEvents {
|
||||
|
||||
@SubscribeEvent
|
||||
public void onCommandRegister(RegisterCommandsEvent event) {
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent());
|
||||
CommandsRegistry.INSTANCE.registerCommands(event.getDispatcher());
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent(event.getDispatcher()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
package com.hypherionmc.craterlib.mixin;
|
||||
|
||||
import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen;
|
||||
import com.hypherionmc.craterlib.core.config.AbstractConfig;
|
||||
import com.hypherionmc.craterlib.core.config.ConfigController;
|
||||
import com.hypherionmc.craterlib.core.config.ModuleConfig;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.NoConfigScreen;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
@@ -28,9 +28,9 @@ public class ConfigScreenHandlerMixin {
|
||||
*/
|
||||
@Inject(at = @At("RETURN"), method = "getGuiFactoryFor", cancellable = true, remap = false)
|
||||
private static void injectConfigScreen(IModInfo selectedMod, CallbackInfoReturnable<Optional<BiFunction<Minecraft, Screen, Screen>>> cir) {
|
||||
ConfigController.getMonitoredConfigs().forEach((conf, watcher) -> {
|
||||
ConfigController.getWatchedConfigs().forEach((conf, watcher) -> {
|
||||
if (!conf.getClass().isAnnotationPresent(NoConfigScreen.class)) {
|
||||
ModuleConfig config = (ModuleConfig) conf;
|
||||
AbstractConfig config = watcher.getLeft();
|
||||
if (config.getModId().equals(selectedMod.getModId())) {
|
||||
cir.setReturnValue(
|
||||
Optional.of((minecraft, screen) -> new CraterConfigScreen(config, screen))
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
@@ -15,7 +15,7 @@ A Library mod and modding api for easier multi-version minecraft and mod loader
|
||||
| < 1.18.2 | ❌ |
|
||||
| 1.18.2-1.20.2 | ✳️ |
|
||||
| 1.20.4 | ✳️ |
|
||||
| 1.21 | 🚧 |
|
||||
| 1.21.x | ✳️ |
|
||||
|
||||
- ❌ - Not Supported; no bug fixes or new features.
|
||||
- 🚧 - Work in Progress; not ready for release.
|
||||
|
@@ -57,11 +57,13 @@ subprojects {
|
||||
// All Projects
|
||||
shade "me.hypherionmc.moon-config:core:${moon_config}"
|
||||
shade "me.hypherionmc.moon-config:toml:${moon_config}"
|
||||
shade "me.hypherionmc.moon-config:json:${moon_config}"
|
||||
shade "com.hypherionmc:rpcsdk:${rpc_sdk}"
|
||||
shade "me.hypherionmc.sdlink:mcdiscordformatter-1.18.1:${discord_formatter}"
|
||||
shade "net.kyori:adventure-api:${adventure}"
|
||||
shade "net.kyori:adventure-text-serializer-gson:${adventure}"
|
||||
|
||||
compileOnly 'net.luckperms:api:5.4'
|
||||
compileOnly("org.projectlombok:lombok:${lombok}")
|
||||
annotationProcessor("org.projectlombok:lombok:${lombok}")
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#Project
|
||||
version_major=2
|
||||
version_minor=0
|
||||
version_patch=3
|
||||
version_minor=1
|
||||
version_patch=0
|
||||
version_build=0
|
||||
|
||||
#Mod
|
||||
|
@@ -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;
|
||||
@@ -43,11 +43,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;
|
||||
@@ -58,7 +58,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 com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
@@ -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 = "getFavicon", at = @At("RETURN"), cancellable = true)
|
||||
private void injectIconEvent(CallbackInfoReturnable<String> cir) {
|
||||
ServerStatusEvent.FaviconRequestEvent event = new ServerStatusEvent.FaviconRequestEvent(cir.getReturnValue().isEmpty() ? Optional.empty() : Optional.of(new WrappedServerStatus.WrappedFavicon(cir.getReturnValue())));
|
||||
CraterEventBus.INSTANCE.postEvent(event);
|
||||
|
||||
if (event.getNewIcon().isPresent()) {
|
||||
cir.setReturnValue(event.getNewIcon().get().toMojang());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
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.utils.ChatUtils;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
|
||||
import net.minecraft.network.protocol.status.ServerStatus;
|
||||
import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerStatusPacketListenerImpl;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerStatusPacketListenerImpl.class)
|
||||
public class ServerStatusPacketListenerMixin {
|
||||
|
||||
@Shadow @Final private Connection connection;
|
||||
|
||||
@Shadow @Final private MinecraftServer server;
|
||||
|
||||
@Inject(method = "handleStatusRequest",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/network/Connection;send(Lnet/minecraft/network/protocol/Packet;)V",
|
||||
shift = At.Shift.BEFORE),
|
||||
cancellable = true
|
||||
)
|
||||
private void injectHandleStatusRequest(ServerboundStatusRequestPacket arg, CallbackInfo ci) {
|
||||
ServerStatusEvent.StatusRequestEvent event = new ServerStatusEvent.StatusRequestEvent(ChatUtils.mojangToAdventure(server.getStatus().getDescription()));
|
||||
CraterEventBus.INSTANCE.postEvent(event);
|
||||
|
||||
if (event.getNewStatus() != null) {
|
||||
ci.cancel();
|
||||
ServerStatus serverStatus = this.server.getStatus();
|
||||
serverStatus.setDescription(ChatUtils.adventureToMojang(event.getNewStatus()));
|
||||
|
||||
this.connection.send(new ClientboundStatusResponsePacket(serverStatus));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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,43 @@
|
||||
package com.hypherionmc.craterlib.nojang.network.protocol.status;
|
||||
|
||||
import net.minecraft.network.protocol.status.ServerStatus;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
public final class WrappedServerStatus {
|
||||
|
||||
public static final class WrappedFavicon {
|
||||
|
||||
private final String internal;
|
||||
private final byte[] iconBytes;
|
||||
|
||||
public WrappedFavicon(byte[] iconBytes) {
|
||||
this.iconBytes = iconBytes;
|
||||
|
||||
if (iconBytes != null) {
|
||||
byte[] encoded = Base64.getEncoder().encode(iconBytes);
|
||||
internal = "data:image/png;base64," + new String(encoded, StandardCharsets.UTF_8);
|
||||
} else {
|
||||
internal = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public WrappedFavicon(String internal) {
|
||||
this.internal = internal;
|
||||
this.iconBytes = new byte[0];
|
||||
}
|
||||
|
||||
public byte[] iconBytes() {
|
||||
return iconBytes;
|
||||
}
|
||||
|
||||
public String 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;
|
||||
}
|
||||
|
@@ -92,4 +92,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,9 @@
|
||||
"events.CommandMixin",
|
||||
"events.PlayerAdvancementsMixin",
|
||||
"events.PlayerListMixin",
|
||||
"events.ServerPlayerMixin"
|
||||
"events.ServerPlayerMixin",
|
||||
"events.ServerStatusMixin",
|
||||
"events.ServerStatusPacketListenerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
@@ -9,7 +9,6 @@ import com.hypherionmc.craterlib.core.networking.CraterPacketNetwork;
|
||||
import com.hypherionmc.craterlib.core.networking.data.PacketSide;
|
||||
import com.hypherionmc.craterlib.core.platform.ModloaderEnvironment;
|
||||
import com.hypherionmc.craterlib.network.CraterFabricNetworkHandler;
|
||||
import com.hypherionmc.craterlib.nojang.commands.CommandsRegistry;
|
||||
import com.hypherionmc.craterlib.nojang.server.BridgedMinecraftServer;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
@@ -21,8 +20,7 @@ public class CraterLibInitializer implements ModInitializer {
|
||||
public void onInitialize() {
|
||||
new CraterPacketNetwork(new CraterFabricNetworkHandler(PacketSide.SERVER));
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent());
|
||||
CommandsRegistry.INSTANCE.registerCommands(dispatcher);
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent(dispatcher));
|
||||
});
|
||||
|
||||
|
||||
|
@@ -2,7 +2,6 @@ package com.hypherionmc.craterlib;
|
||||
|
||||
import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen;
|
||||
import com.hypherionmc.craterlib.core.config.ConfigController;
|
||||
import com.hypherionmc.craterlib.core.config.ModuleConfig;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.NoConfigScreen;
|
||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
@@ -19,9 +18,9 @@ public class CraterLibModMenuIntegration implements ModMenuApi {
|
||||
public Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() {
|
||||
Map<String, ConfigScreenFactory<?>> configScreens = new HashMap<>();
|
||||
|
||||
ConfigController.getMonitoredConfigs().forEach((conf, watcher) -> {
|
||||
ConfigController.getWatchedConfigs().forEach((conf, watcher) -> {
|
||||
if (!conf.getClass().isAnnotationPresent(NoConfigScreen.class)) {
|
||||
configScreens.put(((ModuleConfig) conf).getModId(), screen -> new CraterConfigScreen((ModuleConfig) conf, screen));
|
||||
configScreens.put(watcher.getLeft().getModId(), screen -> new CraterConfigScreen(watcher.getLeft(), screen));
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -3,7 +3,6 @@ package com.hypherionmc.craterlib.common;
|
||||
import com.hypherionmc.craterlib.api.events.server.CraterRegisterCommandEvent;
|
||||
import com.hypherionmc.craterlib.api.events.server.CraterServerLifecycleEvent;
|
||||
import com.hypherionmc.craterlib.core.event.CraterEventBus;
|
||||
import com.hypherionmc.craterlib.nojang.commands.CommandsRegistry;
|
||||
import com.hypherionmc.craterlib.nojang.server.BridgedMinecraftServer;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import net.minecraftforge.event.server.ServerStartedEvent;
|
||||
@@ -36,8 +35,7 @@ public class ForgeServerEvents {
|
||||
|
||||
@SubscribeEvent
|
||||
public void onCommandRegister(RegisterCommandsEvent event) {
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent());
|
||||
CommandsRegistry.INSTANCE.registerCommands(event.getDispatcher());
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent(event.getDispatcher()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
package com.hypherionmc.craterlib.mixin;
|
||||
|
||||
import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen;
|
||||
import com.hypherionmc.craterlib.core.config.AbstractConfig;
|
||||
import com.hypherionmc.craterlib.core.config.ConfigController;
|
||||
import com.hypherionmc.craterlib.core.config.ModuleConfig;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.NoConfigScreen;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
@@ -28,9 +28,9 @@ public class ConfigScreenHandlerMixin {
|
||||
*/
|
||||
@Inject(at = @At("RETURN"), method = "getScreenFactoryFor", cancellable = true, remap = false)
|
||||
private static void injectConfigScreen(IModInfo selectedMod, CallbackInfoReturnable<Optional<BiFunction<Minecraft, Screen, Screen>>> cir) {
|
||||
ConfigController.getMonitoredConfigs().forEach((conf, watcher) -> {
|
||||
ConfigController.getWatchedConfigs().forEach((conf, watcher) -> {
|
||||
if (!conf.getClass().isAnnotationPresent(NoConfigScreen.class)) {
|
||||
ModuleConfig config = (ModuleConfig) conf;
|
||||
AbstractConfig config = watcher.getLeft();
|
||||
if (config.getModId().equals(selectedMod.getModId())) {
|
||||
cir.setReturnValue(
|
||||
Optional.of((minecraft, screen) -> new CraterConfigScreen(config, screen))
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
@@ -15,7 +15,7 @@ A Library mod and modding api for easier multi-version minecraft and mod loader
|
||||
| < 1.18.2 | ❌ |
|
||||
| 1.18.2-1.20.2 | ✳️ |
|
||||
| 1.20.4 | ✳️ |
|
||||
| 1.21 | 🚧 |
|
||||
| 1.21.x | ✳️ |
|
||||
|
||||
- ❌ - Not Supported; no bug fixes or new features.
|
||||
- 🚧 - Work in Progress; not ready for release.
|
||||
|
@@ -57,11 +57,13 @@ subprojects {
|
||||
// All Projects
|
||||
shade "me.hypherionmc.moon-config:core:${moon_config}"
|
||||
shade "me.hypherionmc.moon-config:toml:${moon_config}"
|
||||
shade "me.hypherionmc.moon-config:json:${moon_config}"
|
||||
shade "com.hypherionmc:rpcsdk:${rpc_sdk}"
|
||||
shade "me.hypherionmc.sdlink:mcdiscordformatter-1.19.1:${discord_formatter}"
|
||||
shade "net.kyori:adventure-api:${adventure}"
|
||||
shade "net.kyori:adventure-text-serializer-gson:${adventure}"
|
||||
|
||||
compileOnly 'net.luckperms:api:5.4'
|
||||
compileOnly("org.projectlombok:lombok:${lombok}")
|
||||
annotationProcessor("org.projectlombok:lombok:${lombok}")
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#Project
|
||||
version_major=2
|
||||
version_minor=0
|
||||
version_patch=3
|
||||
version_minor=1
|
||||
version_patch=0
|
||||
version_build=0
|
||||
|
||||
#Mod
|
||||
|
@@ -3,7 +3,7 @@ def projectIcon = "https://cdn.modrinth.com/data/Nn8Wasaq/a172c634683a11a2e9ae59
|
||||
def JDK = "17";
|
||||
def majorMc = "1.19.3";
|
||||
def modLoaders = "forge|fabric|quilt";
|
||||
def supportedMc = "1.19.3|1.19.4";
|
||||
def supportedMc = "1.19.4";
|
||||
def reltype = "snapshot";
|
||||
|
||||
pipeline {
|
||||
|
@@ -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;
|
||||
@@ -43,11 +43,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;
|
||||
@@ -58,7 +58,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 com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
@@ -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;
|
||||
}
|
||||
|
@@ -92,4 +92,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
|
||||
|
@@ -113,8 +113,8 @@ publisher {
|
||||
setVersionType("release")
|
||||
setChangelog("https://raw.githubusercontent.com/hypherionmc/changelogs/main/craterlib/changelog-fabric.md")
|
||||
setProjectVersion("${minecraft_version}-${project.version}")
|
||||
setDisplayName("[FABRIC/QUILT 1.19.3/1.19.4] CraterLib - ${project.version}")
|
||||
setGameVersions("1.19.3", "1.19.4")
|
||||
setDisplayName("[FABRIC/QUILT 1.19.4] CraterLib - ${project.version}")
|
||||
setGameVersions("1.19.4")
|
||||
setLoaders("fabric", "quilt")
|
||||
setArtifact(remapJar)
|
||||
setCurseEnvironment("both")
|
||||
|
@@ -9,7 +9,6 @@ import com.hypherionmc.craterlib.core.networking.CraterPacketNetwork;
|
||||
import com.hypherionmc.craterlib.core.networking.data.PacketSide;
|
||||
import com.hypherionmc.craterlib.core.platform.ModloaderEnvironment;
|
||||
import com.hypherionmc.craterlib.network.CraterFabricNetworkHandler;
|
||||
import com.hypherionmc.craterlib.nojang.commands.CommandsRegistry;
|
||||
import com.hypherionmc.craterlib.nojang.server.BridgedMinecraftServer;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
@@ -21,8 +20,7 @@ public class CraterLibInitializer implements ModInitializer {
|
||||
public void onInitialize() {
|
||||
new CraterPacketNetwork(new CraterFabricNetworkHandler(PacketSide.SERVER));
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent());
|
||||
CommandsRegistry.INSTANCE.registerCommands(dispatcher);
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent(dispatcher));
|
||||
});
|
||||
|
||||
|
||||
|
@@ -2,7 +2,6 @@ package com.hypherionmc.craterlib;
|
||||
|
||||
import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen;
|
||||
import com.hypherionmc.craterlib.core.config.ConfigController;
|
||||
import com.hypherionmc.craterlib.core.config.ModuleConfig;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.NoConfigScreen;
|
||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
@@ -19,9 +18,9 @@ public class CraterLibModMenuIntegration implements ModMenuApi {
|
||||
public Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() {
|
||||
Map<String, ConfigScreenFactory<?>> configScreens = new HashMap<>();
|
||||
|
||||
ConfigController.getMonitoredConfigs().forEach((conf, watcher) -> {
|
||||
ConfigController.getWatchedConfigs().forEach((conf, watcher) -> {
|
||||
if (!conf.getClass().isAnnotationPresent(NoConfigScreen.class)) {
|
||||
configScreens.put(((ModuleConfig) conf).getModId(), screen -> new CraterConfigScreen((ModuleConfig) conf, screen));
|
||||
configScreens.put(watcher.getLeft().getModId(), screen -> new CraterConfigScreen(watcher.getLeft(), screen));
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -0,0 +1,52 @@
|
||||
package com.hypherionmc.craterlib.mixin;
|
||||
|
||||
import com.hypherionmc.craterlib.api.events.server.ServerStatusEvent;
|
||||
import com.hypherionmc.craterlib.core.event.CraterEventBus;
|
||||
import com.hypherionmc.craterlib.utils.ChatUtils;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
|
||||
import net.minecraft.network.protocol.status.ServerStatus;
|
||||
import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
|
||||
import net.minecraft.server.network.ServerStatusPacketListenerImpl;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerStatusPacketListenerImpl.class)
|
||||
public class ServerStatusPacketListenerMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private ServerStatus status;
|
||||
|
||||
@Shadow @Final private Connection connection;
|
||||
|
||||
@Inject(method = "handleStatusRequest",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/network/Connection;send(Lnet/minecraft/network/protocol/Packet;)V",
|
||||
shift = At.Shift.BEFORE),
|
||||
cancellable = true
|
||||
)
|
||||
private void injectHandleStatusRequest(ServerboundStatusRequestPacket arg, CallbackInfo ci) {
|
||||
ServerStatusEvent.StatusRequestEvent event = new ServerStatusEvent.StatusRequestEvent(ChatUtils.mojangToAdventure(status.description()));
|
||||
CraterEventBus.INSTANCE.postEvent(event);
|
||||
|
||||
if (event.getNewStatus() != null) {
|
||||
ci.cancel();
|
||||
this.connection.send(new ClientboundStatusResponsePacket(
|
||||
new ServerStatus(ChatUtils.adventureToMojang(
|
||||
event.getNewStatus()),
|
||||
status.players(),
|
||||
status.version(),
|
||||
status.favicon(),
|
||||
status.enforcesSecureChat()
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -9,7 +9,8 @@
|
||||
"TutorialMixin"
|
||||
],
|
||||
"server": [
|
||||
"ServerGamePacketListenerImplMixin"
|
||||
"ServerGamePacketListenerImplMixin",
|
||||
"ServerStatusPacketListenerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
@@ -33,7 +33,7 @@
|
||||
"depends": {
|
||||
"fabricloader": ">=0.15.0",
|
||||
"fabric-api": "*",
|
||||
"minecraft": ">=1.19.3",
|
||||
"minecraft": ">=1.19.4",
|
||||
"java": ">=17"
|
||||
}
|
||||
}
|
||||
|
@@ -107,8 +107,8 @@ publisher {
|
||||
setVersionType("release")
|
||||
setChangelog("https://raw.githubusercontent.com/hypherionmc/changelogs/main/craterlib/changelog-forge.md")
|
||||
setProjectVersion("${minecraft_version}-${project.version}")
|
||||
setDisplayName("[Forge 1.19.3/1.19.4] CraterLib - ${project.version}")
|
||||
setGameVersions("1.19.3", "1.19.4")
|
||||
setDisplayName("[Forge 1.19.4] CraterLib - ${project.version}")
|
||||
setGameVersions("1.19.4")
|
||||
setLoaders("forge")
|
||||
setArtifact(remapJar)
|
||||
setCurseEnvironment("both")
|
||||
|
@@ -3,7 +3,6 @@ package com.hypherionmc.craterlib.common;
|
||||
import com.hypherionmc.craterlib.api.events.server.CraterRegisterCommandEvent;
|
||||
import com.hypherionmc.craterlib.api.events.server.CraterServerLifecycleEvent;
|
||||
import com.hypherionmc.craterlib.core.event.CraterEventBus;
|
||||
import com.hypherionmc.craterlib.nojang.commands.CommandsRegistry;
|
||||
import com.hypherionmc.craterlib.nojang.server.BridgedMinecraftServer;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import net.minecraftforge.event.server.ServerStartedEvent;
|
||||
@@ -36,8 +35,7 @@ public class ForgeServerEvents {
|
||||
|
||||
@SubscribeEvent
|
||||
public void onCommandRegister(RegisterCommandsEvent event) {
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent());
|
||||
CommandsRegistry.INSTANCE.registerCommands(event.getDispatcher());
|
||||
CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent(event.getDispatcher()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package com.hypherionmc.craterlib.mixin;
|
||||
|
||||
import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen;
|
||||
import com.hypherionmc.craterlib.core.config.AbstractConfig;
|
||||
import com.hypherionmc.craterlib.core.config.ConfigController;
|
||||
import com.hypherionmc.craterlib.core.config.ModuleConfig;
|
||||
import com.hypherionmc.craterlib.core.config.annotations.NoConfigScreen;
|
||||
@@ -28,9 +29,9 @@ public class ConfigScreenHandlerMixin {
|
||||
*/
|
||||
@Inject(at = @At("RETURN"), method = "getScreenFactoryFor", cancellable = true, remap = false)
|
||||
private static void injectConfigScreen(IModInfo selectedMod, CallbackInfoReturnable<Optional<BiFunction<Minecraft, Screen, Screen>>> cir) {
|
||||
ConfigController.getMonitoredConfigs().forEach((conf, watcher) -> {
|
||||
ConfigController.getWatchedConfigs().forEach((conf, watcher) -> {
|
||||
if (!conf.getClass().isAnnotationPresent(NoConfigScreen.class)) {
|
||||
ModuleConfig config = (ModuleConfig) conf;
|
||||
AbstractConfig config = watcher.getLeft();
|
||||
if (config.getModId().equals(selectedMod.getModId())) {
|
||||
cir.setReturnValue(
|
||||
Optional.of((minecraft, screen) -> new CraterConfigScreen(config, screen))
|
||||
|
@@ -0,0 +1,53 @@
|
||||
package com.hypherionmc.craterlib.mixin;
|
||||
|
||||
import com.hypherionmc.craterlib.api.events.server.ServerStatusEvent;
|
||||
import com.hypherionmc.craterlib.core.event.CraterEventBus;
|
||||
import com.hypherionmc.craterlib.utils.ChatUtils;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
|
||||
import net.minecraft.network.protocol.status.ServerStatus;
|
||||
import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
|
||||
import net.minecraft.server.network.ServerStatusPacketListenerImpl;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerStatusPacketListenerImpl.class)
|
||||
public class ServerStatusPacketListenerMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private ServerStatus status;
|
||||
|
||||
@Shadow @Final private Connection connection;
|
||||
|
||||
@Inject(method = "handleStatusRequest",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/network/Connection;send(Lnet/minecraft/network/protocol/Packet;)V",
|
||||
shift = At.Shift.BEFORE),
|
||||
cancellable = true
|
||||
)
|
||||
private void injectHandleStatusRequest(ServerboundStatusRequestPacket arg, CallbackInfo ci) {
|
||||
ServerStatusEvent.StatusRequestEvent event = new ServerStatusEvent.StatusRequestEvent(ChatUtils.mojangToAdventure(status.description()));
|
||||
CraterEventBus.INSTANCE.postEvent(event);
|
||||
|
||||
if (event.getNewStatus() != null) {
|
||||
ci.cancel();
|
||||
this.connection.send(new ClientboundStatusResponsePacket(
|
||||
new ServerStatus(ChatUtils.adventureToMojang(
|
||||
event.getNewStatus()),
|
||||
status.players(),
|
||||
status.version(),
|
||||
status.favicon(),
|
||||
status.enforcesSecureChat(),
|
||||
status.forgeData()
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
modLoader = "javafml"
|
||||
loaderVersion = "[44,)"
|
||||
loaderVersion = "[45,)"
|
||||
license = "MIT"
|
||||
issueTrackerURL = "https://github.com/firstdarkdev/craterLib/issues"
|
||||
|
||||
@@ -19,13 +19,13 @@ issueTrackerURL = "https://github.com/firstdarkdev/craterLib/issues"
|
||||
[[dependencies.${ mod_id }]]
|
||||
modId = "forge"
|
||||
mandatory = true
|
||||
versionRange = "[44,)"
|
||||
versionRange = "[45,)"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
||||
[[dependencies.${ mod_id }]]
|
||||
modId = "minecraft"
|
||||
mandatory = true
|
||||
versionRange = "[1.19.3,1.20)"
|
||||
versionRange = "[1.19.4,1.20)"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
@@ -9,7 +9,8 @@
|
||||
"ConfigScreenHandlerMixin"
|
||||
],
|
||||
"server": [
|
||||
"ServerGamePacketListenerImplMixin"
|
||||
"ServerGamePacketListenerImplMixin",
|
||||
"ServerStatusPacketListenerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
@@ -15,8 +15,8 @@ A Library mod and modding api for easier multi-version minecraft and mod loader
|
||||
| < 1.18.2 | ❌ |
|
||||
| 1.18.2-1.20.2 | ✳️ |
|
||||
| 1.20.4 | ✳️ |
|
||||
| 1.21 | ✳️ |
|
||||
| 1.21 | 🚧 |
|
||||
| 1.21.x | ✳️ |
|
||||
|
||||
|
||||
- ❌ - Not Supported; no bug fixes or new features.
|
||||
- 🚧 - Work in Progress; not ready for release.
|
||||
|
@@ -57,11 +57,13 @@ subprojects {
|
||||
// All Projects
|
||||
shade "me.hypherionmc.moon-config:core:${moon_config}"
|
||||
shade "me.hypherionmc.moon-config:toml:${moon_config}"
|
||||
shade "me.hypherionmc.moon-config:json:${moon_config}"
|
||||
shade "com.hypherionmc:rpcsdk:${rpc_sdk}"
|
||||
shade "me.hypherionmc.sdlink:mcdiscordformatter-1.19.1:${discord_formatter}"
|
||||
shade "net.kyori:adventure-api:${adventure}"
|
||||
shade "net.kyori:adventure-text-serializer-gson:${adventure}"
|
||||
|
||||
compileOnly 'net.luckperms:api:5.4'
|
||||
compileOnly("org.projectlombok:lombok:${lombok}")
|
||||
annotationProcessor("org.projectlombok:lombok:${lombok}")
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#Project
|
||||
version_major=2
|
||||
version_minor=0
|
||||
version_patch=3
|
||||
version_minor=1
|
||||
version_patch=0
|
||||
version_build=0
|
||||
|
||||
#Mod
|
||||
@@ -10,15 +10,15 @@ mod_id=craterlib
|
||||
mod_name=CraterLib
|
||||
|
||||
# Shared
|
||||
minecraft_version=1.19.3
|
||||
minecraft_version=1.19.4
|
||||
project_group=com.hypherionmc.craterlib
|
||||
|
||||
# Fabric
|
||||
fabric_loader=0.15.11
|
||||
fabric_api=0.76.1+1.19.3
|
||||
fabric_api=0.87.2+1.19.4
|
||||
|
||||
# Forge
|
||||
forge_version=44.1.0
|
||||
forge_version=45.3.0
|
||||
|
||||
# Dependencies
|
||||
moon_config=1.0.9
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user