From 1a7ecf19977d9b499d06ce1749ad8830a1a1d57a Mon Sep 17 00:00:00 2001 From: rhysdh540 Date: Tue, 1 Aug 2023 23:38:57 +0800 Subject: [PATCH] a lot of things - config - qodana - rebuild .idea folder lol --- .github/workflows/qodana.yml | 19 ++ .gitignore | 5 +- 1.19.2.properties | 18 +- README.md | 25 -- build.gradle | 9 +- build.properties | 4 +- .../rdh/createunlimited/CreateUnlimited.java | 30 ++- .../rdh/createunlimited/config/CUConfig.java | 136 ++++++++++ .../config/command/CUCommands.java | 233 ++++++++++++++++++ .../config/command/EnumArgument.java | 130 ++++++++++ .../util/{PlatformUtils.java => Util.java} | 38 ++- .../createunlimited/util/VersionUtils.java | 14 -- .../resources/createunlimited.accesswidener | 2 - .../fabric/ModMenuIntegration.java | 13 + .../{PlatformUtilsImpl.java => UtilImpl.java} | 2 +- fabric/src/main/resources/fabric.mod.json | 3 + .../forge/CreateUnlimitedForge.java | 3 + .../dev/rdh/createunlimited/forge/Events.java | 28 +++ .../{PlatformUtilsImpl.java => UtilImpl.java} | 2 +- qodana.yaml | 31 +++ 20 files changed, 683 insertions(+), 62 deletions(-) create mode 100644 .github/workflows/qodana.yml create mode 100644 common/src/main/java/dev/rdh/createunlimited/config/CUConfig.java create mode 100644 common/src/main/java/dev/rdh/createunlimited/config/command/CUCommands.java create mode 100644 common/src/main/java/dev/rdh/createunlimited/config/command/EnumArgument.java rename common/src/main/java/dev/rdh/createunlimited/util/{PlatformUtils.java => Util.java} (51%) delete mode 100644 common/src/main/java/dev/rdh/createunlimited/util/VersionUtils.java delete mode 100644 common/src/main/resources/createunlimited.accesswidener create mode 100644 fabric/src/main/java/dev/rdh/createunlimited/fabric/ModMenuIntegration.java rename fabric/src/main/java/dev/rdh/createunlimited/util/fabric/{PlatformUtilsImpl.java => UtilImpl.java} (98%) rename forge/src/main/java/dev/rdh/createunlimited/util/forge/{PlatformUtilsImpl.java => UtilImpl.java} (97%) create mode 100644 qodana.yaml diff --git a/.github/workflows/qodana.yml b/.github/workflows/qodana.yml new file mode 100644 index 0000000..bfd21bf --- /dev/null +++ b/.github/workflows/qodana.yml @@ -0,0 +1,19 @@ +name: Qodana +on: + workflow_dispatch: + pull_request: + push: + branches: + - multiversion + +jobs: + qodana: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: 'Qodana Scan' + uses: JetBrains/qodana-action@v2023.2 + env: + QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index ccb0c56..12b17e6 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,7 @@ classes/ .metadata .vscode .settings -*.launch \ No newline at end of file +*.launch + +build.properties +common/src/main/resources/*.accesswidener \ No newline at end of file diff --git a/1.19.2.properties b/1.19.2.properties index 7e3f340..c5db447 100755 --- a/1.19.2.properties +++ b/1.19.2.properties @@ -27,12 +27,12 @@ lazydfu=0.1.3 smoothboot_fabric=3821513 modmenu=7.2.1 -### Forge Mods -## Better Mods Button - https://www.curseforge.com/minecraft/mc-mods/better-mods-button/files -#bmb = 4613425 -## Catalogue - https://www.curseforge.com/minecraft/mc-mods/catalogue/files -#catalogue = 4590890 -## FerriteCore - https://www.curseforge.com/minecraft/mc-mods/ferritecore/files -#ferritecore = 4574361 -## Smooth Boot -#smoothboot_forge = 4162940 \ No newline at end of file +## Forge Mods +# Better Mods Button - https://www.curseforge.com/minecraft/mc-mods/better-mods-button/files +bmb = 4665753 +# Catalogue - https://www.curseforge.com/minecraft/mc-mods/catalogue/files +catalogue = 4171024 +# FerriteCore - https://www.curseforge.com/minecraft/mc-mods/ferritecore/files +ferritecore = 4117906 +# Smooth Boot - https://www.curseforge.com/minecraft/mc-mods/smooth-boot-reloaded/files/ +smoothboot_forge = 4162940 \ No newline at end of file diff --git a/README.md b/README.md index be06de2..e69de29 100755 --- a/README.md +++ b/README.md @@ -1,25 +0,0 @@ -# Ranplate -A template repo for my minecraft mods which is multi-loader & multi-versioned - -Current Preprocessor System: -- MC_`` - - so `MC_1_19_2` would mean if 1.19.2 is the current version -- POST_MC_`` - - so `POST_MC_1_19_2` would mean if the version is after 1.19.2 -- POST_CURRENT_MC_`` - - so `POST_CURRENT_MC_1_19_2` would mean if the current version is after 1.19.2 or is 1.19.2 -- PRE_MC_`` - - so `PRE_MC_1_19_2` would mean if the version is before 1.19.2 -- PRE_CURRENT_MC_`` - - so `PRE_CURRENT_MC_1_19_2` would mean if the current version is before 1.19.2 or is 1.19.2 - -Remember to install the [Manifold](https://plugins.jetbrains.com/plugin/10057-manifold) plugin in IntelliJ!\ -Also could look in this [class](https://github.com/Ran-helo/Ranplate/blob/master/common/src/main/java/net/examplemod/ExampleMod.java) if you need an example of how to use it! - -This repo contains [MixinExtras](https://github.com/LlamaLad7/MixinExtras) so remember to [check](https://github.com/LlamaLad7/MixinExtras/wiki) that out!\ -It also contains a lot of optimization mods to run the development environment a bit better.\ -And also contains [Forgix](https://github.com/PacifistMC/Forgix) which basically merges the mod-loaders into one jar! - ---- -When adding more versions, remember to edit the `.github/workflows/build.yml` file and make sure the merged jars doesn't overwrite each other!\ -And do note that if you're going to use Architectury API then `dev.architectury` is `me.shedaniel.architectury` in 1.16.5 and below. diff --git a/build.gradle b/build.gradle index 140a021..20845a7 100755 --- a/build.gradle +++ b/build.gradle @@ -219,12 +219,11 @@ def setupManifoldProcessors(List mcVers, int mcIndex) { } StringBuilder sb = new StringBuilder() - sb.append("# No need to edit this file since it's generated by the build script\n") - sb.append("# If you need to change versions then edit \"mc_versions\" in gradle.properties\n\n") + sb.append("# DO NOT EDIT\n") + .append("# Generated by the build script. Change mcVer property to change minecraft version.\n\n") for (String redefinedVersion : redefineList) { - sb.append(redefinedVersion) - sb.append("=\n") + sb.append(redefinedVersion).append("=\n") } new File(projectDir, "build.properties").text = sb.toString() @@ -281,7 +280,7 @@ def makeAccessWidener() { rename "${rootProject.accessWidenerVersion}.createunlimited.aw", "createunlimited.accesswidener" } def text = accessWidenerFile.text - text = text + "\n# Do not edit this file. It is automatically generated by the build script. Edit ${versionAccessWidenerFile.name} instead!" + text = text + "\n# DO NOT EDIT\n# Generated by the build script. Edit ${versionAccessWidenerFile.name} instead!" accessWidenerFile.text = text } else { diff --git a/build.properties b/build.properties index e50229f..1e9e60d 100644 --- a/build.properties +++ b/build.properties @@ -1,5 +1,5 @@ -# No need to edit this file since it's generated by the build script -# If you need to change versions then edit "mc_versions" in gradle.properties +# DO NOT EDIT +# Generated by the build script. Change mcVer property to change minecraft version. POST_MC_1_19_2= POST_CURRENT_MC_1_19_2= diff --git a/common/src/main/java/dev/rdh/createunlimited/CreateUnlimited.java b/common/src/main/java/dev/rdh/createunlimited/CreateUnlimited.java index 4a6a6db..abe9bb2 100755 --- a/common/src/main/java/dev/rdh/createunlimited/CreateUnlimited.java +++ b/common/src/main/java/dev/rdh/createunlimited/CreateUnlimited.java @@ -1,9 +1,37 @@ package dev.rdh.createunlimited; +import com.simibubi.create.Create; + +import dev.rdh.createunlimited.config.CUConfig; + +import dev.rdh.createunlimited.config.command.CUCommands; +import dev.rdh.createunlimited.config.command.EnumArgument; +import dev.rdh.createunlimited.util.Util; + +import net.minecraft.resources.ResourceLocation; + +import net.minecraftforge.fml.config.ModConfig; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class CreateUnlimited { - public static final String ID = "createunlimited"; + public static final String ID = "createunlimited"; + public static final String NAME = "Create Unlimited"; + public static final String VERSION = "0.4.1"; + public static final Logger LOGGER = LoggerFactory.getLogger(NAME); public static void init() { + LOGGER.info("{} initializing! Create version: {} on platform: {}", NAME, Create.VERSION, Util.platformName()); + Util.registerConfig(ID, ModConfig.Type.SERVER, CUConfig.SPEC, "createunlimited.toml"); + CUConfig.init(Util.getConfigDirectory().resolve("createunlimited-IGNOREME.toml")); + + CUCommands.registerConfigCommand(); + Util.registerArgument("enumargument", EnumArgument.class, new EnumArgument.Info(), asResource("enumargument")); } + + public static ResourceLocation asResource(String path) { + return new ResourceLocation(ID, path); + } } diff --git a/common/src/main/java/dev/rdh/createunlimited/config/CUConfig.java b/common/src/main/java/dev/rdh/createunlimited/config/CUConfig.java new file mode 100644 index 0000000..39f5511 --- /dev/null +++ b/common/src/main/java/dev/rdh/createunlimited/config/CUConfig.java @@ -0,0 +1,136 @@ +package dev.rdh.createunlimited.config; + +import com.electronwill.nightconfig.core.file.CommentedFileConfig; +import com.electronwill.nightconfig.core.io.WritingMode; + +import com.simibubi.create.foundation.config.ui.BaseConfigScreen; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; + +import net.minecraftforge.common.ForgeConfigSpec; + +import dev.rdh.createunlimited.CreateUnlimited; + +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; + +public class CUConfig { + private CUConfig() { throw new UnsupportedOperationException(); } + public static final ForgeConfigSpec SPEC; + public static ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); + + public enum PlacementCheck { + ON, + SURVIVAL_ONLY, + OFF, + } + + public static final Map comments = new HashMap<>(); + static { + comments.put("trains", "Train Settings"); + comments.put("placementChecks", "Whether or not to enable the placement checks for train tracks."); + comments.put("extendedDriving", "Whether or not to allow trains to drive on tracks with very small turn radii. Slightly buggy."); + comments.put("extendedDrivingValue", "The minimum turn that trains can drive on. Only works if extendedDriving is enabled."); + comments.put("maxTrainRelocationDistance", "Maximum distance a train can be relocated using the wrench."); + comments.put("maxAllowedStress", "Maximum stress from couplings before train derails. Set to -1 to disable."); + + comments.put("glue", "Glue Settings"); + comments.put("maxGlueConnectionRange", "Maximum distance between two blocks for them to be considered for glue connections."); + comments.put("physicalBlockConnection", "Require blocks to be connected for glue connections."); + + comments.put("extendo", "Extendo Grip Settings"); + comments.put("singleExtendoGripRange", "How much to extend your reach when holding an Extendo-Grip. Adds to your base reach."); + comments.put("doubleExtendoGripRange", "How much to extend your reach when holding two Extendo-Grips. Adds to your base reach."); + + comments.put("copycat", "Copycat Settings"); + comments.put("allowAllCopycatBlocks", "Whether or not to allow all blocks to be inserted into Copycat blocks."); + } + + public static String trains; + public static ForgeConfigSpec.EnumValue placementChecks; + public static ForgeConfigSpec.BooleanValue extendedDriving; + public static ForgeConfigSpec.DoubleValue extendedDrivingValue; + public static ForgeConfigSpec.IntValue maxTrainRelocationDistance; + public static ForgeConfigSpec.DoubleValue maxAllowedStress; + + public static String glue; + public static ForgeConfigSpec.IntValue maxGlueConnectionRange; + public static ForgeConfigSpec.BooleanValue physicalBlockConnection; + +// public static String extendo; +// public static ForgeConfigSpec.IntValue singleExtendoGripRange; +// public static ForgeConfigSpec.IntValue doubleExtendoGripRange; + + public static String copycat; + public static ForgeConfigSpec.BooleanValue allowAllCopycatBlocks; + + static { + BUILDER.comment("Create Unlimited Config").push("CreateUnlimited"); + + cat("Trains"); + placementChecks = BUILDER.comment(comments.get("placementChecks")).defineEnum("placementChecks", PlacementCheck.ON); + extendedDriving = b(false, "extendedDriving"); + extendedDrivingValue = d(0.1, 0.0, 0.875, "extendedDrivingValue"); + maxTrainRelocationDistance = i(24, 0, "maxTrainRelocationDistance"); + maxAllowedStress = d(4.0, -1.0, "maxAllowedStress"); + + BUILDER.pop(); + cat("Glue"); + maxGlueConnectionRange = i(24, 0, "maxGlueConnectionRange"); + physicalBlockConnection = b(true, "physicalBlockConnection"); + +// BUILDER.pop().comment(comments.get("extendo")).push("ExtendoGrip"); +// singleExtendoGripRange = i(3, 0, "singleExtendoGripRange", comments.get("singleExtendoGripRange")); +// doubleExtendoGripRange = i(5, 0, "doubleExtendoGripRange", comments.get("doubleExtendoGripRange")); + + BUILDER.pop(); + cat("Copycat"); + allowAllCopycatBlocks = b(false, "allowAllCopycatBlocks"); + BUILDER.pop(2); + + SPEC = BUILDER.build(); + } + + public static void init(Path path) { + CreateUnlimited.LOGGER.info("Loading Create Unlimited config!"); + final CommentedFileConfig configData = CommentedFileConfig.builder(path) + .sync() + .autosave() + .writingMode(WritingMode.REPLACE) + .build(); + configData.load(); + SPEC.setConfig(configData); + } + + // helper methods for initializing config values + private static ForgeConfigSpec.BooleanValue b(boolean normal, String path) { + return BUILDER.comment(comments.get(path)).define(path, normal); + } + private static ForgeConfigSpec.IntValue i(int normal, int min, String path) { + return BUILDER.comment(comments.get(path)).defineInRange(path, normal, min, Integer.MAX_VALUE); + } + private static ForgeConfigSpec.DoubleValue d(double normal, double min, String path) { + return d(normal, min, Double.MAX_VALUE, path); + } + private static ForgeConfigSpec.DoubleValue d(double normal, double min, double max, String path) { + return BUILDER.comment(comments.get(path)).defineInRange(path, normal, min, max); + } + private static void cat(String path) { + BUILDER.comment(comments.get(path.toLowerCase())).push(path); + } + + public static BaseConfigScreen createConfigScreen(Screen parent) { + BaseConfigScreen.setDefaultActionFor(CreateUnlimited.ID, (base) -> + base.withSpecs(null, null, CUConfig.SPEC) + .withTitles("", "", "Settings") + ); + return new BaseConfigScreen(parent, CreateUnlimited.ID); + } + public static BaseConfigScreen createConfigScreen(@Nullable Minecraft mc, Screen parent) { + return createConfigScreen(parent); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/rdh/createunlimited/config/command/CUCommands.java b/common/src/main/java/dev/rdh/createunlimited/config/command/CUCommands.java new file mode 100644 index 0000000..6b406a9 --- /dev/null +++ b/common/src/main/java/dev/rdh/createunlimited/config/command/CUCommands.java @@ -0,0 +1,233 @@ +package dev.rdh.createunlimited.config.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.BoolArgumentType; +import com.mojang.brigadier.arguments.DoubleArgumentType; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; + +import com.mojang.brigadier.context.CommandContext; + +import com.simibubi.create.foundation.utility.Components; + +import dev.rdh.createunlimited.util.Util; +import dev.rdh.createunlimited.CreateUnlimited; +import dev.rdh.createunlimited.config.CUConfig; + +import net.minecraft.ChatFormatting; +import net.minecraft.commands.CommandSourceStack; + +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentUtils; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; + +import net.minecraftforge.common.ForgeConfigSpec; + +import java.lang.reflect.Field; +import java.util.List; + +import static net.minecraft.commands.Commands.argument; +import static net.minecraft.commands.Commands.literal; +import static net.minecraft.network.chat.Component.nullToEmpty; + +public class CUCommands { + /** + * Builds and registers the {@code /createunlimited} command, that changes configuration values. + *

+ * Base command: {@code /createunlimited} + *
+ * Subcommands: + *

    + *
  • {@code /createunlimited get} - Gets the value of the config
  • + *
  • {@code /createunlimited set } - Sets the value of the config + *
      + *
    • Requires operator permissions on servers.
    • + *
  • + *
  • {@code /createunlimited reset} - Resets the value of the config to its default value + *
      + *
    • Requires operator permissions on servers.
    • + *
  • + *
+ * This command uses Mojang's {@link com.mojang.brigadier Brigadier} library to parse arguments and send them to the server. + * @see Brigadier on GitHub + */ + public static void registerConfigCommand() { + List links = List.of( + link("https://github.com/rhysdh540/create-unlimited", "GitHub", ChatFormatting.GRAY), + link("https://modrinth.com/mod/create-unlimited", "Modrinth", ChatFormatting.GREEN), + link("https://curseforge.com/minecraft/mc-mods/create-unlimited", "CurseForge", ChatFormatting.GOLD), + link("https://discord.gg/2ubhDbMaZY", "Discord", ChatFormatting.BLUE) + ); + + LiteralArgumentBuilder base = literal(CreateUnlimited.ID).executes(context -> { + message(CreateUnlimited.NAME + " v" + CreateUnlimited.VERSION + " by rdh\nVisit us on:", context); + + MutableComponent link = (MutableComponent) CommonComponents.EMPTY; + links.forEach(a -> link.append(a).append(Component.literal(" "))); + + message(link, context); + return Command.SINGLE_SUCCESS; + }); + + LiteralArgumentBuilder category = null; + for (Field field : CUConfig.class.getDeclaredFields()) { + //skip if not config value or string + if (!ForgeConfigSpec.ConfigValue.class.isAssignableFrom(field.getType()) && field.getType() != String.class) continue; + + //change category if needed + if (field.getType() == String.class) { + if (category != null) base.then(category); + category = literal(field.getName()); + + //add description for category + base.then(literal(field.getName()).executes(context -> { + message(CUConfig.comments.get(field.getName()), context); + return Command.SINGLE_SUCCESS; + })); + + continue; + } + if(category == null) + category = base; // if no category, append everything to base + + // get config as ConfigValue + ForgeConfigSpec.ConfigValue value; + try { + value = (ForgeConfigSpec.ConfigValue) field.get(null); + } catch (IllegalAccessException | ClassCastException e) { + CreateUnlimited.LOGGER.error("Failed to get config value for " + field.getName(), e); + continue; + } + + //get, description, reset + gdr(category, field, value); + + //set for boolean + if (value instanceof ForgeConfigSpec.BooleanValue bValue) + setBoolean(category, field, bValue); + + // set for enums + else if (value.get() instanceof Enum) + setEnum(category, field, (ForgeConfigSpec.EnumValue>) value); + + // set for int + else if (value instanceof ForgeConfigSpec.IntValue iValue) + setInt(category, field, iValue); + + // set for double + else if (value instanceof ForgeConfigSpec.DoubleValue dValue) + setDouble(category, field, dValue); + + } + if (category != null) + base.then(category); + Util.registerCommand(base); + } + + private static boolean perms(CommandSourceStack source) { + return source.hasPermission(4) || !source.getLevel().getServer().isDedicatedServer(); + } + + + private static void gdr(LiteralArgumentBuilder category, Field field, ForgeConfigSpec.ConfigValue value) { + category.then(literal(field.getName()) + .executes(context -> { + message(field.getName() + ": " + CUConfig.comments.get(field.getName()), context); + message("Current value: " + value.get(), context); + message("Default value: " + value.getDefault(), context); + return Command.SINGLE_SUCCESS; + }) + .then(literal("reset").requires(CUCommands::perms) + .executes(context -> { + if(value.get().equals(value.getDefault())) { + error("Value is already default!", context); + return 0; + } + value.set(value.getDefault()); + message(field.getName() + " reset to: " + value.get(), context); + return Command.SINGLE_SUCCESS; + }) + ) + ); + } + + private static void setBoolean(LiteralArgumentBuilder category, Field field, ForgeConfigSpec.BooleanValue value) { + category.then(literal(field.getName()) + .then(argument("value", BoolArgumentType.bool()).requires(CUCommands::perms) + .executes(context -> { + boolean set = BoolArgumentType.getBool(context, "value"); + value.set(set); + message(field.getName() + " set to: " + set, context); + return Command.SINGLE_SUCCESS; + }) + ) + ); + } + + private static void setInt(LiteralArgumentBuilder category, Field field, ForgeConfigSpec.IntValue value) { + category.then(literal(field.getName()) + .then(argument("value", IntegerArgumentType.integer()).requires(CUCommands::perms) + .executes(context -> { + int set = IntegerArgumentType.getInteger(context, "value"); + value.set(set); + message(field.getName() + " set to: " + set, context); + return Command.SINGLE_SUCCESS; + }) + ) + ); + } + + private static void setDouble(LiteralArgumentBuilder category, Field field, ForgeConfigSpec.DoubleValue value) { + category.then(literal(field.getName()) + .then(argument("value", DoubleArgumentType.doubleArg()).requires(CUCommands::perms) + .executes(context -> { + double set = DoubleArgumentType.getDouble(context, "value"); + value.set(set); + message(field.getName() + " set to: " + set, context); + return Command.SINGLE_SUCCESS; + }) + ) + ); + } + + private static > void setEnum(LiteralArgumentBuilder category, Field field, ForgeConfigSpec.EnumValue value) { + category.then(literal(field.getName()) + .then(argument("value", EnumArgument.enumArg(value.get().getClass(), true)) + .executes(context -> { + T set = (T) context.getArgument("value", value.get().getClass()); + value.set(set); + message(field.getName() + " set to: " + set.name().toLowerCase(), context); + return Command.SINGLE_SUCCESS; + }) + ) + ); + } + + private static MutableComponent link(String link, String display, ChatFormatting color) { + return ComponentUtils.wrapInSquareBrackets(Component.nullToEmpty(display)) + .withStyle(color) + .withStyle(style -> style + .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, link)) + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Components.literal("Click to open " + display + " page"))) + .withUnderlined(false)); + } + + private static void message(String message, CommandContext context) { + message(nullToEmpty(message), context); + } + private static void message(Component message, CommandContext context) { + #if PRE_CURRENT_MC_1_19_2 + context.getSource().sendSuccess(message, false); + #elif POST_CURRENT_MC_1_20_1 + context.getSource().sendSuccess(() -> message, false); + #else + #error "Unsupported Minecraft version" + #endif + } + private static void error(String message, CommandContext context) { + context.getSource().sendFailure(nullToEmpty(message)); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/rdh/createunlimited/config/command/EnumArgument.java b/common/src/main/java/dev/rdh/createunlimited/config/command/EnumArgument.java new file mode 100644 index 0000000..cf4fbce --- /dev/null +++ b/common/src/main/java/dev/rdh/createunlimited/config/command/EnumArgument.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package dev.rdh.createunlimited.config.command; + +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * copied from froge + *

+ * oh yeah i also added configurable lowercase because yes + */ +public class EnumArgument> implements ArgumentType { + private static final Dynamic2CommandExceptionType INVALID_ENUM = new Dynamic2CommandExceptionType( + (found, constants) -> Component.literal(String.format("Invalid enum value '%s', expected one of: %s", found, constants))); + private final Class enumClass; + private final boolean lowercase; + + public static > EnumArgument enumArg(Class enumClass, boolean lowercase) { + return new EnumArgument<>(enumClass, lowercase); + } + + private EnumArgument(final Class enumClass, final boolean lowercase) { + this.enumClass = enumClass; + this.lowercase = lowercase; + } + + @Override + public T parse(final StringReader reader) throws CommandSyntaxException { + String name = reader.readUnquotedString(); + try { + return Enum.valueOf(enumClass, unlowercase(name)); + } catch (IllegalArgumentException e) { + throw INVALID_ENUM.createWithContext(reader, name, Arrays.toString(Arrays.stream(enumClass.getEnumConstants()).map(Enum::name).map(this::lowercase).toArray())); + } + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(Stream.of(enumClass.getEnumConstants()).map(Enum::name).map(this::lowercase), builder); + } + + @Override + public Collection getExamples() { + return Stream.of(enumClass.getEnumConstants()).map(Enum::name).map(this::lowercase).collect(Collectors.toList()); + } + + public static class Info> implements ArgumentTypeInfo, Info.Template> { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + buffer.writeUtf(template.enumClass.getName()); + buffer.writeBoolean(template.lowercase); + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + try { + String name = buffer.readUtf(); + boolean l = buffer.readBoolean(); + return new Template((Class) Class.forName(name), l); + } + catch (ClassNotFoundException e) { + return null; + } + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + json.addProperty("enum", template.enumClass.getName()); + } + + @Override + public Template unpack(EnumArgument argument) { + return new Template(argument.enumClass, argument.lowercase); + } + + public class Template implements ArgumentTypeInfo.Template> { + final Class enumClass; + final boolean lowercase; + + Template(Class enumClass, boolean lowercase) { + this.enumClass = enumClass; + this.lowercase = lowercase; + } + + @Override + public EnumArgument instantiate(CommandBuildContext ctx) { + return new EnumArgument<>(this.enumClass, this.lowercase); + } + + @Override + public ArgumentTypeInfo, ?> type() { + return Info.this; + } + } + } + + private String lowercase(String s) { + return lowercase ? s.toLowerCase() : s; + } + private String unlowercase(String s) { + if(!lowercase) + return s; + return Arrays.stream(enumClass.getEnumConstants()) + .map(Enum::name) + .filter(n -> n.equalsIgnoreCase(s)) + .findFirst() + .orElse(s); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/rdh/createunlimited/util/PlatformUtils.java b/common/src/main/java/dev/rdh/createunlimited/util/Util.java similarity index 51% rename from common/src/main/java/dev/rdh/createunlimited/util/PlatformUtils.java rename to common/src/main/java/dev/rdh/createunlimited/util/Util.java index 3621773..6ea4292 100644 --- a/common/src/main/java/dev/rdh/createunlimited/util/PlatformUtils.java +++ b/common/src/main/java/dev/rdh/createunlimited/util/Util.java @@ -9,13 +9,17 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.resources.ResourceLocation; +import net.minecraft.core.Direction.Axis; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.fml.config.IConfigSpec; import net.minecraftforge.fml.config.ModConfig; import java.nio.file.Path; -public class PlatformUtils { +public class Util { @ExpectPlatform public static String platformName() { @@ -42,4 +46,36 @@ public static void registerConfig(String id, ModConfig.Type type, IConfigSpec void registerArgument(String name, Class clazz, I info, ResourceLocation id) { throw new AssertionError(); } + + @SuppressWarnings("SuspiciousNameCombination") // javac doesn't like when we pass a value called "y" to a method that expects a value called "x" + public static double[] intersect(Vec3 p1, Vec3 p2, Vec3 r, Vec3 s, Axis plane) { + if (plane == Axis.X) { + p1 = new Vec3(p1.y, 0, p1.z); + p2 = new Vec3(p2.y, 0, p2.z); + r = new Vec3(r.y, 0, r.z); + s = new Vec3(s.y, 0, s.z); + } + + if (plane == Axis.Z) { + p1 = new Vec3(p1.x, 0, p1.y); + p2 = new Vec3(p2.x, 0, p2.y); + r = new Vec3(r.x, 0, r.y); + s = new Vec3(s.x, 0, s.y); + } + + Vec3 qminusp = p2.subtract(p1); + double rcs = r.x * s.z - r.z * s.x; + Vec3 rdivrcs = r.scale(1 / rcs); + Vec3 sdivrcs = s.scale(1 / rcs); + double t = qminusp.x * sdivrcs.z - qminusp.z * sdivrcs.x; + double u = qminusp.x * rdivrcs.z - qminusp.z * rdivrcs.x; + return new double[]{t, u}; + } + + public static ItemStack copyStackWithSize(ItemStack stack, int size) { + if (size == 0) return ItemStack.EMPTY; + ItemStack copy = stack.copy(); + copy.setCount(size); + return copy; + } } diff --git a/common/src/main/java/dev/rdh/createunlimited/util/VersionUtils.java b/common/src/main/java/dev/rdh/createunlimited/util/VersionUtils.java deleted file mode 100644 index 3f986ad..0000000 --- a/common/src/main/java/dev/rdh/createunlimited/util/VersionUtils.java +++ /dev/null @@ -1,14 +0,0 @@ -package dev.rdh.createunlimited.util; - -public class VersionUtils { - - public static String getVersion() { - #if MC_1_19_2 - return "1.19.2"; - #elif MC_1_20_1 - return "1.20.1"; - #else - return "unknown" - #endif - } -} diff --git a/common/src/main/resources/createunlimited.accesswidener b/common/src/main/resources/createunlimited.accesswidener deleted file mode 100644 index 23604fd..0000000 --- a/common/src/main/resources/createunlimited.accesswidener +++ /dev/null @@ -1,2 +0,0 @@ -accessWidener v2 named -# Do not edit this file. It is automatically generated by the build script. Edit 1_20_1.createunlimited.aw instead! \ No newline at end of file diff --git a/fabric/src/main/java/dev/rdh/createunlimited/fabric/ModMenuIntegration.java b/fabric/src/main/java/dev/rdh/createunlimited/fabric/ModMenuIntegration.java new file mode 100644 index 0000000..c2936f6 --- /dev/null +++ b/fabric/src/main/java/dev/rdh/createunlimited/fabric/ModMenuIntegration.java @@ -0,0 +1,13 @@ +package dev.rdh.createunlimited.fabric; + +import com.terraformersmc.modmenu.api.ConfigScreenFactory; +import com.terraformersmc.modmenu.api.ModMenuApi; + +import dev.rdh.createunlimited.config.CUConfig; + +public class ModMenuIntegration implements ModMenuApi { + @Override + public ConfigScreenFactory getModConfigScreenFactory() { + return CUConfig::createConfigScreen; + } +} \ No newline at end of file diff --git a/fabric/src/main/java/dev/rdh/createunlimited/util/fabric/PlatformUtilsImpl.java b/fabric/src/main/java/dev/rdh/createunlimited/util/fabric/UtilImpl.java similarity index 98% rename from fabric/src/main/java/dev/rdh/createunlimited/util/fabric/PlatformUtilsImpl.java rename to fabric/src/main/java/dev/rdh/createunlimited/util/fabric/UtilImpl.java index 3fd0371..a1d9564 100644 --- a/fabric/src/main/java/dev/rdh/createunlimited/util/fabric/PlatformUtilsImpl.java +++ b/fabric/src/main/java/dev/rdh/createunlimited/util/fabric/UtilImpl.java @@ -25,7 +25,7 @@ import java.nio.file.Path; -public class PlatformUtilsImpl { +public class UtilImpl { public static String platformName() { return FabricLoader.getInstance().isModLoaded("quilt_loader") ? "Quilt" : "Fabric"; diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 7a18808..37abcc7 100755 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -15,6 +15,9 @@ "entrypoints": { "main": [ "dev.rdh.createunlimited.fabric.CreateUnlimitedFabric" + ], + "modmenu": [ + "dev.rdh.createunlimited.fabric.ModMenuIntegration" ] }, "mixins": [ diff --git a/forge/src/main/java/dev/rdh/createunlimited/forge/CreateUnlimitedForge.java b/forge/src/main/java/dev/rdh/createunlimited/forge/CreateUnlimitedForge.java index 3dd2e2c..f2cb5cc 100755 --- a/forge/src/main/java/dev/rdh/createunlimited/forge/CreateUnlimitedForge.java +++ b/forge/src/main/java/dev/rdh/createunlimited/forge/CreateUnlimitedForge.java @@ -9,12 +9,15 @@ @Mod(CreateUnlimited.ID) public class CreateUnlimitedForge { + public CreateUnlimitedForge() { IEventBus modEventBus = FMLJavaModLoadingContext.get() .getModEventBus(); IEventBus forgeEventBus = MinecraftForge.EVENT_BUS; forgeEventBus.register(Events.ClientModBusEvents.class); + forgeEventBus.addListener(Events::registerCommands); + modEventBus.addListener(Events.ClientModBusEvents::onLoadComplete); CreateUnlimited.init(); } } diff --git a/forge/src/main/java/dev/rdh/createunlimited/forge/Events.java b/forge/src/main/java/dev/rdh/createunlimited/forge/Events.java index e0287ac..34f0780 100644 --- a/forge/src/main/java/dev/rdh/createunlimited/forge/Events.java +++ b/forge/src/main/java/dev/rdh/createunlimited/forge/Events.java @@ -1,12 +1,40 @@ package dev.rdh.createunlimited.forge; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; + import dev.rdh.createunlimited.CreateUnlimited; +import dev.rdh.createunlimited.config.CUConfig; + +import dev.rdh.createunlimited.util.forge.UtilImpl; + +import net.minecraft.commands.CommandSourceStack; + import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.ConfigScreenHandler; +import net.minecraftforge.event.RegisterCommandsEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModContainer; +import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; public abstract class Events { @Mod.EventBusSubscriber(modid = CreateUnlimited.ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public static abstract class ClientModBusEvents { + @SubscribeEvent + static void onLoadComplete(FMLLoadCompleteEvent event) { + ModContainer container = ModList.get() + .getModContainerById(CreateUnlimited.ID) + .orElseThrow(() -> new IllegalStateException("Create Unlimited mod container missing on LoadComplete")); + container.registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, + () -> new ConfigScreenHandler.ConfigScreenFactory(CUConfig::createConfigScreen)); + } + } + + @SubscribeEvent + static void registerCommands(RegisterCommandsEvent event) { + for(LiteralArgumentBuilder command : UtilImpl.commands) + event.getDispatcher().register(command); } } \ No newline at end of file diff --git a/forge/src/main/java/dev/rdh/createunlimited/util/forge/PlatformUtilsImpl.java b/forge/src/main/java/dev/rdh/createunlimited/util/forge/UtilImpl.java similarity index 97% rename from forge/src/main/java/dev/rdh/createunlimited/util/forge/PlatformUtilsImpl.java rename to forge/src/main/java/dev/rdh/createunlimited/util/forge/UtilImpl.java index 280042b..e2d629c 100644 --- a/forge/src/main/java/dev/rdh/createunlimited/util/forge/PlatformUtilsImpl.java +++ b/forge/src/main/java/dev/rdh/createunlimited/util/forge/UtilImpl.java @@ -22,7 +22,7 @@ #if MC_1_19_2 @SuppressWarnings("UnstableApiUsage") #endif -public class PlatformUtilsImpl { +public class UtilImpl { public static List> commands = new ArrayList<>(); diff --git a/qodana.yaml b/qodana.yaml new file mode 100644 index 0000000..06e180d --- /dev/null +++ b/qodana.yaml @@ -0,0 +1,31 @@ +#-------------------------------------------------------------------------------# +# Qodana analysis is configured by qodana.yaml file # +# https://www.jetbrains.com/help/qodana/qodana-yaml.html # +#-------------------------------------------------------------------------------# +version: "1.0" + +#Specify inspection profile for code analysis +profile: + name: qodana.starter + +#Enable inspections +#include: +# - name: + +#Disable inspections +#exclude: +# - name: +# paths: +# - + +projectJDK: zulu-17 #(Applied in CI/CD pipeline) + +#Execute shell command before Qodana execution (Applied in CI/CD pipeline) +#bootstrap: sh ./prepare-qodana.sh + +#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline) +#plugins: +# - id: #(plugin id can be found at https://plugins.jetbrains.com) + +#Specify Qodana linter for analysis (Applied in CI/CD pipeline) +linter: jetbrains/qodana-jvm:latest