Compare commits

...

10 Commits

Author SHA1 Message Date
Martin Prokoph
2b70a553a1 release: v1.9.2 2025-12-11 01:12:23 +01:00
Martin Prokoph
8e6c76d804 port: MC 1.21.11(-rc2) 2025-12-07 20:11:35 +01:00
Martin Prokoph
6c732783c7 fix: crash when loading existing NeoForge configs
- Closes #120, #119
2025-11-23 21:10:22 +01:00
Martin Prokoph
1ea57b1a23 release: MidnightLib 1.9.0
here we go!
2025-11-23 13:47:17 +01:00
Martin Prokoph
312096d989 stonecutter: fix crash w/o ModMenu, optimize assets 2025-11-22 20:01:19 +01:00
Martin Prokoph
4831da5076 stonecutter: fix crash on fabric server startup 2025-11-22 19:10:22 +01:00
Martin Prokoph
4076ee2b6f stonecutter: improve backwards-compatibility
Builds targetting Minecraft versions below 1.21.6 will now once again contain the `getScreen` method with `Screen` as their return value instead of `MidnightConfigScreen`.
This ensures that mods compiled for older MidnightLib versions continue working as expected.

The return value has to be changed to `MidnightConfigScreen` in 1.21.6 and up due to NeoForge removing support for the `@OnlyIn` annotation – thus breaking server-only installations when referencing client-only classes like `Screen`.
2025-11-22 17:49:48 +01:00
Martin Prokoph
071f79b763 misc: new, more compressed icon
The fabric midnightlib jar size is now below 60 KB again!
2025-11-21 22:15:32 +01:00
Martin Prokoph
333af2cfe3 docs: document all developer-facing methods 2025-11-20 21:45:16 +01:00
Martin Prokoph
0cf6dde5ef stonecutter: cleaner versioned code 2025-11-20 20:09:52 +01:00
45 changed files with 664 additions and 185 deletions

View File

@@ -0,0 +1,15 @@
## MidnightLib v1.9.2
- Add support for using `StringRepresentable` to translate enums
## MidnightLib v1.9.1
- Fix crash when loading existing main config on NeoForge
# MidnightLib v1.9.0
- Setup a **multiversion** build environment
- MidnightLib will now always be up-to-date on all relevant versions of Minecraft
(Fabric/Forge 1.20.1; Fabric/NeoForge 1.21.1, 1.21.5, 1.21.8, 1.21.10)
- Measures were taken to ensure this doesn't break mods targeting old MidnightLib versions.
In case you still find a broken mod, please [report it](https://github.com/TeamMidnightDust/MidnightLib/issues/new/choose) and tag the issue with `1.9.0`.
- New logo! This offers improved visibility on light themes and a more modern, fresh look.
- Added JavaDocs to improve the developer experience.
- To be able to view them, adjust your midnightlib gradle dependency by following the [wiki](https://midnightdust.eu/wiki/midnightlib).
- Reduced jar size now under 60KB again for Fabric builds :)
- Migrate to Mojang mappings in preparation for upcoming non-obfuscated releases

View File

@@ -62,12 +62,15 @@ publishMods {
file = project.tasks.remapJar.get().archiveFile file = project.tasks.remapJar.get().archiveFile
dryRun = modrinthToken == null || curseforgeToken == null dryRun = modrinthToken == null || curseforgeToken == null
displayName = "${mod.name} ${loader.replaceFirstChar { it.uppercase() }} ${property("mod.mc_title")}-${mod.version}" displayName = "${mod.name} ${mod.version} - ${loader.replaceFirstChar { it.uppercase() }} ${property("mod.mc_title")}"
version = mod.version version = "${mod.version}+${property("mod.mc_title")}-${loader}"
changelog = rootProject.file("CHANGELOG.md").readText() changelog = rootProject.file("CHANGELOG.md").readText()
type = BETA type = STABLE
modLoaders.add(loader) modLoaders.add(loader)
if (loader == "fabric") {
modLoaders.add("quilt")
}
val targets = property("mod.mc_targets").toString().split(' ') val targets = property("mod.mc_targets").toString().split(' ')
modrinth { modrinth {
@@ -76,7 +79,6 @@ publishMods {
targets.forEach(minecraftVersions::add) targets.forEach(minecraftVersions::add)
if (loader == "fabric") { if (loader == "fabric") {
requires("fabric-api") requires("fabric-api")
optional("modmenu")
} }
} }
@@ -86,39 +88,25 @@ publishMods {
targets.forEach(minecraftVersions::add) targets.forEach(minecraftVersions::add)
if (loader == "fabric") { if (loader == "fabric") {
requires("fabric-api") requires("fabric-api")
optional("modmenu")
} }
} }
github { // github {
accessToken = githubToken // accessToken = githubToken
repository = "TeamMidnightDust/MidnightLib" // repository = "TeamMidnightDust/MidnightLib"
commitish = "multiversion" // This is the branch the release tag will be created from // commitish = "multiversion" // This is the branch the release tag will be created from
tagName = "v" + properties["mod.version"]
// Allow the release to be initially created without any files.
allowEmptyFiles = true
}
}
//publishing {
// publications {
// create<MavenPublication>("mavenJava") {
// pom {
// groupId = "eu.midnightdust"
// artifactId = "midnightlib"
// version = project.version
// //
// from(components["java"]) // tagName = "v" + properties["mod.version"]
// } //
// } // // Allow the release to be initially created without any files.
// allowEmptyFiles = true
// } // }
//} }
publishing { publishing {
repositories { repositories {
maven { maven {
name = "MidnightDust" name = "MidnightDust"
url = uri("https://maven.midnightdust.eu/snapshots") url = uri("https://maven.midnightdust.eu/releases")
credentials(PasswordCredentials::class) credentials(PasswordCredentials::class)
} }
} }
@@ -217,4 +205,12 @@ stonecutter {
constants { constants {
arrayOf("fabric", "neoforge", "forge").forEach { it -> put(it, loader == it) } arrayOf("fabric", "neoforge", "forge").forEach { it -> put(it, loader == it) }
} }
replacements.string {
direction = eval(current.version, ">=1.21.11-rc2")
replace("ResourceLocation", "Identifier")
}
replacements.string {
direction = eval(current.version, ">=1.21.11-rc2")
replace("net.minecraft.Util", "net.minecraft.util.Util")
}
} }

View File

@@ -7,7 +7,7 @@ org.gradle.parallel=false
#org.gradle.configureondemand=true #org.gradle.configureondemand=true
# Mod properties # Mod properties
mod.version=1.9.0-alpha.1 mod.version=1.9.2
mod.group=eu.midnightdust mod.group=eu.midnightdust
mod.id=midnightlib mod.id=midnightlib
mod.name=MidnightLib mod.name=MidnightLib
@@ -21,7 +21,7 @@ mod.mc_title=[VERSIONED]
mod.mc_targets=[VERSIONED] mod.mc_targets=[VERSIONED]
# Mod setup # Mod setup
deps.fabric_loader=0.17.3 deps.fabric_loader=0.18.1
deps.fabric_version=[VERSIONED] deps.fabric_version=[VERSIONED]
deps.forge_loader=[VERSIONED] deps.forge_loader=[VERSIONED]

View File

@@ -22,10 +22,10 @@ stonecutter {
for (version in versions) vers("$version-$loader", version) for (version in versions) vers("$version-$loader", version)
} }
//i would recommend to use neoforge for mc > 1.20.1, i haven't tested template for forge on versions higher than that //i would recommend to use neoforge for mc > 1.20.1, i haven't tested template for forge on versions higher than that
mc("fabric","1.20.1", "1.21.1", "1.21.5", "1.21.8", "1.21.10") mc("fabric","1.20.1", "1.21.1", "1.21.5", "1.21.8", "1.21.10", "1.21.11")
mc("forge","1.20.1") mc("forge","1.20.1")
//WARNING: neoforge uses mods.toml instead of neoforge.mods.toml for versions 1.20.4 (?) and earlier //WARNING: neoforge uses mods.toml instead of neoforge.mods.toml for versions 1.20.4 (?) and earlier
mc("neoforge", "1.21.1", "1.21.5", "1.21.8", "1.21.10") mc("neoforge", "1.21.1", "1.21.5", "1.21.8", "1.21.10", "1.21.11")
} }
create(rootProject) create(rootProject)
} }

View File

