diff --git a/build.gradle b/build.gradle index 5956010..e6078a2 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,13 @@ dependencies { modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + // Hocon config + include implementation("org.spongepowered:configurate-core:${hocon_version}") + include implementation("org.spongepowered:configurate-hocon:${hocon_version}") + include implementation("org.apache.commons:commons-text:${commons_text_version}") + include implementation("com.typesafe:config:${typesafe_config_version}") + include implementation("io.leangen.geantyref:geantyref:${geantyref_version}") + } tasks.withType(JavaCompile).configureEach { diff --git a/gradle.properties b/gradle.properties index 7b91971..70b01e4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,15 @@ mod_name=Glowing Torchflower mod_id=glowing-torchflower -mod_version=1.1.0 +mod_version=1.2.0 minecraft_version=1.21.2 yarn_mappings=1.21.2+build.1 loader_version=0.16.7 +hocon_version=4.1.2 +commons_text_version=1.10.0 +typesafe_config_version=1.4.3 +geantyref_version=1.3.13 + org.gradle.jvmargs=-Xmx1G org.gradle.parallel=true \ No newline at end of file diff --git a/src/main/java/xyz/nikitacartes/glowingtorchflower/config/ConfigTemplate.java b/src/main/java/xyz/nikitacartes/glowingtorchflower/config/ConfigTemplate.java new file mode 100644 index 0000000..9aaa1db --- /dev/null +++ b/src/main/java/xyz/nikitacartes/glowingtorchflower/config/ConfigTemplate.java @@ -0,0 +1,97 @@ +package xyz.nikitacartes.glowingtorchflower.config; + +import net.fabricmc.loader.api.FabricLoader; +import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.hocon.HoconConfigurationLoader; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + + +public abstract class ConfigTemplate { + private transient final Pattern pattern = Pattern.compile("^[^$\"{}\\[\\]:=,+#`^?!@*&\\\\\\s/]+"); + transient final String configPath; + public static Path gameDirectory = FabricLoader.getInstance().getGameDir(); + private static String modName = "GlowingTorchflower"; + + ConfigTemplate(String configPath) { + this.configPath = configPath; + } + + public static Config loadConfig(Class configClass, String configPath) { + Path path = gameDirectory.resolve("config/" + modName).resolve(configPath); + if (Files.exists(path)) { + final HoconConfigurationLoader loader = HoconConfigurationLoader.builder().path(path).build(); + try { + return loader.load().get(configClass); + } catch (ConfigurateException e) { + throw new RuntimeException("[" + modName + "] Failed to load config file", e); + } + } else { + return null; + } + } + + public void save() { + Path configDirectory = gameDirectory.resolve("config/" + modName); + if (!Files.exists(configDirectory)) { + try { + Files.createDirectories(configDirectory); + } catch (IOException e) { + System.err.println("Failed to create config directory" + e); + } + } + Path path = gameDirectory.resolve("config/" + modName + "/" + configPath); + try { + Files.writeString(path, handleTemplate()); + } catch (IOException e) { + System.err.println("Failed to save config file" + e); + } + } + + private String escapeString(String string) { + return string + .replace("\\", "\\\\") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t") + .replace("\b", "\\b") + .replace("\f", "\\f") + .replace("\"", "\\\"") + .replace("'", "\\'"); + } + + protected String wrapIfNecessary(T string) { + String escapeString = escapeString(String.valueOf(string)); + if (!pattern.matcher(escapeString).matches()) { + return "\"" + escapeString + "\""; + } else { + return escapeString; + } + } + + protected String wrapIfNecessary(double string) { + return String.format(Locale.US, "%.4f", string); + } + + protected String wrapIfNecessary(long string) { + return String.valueOf(string); + } + + protected > String wrapIfNecessary(T strings) { + return "[" + strings + .stream() + .map(this::wrapIfNecessary) + .collect(Collectors.joining(",\n ")) + "]"; + } + + protected abstract String handleTemplate() throws IOException; + + + +} diff --git a/src/main/java/xyz/nikitacartes/glowingtorchflower/config/MainConfigV1.java b/src/main/java/xyz/nikitacartes/glowingtorchflower/config/MainConfigV1.java new file mode 100644 index 0000000..47a04f5 --- /dev/null +++ b/src/main/java/xyz/nikitacartes/glowingtorchflower/config/MainConfigV1.java @@ -0,0 +1,45 @@ +package xyz.nikitacartes.glowingtorchflower.config; + +import com.google.common.io.Resources; +import org.apache.commons.text.StringSubstitutor; +import org.spongepowered.configurate.objectmapping.ConfigSerializable; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.io.Resources.getResource; +import static java.nio.charset.StandardCharsets.UTF_8; + +@ConfigSerializable +public class MainConfigV1 extends ConfigTemplate { + public int torchflowerBrightness = 12; + public int torchflowerPotBrightness = 14; + public int torchflowerStage1Brightness = 3; + public int torchflowerStage2Brightness = 7; + public String configVersion = "1"; + + public MainConfigV1() { + super("main.conf"); + } + + public static MainConfigV1 load() { + MainConfigV1 config = loadConfig(MainConfigV1.class, "main.conf"); + if (config == null) { + config = new MainConfigV1(); + config.save(); + } + return config; + } + + protected String handleTemplate() throws IOException { + Map configValues = new HashMap<>(); + configValues.put("torchflowerBrightness", wrapIfNecessary(torchflowerBrightness)); + configValues.put("torchflowerPotBrightness", wrapIfNecessary(torchflowerPotBrightness)); + configValues.put("torchflowerStage1Brightness", wrapIfNecessary(torchflowerStage1Brightness)); + configValues.put("torchflowerStage2Brightness", wrapIfNecessary(torchflowerStage2Brightness)); + configValues.put("configVersion", wrapIfNecessary(configVersion)); + String configTemplate = Resources.toString(getResource("config/" + configPath), UTF_8); + return new StringSubstitutor(configValues).replace(configTemplate); + } +} diff --git a/src/main/java/xyz/nikitacartes/glowingtorchflower/mixin/BlocksMixin.java b/src/main/java/xyz/nikitacartes/glowingtorchflower/mixin/BlocksMixin.java index a5a7fb2..88e2bf4 100644 --- a/src/main/java/xyz/nikitacartes/glowingtorchflower/mixin/BlocksMixin.java +++ b/src/main/java/xyz/nikitacartes/glowingtorchflower/mixin/BlocksMixin.java @@ -5,19 +5,27 @@ import net.minecraft.block.Blocks; import net.minecraft.block.TorchflowerBlock; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Slice; +import xyz.nikitacartes.glowingtorchflower.config.MainConfigV1; @Mixin(Blocks.class) public class BlocksMixin { + @Unique + private static MainConfigV1 config; + @ModifyExpressionValue(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/AbstractBlock$Settings;create()Lnet/minecraft/block/AbstractBlock$Settings;", ordinal = 0), slice = @Slice(from = @At(value = "CONSTANT", args = "stringValue=torchflower"))) private static AbstractBlock.Settings modifyTorchflower(AbstractBlock.Settings properties) { - return properties.luminance(blockState -> 12); + if (config == null) { + config = MainConfigV1.load(); + } + return properties.luminance(blockState -> config.torchflowerBrightness); } @ModifyExpressionValue(method = "", @@ -25,7 +33,10 @@ private static AbstractBlock.Settings modifyTorchflower(AbstractBlock.Settings p target = "Lnet/minecraft/block/Blocks;createFlowerPotSettings()Lnet/minecraft/block/AbstractBlock$Settings;", ordinal = 1)) private static AbstractBlock.Settings modifyPottedTorchflower(AbstractBlock.Settings properties) { - return properties.luminance(blockState -> 14); + if (config == null) { + config = MainConfigV1.load(); + } + return properties.luminance(blockState -> config.torchflowerPotBrightness); } @ModifyExpressionValue(method = "", @@ -34,11 +45,14 @@ private static AbstractBlock.Settings modifyPottedTorchflower(AbstractBlock.Sett ordinal = 0), slice = @Slice(from = @At(value = "CONSTANT", args = "stringValue=torchflower_crop"))) private static AbstractBlock.Settings modifyTorchflowerCrop(AbstractBlock.Settings properties) { + if (config == null) { + config = MainConfigV1.load(); + } return properties.luminance(blockState -> switch (blockState.get(TorchflowerBlock.AGE)) { - case 0 -> 3; - case 1 -> 7; - default -> 12; + case 0 -> config.torchflowerStage1Brightness; + case 1 -> config.torchflowerStage2Brightness; + default -> config.torchflowerBrightness; }); } diff --git a/src/main/resources/config/main.conf b/src/main/resources/config/main.conf new file mode 100644 index 0000000..a2e6f18 --- /dev/null +++ b/src/main/resources/config/main.conf @@ -0,0 +1,25 @@ +## ## +## Glowing Torchflower ## +## Main Configuration ## +## ## + +# Brightness of the fully grown torchflower +# Default: 12 +torchflower-brightness: ${torchflowerBrightness} + +# Brightness of the torchflower in flowerpot +# Default: 14 +torchflower-pot-brightness: ${torchflowerPotBrightness} + +# Torchflower has three stages of growth (third stage is fully grown) +# Brightness of the first stage +# Default: 3 +torchflower-stage1-brightness: ${torchflowerStage1Brightness} + +# Brightness of the second stage +# Default: 7 +torchflower-stage2-brightness: ${torchflowerStage2Brightness} + +# Config Version. Used for automatic migration of config files. +# Do not change this value manually. +config-version: ${configVersion}