diff --git a/.jenkins/Jenkinsfile.snapshot b/.jenkins/Jenkinsfile.snapshot index 29c65dc..d530d93 100644 --- a/.jenkins/Jenkinsfile.snapshot +++ b/.jenkins/Jenkinsfile.snapshot @@ -3,7 +3,7 @@ def projectIcon = "https://cdn.modrinth.com/data/Nn8Wasaq/a172c634683a11a2e9ae59 def JDK = "21"; def majorMc = "1.21"; def modLoaders = "neoforge|fabric|quilt"; -def supportedMc = "1.21"; +def supportedMc = "1.21|1.21.1"; def reltype = "port"; pipeline { diff --git a/Common/src/main/java/com/hypherionmc/craterlib/api/commands/CraterCommand.java b/Common/src/main/java/com/hypherionmc/craterlib/api/commands/CraterCommand.java index cc4969e..35f29f0 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/api/commands/CraterCommand.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/api/commands/CraterCommand.java @@ -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, TriConsumer>> arguments = new LinkedHashMap<>(); - private Consumer executor; + private final LiteralArgumentBuilder mojangCommand; + private int permLevel = 4; + private String luckPermNode = ""; - private final String commandName; - private int permissionLevel = 4; - - CraterCommand(String commandName) { - this.commandName = commandName; + CraterCommand(LiteralArgumentBuilder 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, 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> 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 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 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 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 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 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 executor) { + this.mojangCommand.executes(context -> executor.run(BridgedCommandSourceStack.of(context.getSource()))); + return this; + } + + @Deprecated(forRemoval = true) public CraterCommand executes(Consumer 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, BridgedCommandSourceStack> executor) { + return this.withGameProfilesArgument(key, (player, argument, stack) -> { + executor.accept(player, argument, stack); + return 1; + }); } + @ApiStatus.Internal + public void register(CommandDispatcher 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 { + int run(BridgedPlayer player, S argument, BridgedCommandSourceStack stack); + } + + @FunctionalInterface + public interface SingleCommandExecutor { + int run(S stack); + } } diff --git a/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/CraterPlayerEvent.java b/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/CraterPlayerEvent.java index 94be675..9e7d7a2 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/CraterPlayerEvent.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/CraterPlayerEvent.java @@ -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 diff --git a/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/CraterRegisterCommandEvent.java b/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/CraterRegisterCommandEvent.java index 269065a..5adac03 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/CraterRegisterCommandEvent.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/CraterRegisterCommandEvent.java @@ -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 stack; + public void registerCommand(CraterCommand cmd) { - CommandsRegistry.INSTANCE.registerCommand(cmd); + cmd.register(stack); } } diff --git a/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/ServerStatusEvent.java b/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/ServerStatusEvent.java new file mode 100644 index 0000000..b58dafa --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/api/events/server/ServerStatusEvent.java @@ -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 favicon; + private Optional newIcon = Optional.empty(); + + } +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/client/gui/config/CraterConfigScreen.java b/Common/src/main/java/com/hypherionmc/craterlib/client/gui/config/CraterConfigScreen.java index c9e70ca..4072ea9 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/client/gui/config/CraterConfigScreen.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/client/gui/config/CraterConfigScreen.java @@ -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> 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); } diff --git a/Common/src/main/java/com/hypherionmc/craterlib/client/gui/config/widgets/SubConfigWidget.java b/Common/src/main/java/com/hypherionmc/craterlib/client/gui/config/widgets/SubConfigWidget.java index 9426ccf..056f32c 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/client/gui/config/widgets/SubConfigWidget.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/client/gui/config/widgets/SubConfigWidget.java @@ -1,7 +1,7 @@ package com.hypherionmc.craterlib.client.gui.config.widgets; import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen; -import com.hypherionmc.craterlib.core.config.ModuleConfig; +import com.hypherionmc.craterlib.core.config.AbstractConfig; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; @@ -15,10 +15,10 @@ import net.minecraft.network.chat.Component; public class SubConfigWidget extends AbstractConfigWidget { 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; diff --git a/Common/src/main/java/com/hypherionmc/craterlib/compat/LuckPermsCompat.java b/Common/src/main/java/com/hypherionmc/craterlib/compat/LuckPermsCompat.java new file mode 100644 index 0000000..a77e1f4 --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/compat/LuckPermsCompat.java @@ -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(); + } + +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/core/config/AbstractConfig.java b/Common/src/main/java/com/hypherionmc/craterlib/core/config/AbstractConfig.java new file mode 100644 index 0000000..eceac79 --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/core/config/AbstractConfig.java @@ -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 { + + /* 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 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(); +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/core/config/ConfigController.java b/Common/src/main/java/com/hypherionmc/craterlib/core/config/ConfigController.java index 41c9471..760ca93 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/core/config/ConfigController.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/core/config/ConfigController.java @@ -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 monitoredConfigs = new HashMap<>(); + private static final HashMap> 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()); } } diff --git a/Common/src/main/java/com/hypherionmc/craterlib/core/config/ModuleConfig.java b/Common/src/main/java/com/hypherionmc/craterlib/core/config/ModuleConfig.java index 181efdc..e4850bf 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/core/config/ModuleConfig.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/core/config/ModuleConfig.java @@ -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 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(); } } diff --git a/Common/src/main/java/com/hypherionmc/craterlib/core/config/formats/AbstractConfigFormat.java b/Common/src/main/java/com/hypherionmc/craterlib/core/config/formats/AbstractConfigFormat.java new file mode 100644 index 0000000..20511ba --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/core/config/formats/AbstractConfigFormat.java @@ -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 { + + 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); + +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/core/config/formats/JsonConfigFormat.java b/Common/src/main/java/com/hypherionmc/craterlib/core/config/formats/JsonConfigFormat.java new file mode 100644 index 0000000..0db35fa --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/core/config/formats/JsonConfigFormat.java @@ -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 extends AbstractConfigFormat { + + 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); + } + }); + } +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/core/config/formats/TomlConfigFormat.java b/Common/src/main/java/com/hypherionmc/craterlib/core/config/formats/TomlConfigFormat.java new file mode 100644 index 0000000..e3f9763 --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/core/config/formats/TomlConfigFormat.java @@ -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 extends AbstractConfigFormat { + + 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); + } + }); + } +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/mixin/events/ServerStatusMixin.java b/Common/src/main/java/com/hypherionmc/craterlib/mixin/events/ServerStatusMixin.java new file mode 100644 index 0000000..53985e7 --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/mixin/events/ServerStatusMixin.java @@ -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> 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())); + } + } + +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/nojang/commands/BridgedCommandSourceStack.java b/Common/src/main/java/com/hypherionmc/craterlib/nojang/commands/BridgedCommandSourceStack.java index 5a15402..5529824 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/nojang/commands/BridgedCommandSourceStack.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/nojang/commands/BridgedCommandSourceStack.java @@ -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; } diff --git a/Common/src/main/java/com/hypherionmc/craterlib/nojang/commands/CommandsRegistry.java b/Common/src/main/java/com/hypherionmc/craterlib/nojang/commands/CommandsRegistry.java deleted file mode 100644 index 37ad15b..0000000 --- a/Common/src/main/java/com/hypherionmc/craterlib/nojang/commands/CommandsRegistry.java +++ /dev/null @@ -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 commands = new ArrayList<>(); - - public void registerCommand(CraterCommand cmd) { - commands.add(cmd); - } - - public void registerCommands(CommandDispatcher 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 dispatcher) { - LiteralArgumentBuilder 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 dispatcher) { - LiteralArgumentBuilder 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 profiles = GameProfileArgument.getGameProfiles(context, key); - List bridgedGameProfiles = new ArrayList<>(); - - profiles.forEach(p -> bridgedGameProfiles.add(BridgedGameProfile.of(p))); - - ((TriConsumer, BridgedCommandSourceStack>) pair.getRight()) - .accept(BridgedPlayer.of(context.getSource().getPlayer()), bridgedGameProfiles, BridgedCommandSourceStack.of(context.getSource())); - return 1; - } - - return 1; - }))); - - dispatcher.register(command); - } - - } - -} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/nojang/network/protocol/status/WrappedServerStatus.java b/Common/src/main/java/com/hypherionmc/craterlib/nojang/network/protocol/status/WrappedServerStatus.java new file mode 100644 index 0000000..ae6f773 --- /dev/null +++ b/Common/src/main/java/com/hypherionmc/craterlib/nojang/network/protocol/status/WrappedServerStatus.java @@ -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; + } + + } + +} diff --git a/Common/src/main/java/com/hypherionmc/craterlib/nojang/world/entity/player/BridgedPlayer.java b/Common/src/main/java/com/hypherionmc/craterlib/nojang/world/entity/player/BridgedPlayer.java index 8aa6d49..2241836 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/nojang/world/entity/player/BridgedPlayer.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/nojang/world/entity/player/BridgedPlayer.java @@ -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; } diff --git a/Common/src/main/java/com/hypherionmc/craterlib/utils/ChatUtils.java b/Common/src/main/java/com/hypherionmc/craterlib/utils/ChatUtils.java index 02ddae4..c09982c 100644 --- a/Common/src/main/java/com/hypherionmc/craterlib/utils/ChatUtils.java +++ b/Common/src/main/java/com/hypherionmc/craterlib/utils/ChatUtils.java @@ -108,4 +108,11 @@ public class ChatUtils { return mojangToAdventure(Component.translatable(Util.makeDescriptionId("biome", identifier.toMojang()))); } + public static net.kyori.adventure.text.Component format(String value) { + return net.kyori.adventure.text.Component.translatable(convertFormattingCodes(value)); + } + + private static String convertFormattingCodes(String input) { + return input.replaceAll("§([0-9a-fklmnor])", "\u00A7$1"); + } } diff --git a/Common/src/main/resources/craterlib.mixins.json b/Common/src/main/resources/craterlib.mixins.json index 1a739db..c910ed2 100644 --- a/Common/src/main/resources/craterlib.mixins.json +++ b/Common/src/main/resources/craterlib.mixins.json @@ -16,7 +16,8 @@ "events.CommandMixin", "events.PlayerAdvancementsMixin", "events.PlayerListMixin", - "events.ServerPlayerMixin" + "events.ServerPlayerMixin", + "events.ServerStatusMixin" ], "injectors": { "defaultRequire": 1 diff --git a/Fabric/build.gradle b/Fabric/build.gradle index d3a187f..0fd9480 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -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.21.0] CraterLib - ${project.version}") - setGameVersions("1.21") + setDisplayName("[FABRIC/QUILT 1.21.x] CraterLib - ${project.version}") + setGameVersions("1.21", "1.21.1") setLoaders("fabric", "quilt") setArtifact(remapJar) setCurseEnvironment("both") diff --git a/Fabric/src/main/java/com/hypherionmc/craterlib/CraterLibInitializer.java b/Fabric/src/main/java/com/hypherionmc/craterlib/CraterLibInitializer.java index c66c210..5e93a3a 100644 --- a/Fabric/src/main/java/com/hypherionmc/craterlib/CraterLibInitializer.java +++ b/Fabric/src/main/java/com/hypherionmc/craterlib/CraterLibInitializer.java @@ -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)); }); diff --git a/Fabric/src/main/java/com/hypherionmc/craterlib/CraterLibModMenuIntegration.java b/Fabric/src/main/java/com/hypherionmc/craterlib/CraterLibModMenuIntegration.java index 6615352..5b34ff1 100644 --- a/Fabric/src/main/java/com/hypherionmc/craterlib/CraterLibModMenuIntegration.java +++ b/Fabric/src/main/java/com/hypherionmc/craterlib/CraterLibModMenuIntegration.java @@ -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> getProvidedConfigScreenFactories() { Map> 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)); } }); diff --git a/Fabric/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java b/Fabric/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java index 91b157b..576a276 100644 --- a/Fabric/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java +++ b/Fabric/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java @@ -27,8 +27,8 @@ public class ServerGamePacketListenerImplMixin { cancellable = true ) private void injectChatEvent(PlayerChatMessage arg, Component arg2, FilteredText arg3, CallbackInfo ci) { - Component finalArg = arg2 == null ? arg.decoratedContent() : arg2; - CraterServerChatEvent event = new CraterServerChatEvent(BridgedPlayer.of(this.player), finalArg.getString(), ChatUtils.mojangToAdventure(finalArg)); + Component finalcomp = arg2 == null ? arg.decoratedContent() : arg2; + CraterServerChatEvent event = new CraterServerChatEvent(BridgedPlayer.of(this.player), finalcomp.getString(), ChatUtils.mojangToAdventure(finalcomp)); CraterEventBus.INSTANCE.postEvent(event); if (event.wasCancelled()) ci.cancel(); diff --git a/Fabric/src/main/java/com/hypherionmc/craterlib/mixin/ServerStatusPacketListenerMixin.java b/Fabric/src/main/java/com/hypherionmc/craterlib/mixin/ServerStatusPacketListenerMixin.java new file mode 100644 index 0000000..f3dc866 --- /dev/null +++ b/Fabric/src/main/java/com/hypherionmc/craterlib/mixin/ServerStatusPacketListenerMixin.java @@ -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() + ) + )); + } + } + +} \ No newline at end of file diff --git a/Fabric/src/main/resources/craterlib.fabric.mixins.json b/Fabric/src/main/resources/craterlib.fabric.mixins.json index 7c59043..a6d0bc1 100644 --- a/Fabric/src/main/resources/craterlib.fabric.mixins.json +++ b/Fabric/src/main/resources/craterlib.fabric.mixins.json @@ -9,7 +9,8 @@ "TutorialMixin" ], "server": [ - "ServerGamePacketListenerImplMixin" + "ServerGamePacketListenerImplMixin", + "ServerStatusPacketListenerMixin" ], "injectors": { "defaultRequire": 1 diff --git a/Forge/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java b/Forge/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java index 7adbbe1..012b6ff 100644 --- a/Forge/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java +++ b/Forge/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java @@ -27,8 +27,8 @@ public class ServerGamePacketListenerImplMixin { cancellable = true ) private void injectChatEvent(Component component, PlayerChatMessage arg, FilteredText p_296589_, CallbackInfo ci) { - Component finalArg = component == null ? arg.decoratedContent() : component; - CraterServerChatEvent event = new CraterServerChatEvent(BridgedPlayer.of(this.player), finalArg.getString(), ChatUtils.mojangToAdventure(finalArg)); + Component finalcomp = component == null ? arg.decoratedContent() : component; + CraterServerChatEvent event = new CraterServerChatEvent(BridgedPlayer.of(this.player), finalcomp.getString(), ChatUtils.mojangToAdventure(finalcomp)); CraterEventBus.INSTANCE.postEvent(event); if (event.wasCancelled()) ci.cancel(); diff --git a/Forge/src/main/java/com/hypherionmc/craterlib/mixin/ServerStatusPacketListenerMixin.java b/Forge/src/main/java/com/hypherionmc/craterlib/mixin/ServerStatusPacketListenerMixin.java new file mode 100644 index 0000000..cb697db --- /dev/null +++ b/Forge/src/main/java/com/hypherionmc/craterlib/mixin/ServerStatusPacketListenerMixin.java @@ -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.isModded() + ) + )); + } + } + +} \ No newline at end of file diff --git a/Forge/src/main/resources/craterlib.forge.mixins.json b/Forge/src/main/resources/craterlib.forge.mixins.json index aa072d1..892f6d7 100644 --- a/Forge/src/main/resources/craterlib.forge.mixins.json +++ b/Forge/src/main/resources/craterlib.forge.mixins.json @@ -9,7 +9,8 @@ "ConfigScreenHandlerMixin" ], "server": [ - "ServerGamePacketListenerImplMixin" + "ServerGamePacketListenerImplMixin", + "ServerStatusPacketListenerMixin" ], "injectors": { "defaultRequire": 1 diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index b3b5659..f6ef5c7 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -106,8 +106,8 @@ publisher { setVersionType("release") setChangelog("https://raw.githubusercontent.com/hypherionmc/changelogs/main/craterlib/changelog-forge.md") setProjectVersion("${minecraft_version}-${project.version}") - setDisplayName("[NeoForge 1.21.0] CraterLib - ${project.version}") - setGameVersions("1.21") + setDisplayName("[NeoForge 1.21.x] CraterLib - ${project.version}") + setGameVersions("1.21", "1.21.1") setLoaders("neoforge") setArtifact(remapJar) setCurseEnvironment("both") diff --git a/NeoForge/src/main/java/com/hypherionmc/craterlib/client/NeoForgeClientHelper.java b/NeoForge/src/main/java/com/hypherionmc/craterlib/client/NeoForgeClientHelper.java index 5aeb1fd..e7d9013 100644 --- a/NeoForge/src/main/java/com/hypherionmc/craterlib/client/NeoForgeClientHelper.java +++ b/NeoForge/src/main/java/com/hypherionmc/craterlib/client/NeoForgeClientHelper.java @@ -2,8 +2,8 @@ package com.hypherionmc.craterlib.client; import com.hypherionmc.craterlib.api.events.client.LateInitEvent; 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 com.hypherionmc.craterlib.core.event.CraterEventBus; import com.hypherionmc.craterlib.core.platform.ClientPlatform; @@ -51,9 +51,9 @@ public class NeoForgeClientHelper implements ClientPlatform { LateInitEvent event = new LateInitEvent(new BridgedMinecraft(), BridgedOptions.of(Minecraft.getInstance().options)); CraterEventBus.INSTANCE.postEvent(event); - ConfigController.getMonitoredConfigs().forEach((conf, watcher) -> { + ConfigController.getWatchedConfigs().forEach((conf, watcher) -> { if (!conf.getClass().isAnnotationPresent(NoConfigScreen.class)) { - ModuleConfig config = (ModuleConfig) conf; + AbstractConfig config = watcher.getLeft(); ModList.get().getModContainerById(config.getModId()).ifPresent(c -> c.registerExtensionPoint(IConfigScreenFactory.class, ((minecraft, screen) -> new CraterConfigScreen(config, screen)))); } }); diff --git a/NeoForge/src/main/java/com/hypherionmc/craterlib/common/NeoForgeServerEvents.java b/NeoForge/src/main/java/com/hypherionmc/craterlib/common/NeoForgeServerEvents.java index 91ca5b7..868b89f 100644 --- a/NeoForge/src/main/java/com/hypherionmc/craterlib/common/NeoForgeServerEvents.java +++ b/NeoForge/src/main/java/com/hypherionmc/craterlib/common/NeoForgeServerEvents.java @@ -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.neoforged.bus.api.SubscribeEvent; import net.neoforged.neoforge.event.RegisterCommandsEvent; @@ -36,8 +35,7 @@ public class NeoForgeServerEvents { @SubscribeEvent public void onCommandRegister(RegisterCommandsEvent event) { - CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent()); - CommandsRegistry.INSTANCE.registerCommands(event.getDispatcher()); + CraterEventBus.INSTANCE.postEvent(new CraterRegisterCommandEvent(event.getDispatcher())); } } diff --git a/NeoForge/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java b/NeoForge/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java index 7adbbe1..012b6ff 100644 --- a/NeoForge/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java +++ b/NeoForge/src/main/java/com/hypherionmc/craterlib/mixin/ServerGamePacketListenerImplMixin.java @@ -27,8 +27,8 @@ public class ServerGamePacketListenerImplMixin { cancellable = true ) private void injectChatEvent(Component component, PlayerChatMessage arg, FilteredText p_296589_, CallbackInfo ci) { - Component finalArg = component == null ? arg.decoratedContent() : component; - CraterServerChatEvent event = new CraterServerChatEvent(BridgedPlayer.of(this.player), finalArg.getString(), ChatUtils.mojangToAdventure(finalArg)); + Component finalcomp = component == null ? arg.decoratedContent() : component; + CraterServerChatEvent event = new CraterServerChatEvent(BridgedPlayer.of(this.player), finalcomp.getString(), ChatUtils.mojangToAdventure(finalcomp)); CraterEventBus.INSTANCE.postEvent(event); if (event.wasCancelled()) ci.cancel(); diff --git a/NeoForge/src/main/java/com/hypherionmc/craterlib/mixin/ServerStatusPacketListenerMixin.java b/NeoForge/src/main/java/com/hypherionmc/craterlib/mixin/ServerStatusPacketListenerMixin.java new file mode 100644 index 0000000..cb697db --- /dev/null +++ b/NeoForge/src/main/java/com/hypherionmc/craterlib/mixin/ServerStatusPacketListenerMixin.java @@ -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.isModded() + ) + )); + } + } + +} \ No newline at end of file diff --git a/NeoForge/src/main/resources/craterlib.neoforge.mixins.json b/NeoForge/src/main/resources/craterlib.neoforge.mixins.json index e1af981..147f7e0 100644 --- a/NeoForge/src/main/resources/craterlib.neoforge.mixins.json +++ b/NeoForge/src/main/resources/craterlib.neoforge.mixins.json @@ -7,7 +7,8 @@ ], "client": [], "server": [ - "ServerGamePacketListenerImplMixin" + "ServerGamePacketListenerImplMixin", + "ServerStatusPacketListenerMixin" ], "injectors": { "defaultRequire": 1 diff --git a/README.md b/README.md index 63c4aed..3d8f0a8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ A Library mod and modding api for easier multi-version minecraft and mod loader | 1.18.2-1.20.2 | ✳️ | | 1.20.4 | ✳️ | | 1.20.6 | ❌ | -| 1.21 | ✳️ | +| 1.21.x | ✳️ | - ❌ - Not Supported; no bug fixes or new features. - 🚧 - Work in Progress; not ready for release. diff --git a/build.gradle b/build.gradle index c4a979f..861a660 100644 --- a/build.gradle +++ b/build.gradle @@ -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.20.3:${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}") } diff --git a/gradle.properties b/gradle.properties index cee5ea2..7e92dff 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ #Project version_major=2 -version_minor=0 -version_patch=3 +version_minor=1 +version_patch=0 version_build=0 #Mod