@@ -1,22 +1,19 @@
package eu.midnightdust.core; package eu.midnightdust.core;
import eu.midnightdust.core.config.MidnightLibConfig; import eu.midnightdust.core.config.MidnightLibConfig;
import eu.midnightdust.lib.config.AutoCommand;
import eu.midnightdust.lib.config.MidnightConfig; import eu.midnightdust.lib.config.MidnightConfig;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.swing.UIManager; import javax.swing.UIManager;
import net.minecraft.Util; import net.minecraft.util.Util;
import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
//? if fabric { //? if fabric {
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.DedicatedServerModInitializer;
import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi; import com.terraformersmc.modmenu.api.ModMenuApi;
@@ -24,9 +21,10 @@ import com.terraformersmc.modmenu.api.ModMenuApi;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class MidnightLib implements DedicatedServerModInitializer, ClientModInitializer, ModMenuApi { public class MidnightLib implements ClientModInitializer {
//?} else if neoforge { //?} else if neoforge {
/*import com.mojang.brigadier.builder.LiteralArgumentBuilder; /*import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import eu.midnightdust.lib.config.AutoCommand;
import eu.midnightdust.lib.util.PlatformFunctions; import eu.midnightdust.lib.util.PlatformFunctions;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
@@ -45,6 +43,7 @@ import java.util.ConcurrentModificationException;
public class MidnightLib { public class MidnightLib {
*///?} else if forge { *///?} else if forge {
/*import java.util.ConcurrentModificationException; /*import java.util.ConcurrentModificationException;
import eu.midnightdust.lib.config.AutoCommand;
import eu.midnightdust.lib.util.PlatformFunctions; import eu.midnightdust.lib.util.PlatformFunctions;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
@@ -54,7 +53,6 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.IExtensionPoint; import net.minecraftforge.fml.IExtensionPoint;
import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@@ -77,25 +75,11 @@ public class MidnightLib {
MidnightLibConfig.init(MOD_ID, MidnightLibConfig.class); MidnightLibConfig.init(MOD_ID, MidnightLibConfig.class);
} }
public static void registerAutoCommand() {
MidnightConfig.configInstances.forEach((modid, config) -> {
for (Field field : config.configClass.getFields()) {
if (field.isAnnotationPresent(MidnightConfig.Entry.class)
&& !field.isAnnotationPresent(MidnightConfig.Client.class)
&& !field.isAnnotationPresent(MidnightConfig.Hidden.class))
new AutoCommand(field, modid);
}
});
}
//? if fabric { //? if fabric {
public void onInitializeServer() { public static class ModMenuInit implements ModMenuApi {
registerAutoCommand();
}
@Override @Override
public ConfigScreenFactory<?> getModConfigScreenFactory() { public ConfigScreenFactory<?> getModConfigScreenFactory() {
return parent -> MidnightLibConfig.getScreen(parent,"midnightlib"); return parent -> MidnightLibConfig.getScreen(parent, MOD_ID);
} }
@Override @Override
@@ -107,12 +91,10 @@ public class MidnightLib {
}); });
return map; return map;
} }
}
//?} //?}
/*? if neoforge {*/ /*? if neoforge {*/
/*public static List<LiteralArgumentBuilder<CommandSourceStack>> commands = new ArrayList<>(); /*public static List<LiteralArgumentBuilder<CommandSourceStack>> commands = new ArrayList<>();
public MidnightLib() { public MidnightLib() {
@@ -120,9 +102,9 @@ public class MidnightLib {
} }
//? if >= 1.21.6 { //? if >= 1.21.6 {
@EventBusSubscriber(modid = "midnightlib", value = Dist.CLIENT) @EventBusSubscriber(modid = MOD_ID, value = Dist.CLIENT)
//?} else { //?} else {
/^@EventBusSubscriber(modid = "midnightlib", bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) /^@EventBusSubscriber(modid = MOD_ID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
^///?} ^///?}
public static class MidnightLibBusEvents { public static class MidnightLibBusEvents {
@SubscribeEvent @SubscribeEvent
@@ -132,11 +114,11 @@ public class MidnightLib {
modContainer.registerExtensionPoint(IConfigScreenFactory.class, (minecraftClient, screen) -> MidnightConfig.getScreen(screen, modid)); modContainer.registerExtensionPoint(IConfigScreenFactory.class, (minecraftClient, screen) -> MidnightConfig.getScreen(screen, modid));
} }
}); });
MidnightLib.registerAutoCommand(); new AutoCommand().onInitializeServer();
} }
} }
@EventBusSubscriber(modid = "midnightlib") @EventBusSubscriber(modid = MOD_ID)
public static class MidnightLibEvents { public static class MidnightLibEvents {
@SubscribeEvent @SubscribeEvent
public static void registerCommands(RegisterCommandsEvent event) { public static void registerCommands(RegisterCommandsEvent event) {
@@ -156,7 +138,7 @@ public class MidnightLib {
public static List<LiteralArgumentBuilder<CommandSourceStack>> commands = new ArrayList<>(); public static List<LiteralArgumentBuilder<CommandSourceStack>> commands = new ArrayList<>();
@Mod.EventBusSubscriber(modid = "midnightlib", bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) @Mod.EventBusSubscriber(modid = MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public static class MidnightLibBusEvents { public static class MidnightLibBusEvents {
@SubscribeEvent @SubscribeEvent
public static void onPostInit(FMLClientSetupEvent event) { public static void onPostInit(FMLClientSetupEvent event) {
@@ -165,11 +147,11 @@ public class MidnightLib {
modContainer.registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () -> new ConfigScreenHandler.ConfigScreenFactory((minecraftClient, screen) -> MidnightConfig.getScreen(screen, modid))); modContainer.registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () -> new ConfigScreenHandler.ConfigScreenFactory((minecraftClient, screen) -> MidnightConfig.getScreen(screen, modid)));
} }
}); });
MidnightLib.registerAutoCommand(); new AutoCommand().onInitializeServer();
} }
} }
@Mod.EventBusSubscriber(modid = "midnightlib") @Mod.EventBusSubscriber(modid = MOD_ID)
public static class MidnightLibEvents { public static class MidnightLibEvents {
@SubscribeEvent @SubscribeEvent
public static void registerCommands(RegisterCommandsEvent event) { public static void registerCommands(RegisterCommandsEvent event) {

View File

@@ -4,25 +4,15 @@ import eu.midnightdust.lib.config.MidnightConfig;
import eu.midnightdust.lib.util.PlatformFunctions; import eu.midnightdust.lib.util.PlatformFunctions;
public class MidnightLibConfig extends MidnightConfig { public class MidnightLibConfig extends MidnightConfig {
//? if fabric { public static final boolean HAS_MODMENU = PlatformFunctions.isModLoaded("modmenu") || "neoforge".equals(PlatformFunctions.getPlatformName());
@Entry public static ConfigButton config_screen_list = PlatformFunctions.isModLoaded("modmenu") ? ConfigButton.MODMENU : ConfigButton.TRUE;
@Entry public static ConfigButton config_screen_list = HAS_MODMENU ? ConfigButton.MODMENU : ConfigButton.TRUE;
public enum ConfigButton { public enum ConfigButton {
TRUE, FALSE, MODMENU TRUE, FALSE, MODMENU
} }
public static boolean shouldShowButton() { public static boolean shouldShowButton() {
return config_screen_list.equals(ConfigButton.TRUE) || (config_screen_list.equals(ConfigButton.MODMENU) && !PlatformFunctions.isModLoaded("modmenu")); return config_screen_list.equals(ConfigButton.TRUE) || (config_screen_list.equals(ConfigButton.MODMENU) && !HAS_MODMENU);
} }
//?} else {
/*@Entry public static ConfigButton config_screen_list = ConfigButton.FALSE;
public enum ConfigButton {
TRUE, FALSE
}
public static boolean shouldShowButton() {
return config_screen_list.equals(ConfigButton.TRUE);
}
*///?}
} }

View File

@@ -12,7 +12,7 @@ import java.util.Objects;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
//? if >= 1.21 { //? if >= 1.21 {
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
@@ -35,7 +35,7 @@ public abstract class MixinOptionsScreen extends Screen {
@Shadow @Final private HeaderAndFooterLayout layout; @Shadow @Final private HeaderAndFooterLayout layout;
@Unique SpriteIconButton midnightlib$button = SpriteIconButton.builder(Component.translatable("midnightlib.overview.title"), ( @Unique SpriteIconButton midnightlib$button = SpriteIconButton.builder(Component.translatable("midnightlib.overview.title"), (
buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(new MidnightConfigOverviewScreen(this)), true) buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(new MidnightConfigOverviewScreen(this)), true)
.sprite(ResourceLocation.fromNamespaceAndPath(MOD_ID,"icon/"+MOD_ID), 16, 16).size(20, 20).build(); .sprite(Identifier.fromNamespaceAndPath(MOD_ID,"icon/"+MOD_ID), 16, 16).size(20, 20).build();
@Inject(at = @At("HEAD"), method = "init") @Inject(at = @At("HEAD"), method = "init")
public void midnightlib$onInit(CallbackInfo ci) { public void midnightlib$onInit(CallbackInfo ci) {
@@ -55,7 +55,7 @@ public abstract class MixinOptionsScreen extends Screen {
midnightlib$button.setPosition(layout.getWidth() / 2 + 158, layout.getY() + layout.getFooterHeight() - 4); midnightlib$button.setPosition(layout.getWidth() / 2 + 158, layout.getY() + layout.getFooterHeight() - 4);
} }
//?} else { //?} else {
/*@Unique TextAndImageButton midnightlib$button = TextAndImageButton.builder(Component.translatable("midnightlib.overview.title"), new ResourceLocation("midnightlib", "icon/midnightlib.png"), /*@Unique TextAndImageButton midnightlib$button = TextAndImageButton.builder(Component.translatable("midnightlib.overview.title"), new Identifier("midnightlib", "icon/midnightlib.png"),
button -> Objects.requireNonNull(minecraft).setScreen(new MidnightConfigOverviewScreen(this))).textureSize(16, 16).usedTextureSize(16, 16).offset(0, 2).build(); button -> Objects.requireNonNull(minecraft).setScreen(new MidnightConfigOverviewScreen(this))).textureSize(16, 16).usedTextureSize(16, 16).offset(0, 2).build();
@Inject(at = @At("HEAD"), method = "init") @Inject(at = @At("HEAD"), method = "init")

View File

@@ -7,16 +7,25 @@ import eu.midnightdust.lib.util.PlatformFunctions;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands; import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
public class AutoCommand { //? fabric
import net.fabricmc.api.DedicatedServerModInitializer;
//? if >= 1.21.11
import net.minecraft.server.permissions.*;
public class AutoCommand /*? fabric {*/ implements DedicatedServerModInitializer /*?}*/ {
final static String VALUE = "value"; final static String VALUE = "value";
final Field field; Field field;
final Class<?> type; Class<?> type;
final String modid; String modid;
final boolean isList; boolean isList;
public AutoCommand() {}
public AutoCommand(Field field, String modid) { public AutoCommand(Field field, String modid) {
this.field = field; this.modid = modid; this.field = field; this.modid = modid;
@@ -35,7 +44,8 @@ public class AutoCommand {
.then(Commands.argument(VALUE, getArgType()).executes(ctx -> setValueFromArg(ctx, action)))); .then(Commands.argument(VALUE, getArgType()).executes(ctx -> setValueFromArg(ctx, action))));
} else command = command.then(Commands.argument(VALUE, getArgType()).executes(ctx -> setValueFromArg(ctx, ""))); } else command = command.then(Commands.argument(VALUE, getArgType()).executes(ctx -> setValueFromArg(ctx, "")));
PlatformFunctions.registerCommand(Commands.literal("midnightconfig").requires(source -> source.hasPermission(2)).then(Commands.literal(modid).then(command))); PlatformFunctions.registerCommand(Commands.literal("midnightconfig").requires(source ->
source/*? if >= 1.21.11 {*/.permissions().hasPermission(new Permission.HasCommandLevel(PermissionLevel.GAMEMASTERS))/*?} else {*/ /*.hasPermission(2) *//*?}*/).then(Commands.literal(modid).then(command)));
} }
public ArgumentType<?> getArgType() { public ArgumentType<?> getArgType() {
@@ -81,4 +91,15 @@ public class AutoCommand {
}, true); }, true);
return 0; return 0;
} }
public void onInitializeServer() {
MidnightConfig.configInstances.forEach((modid, config) -> {
for (Field field : config.configClass.getFields()) {
if (field.isAnnotationPresent(MidnightConfig.Entry.class)
&& !field.isAnnotationPresent(MidnightConfig.Client.class)
&& !field.isAnnotationPresent(MidnightConfig.Hidden.class))
new AutoCommand(field, modid);
}
});
}
} }

View File

@@ -15,9 +15,9 @@ import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.screens.ConfirmLinkScreen; import net.minecraft.client.gui.screens.ConfirmLinkScreen;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
//? if >= 1.21.9 { //? if >= 1.21.9 {
import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.client.input.MouseButtonEvent;
//?} //?}
public class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry> { public class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry> {
@@ -37,13 +37,7 @@ public class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry>
int scaledWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); int scaledWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth();
if (text != null && (!text.getString().contains("spacer") || !buttons.isEmpty())) { if (text != null && (!text.getString().contains("spacer") || !buttons.isEmpty())) {
title = new MultiLineTextWidget(12, 0, title = new MultiLineTextWidget(12, 0, text.copy(), textRenderer).setCentered(centered);
//? if >= 1.21 {
Component.translationArg(text)
//?} else {
/*text.copy()
*///?}
, textRenderer).setCentered(centered);
if (info != null) if (info != null)
title.setTooltip(info.getTooltip(false)); title.setTooltip(info.getTooltip(false));
title.setMaxWidth(!buttons.isEmpty() ? buttons.get(buttons.size() > 2 ? buttons.size() - 1 : 0).getX() - 16 : scaledWidth - 24); title.setMaxWidth(!buttons.isEmpty() ? buttons.get(buttons.size() > 2 ? buttons.size() - 1 : 0).getX() - 16 : scaledWidth - 24);
@@ -70,13 +64,8 @@ public class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry>
Optional.ofNullable(this.buttons.get(0)).ifPresent(widget -> { Optional.ofNullable(this.buttons.get(0)).ifPresent(widget -> {
int idMode = this.info.entry.idMode(); int idMode = this.info.entry.idMode();
if (idMode != -1) context.renderItem(idMode == 0 ? if (idMode != -1) context.renderItem(idMode == 0 ?
//? if >= 1.21.4 { BuiltInRegistries.ITEM./*? if >= 1.21.4 {*/ getValue /*?} else {*/ /*get *//*?}*/(Identifier.tryParse(this.info.tempValue)).getDefaultInstance()
BuiltInRegistries.ITEM.getValue(ResourceLocation.tryParse(this.info.tempValue)).getDefaultInstance() : BuiltInRegistries.BLOCK./*? if >= 1.21.4 {*/ getValue /*?} else {*/ /*get *//*?}*/(Identifier.tryParse(this.info.tempValue)).asItem().getDefaultInstance(),
: BuiltInRegistries.BLOCK.getValue(ResourceLocation.tryParse(this.info.tempValue)).asItem().getDefaultInstance(),
//?} else {
/*BuiltInRegistries.ITEM.get(ResourceLocation.tryParse(this.info.tempValue)).getDefaultInstance()
: BuiltInRegistries.BLOCK.get(ResourceLocation.tryParse(this.info.tempValue)).asItem().getDefaultInstance(),
*///?}
widget.getX() + widget.getWidth() - 18, y + 2); widget.getX() + widget.getWidth() - 18, y + 2);
}); });
} }

View File

@@ -10,7 +10,7 @@ import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.resources.language.I18n; import net.minecraft.client.resources.language.I18n;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style; import net.minecraft.network.chat.Style;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
import net.minecraft.util.*; import net.minecraft.util.*;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -29,12 +29,17 @@ import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** MidnightConfig by Martin "Motschen" Prokoph //? if < 1.21.6 {
* Minimalist config library - feel free to copy! /*//? fabric
* Originally based on <a href="https://github.com/Minenash/TinyConfig">...</a> import net.fabricmc.api.*;
* Credits to Minenash */ //? neoforge
/^import net.neoforged.api.distmarker.*;^/
//? forge
/^import net.minecraftforge.api.distmarker.*;^/
*///?}
@SuppressWarnings("unchecked") /** MidnightConfig is an incredibly lightweight, but still fully-featured config library for Minecraft mods.<br>
* Originally based on <a href="https://github.com/Minenash/TinyConfig">TinyConfig</a> by Minenash.*/
public abstract class MidnightConfig { public abstract class MidnightConfig {
private static final Pattern INTEGER_ONLY = Pattern.compile("(-?[0-9]*)"); private static final Pattern INTEGER_ONLY = Pattern.compile("(-?[0-9]*)");
private static final Pattern DECIMAL_ONLY = Pattern.compile("-?(\\d+\\.?\\d*|\\d*\\.?\\d+|\\.)"); private static final Pattern DECIMAL_ONLY = Pattern.compile("-?(\\d+\\.?\\d*|\\d*\\.?\\d+|\\.)");
@@ -45,14 +50,14 @@ public abstract class MidnightConfig {
public boolean shouldSkipClass(Class<?> clazz) { return false; } public boolean shouldSkipClass(Class<?> clazz) { return false; }
public boolean shouldSkipField(FieldAttributes fieldAttributes) { return fieldAttributes.getAnnotation(Entry.class) == null; } public boolean shouldSkipField(FieldAttributes fieldAttributes) { return fieldAttributes.getAnnotation(Entry.class) == null; }
}) })
.registerTypeAdapter(ResourceLocation.class, .registerTypeAdapter(Identifier.class,
//? if >= 1.21.4 { //? if >= 1.21.4 {
new TypeAdapter<ResourceLocation>() { new TypeAdapter<Identifier>() {
public void write(JsonWriter out, ResourceLocation id) throws IOException { out.value(id.toString()); } public void write(JsonWriter out, Identifier id) throws IOException { out.value(id.toString()); }
public ResourceLocation read(JsonReader in) throws IOException { return ResourceLocation.parse(in.nextString()); } public Identifier read(JsonReader in) throws IOException { return Identifier.parse(in.nextString()); }
} }
//?} else { //?} else {
/*new ResourceLocation.Serializer() /*new Identifier.Serializer()
*///?} *///?}
).setPrettyPrinting().create(); ).setPrettyPrinting().create();
@@ -64,8 +69,13 @@ public abstract class MidnightConfig {
protected boolean reloadScreen = false; protected boolean reloadScreen = false;
public Class<? extends MidnightConfig> configClass; public Class<? extends MidnightConfig> configClass;
public static <T extends MidnightConfig> T createInstance(String modid, Class<? extends MidnightConfig> configClass) { // This is basically an argumented constructor without the requirement of having one in each config class /**
* This is basically an argumented constructor without the requirement of having one in each config class.<br>
* Not meant to be used externally.
* */
protected static <T extends MidnightConfig> T createInstance(String modid, Class<? extends MidnightConfig> configClass) {
try { try {
//noinspection unchecked
T instance = (T) configClass.getDeclaredConstructor().newInstance(); T instance = (T) configClass.getDeclaredConstructor().newInstance();
instance.modid = modid; instance.modid = modid;
instance.configClass = configClass; instance.configClass = configClass;
@@ -75,11 +85,15 @@ public abstract class MidnightConfig {
catch (Exception e) { throw new RuntimeException(e); } catch (Exception e) { throw new RuntimeException(e); }
} }
/**
* Initializes the config by registering all fields annotated with {@link Entry} or {@link Comment}<br>
* @param modid Your mod's id
* @param config The class containing your mod's config
* */
public static void init(String modid, Class<? extends MidnightConfig> config) { public static void init(String modid, Class<? extends MidnightConfig> config) {
MidnightConfig instance = createInstance(modid, config); MidnightConfig instance = createInstance(modid, config);
for (Field field : config.getFields()) { for (Field field : config.getFields()) {
//noinspection ConstantValue
if ((field.isAnnotationPresent(Entry.class) || field.isAnnotationPresent(Comment.class)) if ((field.isAnnotationPresent(Entry.class) || field.isAnnotationPresent(Comment.class))
&& !field.isAnnotationPresent(Server.class) && !field.isAnnotationPresent(Server.class)
&& !field.isAnnotationPresent(Hidden.class) && !field.isAnnotationPresent(Hidden.class)
@@ -89,13 +103,18 @@ public abstract class MidnightConfig {
instance.loadValuesFromJson(); instance.loadValuesFromJson();
} }
public void addClientEntry(Field field, EntryInfo info) { /**
* Loads the config entry and saves relevant information into the {@link EntryInfo} object.
* @param field The config entry's Java field
* @param info The {@link EntryInfo} object to associate with this field
* */
protected void addClientEntry(Field field, EntryInfo info) {
Entry e = info.entry; Entry e = info.entry;
if (e != null && info.dataType != null) { if (e != null && info.dataType != null) {
if (info.dataType == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, (int) e.min(), (int) e.max(), true); if (info.dataType == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, (int) e.min(), (int) e.max(), true);
else if (info.dataType == float.class) textField(info, Float::parseFloat, DECIMAL_ONLY, (float) e.min(), (float) e.max(), false); else if (info.dataType == float.class) textField(info, Float::parseFloat, DECIMAL_ONLY, (float) e.min(), (float) e.max(), false);
else if (info.dataType == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(), false); else if (info.dataType == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(), false);
else if (info.dataType == String.class || info.dataType == ResourceLocation.class) textField(info, String::length, null, Math.min(e.min(), 0), Math.max(e.max(), 1), true); else if (info.dataType == String.class || info.dataType == Identifier.class) textField(info, String::length, null, Math.min(e.min(), 0), Math.max(e.max(), 1), true);
else if (info.dataType == boolean.class) { else if (info.dataType == boolean.class) {
Function<Object, Component> func = value -> Component.translatable((Boolean) value ? "gui.yes" : "gui.no").withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED); Function<Object, Component> func = value -> Component.translatable((Boolean) value ? "gui.yes" : "gui.no").withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
info.function = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> { info.function = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
@@ -117,6 +136,12 @@ public abstract class MidnightConfig {
entries.put(modid + ":" + field.getName(), info); entries.put(modid + ":" + field.getName(), info);
} }
/**
* Identifies a field's underlying data type.<br>
* For non-primitive data types, the class of the primitive equivalent is returned.<br>
* For lists, this is the data type of list entries.
* @param field The field to investigate
* */
public static Class<?> getUnderlyingType(Field field) { public static Class<?> getUnderlyingType(Field field) {
Class<?> rawType = field.getType(); Class<?> rawType = field.getType();
if (field.getType() == List.class) if (field.getType() == List.class)
@@ -125,18 +150,15 @@ public abstract class MidnightConfig {
} catch (NoSuchFieldException | IllegalAccessException ignored) { return rawType; } } catch (NoSuchFieldException | IllegalAccessException ignored) { return rawType; }
} }
private static void textField(EntryInfo info, Function<String,Number> f, Pattern pattern, double min, double max, boolean cast) { /**
* Defines a function to validate number, text, identifier or color inputs and saves it into the {@link EntryInfo} object.
* */
protected static void textField(EntryInfo info, Function<String,Number> f, Pattern pattern, double min, double max, boolean cast) {
boolean isNumber = pattern != null; boolean isNumber = pattern != null;
info.function = (BiFunction<EditBox, Button, Predicate<String>>) (t, b) -> s -> { info.function = (BiFunction<EditBox, Button, Predicate<String>>) (t, b) -> s -> {
s = s.trim(); s = s.trim();
if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches()) || if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches()) ||
(info.dataType == ResourceLocation.class && ResourceLocation.read(s) (info.dataType == Identifier.class && Identifier.read(s)./*? if >= 1.21 {*/isError() /*?} else {*/ /*error().isPresent() *//*?}*/)) return false;
//? if >= 1.21 {
.isError()
//?} else {
/*.error().isPresent()
*///?}
)) return false;
Number value = 0; boolean inLimits = false; info.error = null; Number value = 0; boolean inLimits = false; info.error = null;
if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) { if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) {
@@ -154,8 +176,8 @@ public abstract class MidnightConfig {
b.active = entries.values().stream().allMatch(e -> e.inLimits); b.active = entries.values().stream().allMatch(e -> e.inLimits);
if (inLimits) { if (inLimits) {
if (info.dataType == ResourceLocation.class) if (info.dataType == Identifier.class)
info.setValue(ResourceLocation.tryParse(s)); info.setValue(Identifier.tryParse(s));
else info.setValue(isNumber ? value : s); else info.setValue(isNumber ? value : s);
} }
@@ -169,13 +191,24 @@ public abstract class MidnightConfig {
}; };
} }
/**
* Gets the translated title of an enum option
* @param value the enum option to translate
* @param info the associated {@link EntryInfo} object
* */
protected Component getEnumTranslatableText(Object value, EntryInfo info) { protected Component getEnumTranslatableText(Object value, EntryInfo info) {
if (value instanceof OptionEnum translatableOption) return translatableOption.getCaption(); if (value instanceof StringRepresentable option) return Component.translatable(option.getSerializedName());
//? if < 1.21.11
/*if (value instanceof OptionEnum option) return option.getCaption();*/
assert info.dataType != null;
String translationKey = "%s.midnightconfig.enum.%s.%s".formatted(modid, info.dataType.getSimpleName(), info.toTemporaryValue()); String translationKey = "%s.midnightconfig.enum.%s.%s".formatted(modid, info.dataType.getSimpleName(), info.toTemporaryValue());
return I18n.exists(translationKey) ? Component.translatable(translationKey) : Component.literal(info.toTemporaryValue()); return I18n.exists(translationKey) ? Component.translatable(translationKey) : Component.literal(info.toTemporaryValue());
} }
/**
* (Re-)Loads the config by reading json file defined at {@link #getJsonFilePath()}
* */
public void loadValuesFromJson() { public void loadValuesFromJson() {
try { try {
gson.fromJson(Files.newBufferedReader(getJsonFilePath()), configClass); gson.fromJson(Files.newBufferedReader(getJsonFilePath()), configClass);
@@ -194,15 +227,28 @@ public abstract class MidnightConfig {
}); });
} }
/**
* Writes the mod's current config state to disk.
* @param modid Specifies which mod's config to save.
* */
public static void write(String modid) { public static void write(String modid) {
configInstances.get(modid).writeChanges(modid); configInstances.get(modid).writeChanges(modid);
} }
/**
* DO NOT USE OR OVERRIDE!<br>
* This is only present to keep compatibility with mods that were overriding the previous method.
* */
@Deprecated @Deprecated
public void writeChanges(String modid) { public void writeChanges(String modid) {
this.writeChanges(); this.writeChanges();
} }
/**
* Writes the mod's current config state to disk.<br>
* This method can be overridden to define custom onSave behaviour.<br>
* Make sure to call {@code super.writeChanges()}!
* */
public void writeChanges() { public void writeChanges() {
try { try {
Path path; Path path;
@@ -212,30 +258,61 @@ public abstract class MidnightConfig {
} catch (Exception e) { e.fillInStackTrace(); } } catch (Exception e) { e.fillInStackTrace(); }
} }
/**
* Gets the path to store the config json file at.<br>
* Override to set a custom file path.
* */
public Path getJsonFilePath() { public Path getJsonFilePath() {
return PlatformFunctions.getConfigDirectory().resolve(modid + ".json"); return PlatformFunctions.getConfigDirectory().resolve(modid + ".json");
} }
@SuppressWarnings("unused") // Utility for mod authors /**
* Gets a config field's default value.
* @param modid The entry's mod id
* @param entry The entry's field name
* */
@SuppressWarnings("unused")
public static @Nullable Object getDefaultValue(String modid, String entry) { public static @Nullable Object getDefaultValue(String modid, String entry) {
String key = modid + ":" + entry; String key = modid + ":" + entry;
return entries.containsKey(key) ? entries.get(key).defaultValue : null; return entries.containsKey(key) ? entries.get(key).defaultValue : null;
} }
// Overridable method /**
* Add custom widgets to the config screen by overriding this method.
* @param tabName Name of the currently selected tab
* @param list The scrollable list containing regular config entries
* @param screen The entire config screen
* */
public void onTabInit(String tabName, MidnightConfigListWidget list, MidnightConfigScreen screen) { public void onTabInit(String tabName, MidnightConfigListWidget list, MidnightConfigScreen screen) {
} }
/**
* Creates an instance of the config screen.
* @param parent The parent screen, which will be returned to when exiting the config
* @param modid The mod of which to load the config screen
* */
//? if < 1.21.6 {
/*/^? fabric {^/ @Environment(EnvType.CLIENT) /^?} else {^/ /^@OnlyIn(Dist.CLIENT) ^//^?}^/
public static Screen getScreen(Screen parent, String modid) {
*///?} else {
public static MidnightConfigScreen getScreen(Screen parent, String modid) { public static MidnightConfigScreen getScreen(Screen parent, String modid) {
//?}
return configInstances.get(modid).getScreen(parent); return configInstances.get(modid).getScreen(parent);
} }
/**
* Creates an instance of the config screen.
* This can be overridden to return a fully custom config screen.
* @param parent The parent screen, which will be returned to when exiting the config
* */
public MidnightConfigScreen getScreen(Screen parent) { public MidnightConfigScreen getScreen(Screen parent) {
return new MidnightConfigScreen(parent, modid); return new MidnightConfigScreen(parent, modid);
} }
/** /**
* Entry Annotation<br> * Entry Annotation<br>
* - <b>width</b>: The maximum character length of the {@link String}, {@link ResourceLocation} or String/Identifier {@link List<>} field<br> * - <b>width</b>: The maximum character length of the {@link String}, {@link Identifier} or String/Identifier {@link List<>} field<br>
* - <b>min</b>: The minimum value of the <code>int</code>, <code>float</code> or <code>double</code> field<br> * - <b>min</b>: The minimum value of the <code>int</code>, <code>float</code> or <code>double</code> field<br>
* - <b>max</b>: The maximum value of the <code>int</code>, <code>float</code> or <code>double</code> field<br> * - <b>max</b>: The maximum value of the <code>int</code>, <code>float</code> or <code>double</code> field<br>
* - <b>name</b>: Will be used instead of the default translation key, if not empty<br> * - <b>name</b>: Will be used instead of the default translation key, if not empty<br>

View File

@@ -18,19 +18,11 @@ public class MidnightConfigListWidget extends ContainerObjectSelectionList<Butto
public boolean renderHeaderSeparator = true; public boolean renderHeaderSeparator = true;
public MidnightConfigListWidget(Minecraft client, int width, int height, int y, int itemHeight) { public MidnightConfigListWidget(Minecraft client, int width, int height, int y, int itemHeight) {
//? if >= 1.21 { super(client, width, height, y, /*? if < 1.21 {*/ /*height + y, *//*?}*/ itemHeight);
super(client, width, height, y, itemHeight);
//?} else {
/*super(client, width, height, y, height + y, itemHeight);
*///?}
} }
@Override @Override
//? if >= 1.21.4 { public int /*? if >= 1.21.4 {*/ scrollBarX() /*?} else {*/ /*getScrollbarPosition() *//*?}*/ {
public int scrollBarX() {
//?} else {
/*public int getScrollbarPosition() {
*///?}
return this.width - 7; return this.width - 7;
} }

View File

@@ -2,7 +2,7 @@ package eu.midnightdust.lib.config;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.Util; import net.minecraft.util.Util;
import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.*; import net.minecraft.client.gui.components.*;
import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.Button;
@@ -16,7 +16,7 @@ import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style; import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.contents.TranslatableContents; import net.minecraft.network.chat.contents.TranslatableContents;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
import javax.swing.*; import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*; import java.awt.*;
@@ -30,7 +30,7 @@ import net.minecraft.client.input.KeyEvent;
//?} //?}
//? if >=1.21 { //? if >=1.21 {
import net.minecraft.client.gui.components.SpriteIconButton; import net.minecraft.client.gui.components.SpriteIconButton;
//?} //?}
public class MidnightConfigScreen extends Screen { public class MidnightConfigScreen extends Screen {
@@ -79,7 +79,7 @@ public class MidnightConfigScreen extends Screen {
updateList(); updateList();
list.setScrollAmount(0); list.setScrollAmount(0);
} }
scrollProgress = /*? < 1.21.4 {*/ /*list.getScrollAmount() *//*?} else {*/ list.scrollAmount() /*?}*/; scrollProgress = /*? if < 1.21.4 {*/ /*list.getScrollAmount() *//*?} else {*/ list.scrollAmount() /*?}*/;
for (EntryInfo info : MidnightConfig.entries.values()) for (EntryInfo info : MidnightConfig.entries.values())
if (Objects.equals(modid, info.modid)) info.updateFieldValue(); if (Objects.equals(modid, info.modid)) info.updateFieldValue();
updateButtons(); updateButtons();
@@ -170,7 +170,7 @@ public class MidnightConfigScreen extends Screen {
//? if >= 1.21 { //? if >= 1.21 {
SpriteIconButton resetButton = SpriteIconButton.builder(Component.translatable("controls.reset"), SpriteIconButton resetButton = SpriteIconButton.builder(Component.translatable("controls.reset"),
//?} else { //?} else {
/*TextAndImageButton resetButton = TextAndImageButton.builder(Component.translatable("controls.reset"), new ResourceLocation("midnightlib", "icon/reset.png"), /*TextAndImageButton resetButton = TextAndImageButton.builder(Component.translatable("controls.reset"), new Identifier("midnightlib", "icon/reset.png"),
*///?} *///?}
(button -> { (button -> {
info.value = info.defaultValue; info.value = info.defaultValue;
@@ -179,7 +179,7 @@ public class MidnightConfigScreen extends Screen {
updateList(); updateList();
}) })
//? if >= 1.21 { //? if >= 1.21 {
, true).sprite(ResourceLocation.fromNamespaceAndPath("midnightlib", "icon/reset"), 12, 12).size(20, 20).build(); , true).sprite(Identifier.fromNamespaceAndPath("midnightlib", "icon/reset"), 12, 12).size(20, 20).build();
//?} else { //?} else {
/*).textureSize(12, 12).usedTextureSize(12, 12).offset(0, 4).build(); /*).textureSize(12, 12).usedTextureSize(12, 12).offset(0, 4).build();
resetButton.setWidth(20); resetButton.setWidth(20);
@@ -239,7 +239,7 @@ public class MidnightConfigScreen extends Screen {
//? if >= 1.21 { //? if >= 1.21 {
SpriteIconButton.builder(Component.empty(), SpriteIconButton.builder(Component.empty(),
//?} else { //?} else {
/*TextAndImageButton.builder(Component.empty(), new ResourceLocation("midnightlib", "icon/explorer.png"), /*TextAndImageButton.builder(Component.empty(), new Identifier("midnightlib", "icon/explorer.png"),
*///?} *///?}
button -> new Thread(() -> { button -> new Thread(() -> {
JFileChooser fileChooser = new JFileChooser(info.tempValue); JFileChooser fileChooser = new JFileChooser(info.tempValue);
@@ -255,7 +255,7 @@ public class MidnightConfigScreen extends Screen {
} }
}).start() }).start()
//? if >= 1.21 { //? if >= 1.21 {
, true).sprite(ResourceLocation.fromNamespaceAndPath("midnightlib", "icon/explorer"), 12, 12).size(20, 20) , true).sprite(Identifier.fromNamespaceAndPath("midnightlib", "icon/explorer"), 12, 12).size(20, 20)
//?} else { //?} else {
/*).textureSize(12, 12).usedTextureSize(12, 12).offset(0, 4) /*).textureSize(12, 12).usedTextureSize(12, 12).offset(0, 4)
*///?} *///?}

View File

@@ -1 +0,0 @@
{}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 734 B

View File

@@ -16,7 +16,7 @@ import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.KeyEvent;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
@@ -33,7 +33,7 @@ public class MidnightLibExtras {
SpriteIconButton resetButton = SpriteIconButton.builder(Component.translatable("controls.reset"), (button -> { SpriteIconButton resetButton = SpriteIconButton.builder(Component.translatable("controls.reset"), (button -> {
binding.setKey(binding.getDefaultKey()); binding.setKey(binding.getDefaultKey());
screen.updateList(); screen.updateList();
}), true).sprite(ResourceLocation.fromNamespaceAndPath("midnightlib","icon/reset"), 12, 12).size(20, 20).build(); }), true).sprite(Identifier.fromNamespaceAndPath("midnightlib","icon/reset"), 12, 12).size(20, 20).build();
resetButton.setPosition(screen.width - 205 + 150 + 25, 0); resetButton.setPosition(screen.width - 205 + 150 + 25, 0);
editButton.resetButton = resetButton; editButton.resetButton = resetButton;
editButton.updateMessage(false); editButton.updateMessage(false);

View File

@@ -10,7 +10,7 @@ import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
import net.minecraft.util.OptionEnum; import net.minecraft.util.OptionEnum;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -38,7 +38,7 @@ public class MidnightConfigExample extends MidnightConfig {
@Entry(category = TEXT, name="I am a (non-primitive) Boolean") public static Boolean nonPrimitive = true; // Example for a non-primative boolean option @Entry(category = TEXT, name="I am a (non-primitive) Boolean") public static Boolean nonPrimitive = true; // Example for a non-primative boolean option
@Entry(category = TEXT) public static String name = "Hello World!"; // Example for a string option, which is in a category! @Entry(category = TEXT) public static String name = "Hello World!"; // Example for a string option, which is in a category!
@Entry(category = TEXT, width = 7, min = 7, isColor = true, name = "I am a color!") public static String titleColor = "#ffffff"; // The isColor property adds a color chooser for a hexadecimal color @Entry(category = TEXT, width = 7, min = 7, isColor = true, name = "I am a color!") public static String titleColor = "#ffffff"; // The isColor property adds a color chooser for a hexadecimal color
@Entry(category = TEXT, idMode = 0) public static ResourceLocation id = ResourceLocation.withDefaultNamespace("diamond"); // Example for an identifier with matching items displayed next to it! @Entry(category = TEXT, idMode = 0) public static Identifier id = Identifier.withDefaultNamespace("diamond"); // Example for an identifier with matching items displayed next to it!
@Entry(category = TEXT) public static ModPlatform modPlatform = ModPlatform.FABRIC; // Example for an enum option @Entry(category = TEXT) public static ModPlatform modPlatform = ModPlatform.FABRIC; // Example for an enum option
public enum ModPlatform { // Enums allow the user to cycle through predefined options public enum ModPlatform { // Enums allow the user to cycle through predefined options
QUILT, FABRIC, FORGE, NEOFORGE, VANILLA QUILT, FABRIC, FORGE, NEOFORGE, VANILLA
@@ -56,7 +56,7 @@ public class MidnightConfigExample extends MidnightConfig {
// The name field can be used to specify a custom translation string or plain text // The name field can be used to specify a custom translation string or plain text
@Entry(category = LISTS, name = "I am a string list!") public static List<String> stringList = Lists.newArrayList("String1", "String2"); // Array String Lists are also supported @Entry(category = LISTS, name = "I am a string list!") public static List<String> stringList = Lists.newArrayList("String1", "String2"); // Array String Lists are also supported
@Entry(category = LISTS, isColor = true, name = "I am a color list!") public static List<String> colorList = Lists.newArrayList("#ac5f99", "#11aa44"); // Lists also support colors @Entry(category = LISTS, isColor = true, name = "I am a color list!") public static List<String> colorList = Lists.newArrayList("#ac5f99", "#11aa44"); // Lists also support colors
@Entry(category = LISTS, name = "I am an identifier list!", idMode = 1) public static List<ResourceLocation> idList = Lists.newArrayList(ResourceLocation.withDefaultNamespace("dirt")); // A list of block identifiers @Entry(category = LISTS, name = "I am an identifier list!", idMode = 1) public static List<Identifier> idList = Lists.newArrayList(Identifier.withDefaultNamespace("dirt")); // A list of block identifiers
@Entry(category = LISTS, name = "I am an integer list!") public static List<Integer> intList = Lists.newArrayList(69, 420); @Entry(category = LISTS, name = "I am an integer list!") public static List<Integer> intList = Lists.newArrayList(69, 420);
@Entry(category = LISTS, name = "I am a float list!") public static List<Float> floatList = Lists.newArrayList(4.1f, -1.3f, -1f); @Entry(category = LISTS, name = "I am a float list!") public static List<Float> floatList = Lists.newArrayList(4.1f, -1.3f, -1f);

View File

@@ -5,7 +5,7 @@ plugins {
id("com.github.johnrengelman.shadow") version "8.1.1" apply false id("com.github.johnrengelman.shadow") version "8.1.1" apply false
id("me.modmuss50.mod-publish-plugin") version "0.8.4" apply false id("me.modmuss50.mod-publish-plugin") version "0.8.4" apply false
} }
stonecutter active "1.21.10-fabric" /* [SC] DO NOT EDIT */ stonecutter active "1.21.11-fabric" /* [SC] DO NOT EDIT */
// See https://stonecutter.kikugie.dev/wiki/config/params // See https://stonecutter.kikugie.dev/wiki/config/params
stonecutter parameters { stonecutter parameters {

View File

@@ -1,7 +1,7 @@
mod.mc_dep_fabric==1.20.1 mod.mc_dep_fabric=>=1.20 <=1.20.1
mod.mc_dep_forgelike=[1.20, 1.20.1] mod.mc_dep_forgelike=[1.20, 1.20.1]
mod.mc_title=1.20.1 mod.mc_title=1.20.1
mod.mc_targets=1.20.1 mod.mc_targets=1.20 1.20.1
deps.forge_loader=47.3.0 deps.forge_loader=47.3.0
deps.neoforge_loader=[UNSUPPORTED] deps.neoforge_loader=[UNSUPPORTED]

View File

@@ -23,18 +23,18 @@
"environment": "*", "environment": "*",
"entrypoints": { "entrypoints": {
"server": [ "server": [
"eu.midnightdust.core.MidnightLib" "eu.midnightdust.lib.config.AutoCommand"
], ],
"client": [ "client": [
"eu.midnightdust.core.MidnightLib" "eu.midnightdust.core.MidnightLib"
], ],
"modmenu": [ "modmenu": [
"eu.midnightdust.core.MidnightLib" "eu.midnightdust.core.MidnightLib\$ModMenuInit"
] ]
}, },
"depends": { "depends": {
"fabric-resource-loader-v0": "*", "fabric-resource-loader-v0": "*",
"minecraft": "*" "minecraft": "${minecraft}"
}, },
"mixins": [ "mixins": [

View File

@@ -1,7 +1,7 @@
mod.mc_dep_fabric==1.20.1 mod.mc_dep_fabric=>=1.20 <=1.20.1
mod.mc_dep_forgelike=[1.20, 1.20.1] mod.mc_dep_forgelike=[1.20, 1.20.1]
mod.mc_title=1.20.1 mod.mc_title=1.20.1
mod.mc_targets=1.20.1 mod.mc_targets=1.20 1.20.1
deps.forge_loader=47.3.0 deps.forge_loader=47.3.0
deps.neoforge_loader=[UNSUPPORTED] deps.neoforge_loader=[UNSUPPORTED]

View File

@@ -26,6 +26,6 @@ side = "BOTH"
[[dependencies.midnightlib]] [[dependencies.midnightlib]]
modId = "minecraft" modId = "minecraft"
mandatory = true mandatory = true
versionRange = "[1.20,)" versionRange = "${minecraft}"
ordering = "NONE" ordering = "NONE"
side = "BOTH" side = "BOTH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

View File

@@ -0,0 +1,54 @@
{
"schemaVersion": 1,
"id": "${id}",
"version": "${version}",
"name": "${name}",
"description": "Lightweight config library with config screens and commands.",
"authors": [
"Motschen"
],
"contributors": [
"maloryware",
"Jaffe2718"
],
"contact": {
"homepage": "https://www.midnightdust.eu/",
"sources": "https://github.com/TeamMidnightDust/MidnightLib",
"issues": "https://github.com/TeamMidnightDust/MidnightLib/issues"
},
"license": "MIT",
"icon": "assets/midnightlib/icon.png",
"environment": "*",
"entrypoints": {
"server": [
"eu.midnightdust.lib.config.AutoCommand"
],
"client": [
"eu.midnightdust.core.MidnightLib"
],
"modmenu": [
"eu.midnightdust.core.MidnightLib\$ModMenuInit"
]
},
"depends": {
"fabric-resource-loader-v0": "*",
"minecraft": "${minecraft}"
},
"mixins": [
"midnightlib.mixins.json"
],
"custom": {
"modmenu": {
"links": {
"modmenu.discord": "http://discord.midnightdust.eu/",
"modmenu.website": "https://midnightdust.eu/midnightlib",
"midnightlib.wiki": "https://midnightdust.eu/wiki/midnightlib"
},
"badges": [ "library" ]
}
}
}

View File

@@ -26,6 +26,6 @@ side = "BOTH"
[[dependencies.midnightlib]] [[dependencies.midnightlib]]
modId = "minecraft" modId = "minecraft"
mandatory = true mandatory = true
versionRange = "[1.20.5,)" versionRange = "${minecraft}"
ordering = "NONE" ordering = "NONE"
side = "BOTH" side = "BOTH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

View File

@@ -1,7 +1,7 @@
mod.mc_dep_fabric=>=1.21.9 mod.mc_dep_fabric=>=1.21.9 <=1.21.10
mod.mc_dep_forgelike=[1.21.10,) mod.mc_dep_forgelike=[1.21.9,1.21.10]
mod.mc_title=1.21.10 mod.mc_title=1.21.10
mod.mc_targets=1.21.9, 1.21.10 mod.mc_targets=1.21.9 1.21.10
deps.forge_loader=0 deps.forge_loader=0
deps.neoforge_loader=21.10.47-beta deps.neoforge_loader=21.10.47-beta

View File

@@ -0,0 +1,54 @@
{
"schemaVersion": 1,
"id": "${id}",
"version": "${version}",
"name": "${name}",
"description": "Lightweight config library with config screens and commands.",
"authors": [
"Motschen"
],
"contributors": [
"maloryware",
"Jaffe2718"
],
"contact": {
"homepage": "https://www.midnightdust.eu/",
"sources": "https://github.com/TeamMidnightDust/MidnightLib",
"issues": "https://github.com/TeamMidnightDust/MidnightLib/issues"
},
"license": "MIT",
"icon": "assets/midnightlib/icon.png",
"environment": "*",
"entrypoints": {
"server": [
"eu.midnightdust.lib.config.AutoCommand"
],
"client": [
"eu.midnightdust.core.MidnightLib"
],
"modmenu": [
"eu.midnightdust.core.MidnightLib\$ModMenuInit"
]
},
"depends": {
"fabric-resource-loader-v0": "*",
"minecraft": "${minecraft}"
},
"mixins": [
"midnightlib.mixins.json"
],
"custom": {
"modmenu": {
"links": {
"modmenu.discord": "http://discord.midnightdust.eu/",
"modmenu.website": "https://midnightdust.eu/midnightlib",
"midnightlib.wiki": "https://midnightdust.eu/wiki/midnightlib"
},
"badges": [ "library" ]
}
}
}

View File

@@ -1,7 +1,7 @@
mod.mc_dep_fabric=>=1.21.9 mod.mc_dep_fabric=>=1.21.9 <= 1.21.10
mod.mc_dep_forgelike=[1.21.10,) mod.mc_dep_forgelike=[1.21.9,1.21.10]
mod.mc_title=1.21.10 mod.mc_title=1.21.10
mod.mc_targets=1.21.9, 1.21.10 mod.mc_targets=1.21.9 1.21.10
deps.forge_loader=0 deps.forge_loader=0
deps.neoforge_loader=21.10.47-beta deps.neoforge_loader=21.10.47-beta

View File

@@ -0,0 +1,31 @@
modLoader = "javafml"
loaderVersion = "[2,)"
#issueTrackerURL = ""
license = "MIT License"
[[mods]]
modId = "midnightlib"
version = "${version}"
displayName = "${name}"
logoFile = "midnightlib.png"
authors = "TeamMidnightDust, Motschen"
description = '''
Lightweight config library with config screens and commands.
'''
[[mixins]]
config = "midnightlib.mixins.json"
[[dependencies.midnightlib]]
modId = "neoforge"
mandatory = true
versionRange = "[20.5,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.midnightlib]]
modId = "minecraft"
mandatory = true
versionRange = "${minecraft}"
ordering = "NONE"
side = "BOTH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

View File

@@ -0,0 +1,12 @@
mod.mc_dep_fabric=>=1.21.11
mod.mc_dep_forgelike=[1.21.11,)
mod.mc_title=1.21.11
mod.mc_targets=1.21.11
deps.forge_loader=0
deps.neoforge_loader=21.11.3-beta
deps.fabric_version=0.139.4+1.21.11
deps.modmenu_version=17.0.0-alpha.1
loom.platform=fabric

View File

@@ -0,0 +1,54 @@
{
"schemaVersion": 1,
"id": "${id}",
"version": "${version}",
"name": "${name}",
"description": "Lightweight config library with config screens and commands.",
"authors": [
"Motschen"
],
"contributors": [
"maloryware",
"Jaffe2718"
],
"contact": {
"homepage": "https://www.midnightdust.eu/",
"sources": "https://github.com/TeamMidnightDust/MidnightLib",
"issues": "https://github.com/TeamMidnightDust/MidnightLib/issues"
},
"license": "MIT",
"icon": "assets/midnightlib/icon.png",
"environment": "*",
"entrypoints": {
"server": [
"eu.midnightdust.lib.config.AutoCommand"
],
"client": [
"eu.midnightdust.core.MidnightLib"
],
"modmenu": [
"eu.midnightdust.core.MidnightLib\$ModMenuInit"
]
},
"depends": {
"fabric-resource-loader-v0": "*",
"minecraft": "${minecraft}"
},
"mixins": [
"midnightlib.mixins.json"
],
"custom": {
"modmenu": {
"links": {
"modmenu.discord": "http://discord.midnightdust.eu/",
"modmenu.website": "https://midnightdust.eu/midnightlib",
"midnightlib.wiki": "https://midnightdust.eu/wiki/midnightlib"
},
"badges": [ "library" ]
}
}
}

View File

@@ -0,0 +1,12 @@
mod.mc_dep_fabric=>=1.21.11
mod.mc_dep_forgelike=[1.21.11,)
mod.mc_title=1.21.11
mod.mc_targets=1.21.11
deps.forge_loader=0
deps.neoforge_loader=21.11.3-beta
deps.fabric_version=0.139.4+1.21.11
deps.modmenu_version=17.0.0-alpha.1
loom.platform=neoforge

View File

@@ -0,0 +1,31 @@
modLoader = "javafml"
loaderVersion = "[2,)"
#issueTrackerURL = ""
license = "MIT License"
[[mods]]
modId = "midnightlib"
version = "${version}"
displayName = "${name}"
logoFile = "midnightlib.png"
authors = "TeamMidnightDust, Motschen"
description = '''
Lightweight config library with config screens and commands.
'''
[[mixins]]
config = "midnightlib.mixins.json"
[[dependencies.midnightlib]]
modId = "neoforge"
mandatory = true
versionRange = "[20.5,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.midnightlib]]
modId = "minecraft"
mandatory = true
versionRange = "${minecraft}"
ordering = "NONE"
side = "BOTH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

View File

@@ -1,7 +1,7 @@
mod.mc_dep_fabric==1.21.5 mod.mc_dep_fabric=>=1.21.4 <=1.21.5
mod.mc_dep_forgelike=[1.21.5] mod.mc_dep_forgelike=[1.21.4, 1.21.5]
mod.mc_title=1.21.5 mod.mc_title=1.21.5
mod.mc_targets=1.21.5 mod.mc_targets=1.21.4 1.21.5
deps.forge_loader=54.0.13 deps.forge_loader=54.0.13
deps.neoforge_loader=21.4.47-beta deps.neoforge_loader=21.4.47-beta

View File

@@ -0,0 +1,54 @@
{
"schemaVersion": 1,
"id": "${id}",
"version": "${version}",
"name": "${name}",
"description": "Lightweight config library with config screens and commands.",
"authors": [
"Motschen"
],
"contributors": [
"maloryware",
"Jaffe2718"
],
"contact": {
"homepage": "https://www.midnightdust.eu/",
"sources": "https://github.com/TeamMidnightDust/MidnightLib",
"issues": "https://github.com/TeamMidnightDust/MidnightLib/issues"
},
"license": "MIT",
"icon": "assets/midnightlib/icon.png",
"environment": "*",
"entrypoints": {
"server": [
"eu.midnightdust.lib.config.AutoCommand"
],
"client": [
"eu.midnightdust.core.MidnightLib"
],
"modmenu": [
"eu.midnightdust.core.MidnightLib\$ModMenuInit"
]
},
"depends": {
"fabric-resource-loader-v0": "*",
"minecraft": "${minecraft}"
},
"mixins": [
"midnightlib.mixins.json"
],
"custom": {
"modmenu": {
"links": {
"modmenu.discord": "http://discord.midnightdust.eu/",
"modmenu.website": "https://midnightdust.eu/midnightlib",
"midnightlib.wiki": "https://midnightdust.eu/wiki/midnightlib"
},
"badges": [ "library" ]
}
}
}

View File

@@ -1,7 +1,7 @@
mod.mc_dep_fabric==1.21.5 mod.mc_dep_fabric=>=1.21.4 <=1.21.5
mod.mc_dep_forgelike=[1.21.5] mod.mc_dep_forgelike=[1.21.4, 1.21.5]
mod.mc_title=1.21.5 mod.mc_title=1.21.5
mod.mc_targets=1.21.5 mod.mc_targets=1.21.4 1.21.5
deps.forge_loader=0 deps.forge_loader=0
deps.neoforge_loader=21.5.54-beta deps.neoforge_loader=21.5.54-beta

View File

@@ -0,0 +1,31 @@
modLoader = "javafml"
loaderVersion = "[2,)"
#issueTrackerURL = ""
license = "MIT License"
[[mods]]
modId = "midnightlib"
version = "${version}"
displayName = "${name}"
logoFile = "midnightlib.png"
authors = "TeamMidnightDust, Motschen"
description = '''
Lightweight config library with config screens and commands.
'''
[[mixins]]
config = "midnightlib.mixins.json"
[[dependencies.midnightlib]]
modId = "neoforge"
mandatory = true
versionRange = "[20.5,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.midnightlib]]
modId = "minecraft"
mandatory = true
versionRange = "${minecraft}"
ordering = "NONE"
side = "BOTH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

View File

@@ -1,7 +1,7 @@
mod.mc_dep_fabric==1.21.8 mod.mc_dep_fabric=>=1.21.6 <=1.21.8
mod.mc_dep_forgelike=[1.21.8] mod.mc_dep_forgelike=[1.21.6, 1.21.8]
mod.mc_title=1.21.8 mod.mc_title=1.21.8
mod.mc_targets=1.21.8 mod.mc_targets=1.21.6 1.21.7 1.21.8
deps.forge_loader=0 deps.forge_loader=0
deps.neoforge_loader=21.8.50 deps.neoforge_loader=21.8.50

View File

@@ -0,0 +1,54 @@
{
"schemaVersion": 1,
"id": "${id}",
"version": "${version}",
"name": "${name}",
"description": "Lightweight config library with config screens and commands.",
"authors": [
"Motschen"
],
"contributors": [
"maloryware",
"Jaffe2718"
],
"contact": {
"homepage": "https://www.midnightdust.eu/",
"sources": "https://github.com/TeamMidnightDust/MidnightLib",
"issues": "https://github.com/TeamMidnightDust/MidnightLib/issues"
},
"license": "MIT",
"icon": "assets/midnightlib/icon.png",
"environment": "*",
"entrypoints": {
"server": [
"eu.midnightdust.lib.config.AutoCommand"
],
"client": [
"eu.midnightdust.core.MidnightLib"
],
"modmenu": [
"eu.midnightdust.core.MidnightLib\$ModMenuInit"
]
},
"depends": {
"fabric-resource-loader-v0": "*",
"minecraft": "${minecraft}"
},
"mixins": [
"midnightlib.mixins.json"
],
"custom": {
"modmenu": {
"links": {
"modmenu.discord": "http://discord.midnightdust.eu/",
"modmenu.website": "https://midnightdust.eu/midnightlib",
"midnightlib.wiki": "https://midnightdust.eu/wiki/midnightlib"
},
"badges": [ "library" ]
}
}
}

View File

@@ -1,7 +1,7 @@
mod.mc_dep_fabric==1.21.5 mod.mc_dep_fabric=>=1.21.6 <=1.21.8
mod.mc_dep_forgelike=[1.21.5] mod.mc_dep_forgelike=[1.21.6, 1.21.8]
mod.mc_title=1.21.5 mod.mc_title=1.21.8
mod.mc_targets=1.21.5 mod.mc_targets=1.21.6 1.21.7 1.21.8
deps.forge_loader=0 deps.forge_loader=0
deps.neoforge_loader=21.8.50 deps.neoforge_loader=21.8.50

View File

@@ -0,0 +1,31 @@
modLoader = "javafml"
loaderVersion = "[2,)"
#issueTrackerURL = ""
license = "MIT License"
[[mods]]
modId = "midnightlib"
version = "${version}"
displayName = "${name}"
logoFile = "midnightlib.png"
authors = "TeamMidnightDust, Motschen"
description = '''
Lightweight config library with config screens and commands.
'''
[[mixins]]
config = "midnightlib.mixins.json"
[[dependencies.midnightlib]]
modId = "neoforge"
mandatory = true
versionRange = "[20.5,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.midnightlib]]
modId = "minecraft"
mandatory = true
versionRange = "${minecraft}"
ordering = "NONE"
side = "BOTH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B