Compare commits

...

35 Commits

Author SHA1 Message Date
Martin Prokoph
d75d34d675 MidnightLib 1.5.5
- Fixed button always being visible
- Various visual improvements
2024-05-04 17:59:06 +02:00
Martin Prokoph
64ccaf6195 Merge branch '24w09a' of https://github.com/TeamMidnightDust/MidnightLib into 24w09a 2024-04-21 14:46:16 +02:00
Martin Prokoph
a43820c904 Update to 1.20.5-rc2 2024-04-21 14:46:09 +02:00
Martin Prokoph
ce23e811b5 Merge pull request #52 from TeamMidnightDust/architectury
Fixed #48
2024-04-21 14:34:49 +02:00
Martin Prokoph
afc3c09148 Fixed #48
Also reduced code complexity, nice :)
2024-04-04 17:25:53 +02:00
Martin Prokoph
0241f81235 Fix button positioning
- Overview button is now positioned correctly again
- Updated to 24w13a (also works on 24w14a)
2024-04-04 17:03:41 +02:00
Martin Prokoph
2f1bfbf44e Experimental 24w09a port
- Only the overview button position in the Options Screen is not quite right
2024-03-05 12:58:59 +01:00
Martin Prokoph
2ff92526ba Fix ModMenu integration 2023-12-19 14:59:47 +01:00
Martin Prokoph
fb1c4c1158 MidnightLib 1.5.2 - NeoForge & more cleanness
- Native support for NeoForge (& dropped support for regular Forge)
- Cleanup of some code -> Overview button is now added via callbacks instead of a mixin
- Unify client & server classes
  - Minor breaking change only affecting mods using the hiding functionality
2023-12-11 19:28:04 +01:00
Martin Prokoph
29c8a9ccfe MidnightLib 1.5.1 for 1.20.4
- Port to 1.20.4
- Add back fancy list background
- File size optimizations
- Update tooling
2023-12-07 18:07:09 +01:00
Motschen
38e2e55a07 Re-enable Forge support
- QSL is still not released for whatever reason, so Quilt support will come later
2023-09-30 10:55:25 +02:00
Motschen
cbfaeb3c6f MidnightLib 1.5.0 - 1.20.2, slight redesign & cleanup
- Port to 1.20.2
- "Reset" button now uses a custom icon (closes #25)
- Config instances can now specify custom config change behavior (implement "writeChanges" method in your class; closes #33)
- Remove TexturedOverlayButtonWidget (replaced by vanilla's TextIconButtonWidget)
- Removed radialRainbow (used very rarely)
- Updated AutoCommand to support editing list and float config values via commands on serverside installs
- Reworded description
- Forge & Quilt temporarily disabled until they release, as always
2023-09-16 21:52:14 +02:00
Martin Prokoph
59989308f6 Merge pull request #37 from Suel-ki/architectury
Fix forge initialization
2023-09-09 11:33:15 +02:00
Suel_ki
29706d3e39 Add static keyword to registerCommands method 2023-07-18 10:27:18 +08:00
Suel_ki
afdd6549d3 Fix registerCommands registration 2023-07-17 16:47:52 +08:00
Suel_ki
8466b3f21a Fix ConfigScreen registration 2023-07-17 16:44:14 +08:00
Martin Prokoph
f71e8dbdc3 Update README.md 2023-06-11 12:52:21 +02:00
Motschen
dbbf546551 MidnightLib 1.4.1 - Fix tabs & Re-enable Quilt and Forge
- Fix tabs not being visible
- Re-enable Forge and Quilt support
- Fix #28
2023-06-09 18:46:53 +02:00
Motschen
9074abc331 Previous commit had a typo, it's 1.20 ;)
This commit fixes unsaved options resetting when resizing the game window
2023-05-22 12:20:35 +02:00
Motschen
8109eeb74e Update to 1.19.4 & Fix invalid value tooltips 2023-05-18 21:33:17 +02:00
Martin Prokoph
e9e1bec91f Merge pull request #26 from notlin4/patch-1
Create zh_tw.json
2023-05-18 18:41:08 +02:00
notlin4
b723253686 Create zh_tw.json 2023-04-04 23:16:14 +08:00
Motschen
e8ea0da749 Fix quilt.mod.json 2023-04-02 16:57:51 +02:00
Motschen
8ab3b9fa7d MidnightLib 1.3.0 - No more hats
- Re-enable Quilt and Forge support
- Completely remove unnecessary bloat (Hat cosmetics)
- File size is now just around 55KB for the Fabric & Quilt version, 60KB for Forge
2023-04-02 14:58:04 +02:00
Motschen
2db6b33d30 Bump version 2023-03-09 21:11:02 +01:00
Motschen
c881db8be4 Fix <Ctrl>+<Number> keybinds not working for tabs 2023-03-09 21:10:01 +01:00
Motschen
79eb8936ff Update the example config 2023-03-09 20:37:44 +01:00
Motschen
920fb797e1 Minor improvements 2023-03-09 19:50:28 +01:00
Motschen
cacd3516c1 Port to 1.19.4, Add tab support & Large code cleanup 2023-03-08 21:27:41 +01:00
Martin Prokoph
b5052ff324 Merge pull request #24 from Amirhan-Taipovjan-Greatest-I/patch-1
Tatar Translation for MidnightLib
2023-03-08 16:43:38 +01:00
Martin Prokoph
8acc9baa5a Merge pull request #22 from Calvineries/patch-1
Create fr_fr.json
2023-03-08 16:43:27 +01:00
Amirhan-Taipovjan-Greatest-I
ecda37dd13 Tatar Translation for MidnightLib 2023-02-26 09:44:44 +03:00
Motschen
1009dd9e84 Fix #23 2023-02-15 12:12:18 +01:00
Calvineries
9bfa593d4d Create fr_fr.json 2023-01-22 13:11:42 +01:00
Motschen
1ef835a015 Re-enable Quilt and Forge support 2022-12-14 18:22:32 +01:00
57 changed files with 519 additions and 756 deletions

3
.gitignore vendored
View File

@@ -16,4 +16,5 @@ classes/
.metadata .metadata
.vscode .vscode
.settings .settings
*.launch *.launch
.architectury-transformer/debug.log

View File

@@ -1,3 +1,3 @@
# MidnightLib # MidnightLib
Common Library for Team MidnightDust's mods. Lightweight Common Library for Minecraft mods.
Provides a config api, common utils, and cosmetics. Provides a config api with a nice GUI and common utilities, all in a very small file.

View File

@@ -1,6 +1,7 @@
plugins { plugins {
id "architectury-plugin" version "3.4-SNAPSHOT" id "architectury-plugin" version "3.4-SNAPSHOT"
id "dev.architectury.loom" version "1.0-SNAPSHOT" apply false id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false
id "me.shedaniel.unified-publishing" version "0.1.+" apply false
} }
architectury { architectury {
@@ -12,10 +13,8 @@ subprojects {
dependencies { dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
// The following line declares the mojmap mappings, you may use other mappings as well
//mappings loom.officialMojangMappings()
// The following line declares the yarn mappings you may select this one as well. // The following line declares the yarn mappings you may select this one as well.
mappings "net.fabricmc:yarn:1.19.3-rc1+build.2:v2" mappings "net.fabricmc:yarn:${rootProject.yarn_mappings}:v2"
} }
} }
@@ -38,7 +37,22 @@ allprojects {
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {
options.encoding = "UTF-8" options.encoding = "UTF-8"
options.release = 17 options.release = 21
}
ext {
releaseChangelog = {
def changes = new StringBuilder()
changes << "## MidnightLib v$project.version for $project.minecraft_version\n[View the changelog](https://www.github.com/TeamMidnightDust/MidnightLib/commits/)"
def proc = "git log --max-count=1 --pretty=format:%s".execute()
proc.in.eachLine { line ->
def processedLine = line.toString()
if (!processedLine.contains("New translations") && !processedLine.contains("Merge") && !processedLine.contains("branch")) {
changes << "\n- ${processedLine.capitalize()}"
}
}
proc.waitFor()
return changes.toString()
}
} }
java { java {

View File

@@ -2,9 +2,6 @@ architectury {
common(rootProject.enabled_platforms.split(",")) common(rootProject.enabled_platforms.split(","))
} }
loom {
}
dependencies { dependencies {
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies // We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
// Do NOT use other classes from fabric loader // Do NOT use other classes from fabric loader

View File

@@ -1,12 +1,23 @@
package eu.midnightdust.core; package eu.midnightdust.core;
import eu.midnightdust.core.config.MidnightLibConfig;
import eu.midnightdust.lib.config.AutoCommand; import eu.midnightdust.lib.config.AutoCommand;
import eu.midnightdust.lib.config.MidnightConfig; import eu.midnightdust.lib.config.MidnightConfig;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class MidnightLibServer { public class MidnightLib {
public static List<String> hiddenMods = new ArrayList<>();
@Environment(EnvType.CLIENT)
public static void onInitializeClient() {
MidnightLibConfig.init("midnightlib", MidnightLibConfig.class);
}
@Environment(EnvType.SERVER)
public static void onInitializeServer() { public static void onInitializeServer() {
MidnightConfig.configClass.forEach((modid, config) -> { MidnightConfig.configClass.forEach((modid, config) -> {
for (Field field : config.getFields()) { for (Field field : config.getFields()) {

View File

@@ -1,21 +0,0 @@
package eu.midnightdust.core;
import eu.midnightdust.core.config.MidnightLibConfig;
import eu.midnightdust.hats.web.HatLoader;
import eu.midnightdust.lib.config.MidnightConfig;
import java.util.ArrayList;
import java.util.List;
public class MidnightLibClient {
public static List<String> hiddenMods = new ArrayList<>();
public static final String MOD_ID = "midnightlib";
public static void onInitializeClient() {
MidnightConfig.init("midnightlib", MidnightLibConfig.class);
hiddenMods.add("puzzle");
if (MidnightLibConfig.special_hats) HatLoader.init();
}
}

View File

@@ -1,5 +1,6 @@
package eu.midnightdust.core.config; package eu.midnightdust.core.config;
import com.google.common.collect.Lists;
import eu.midnightdust.lib.config.MidnightConfig; import eu.midnightdust.lib.config.MidnightConfig;
import java.util.List; import java.util.List;
@@ -12,21 +13,22 @@ import java.util.List;
public class MidnightConfigExample extends MidnightConfig { public class MidnightConfigExample extends MidnightConfig {
@Comment public static Comment text1; // Comments are rendered like an option without a button and are excluded from the config file @Comment(category = "text") public static Comment text1; // Comments are rendered like an option without a button and are excluded from the config file
@Comment(centered = true) public static Comment text2; // Centered comments are the same as normal ones - just centered! @Comment(category = "text", centered = true) public static Comment text2; // Centered comments are the same as normal ones - just centered!
@Entry public static int fabric = 16777215; // Example for an int option @Comment(category = "text") public static Comment spacer1; // Comments containing the word "spacer" will just appear as a blank line
@Entry public static double world = 1.4D; // Example for a double option @Entry(category = "text") public static boolean showInfo = true; // Example for a boolean option
@Entry public static boolean showInfo = true; // Example for a boolean option @Entry(category = "text") public static String name = "Hello World!"; // Example for a string option, which is in a category!
@Entry public static String name = "Hello World!"; // Example for a string option @Entry(category = "text") public static TestEnum testEnum = TestEnum.FABRIC; // Example for an enum option
@Entry public static TestEnum testEnum = TestEnum.FABRIC; // Example for an enum option public enum TestEnum { // Enums allow the user to cycle through predefined options
public enum TestEnum { // Enums allow the user to cycle through predefined options
QUILT, FABRIC, FORGE QUILT, FABRIC, FORGE
} }
@Entry(min=69,max=420) public static int hello = 420; // - The entered number has to be larger than 69 and smaller than 420 @Entry(category = "numbers") public static int fabric = 16777215; // Example for an int option
@Entry(width = 7, min = 7, isColor = true, name = "I am a color!") public static String titleColor = "#ffffff"; // The isColor property adds a preview box for a hexadecimal color @Entry(category = "numbers") public static double world = 1.4D; // Example for a double option
@Entry(name = "I am an array list!") public static List<String> arrayList = List.of("String1", "String2"); // Array String Lists are also supported @Entry(category = "numbers", min=69,max=420) public static int hello = 420; // - The entered number has to be larger than 69 and smaller than 420
@Entry(name = "I am an int slider.",isSlider = true, min = 0, max = 100) public static int intSlider = 35; // Int fields can also be displayed as a Slider @Entry(category = "text", isColor = true) public static String titleColor = "#ffffff"; // The isColor property adds a preview box for a hexadecimal color
@Entry(name = "I am a float slider!", isSlider = true, min = 0f, max = 1f, precision = 1000) public static float floatSlider = 0.24f; // And so can floats! Precision defines the amount of decimal places @Entry(category = "text") public static List<String> arrayList = Lists.newArrayList(); // Array String Lists are also supported
@Entry(isSlider = true, min = 0, max = 100) public static int intSlider = 35; // Int fields can also be displayed as a Slider
@Entry(isSlider = true, min = 0f, max = 1f) public static float floatSlider = 0.24f; // And so can floats! Precision defines the amount of decimal places
// 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
public static int imposter = 16777215; // - Entries without an @Entry or @Comment annotation are ignored public static int imposter = 16777215; // - Entries without an @Entry or @Comment annotation are ignored
@@ -49,11 +51,13 @@ public class MidnightConfigExample extends MidnightConfig {
"modid.midnightconfig.testEnum":"I am an enum!", "modid.midnightconfig.testEnum":"I am an enum!",
"modid.midnightconfig.enum.TestEnum.FORGE":"Slow", "modid.midnightconfig.enum.TestEnum.FORGE":"Slow",
"modid.midnightconfig.enum.TestEnum.FABRIC":"Fancy", "modid.midnightconfig.enum.TestEnum.FABRIC":"Fancy",
"modid.midnightconfig.enum.TestEnum.QUILT":"Fabulous" "modid.midnightconfig.enum.TestEnum.QUILT":"Fabulous",
"modid.midnightconfig.category.numbers": "Numbers",
"modid.midnightconfig.category.text": "Text",
"modid.midnightconfig.category.sliders": "Sliders"
} }
To initialize the config you have to call "MidnightConfig.init("modid", MidnightConfigExample.class)" in your ModInitializer To initialize the config you have to call "MidnightConfig.init("modid", MidnightConfigExample.class)" in your ModInitializer
To get an instance of the config screen you have to call "MidnightConfig.getScreen(parent, "modid");" To get an instance of the config screen you have to call "MidnightConfig.getScreen(parent, "modid");"
If you don't use the whole library and therefore not the automatic ModMenu integration, the code in your ModMenu integration class would look something like this: If you don't use the whole library and therefore not the automatic ModMenu integration, the code in your ModMenu integration class would look something like this:
@Override @Override
public ConfigScreenFactory<?> getModConfigScreenFactory() { public ConfigScreenFactory<?> getModConfigScreenFactory() {

View File

@@ -4,12 +4,8 @@ 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 {
@Comment(centered = true) public static Comment midnightlib_description; @Entry
@Entry // Enable or disable the MidnightConfig overview screen button
public static ConfigButton config_screen_list = PlatformFunctions.isModLoaded("modmenu") ? ConfigButton.MODMENU : ConfigButton.TRUE; public static ConfigButton config_screen_list = PlatformFunctions.isModLoaded("modmenu") ? ConfigButton.MODMENU : ConfigButton.TRUE;
@Comment(centered = true) public static Comment midnighthats_description;
@Entry // Enable or disable hats for contributors, friends and donors.
public static boolean special_hats = true;
public enum ConfigButton { public enum ConfigButton {
TRUE,FALSE,MODMENU TRUE,FALSE,MODMENU

View File

@@ -3,12 +3,17 @@ package eu.midnightdust.core.mixin;
import eu.midnightdust.core.config.MidnightLibConfig; import eu.midnightdust.core.config.MidnightLibConfig;
import eu.midnightdust.core.screen.MidnightConfigOverviewScreen; import eu.midnightdust.core.screen.MidnightConfigOverviewScreen;
import eu.midnightdust.lib.util.PlatformFunctions; import eu.midnightdust.lib.util.PlatformFunctions;
import eu.midnightdust.lib.util.screen.TexturedOverlayButtonWidget; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.option.OptionsScreen; import net.minecraft.client.gui.screen.option.OptionsScreen;
import net.minecraft.client.gui.widget.TextIconButtonWidget;
import net.minecraft.client.gui.widget.ThreePartsLayoutWidget;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -17,14 +22,28 @@ import java.util.Objects;
@Mixin(OptionsScreen.class) @Mixin(OptionsScreen.class)
public class MixinOptionsScreen extends Screen { public class MixinOptionsScreen extends Screen {
private static final Identifier MIDNIGHTLIB_ICON_TEXTURE = new Identifier("midnightlib","textures/gui/midnightlib_button.png"); @Shadow @Final private ThreePartsLayoutWidget layout;
protected MixinOptionsScreen(Text title) { @Unique TextIconButtonWidget button = TextIconButtonWidget.builder(Text.translatable("midnightlib.overview.title"), (
super(title); buttonWidget) -> Objects.requireNonNull(client).setScreen(new MidnightConfigOverviewScreen(this)), true)
.texture(new Identifier("midnightlib","icon/midnightlib"), 16, 16).dimension(20, 20).build();
@Unique boolean shouldShowButton = MidnightLibConfig.config_screen_list.equals(MidnightLibConfig.ConfigButton.TRUE) || (MidnightLibConfig.config_screen_list.equals(MidnightLibConfig.ConfigButton.MODMENU) && !PlatformFunctions.isModLoaded("modmenu"));
protected MixinOptionsScreen(Text title) {super(title);}
@Inject(at = @At("HEAD"), method = "init")
public void midnightlib$onInit(CallbackInfo ci) {
if (shouldShowButton) {
this.midnightlib$setupButton();
this.addDrawableChild(button);
}
} }
@Inject(at = @At("HEAD"),method = "init") @Override
private void midnightlib$init(CallbackInfo ci) { public void resize(MinecraftClient client, int width, int height) {
if (MidnightLibConfig.config_screen_list.equals(MidnightLibConfig.ConfigButton.TRUE) || (MidnightLibConfig.config_screen_list.equals(MidnightLibConfig.ConfigButton.MODMENU) && !PlatformFunctions.isModLoaded("modmenu"))) super.resize(client, width, height);
this.addDrawableChild(new TexturedOverlayButtonWidget(this.width / 2 + 158, this.height / 6 - 12, 20, 20, 0, 0, 20, MIDNIGHTLIB_ICON_TEXTURE, 32, 64, (buttonWidget) -> Objects.requireNonNull(client).setScreen(new MidnightConfigOverviewScreen(this)), Text.translatable("midnightlib.overview.title"))); if (shouldShowButton) this.midnightlib$setupButton();
} }
} @Unique
public void midnightlib$setupButton() {
button.setPosition(layout.getWidth() / 2 + 158, layout.getY() + layout.getFooterHeight() - 4);
}
}

View File

@@ -1,24 +0,0 @@
package eu.midnightdust.core.mixin;
import eu.midnightdust.hats.witch.WitchHatFeatureRenderer;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.LivingEntityRenderer;
import net.minecraft.client.render.entity.PlayerEntityRenderer;
import net.minecraft.client.render.entity.model.PlayerEntityModel;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerEntityRenderer.class)
public abstract class MixinPlayerEntityRenderer extends LivingEntityRenderer<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> {
public MixinPlayerEntityRenderer(EntityRendererFactory.Context ctx, PlayerEntityModel<AbstractClientPlayerEntity> model, float shadowSize) {
super(ctx, model, shadowSize);
}
@Inject(at = @At("TAIL"), method = "<init>")
public void addFeatures(EntityRendererFactory.Context ctx, boolean slim, CallbackInfo ci) {
this.addFeature(new WitchHatFeatureRenderer<>(this, ctx.getModelLoader()));
}
}

View File

@@ -1,18 +1,15 @@
package eu.midnightdust.core.screen; package eu.midnightdust.core.screen;
import eu.midnightdust.core.MidnightLibClient; import eu.midnightdust.core.MidnightLib;
import eu.midnightdust.lib.config.MidnightConfig; import eu.midnightdust.lib.config.MidnightConfig;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.Selectable;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.*; import net.minecraft.client.gui.widget.*;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.ScreenTexts; import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.*; import net.minecraft.text.*;
import java.util.*; import java.util.*;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
@@ -23,64 +20,29 @@ public class MidnightConfigOverviewScreen extends Screen {
this.parent = parent; this.parent = parent;
} }
private final Screen parent; private final Screen parent;
private MidnightOverviewListWidget list; private MidnightConfig.MidnightConfigListWidget list;
@Override @Override
protected void init() { protected void init() {
this.addDrawableChild(ButtonWidget.builder(ScreenTexts.DONE, (button) -> Objects.requireNonNull(client).setScreen(parent)).dimensions(this.width / 2 - 100, this.height - 28, 200, 20).build()); this.addDrawableChild(ButtonWidget.builder(ScreenTexts.DONE, (button) -> Objects.requireNonNull(client).setScreen(parent)).dimensions(this.width / 2 - 100, this.height - 26, 200, 20).build());
this.list = new MidnightOverviewListWidget(this.client, this.width, this.height, 32, this.height - 32, 25); this.list = new MidnightConfig.MidnightConfigListWidget(this.client, this.width, this.height - 57, 24, 25);
if (this.client != null && this.client.world != null) this.list.setRenderBackground(false);
this.addSelectableChild(this.list); this.addSelectableChild(this.list);
List<String> sortedMods = new ArrayList<>(MidnightConfig.configClass.keySet()); List<String> sortedMods = new ArrayList<>(MidnightConfig.configClass.keySet());
Collections.sort(sortedMods); Collections.sort(sortedMods);
sortedMods.forEach((modid) -> { sortedMods.forEach((modid) -> {
if (!MidnightLibClient.hiddenMods.contains(modid)) { if (!MidnightLib.hiddenMods.contains(modid)) {
list.addButton(ButtonWidget.builder(Text.translatable(modid +".midnightconfig.title"), (button) -> list.addButton(List.of(ButtonWidget.builder(Text.translatable(modid +".midnightconfig.title"), (button) ->
Objects.requireNonNull(client).setScreen(MidnightConfig.getScreen(this,modid))).dimensions(this.width / 2 - 100, this.height - 28, 200, 20).build()); Objects.requireNonNull(client).setScreen(MidnightConfig.getScreen(this,modid))).dimensions(this.width / 2 - 125, this.height - 28, 250, 20).build()), null, null);
} }
}); });
super.init(); super.init();
} }
@Override @Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { public void render(DrawContext context, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices); super.render(context, mouseX, mouseY, delta);
this.list.render(matrices, mouseX, mouseY, delta); this.list.render(context, mouseX, mouseY, delta);
drawCenteredText(matrices, textRenderer, title, width / 2, 15, 0xFFFFFF);
super.render(matrices, mouseX, mouseY, delta);
}
@Environment(EnvType.CLIENT)
public static class MidnightOverviewListWidget extends ElementListWidget<OverviewButtonEntry> {
TextRenderer textRenderer;
public MidnightOverviewListWidget(MinecraftClient minecraftClient, int i, int j, int k, int l, int m) { context.drawCenteredTextWithShadow(textRenderer, title, width / 2, 10, 0xFFFFFF);
super(minecraftClient, i, j, k, l, m);
this.centerListVertically = false;
textRenderer = minecraftClient.textRenderer;
}
@Override
public int getScrollbarPositionX() {return this.width -7;}
public void addButton(ClickableWidget button) {
this.addEntry(OverviewButtonEntry.create(button));
}
@Override
public int getRowWidth() { return 400; }
}
public static class OverviewButtonEntry extends ElementListWidget.Entry<OverviewButtonEntry> {
private final ClickableWidget button;
private final List<ClickableWidget> buttonList = new ArrayList<>();
private OverviewButtonEntry(ClickableWidget button) {
this.button = button;
this.buttonList.add(button);
}
public static OverviewButtonEntry create(ClickableWidget button) {return new OverviewButtonEntry(button);}
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
button.setY(y);
button.render(matrices, mouseX, mouseY, tickDelta);
}
public List<? extends Element> children() {return buttonList;}
public List<? extends Selectable> selectableChildren() {return buttonList;}
} }
} }

View File

@@ -1,49 +0,0 @@
package eu.midnightdust.hats.web;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.minecraft.client.MinecraftClient;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@SuppressWarnings("UnstableApiUsage")
public class HatLoader {
public static final System.Logger logger = System.getLogger("MidnightLib");
private final static String HATS_URL = "https://raw.githubusercontent.com/TeamMidnightDust/MidnightHats/master/hats.json";
public static final Type HAT_TYPE = new TypeToken<Map<UUID, PlayerHatData>>(){}.getType();
public static Map<UUID, PlayerHatData> PLAYER_HATS;
private static final Gson GSON = new GsonBuilder().create();
public static void init() {
CompletableFuture.supplyAsync(() -> {
try (Reader reader = new InputStreamReader(new URL(HATS_URL).openStream())) {
return GSON.<Map<UUID, PlayerHatData>>fromJson(reader, HAT_TYPE);
} catch (MalformedURLException error) {
logger.log(System.Logger.Level.ERROR, "Unable to load player hats because of connection problems: " + error.getMessage());
} catch (IOException error) {
logger.log(System.Logger.Level.ERROR, "Unable to load player hats because of an I/O Exception: " + error.getMessage());
}
return null;
}).thenAcceptAsync(playerData -> {
if (playerData != null) {
PLAYER_HATS = playerData;
System.out.println("(MidnightLib) Player hats successfully loaded!");
} else {
PLAYER_HATS = Collections.emptyMap();
logger.log(System.Logger.Level.WARNING, "A problem with the database occurred, the hats could not be initialized.");
}
}, MinecraftClient.getInstance());
}
}

View File

@@ -1,13 +0,0 @@
package eu.midnightdust.hats.web;
public class PlayerHatData {
private final String hat;
public PlayerHatData(String hat) {
this.hat = hat;
}
public String getHatType() {
return hat;
}
}

View File

@@ -1,82 +0,0 @@
package eu.midnightdust.hats.witch;
import eu.midnightdust.hats.web.HatLoader;
import eu.midnightdust.lib.util.MidnightColorUtil;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.model.TexturedModelData;
import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.feature.FeatureRenderer;
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.model.EntityModelLayer;
import net.minecraft.client.render.entity.model.EntityModelLoader;
import net.minecraft.client.render.entity.model.ModelWithHead;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
import java.awt.*;
import java.util.UUID;
import static eu.midnightdust.core.MidnightLibClient.MOD_ID;
@Environment(EnvType.CLIENT)
public class WitchHatFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> {
public static final EntityModelLayer WITCH_HAT_MODEL_LAYER = new EntityModelLayer(new Identifier("midnight-hats","witch_hat"), "main");
private static final UUID MOTSCHEN = UUID.fromString("a44c2660-630f-478f-946a-e518669fcf0c");
private static final Identifier WITCH = new Identifier("textures/entity/witch.png");
private static final Identifier OVERLAY = new Identifier(MOD_ID,"textures/hats/overlay.png");
private static final Color MOTSCHEN_COLOR = MidnightColorUtil.radialRainbow(1,1);
private static final Color ADOPTER_COLOR = MidnightColorUtil.hex2Rgb("ffffff");
private static final Color MODDER_COLOR = MidnightColorUtil.hex2Rgb("7825b4");
private static final Color FRIEND_COLOR = MidnightColorUtil.hex2Rgb("ff0234");
private static final Color DONOR_COLOR = MidnightColorUtil.hex2Rgb("ff6c00");
private static final Color SOCIAL_COLOR = MidnightColorUtil.hex2Rgb("238a9d");
private final WitchHatModel<T> witchHat;
private final MinecraftClient client = MinecraftClient.getInstance();
public WitchHatFeatureRenderer(FeatureRendererContext<T, M> featureRendererContext, EntityModelLoader entityModelLoader) {
super(featureRendererContext);
this.witchHat = new WitchHatModel<>(entityModelLoader.getModelPart(WITCH_HAT_MODEL_LAYER));
}
public static TexturedModelData getTexturedModelData() {
return TexturedModelData.of(WitchHatModel.getModelData(), 64, 128);
}
public void render(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, T livingEntity, float f, float g, float h, float j, float k, float l) {
Color hat_type = getHat(livingEntity.getUuid());
if (hat_type != null && !livingEntity.isInvisibleTo(client.player)) {
if (hat_type == MOTSCHEN_COLOR) hat_type = MidnightColorUtil.radialRainbow(1,1);
matrixStack.push();
((ModelWithHead) this.getContextModel()).getHead().rotate(matrixStack);
VertexConsumer vertexConsumer = vertexConsumerProvider.getBuffer(RenderLayer.getEntityCutoutNoCull(WITCH));
this.witchHat.render(matrixStack, vertexConsumer, i, OverlayTexture.DEFAULT_UV,1f,1f,1f,1);
VertexConsumer glow = vertexConsumerProvider.getBuffer(RenderLayer.getBeaconBeam(OVERLAY,true));
matrixStack.translate(0,0,-0.001f);
this.witchHat.render(matrixStack, glow, 230, OverlayTexture.DEFAULT_UV, hat_type.getRed() / 255f, hat_type.getGreen() / 255f, hat_type.getBlue() / 255f, 1.0F);
matrixStack.pop();
}
}
private Color getHat(UUID uuid) {
if (uuid.equals(MOTSCHEN)) {
return MOTSCHEN_COLOR;
} else if (HatLoader.PLAYER_HATS != null && HatLoader.PLAYER_HATS.containsKey(uuid)) {
return switch (HatLoader.PLAYER_HATS.get(uuid).getHatType()) {
case "adopter" -> ADOPTER_COLOR;
case "contributer", "modder" -> MODDER_COLOR;
case "friend" -> FRIEND_COLOR;
case "donator", "donor" -> DONOR_COLOR;
case "social" -> SOCIAL_COLOR;
default -> MidnightColorUtil.hex2Rgb(HatLoader.PLAYER_HATS.get(uuid).getHatType());
};
}
return null;
}
}

View File

@@ -1,59 +0,0 @@
package eu.midnightdust.hats.witch;
import net.minecraft.client.model.*;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.entity.model.SinglePartEntityModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
public class WitchHatModel<T extends LivingEntity> extends SinglePartEntityModel<T> {
private final ModelPart headwear;
public WitchHatModel(ModelPart root) {
headwear = root;
root.setPivot(5.0F, -9.0F, -5.0F);
ModelPart bone = headwear.getChild("bone");
bone.setPivot(-8.5F, -0.1F, 1.5F);
setRotationAngle(bone, -0.0524F, 0.0F, 0.0349F);
ModelPart bone2 = bone.getChild("bone2");
bone2.setPivot(1.5F, -4.0F, 1.5F);
setRotationAngle(bone2, -0.1222F, 0.0F, 0.0698F);
ModelPart bone3 = bone2.getChild("bone3");
bone3.setPivot(1.5F, -4.0F, 1.5F);
setRotationAngle(bone3, -0.2618F, 0.0F, 0.1047F);
}
public static ModelData getModelData(){
ModelData modelData = new ModelData();
ModelPartData modelPartData = modelData.getRoot();
modelPartData.addChild("headwear", ModelPartBuilder.create().uv(0, 64).cuboid(-10.0F, -0.1F, 0.0F, 10.0F, 2.0F, 10.0F), ModelTransform.NONE);
ModelPartData modelPartData2 = modelPartData.addChild("bone", ModelPartBuilder.create().uv(0, 76).cuboid(0.0F, -4.0F, 0.0F, 7.0F, 4.0F, 7.0F), ModelTransform.rotation(-0.0524F, 0.0F, 0.0349F));
ModelPartData modelPartData3 = modelPartData2.addChild("bone2", ModelPartBuilder.create().uv(0, 87).cuboid(0.0F, -4.0F, 0.0F, 4.0F, 4.0F, 4.0F), ModelTransform.rotation(-0.1222F, 0.0F, 0.0698F));
modelPartData3.addChild("bone3", ModelPartBuilder.create().uv(0, 95).cuboid(0.0F, -2.0F, 0.0F, 1.0F, 2.0F, 1.0F), ModelTransform.rotation(-0.2618F, 0.0F, 0.1047F));
return modelData;
}
@Override
public void setAngles(T entity, float limbAngle, float limbDistance, float animationProgress, float headYaw, float headPitch) {
}
@Override
public void render(MatrixStack matrixStack, VertexConsumer buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha){
headwear.render(matrixStack, buffer, packedLight, packedOverlay, red, green, blue, alpha);
}
@Override
public ModelPart getPart() {
return headwear;
}
public void setRotationAngle(ModelPart bone, float x, float y, float z) {
bone.pitch = x;
bone.yaw = y;
bone.roll = z;
}
}

View File

@@ -1,6 +1,7 @@
package eu.midnightdust.lib.config; package eu.midnightdust.lib.config;
import com.mojang.brigadier.arguments.DoubleArgumentType; import com.mojang.brigadier.arguments.DoubleArgumentType;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
@@ -14,9 +15,9 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@SuppressWarnings("unchecked")
public class AutoCommand { public class AutoCommand {
public static List<LiteralArgumentBuilder<ServerCommandSource>> commands = new ArrayList<>(); public static List<LiteralArgumentBuilder<ServerCommandSource>> commands = new ArrayList<>();
private LiteralArgumentBuilder<ServerCommandSource> command;
final Field entry; final Field entry;
final String modid; final String modid;
@@ -26,14 +27,7 @@ public class AutoCommand {
} }
public void register() { public void register() {
command = CommandManager.literal(modid); LiteralArgumentBuilder<ServerCommandSource> command = CommandManager.literal(modid);
command();
LiteralArgumentBuilder<ServerCommandSource> finalized = CommandManager.literal("midnightconfig").requires(source -> source.hasPermissionLevel(2)).then(command);
PlatformFunctions.registerCommand(finalized); commands.add(finalized);
}
private void command() {
if (entry.getType() == int.class) if (entry.getType() == int.class)
command = command.then(CommandManager.literal(this.entry.getName()).executes(ctx -> getValue(ctx.getSource())).then( command = command.then(CommandManager.literal(this.entry.getName()).executes(ctx -> getValue(ctx.getSource())).then(
CommandManager.argument("value", IntegerArgumentType.integer((int) entry.getAnnotation(MidnightConfig.Entry.class).min(),(int) entry.getAnnotation(MidnightConfig.Entry.class).max())) CommandManager.argument("value", IntegerArgumentType.integer((int) entry.getAnnotation(MidnightConfig.Entry.class).min(),(int) entry.getAnnotation(MidnightConfig.Entry.class).max()))
@@ -44,15 +38,18 @@ public class AutoCommand {
CommandManager.argument("value", DoubleArgumentType.doubleArg(entry.getAnnotation(MidnightConfig.Entry.class).min(),entry.getAnnotation(MidnightConfig.Entry.class).max())) CommandManager.argument("value", DoubleArgumentType.doubleArg(entry.getAnnotation(MidnightConfig.Entry.class).min(),entry.getAnnotation(MidnightConfig.Entry.class).max()))
.executes(ctx -> this.setValue(ctx.getSource(), DoubleArgumentType.getDouble(ctx, "value"))) .executes(ctx -> this.setValue(ctx.getSource(), DoubleArgumentType.getDouble(ctx, "value")))
)); ));
else if (entry.getType() == float.class)
command = command.then(CommandManager.literal(this.entry.getName()).executes(ctx -> getValue(ctx.getSource())).then(
CommandManager.argument("value", FloatArgumentType.floatArg((float) entry.getAnnotation(MidnightConfig.Entry.class).min(), (float) entry.getAnnotation(MidnightConfig.Entry.class).max()))
.executes(ctx -> this.setValue(ctx.getSource(), FloatArgumentType.getFloat(ctx, "value")))
));
else if (entry.getType() == boolean.class) { else if (entry.getType() == boolean.class) {
command = command.then(CommandManager.literal(this.entry.getName()).executes(ctx -> getValue(ctx.getSource())).then( for (int i = 0; i < 2; i++) {
CommandManager.literal("true") command = command.then(CommandManager.literal(this.entry.getName()).executes(ctx -> getValue(ctx.getSource())).then(
.executes(ctx -> this.setValue(ctx.getSource(), true)) CommandManager.literal(i==0 ? "true":"false")
)); .executes(ctx -> this.setValue(ctx.getSource(), ctx.getInput().endsWith("true")))
command = command.then(CommandManager.literal(this.entry.getName()).executes(ctx -> getValue(ctx.getSource())).then( ));
CommandManager.literal("false") }
.executes(ctx -> this.setValue(ctx.getSource(), false))
));
} }
else if (entry.getType().isEnum()) { else if (entry.getType().isEnum()) {
for (int i = 0; i < entry.getType().getEnumConstants().length; ++i) { for (int i = 0; i < entry.getType().getEnumConstants().length; ++i) {
@@ -63,16 +60,28 @@ public class AutoCommand {
)); ));
} }
} }
else else if (entry.getType() == List.class) {
for (int i = 0; i < 2; i++) {
int finalI = i;
command = command.then(CommandManager.literal(this.entry.getName()).executes(ctx -> getValue(ctx.getSource())).then(CommandManager.literal(i==0 ? "add":"remove").then(
CommandManager.argument("value", StringArgumentType.string())
.executes(ctx -> this.setList(ctx.getSource(), StringArgumentType.getString(ctx, "value"), finalI==0))
)));
}
}
else {
command = command.then(CommandManager.literal(this.entry.getName()).executes(ctx -> getValue(ctx.getSource())).then( command = command.then(CommandManager.literal(this.entry.getName()).executes(ctx -> getValue(ctx.getSource())).then(
CommandManager.argument("value", StringArgumentType.string()) CommandManager.argument("value", StringArgumentType.string())
.executes(ctx -> this.setValue(ctx.getSource(), StringArgumentType.getString(ctx, "value"))) .executes(ctx -> this.setValue(ctx.getSource(), StringArgumentType.getString(ctx, "value")))
)); ));
} }
LiteralArgumentBuilder<ServerCommandSource> finalized = CommandManager.literal("midnightconfig").requires(source -> source.hasPermissionLevel(2)).then(command);
PlatformFunctions.registerCommand(finalized); commands.add(finalized);
}
private int setValue(ServerCommandSource source, Object value) { private int setValue(ServerCommandSource source, Object value) {
try { try {
entry.set(null,value); if (entry.getType() != List.class) entry.set(null,value);
MidnightConfig.write(modid); MidnightConfig.write(modid);
} }
catch (Exception e) { catch (Exception e) {
@@ -80,15 +89,29 @@ public class AutoCommand {
return 0; return 0;
} }
source.sendFeedback(Text.literal("Successfully set " + entry.getName()+" to "+value), true); source.sendFeedback(() -> Text.literal("Successfully set " + entry.getName()+" to "+value), true);
return 1;
}
private int setList(ServerCommandSource source, String value, boolean add) {
try {
List<String> e = (List<String>)entry.get(null);
if (add) e.add(value);
else if (!e.contains(value)) throw new IllegalArgumentException("List does not contain this string!");
else e.remove(value);
MidnightConfig.write(modid);
}
catch (Exception e) {
source.sendError(Text.literal((add ? "Could not add "+value+" to " : "Could not remove "+value+" from ")+entry.getName() +": " + e));
return 0;
}
source.sendFeedback(() -> Text.literal((add ? "Successfully added " +value+" to " : "Successfully removed " +value+" from ") +entry.getName()), true);
return 1; return 1;
} }
private int getValue(ServerCommandSource source) { private int getValue(ServerCommandSource source) {
try { source.sendFeedback(() -> {
source.sendFeedback(Text.literal("The value of "+entry.getName()+" is "+entry.get(null)), false); try {return Text.literal("The value of "+entry.getName()+" is "+entry.get(null));
return 1; } catch (IllegalAccessException e) {throw new RuntimeException(e);}
} }, true);
catch (IllegalAccessException ignored) {}
return 0; return 0;
} }
} }

View File

@@ -1,26 +1,32 @@
package eu.midnightdust.lib.config; package eu.midnightdust.lib.config;
import com.google.common.collect.Lists;
import com.google.gson.ExclusionStrategy; import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes; import com.google.gson.FieldAttributes;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.mojang.blaze3d.systems.RenderSystem;
import eu.midnightdust.lib.util.PlatformFunctions; import eu.midnightdust.lib.util.PlatformFunctions;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.Selectable; import net.minecraft.client.gui.Selectable;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.tab.GridScreenTab;
import net.minecraft.client.gui.tab.Tab;
import net.minecraft.client.gui.tab.TabManager;
import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.tooltip.Tooltip;
import net.minecraft.client.gui.widget.*; import net.minecraft.client.gui.widget.*;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.ScreenTexts; import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.OrderedText;
import net.minecraft.text.Style; import net.minecraft.text.Style;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import java.awt.Color; import java.awt.Color;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
@@ -38,27 +44,25 @@ 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 v2.4.0 by TeamMidnightDust & Motschen /** MidnightConfig v2.5.1 by TeamMidnightDust & Motschen
* Single class config library - feel free to copy! * Single class config library - feel free to copy!
* Based on <a href="https://github.com/Minenash/TinyConfig">...</a>
* Based on https://github.com/Minenash/TinyConfig
* Credits to Minenash */ * Credits to Minenash */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
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+|\\.)");
private static final Pattern HEXADECIMAL_ONLY = Pattern.compile("(-?[#0-9a-fA-F]*)"); private static final Pattern HEXADECIMAL_ONLY = Pattern.compile("(-?[#0-9a-fA-F]*)");
private static final List<EntryInfo> entries = new ArrayList<>(); private static final List<EntryInfo> entries = new ArrayList<>();
protected static class EntryInfo { public static class EntryInfo {
Field field; Field field;
Object widget; Object widget;
int width; int width;
int max;
boolean centered; boolean centered;
Map.Entry<TextFieldWidget,Text> error; Text error;
Object defaultValue; Object defaultValue;
Object value; Object value;
String tempValue; String tempValue;
@@ -67,21 +71,22 @@ public abstract class MidnightConfig {
Text name; Text name;
int index; int index;
ClickableWidget colorButton; ClickableWidget colorButton;
Tab tab;
} }
public static final Map<String,Class<?>> configClass = new HashMap<>(); public static final Map<String, Class<? extends MidnightConfig>> configClass = new HashMap<>();
private static Path path; private static Path path;
private static final Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).excludeFieldsWithModifiers(Modifier.PRIVATE).addSerializationExclusionStrategy(new HiddenAnnotationExclusionStrategy()).setPrettyPrinting().create(); private static final Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).excludeFieldsWithModifiers(Modifier.PRIVATE).addSerializationExclusionStrategy(new HiddenAnnotationExclusionStrategy()).setPrettyPrinting().create();
public static void init(String modid, Class<?> config) { public static void init(String modid, Class<? extends MidnightConfig> config) {
path = PlatformFunctions.getConfigDirectory().resolve(modid + ".json"); path = PlatformFunctions.getConfigDirectory().resolve(modid + ".json");
configClass.put(modid, config); configClass.put(modid, config);
for (Field field : config.getFields()) { for (Field field : config.getFields()) {
EntryInfo info = new EntryInfo(); EntryInfo info = new EntryInfo();
if ((field.isAnnotationPresent(Entry.class) || field.isAnnotationPresent(Comment.class)) && !field.isAnnotationPresent(Server.class) && !field.isAnnotationPresent(Hidden.class)) if ((field.isAnnotationPresent(Entry.class) || field.isAnnotationPresent(Comment.class)) && !field.isAnnotationPresent(Server.class) && !field.isAnnotationPresent(Hidden.class) && PlatformFunctions.isClientEnv())
if (PlatformFunctions.isClientEnv()) initClient(modid, field, info); initClient(modid, field, info);
if (field.isAnnotationPresent(Comment.class)) info.centered = field.getAnnotation(Comment.class).centered(); if (field.isAnnotationPresent(Comment.class)) info.centered = field.getAnnotation(Comment.class).centered();
if (field.isAnnotationPresent(Entry.class)) if (field.isAnnotationPresent(Entry.class))
try { try {
@@ -108,14 +113,12 @@ public abstract class MidnightConfig {
info.id = modid; info.id = modid;
if (e != null) { if (e != null) {
if (!e.name().equals("")) info.name = Text.translatable(e.name()); if (!e.name().isEmpty()) info.name = Text.translatable(e.name());
if (type == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, (int) e.min(), (int) e.max(), true); if (type == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, (int) e.min(), (int) e.max(), true);
else if (type == float.class) textField(info, Float::parseFloat, DECIMAL_ONLY, (float) e.min(), (float) e.max(), false); else if (type == float.class) textField(info, Float::parseFloat, DECIMAL_ONLY, (float) e.min(), (float) e.max(), false);
else if (type == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(), false); else if (type == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(), false);
else if (type == String.class || type == List.class) { else if (type == String.class || type == List.class) textField(info, String::length, null, Math.min(e.min(), 0), Math.max(e.max(), 1), true);
info.max = e.max() == Double.MAX_VALUE ? Integer.MAX_VALUE : (int) e.max(); else if (type == boolean.class) {
textField(info, String::length, null, Math.min(e.min(), 0), Math.max(e.max(), 1), true);
} else if (type == boolean.class) {
Function<Object, Text> func = value -> Text.translatable((Boolean) value ? "gui.yes" : "gui.no").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED); Function<Object, Text> func = value -> Text.translatable((Boolean) value ? "gui.yes" : "gui.no").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED);
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> { info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
info.value = !(Boolean) info.value; info.value = !(Boolean) info.value;
@@ -133,6 +136,10 @@ public abstract class MidnightConfig {
} }
entries.add(info); entries.add(info);
} }
public static Tooltip getTooltip(EntryInfo info) {
String key = info.id + ".midnightconfig."+info.field.getName()+".tooltip";
return Tooltip.of(info.error != null ? info.error : I18n.hasTranslation(key) ? Text.translatable(key) : Text.empty());
}
private static void textField(EntryInfo info, Function<String,Number> f, Pattern pattern, double min, double max, boolean cast) { private 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;
@@ -146,9 +153,10 @@ public abstract class MidnightConfig {
if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) { if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) {
try { value = f.apply(s); } catch(NumberFormatException e){ return false; } try { value = f.apply(s); } catch(NumberFormatException e){ return false; }
inLimits = value.doubleValue() >= min && value.doubleValue() <= max; inLimits = value.doubleValue() >= min && value.doubleValue() <= max;
info.error = inLimits? null : new AbstractMap.SimpleEntry<>(t, Text.literal(value.doubleValue() < min ? info.error = inLimits? null : Text.literal(value.doubleValue() < min ?
"§cMinimum " + (isNumber? "value" : "length") + (cast? " is " + (int)min : " is " + min) : "§cMinimum " + (isNumber? "value" : "length") + (cast? " is " + (int)min : " is " + min) :
"§cMaximum " + (isNumber? "value" : "length") + (cast? " is " + (int)max : " is " + max))); "§cMaximum " + (isNumber? "value" : "length") + (cast? " is " + (int)max : " is " + max)).formatted(Formatting.RED);
t.setTooltip(getTooltip(info));
} }
info.tempValue = s; info.tempValue = s;
@@ -160,7 +168,7 @@ public abstract class MidnightConfig {
info.value = isNumber? value : s; info.value = isNumber? value : s;
else if (inLimits) { else if (inLimits) {
if (((List<String>) info.value).size() == info.index) ((List<String>) info.value).add(""); if (((List<String>) info.value).size() == info.index) ((List<String>) info.value).add("");
((List<String>) info.value).set(info.index, Arrays.stream(info.tempValue.replace("[", "").replace("]", "").split(", ")).toList().get(0)); ((List<String>) info.value).set(info.index, Arrays.stream(info.tempValue.replace("[", "").replace("]", "").split(", ")).toList().getFirst());
} }
if (info.field.getAnnotation(Entry.class).isColor()) { if (info.field.getAnnotation(Entry.class).isColor()) {
@@ -173,14 +181,20 @@ public abstract class MidnightConfig {
return true; return true;
}; };
} }
public static MidnightConfig getClass(String modid) {
try { return configClass.get(modid).getDeclaredConstructor().newInstance(); } catch (Exception e) {throw new RuntimeException(e);}
}
public static void write(String modid) { public static void write(String modid) {
getClass(modid).writeChanges(modid);
}
public void writeChanges(String modid) {
path = PlatformFunctions.getConfigDirectory().resolve(modid + ".json"); path = PlatformFunctions.getConfigDirectory().resolve(modid + ".json");
try { try {
if (!Files.exists(path)) Files.createFile(path); if (!Files.exists(path)) Files.createFile(path);
Files.write(path, gson.toJson(configClass.get(modid).getDeclaredConstructor().newInstance()).getBytes()); Files.write(path, gson.toJson(getClass(modid)).getBytes());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.fillInStackTrace();
} }
} }
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
@@ -194,17 +208,49 @@ public abstract class MidnightConfig {
this.parent = parent; this.parent = parent;
this.modid = modid; this.modid = modid;
this.translationPrefix = modid + ".midnightconfig."; this.translationPrefix = modid + ".midnightconfig.";
loadValues();
for (EntryInfo e : entries) {
if (e.id.equals(modid)) {
String tabId = e.field.isAnnotationPresent(Entry.class) ? e.field.getAnnotation(Entry.class).category() : e.field.getAnnotation(Comment.class).category();
String name = translationPrefix + "category." + tabId;
if (!I18n.hasTranslation(name) && tabId.equals("default"))
name = translationPrefix + "title";
if (!tabs.containsKey(name)) {
Tab tab = new GridScreenTab(Text.translatable(name));
e.tab = tab;
tabs.put(name, tab);
} else e.tab = tabs.get(name);
}
}
tabNavigation = TabNavigationWidget.builder(tabManager, this.width).tabs(tabs.values().toArray(new Tab[0])).build();
tabNavigation.selectTab(0, false);
tabNavigation.init();
prevTab = tabManager.getCurrentTab();
} }
public final String translationPrefix; public final String translationPrefix;
public final Screen parent; public final Screen parent;
public final String modid; public final String modid;
public MidnightConfigListWidget list; public MidnightConfigListWidget list;
public boolean reload = false; public boolean reload = false;
public TabManager tabManager = new TabManager(a -> {}, a -> {});
public Map<String, Tab> tabs = new HashMap<>();
public Tab prevTab;
public TabNavigationWidget tabNavigation;
public ButtonWidget done;
public double scrollProgress = 0d;
// Real Time config update // // Real Time config update //
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
if (prevTab != null && prevTab != tabManager.getCurrentTab()) {
prevTab = tabManager.getCurrentTab();
this.list.clear();
fillList();
list.setScrollAmount(0);
}
scrollProgress = list.getScrollAmount();
for (EntryInfo info : entries) { for (EntryInfo info : entries) {
try {info.field.set(null, info.value);} catch (IllegalAccessException ignored) {} try {info.field.set(null, info.value);} catch (IllegalAccessException ignored) {}
} }
@@ -231,20 +277,23 @@ public abstract class MidnightConfig {
} catch (IllegalAccessException ignored) {} } catch (IllegalAccessException ignored) {}
} }
} }
public Tooltip getTooltip(EntryInfo info) { @Override
return Tooltip.of(I18n.hasTranslation(translationPrefix+info.field.getName()+".tooltip") ? Text.translatable(translationPrefix+info.field.getName()+".tooltip") : Text.empty()); public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (this.tabNavigation.trySwitchTabsWithKey(keyCode)) return true;
return super.keyPressed(keyCode, scanCode, modifiers);
} }
@Override @Override
public void init() { public void init() {
super.init(); super.init();
if (!reload) loadValues(); tabNavigation.setWidth(this.width);
tabNavigation.init();
if (tabs.size() > 1) this.addDrawableChild(tabNavigation);
this.addDrawableChild(ButtonWidget.builder(ScreenTexts.CANCEL, button -> { this.addDrawableChild(ButtonWidget.builder(ScreenTexts.CANCEL, button -> {
loadValues(); loadValues();
Objects.requireNonNull(client).setScreen(parent); Objects.requireNonNull(client).setScreen(parent);
}).dimensions(this.width / 2 - 154, this.height - 28, 150, 20).build()); }).dimensions(this.width / 2 - 154, this.height - 26, 150, 20).build());
done = this.addDrawableChild(ButtonWidget.builder(ScreenTexts.DONE, (button) -> {
ButtonWidget done = this.addDrawableChild(ButtonWidget.builder(ScreenTexts.DONE, (button) -> {
for (EntryInfo info : entries) for (EntryInfo info : entries)
if (info.id.equals(modid)) { if (info.id.equals(modid)) {
try { try {
@@ -253,53 +302,57 @@ public abstract class MidnightConfig {
} }
write(modid); write(modid);
Objects.requireNonNull(client).setScreen(parent); Objects.requireNonNull(client).setScreen(parent);
}).dimensions(this.width / 2 + 4, this.height - 28, 150, 20).build()); }).dimensions(this.width / 2 + 4, this.height - 26, 150, 20).build());
this.list = new MidnightConfigListWidget(this.client, this.width, this.height, 32, this.height - 32, 25); this.list = new MidnightConfigListWidget(this.client, this.width, this.height - 57, 24, 25);
if (this.client != null && this.client.world != null) this.list.setRenderBackground(false);
this.addSelectableChild(this.list); this.addSelectableChild(this.list);
fillList();
reload = true;
}
public void fillList() {
for (EntryInfo info : entries) { for (EntryInfo info : entries) {
if (info.id.equals(modid)) { if (info.id.equals(modid) && (info.tab == null || info.tab == tabManager.getCurrentTab())) {
Text name = Objects.requireNonNullElseGet(info.name, () -> Text.translatable(translationPrefix + info.field.getName())); Text name = Objects.requireNonNullElseGet(info.name, () -> Text.translatable(translationPrefix + info.field.getName()));
ButtonWidget resetButton = ButtonWidget.builder(Text.literal("Reset").formatted(Formatting.RED), (button -> { TextIconButtonWidget resetButton = TextIconButtonWidget.builder(Text.translatable("controls.reset"), (button -> {
info.value = info.defaultValue; info.value = info.defaultValue;
info.tempValue = info.defaultValue.toString(); info.tempValue = info.defaultValue.toString();
info.index = 0; info.index = 0;
double scrollAmount = list.getScrollAmount(); list.clear();
this.reload = true; fillList();
Objects.requireNonNull(client).setScreen(this); }), true).texture(new Identifier("midnightlib","icon/reset"), 12, 12).dimension(40, 20).build();
list.setScrollAmount(scrollAmount); resetButton.setPosition(width - 205, 0);
})).dimensions(width - 205, 0, 40, 20).build();
if (info.widget instanceof Map.Entry) { if (info.widget instanceof Map.Entry) {
Map.Entry<ButtonWidget.PressAction, Function<Object, Text>> widget = (Map.Entry<ButtonWidget.PressAction, Function<Object, Text>>) info.widget; Map.Entry<ButtonWidget.PressAction, Function<Object, Text>> widget = (Map.Entry<ButtonWidget.PressAction, Function<Object, Text>>) info.widget;
if (info.field.getType().isEnum()) widget.setValue(value -> Text.translatable(translationPrefix + "enum." + info.field.getType().getSimpleName() + "." + info.value.toString())); if (info.field.getType().isEnum())
this.list.addButton(List.of(ButtonWidget.builder(widget.getValue().apply(info.value), widget.getKey()).dimensions(width - 160, 0,150, 20).tooltip(getTooltip(info)).build(),resetButton), name, info); widget.setValue(value -> Text.translatable(translationPrefix + "enum." + info.field.getType().getSimpleName() + "." + info.value.toString()));
this.list.addButton(List.of(ButtonWidget.builder(widget.getValue().apply(info.value), widget.getKey()).dimensions(width - 160, 0, 150, 20).tooltip(getTooltip(info)).build(), resetButton), name, info);
} else if (info.field.getType() == List.class) { } else if (info.field.getType() == List.class) {
if (!reload) info.index = 0; if (!reload) info.index = 0;
TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 160, 0, 150, 20, Text.empty()); TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 160, 0, 150, 20, Text.empty());
widget.setMaxLength(info.width); widget.setMaxLength(info.width);
if (info.index < ((List<String>)info.value).size()) widget.setText((String.valueOf(((List<String>)info.value).get(info.index)))); if (info.index < ((List<String>) info.value).size())
widget.setText((String.valueOf(((List<String>) info.value).get(info.index))));
Predicate<String> processor = ((BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) info.widget).apply(widget, done); Predicate<String> processor = ((BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) info.widget).apply(widget, done);
widget.setTextPredicate(processor); widget.setTextPredicate(processor);
resetButton.setWidth(20); resetButton.setWidth(20);
resetButton.setMessage(Text.literal("R").formatted(Formatting.RED));
ButtonWidget cycleButton = ButtonWidget.builder(Text.literal(String.valueOf(info.index)).formatted(Formatting.GOLD), (button -> { ButtonWidget cycleButton = ButtonWidget.builder(Text.literal(String.valueOf(info.index)).formatted(Formatting.GOLD), (button -> {
((List<String>)info.value).remove(""); if (((List<?>) info.value).contains("")) ((List<String>) info.value).remove("");
double scrollAmount = list.getScrollAmount();
this.reload = true;
info.index = info.index + 1; info.index = info.index + 1;
if (info.index > ((List<String>)info.value).size()) info.index = 0; if (info.index > ((List<String>) info.value).size()) info.index = 0;
Objects.requireNonNull(client).setScreen(this); list.clear();
list.setScrollAmount(scrollAmount); fillList();
})).dimensions(width - 185, 0, 20, 20).build(); })).dimensions(width - 185, 0, 20, 20).build();
widget.setTooltip(getTooltip(info)); widget.setTooltip(getTooltip(info));
this.list.addButton(List.of(widget, resetButton, cycleButton), name, info); this.list.addButton(List.of(widget, resetButton, cycleButton), name, info);
} else if (info.widget != null) { } else if (info.widget != null) {
ClickableWidget widget; ClickableWidget widget;
Entry e = info.field.getAnnotation(Entry.class); Entry e = info.field.getAnnotation(Entry.class);
if (e.isSlider()) widget = new MidnightSliderWidget(width - 160, 0, 150, 20, Text.of(info.tempValue), (Double.parseDouble(info.tempValue)-e.min()) / (e.max() - e.min()), info); if (e.isSlider())
else widget = new TextFieldWidget(textRenderer, width - 160, 0, 150, 20, null, Text.of(info.tempValue)); widget = new MidnightSliderWidget(width - 160, 0, 150, 20, Text.of(info.tempValue), (Double.parseDouble(info.tempValue) - e.min()) / (e.max() - e.min()), info);
else
widget = new TextFieldWidget(textRenderer, width - 160, 0, 150, 20, null, Text.of(info.tempValue));
if (widget instanceof TextFieldWidget textField) { if (widget instanceof TextFieldWidget textField) {
textField.setMaxLength(info.width); textField.setMaxLength(info.width);
textField.setText(info.tempValue); textField.setText(info.tempValue);
@@ -309,82 +362,87 @@ public abstract class MidnightConfig {
widget.setTooltip(getTooltip(info)); widget.setTooltip(getTooltip(info));
if (e.isColor()) { if (e.isColor()) {
resetButton.setWidth(20); resetButton.setWidth(20);
resetButton.setMessage(Text.literal("R").formatted(Formatting.RED)); ButtonWidget colorButton = ButtonWidget.builder(Text.literal(""), (button -> {
ButtonWidget colorButton = ButtonWidget.builder(Text.literal(""), (button -> {})).dimensions(width - 185, 0, 20, 20).build(); })).dimensions(width - 185, 0, 20, 20).build();
try {colorButton.setMessage(Text.literal("").setStyle(Style.EMPTY.withColor(Color.decode(info.tempValue).getRGB())));} catch (Exception ignored) {} try {
colorButton.setMessage(Text.literal("").setStyle(Style.EMPTY.withColor(Color.decode(info.tempValue).getRGB())));
} catch (Exception ignored) {}
info.colorButton = colorButton; info.colorButton = colorButton;
colorButton.active = false; colorButton.active = false;
this.list.addButton(List.of(widget, resetButton, colorButton), name, info); this.list.addButton(List.of(widget, resetButton, colorButton), name, info);
} } else this.list.addButton(List.of(widget, resetButton), name, info);
else this.list.addButton(List.of(widget, resetButton), name, info);
} else { } else {
this.list.addButton(List.of(),name, info); this.list.addButton(List.of(), name, info);
} }
} }
list.setScrollAmount(scrollProgress);
updateResetButtons(); updateResetButtons();
} }
} }
@Override @Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { public void render(DrawContext context, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices); super.render(context,mouseX,mouseY,delta);
this.list.render(matrices, mouseX, mouseY, delta); this.list.render(context, mouseX, mouseY, delta);
drawCenteredText(matrices, textRenderer, title, width / 2, 15, 0xFFFFFF);
super.render(matrices,mouseX,mouseY,delta); if (tabs.size() < 2)
context.drawCenteredTextWithShadow(textRenderer, title, width / 2, 10, 0xFFFFFF);
list.renderHeaderSeperator = tabs.size() < 2;
} }
} }
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public static class MidnightConfigListWidget extends ElementListWidget<ButtonEntry> { public static class MidnightConfigListWidget extends ElementListWidget<ButtonEntry> {
TextRenderer textRenderer; boolean renderHeaderSeperator = true;
public MidnightConfigListWidget(MinecraftClient client, int width, int height, int y, int itemHeight) {
public MidnightConfigListWidget(MinecraftClient minecraftClient, int i, int j, int k, int l, int m) { super(client, width, height, y, itemHeight);
super(minecraftClient, i, j, k, l, m);
this.centerListVertically = false;
textRenderer = minecraftClient.textRenderer;
} }
@Override @Override
public int getScrollbarPositionX() { return this.width -7; } public int getScrollbarX() { return this.width -7; }
@Override
protected void drawHeaderAndFooterSeparators(DrawContext context) {
if (renderHeaderSeperator) super.drawHeaderAndFooterSeparators(context);
else {
RenderSystem.enableBlend();
context.drawTexture(this.client.world == null ? Screen.FOOTER_SEPARATOR_TEXTURE : Screen.INWORLD_FOOTER_SEPARATOR_TEXTURE, this.getX(), this.getBottom(), 0.0F, 0.0F, this.getWidth(), 2, 32, 2);
RenderSystem.disableBlend();
}
}
public void addButton(List<ClickableWidget> buttons, Text text, EntryInfo info) { public void addButton(List<ClickableWidget> buttons, Text text, EntryInfo info) {
this.addEntry(new ButtonEntry(buttons, text, info)); this.addEntry(new ButtonEntry(buttons, text, info));
} }
public void clear() { this.clearEntries(); }
@Override @Override
public int getRowWidth() { return 10000; } public int getRowWidth() { return 10000; }
public Optional<ClickableWidget> getHoveredButton(double mouseX, double mouseY) {
for (ButtonEntry buttonEntry : this.children()) {
if (!buttonEntry.buttons.isEmpty() && buttonEntry.buttons.get(0).isMouseOver(mouseX, mouseY)) {
return Optional.of(buttonEntry.buttons.get(0));
}
}
return Optional.empty();
}
} }
public static class ButtonEntry extends ElementListWidget.Entry<ButtonEntry> { public static class ButtonEntry extends ElementListWidget.Entry<ButtonEntry> {
private static final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; private static final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
public final List<ClickableWidget> buttons; public final List<ClickableWidget> buttons;
private final Text text; private final Text text;
public final EntryInfo info; public final EntryInfo info;
private final List<ClickableWidget> children = new ArrayList<>(); public boolean centered = false;
public static final Map<ClickableWidget, Text> buttonsWithText = new HashMap<>(); public static final Map<ClickableWidget, Text> buttonsWithText = new HashMap<>();
private ButtonEntry(List<ClickableWidget> buttons, Text text, EntryInfo info) { public ButtonEntry(List<ClickableWidget> buttons, Text text, EntryInfo info) {
if (!buttons.isEmpty()) buttonsWithText.put(buttons.get(0),text); if (!buttons.isEmpty()) buttonsWithText.put(buttons.getFirst(),text);
this.buttons = buttons; this.buttons = buttons;
this.text = text; this.text = text;
this.info = info; this.info = info;
children.addAll(buttons); if (info != null) this.centered = info.centered;
} }
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
buttons.forEach(b -> { b.setY(y); b.render(matrices, mouseX, mouseY, tickDelta); }); buttons.forEach(b -> { b.setY(y); b.render(context, mouseX, mouseY, tickDelta); });
if (text != null && (!text.getString().contains("spacer") || !buttons.isEmpty())) { if (text != null && (!text.getString().contains("spacer") || !buttons.isEmpty())) {
if (info.centered) textRenderer.drawWithShadow(matrices, text, MinecraftClient.getInstance().getWindow().getScaledWidth() / 2f - (textRenderer.getWidth(text) / 2f), y + 5, 0xFFFFFF); int wrappedY = y;
else DrawableHelper.drawTextWithShadow(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF); for(Iterator<OrderedText> textIterator = textRenderer.wrapLines(text, (buttons.size() > 1 ? buttons.get(1).getX()-24 : MinecraftClient.getInstance().getWindow().getScaledWidth() - 24)).iterator(); textIterator.hasNext(); wrappedY += 9) {
context.drawTextWithShadow(textRenderer, textIterator.next(), (centered) ? (MinecraftClient.getInstance().getWindow().getScaledWidth() / 2 - (textRenderer.getWidth(text) / 2)) : 12, wrappedY + 5, 0xFFFFFF);
}
} }
} }
public List<? extends Element> children() {return children;} public List<? extends Element> children() {return Lists.newArrayList(buttons);}
public List<? extends Selectable> selectableChildren() {return children;} public List<? extends Selectable> selectableChildren() {return Lists.newArrayList(buttons);}
} }
private static class MidnightSliderWidget extends SliderWidget { public static class MidnightSliderWidget extends SliderWidget {
private final EntryInfo info; private final Entry e; private final EntryInfo info; private final Entry e;
public MidnightSliderWidget(int x, int y, int width, int height, Text text, double value, EntryInfo info) { public MidnightSliderWidget(int x, int y, int width, int height, Text text, double value, EntryInfo info) {
super(x, y, width, height, text, value); super(x, y, width, height, text, value);
@@ -413,12 +471,14 @@ public abstract class MidnightConfig {
boolean isColor() default false; boolean isColor() default false;
boolean isSlider() default false; boolean isSlider() default false;
int precision() default 100; int precision() default 100;
String category() default "default";
} }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Client {} @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Client {}
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Server {} @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Server {}
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Hidden {} @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Hidden {}
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Comment { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Comment {
boolean centered() default false; boolean centered() default false;
String category() default "default";
} }
public static class HiddenAnnotationExclusionStrategy implements ExclusionStrategy { public static class HiddenAnnotationExclusionStrategy implements ExclusionStrategy {

View File

@@ -3,12 +3,6 @@ package eu.midnightdust.lib.util;
import java.awt.Color; import java.awt.Color;
public class MidnightColorUtil { public class MidnightColorUtil {
public static float hue;
public static void tick() {
if (hue > 1) hue = 0f;
hue = hue + 0.01f;
}
/** /**
* @param colorStr e.g. "FFFFFF" or "#FFFFFF" * @param colorStr e.g. "FFFFFF" or "#FFFFFF"
* @return Color as RGB * @return Color as RGB
@@ -19,8 +13,4 @@ public class MidnightColorUtil {
} catch (Exception ignored) {} } catch (Exception ignored) {}
return Color.BLACK; return Color.BLACK;
} }
public static Color radialRainbow(float saturation, float brightness) {
return Color.getHSBColor(hue, saturation, brightness);
}
} }

View File

@@ -1,7 +0,0 @@
package eu.midnightdust.lib.util;
public class MidnightMathUtil {
public static boolean isEven(int i) {
return (i | 1) > i;
}
}

View File

@@ -1,42 +0,0 @@
package eu.midnightdust.lib.util.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.widget.TexturedButtonWidget;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public class TexturedOverlayButtonWidget extends TexturedButtonWidget {
public TexturedOverlayButtonWidget(int x, int y, int width, int height, int u, int v, Identifier texture, PressAction pressAction) {
super(x, y, width, height, u, v, texture, pressAction);
}
public TexturedOverlayButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, Identifier texture, PressAction pressAction) {
super(x, y, width, height, u, v, hoveredVOffset, texture, pressAction);
}
public TexturedOverlayButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, Identifier texture, int textureWidth, int textureHeight, PressAction pressAction) {
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction);
}
public TexturedOverlayButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, Identifier texture, int textureWidth, int textureHeight, PressAction pressAction, Text text) {
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, text);
}
@Override
public void renderButton(MatrixStack matrices, int mouseX, int mouseY, float delta) {
RenderSystem.setShader(GameRenderer::getPositionTexProgram);
RenderSystem.setShaderTexture(0, WIDGETS_TEXTURE);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha);
int i = this.getYImage(this.isHovered());
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.enableDepthTest();
this.drawTexture(matrices, this.getX(), this.getY(), 0, 46 + i * 20, this.width / 2, this.height);
this.drawTexture(matrices, this.getX() + this.width / 2, this.getY(), 200 - this.width / 2, 46 + i * 20, this.width / 2, this.height);
super.renderButton(matrices, mouseX, mouseY, delta);
}
}

View File

@@ -1,11 +1,7 @@
{ {
"midnightlib.overview.title":"MidnightConfig Übersicht", "midnightlib.overview.title":"MidnightConfig Übersicht",
"midnightlib.midnightconfig.title":"MidnightLib Konfiguration", "midnightlib.midnightconfig.title":"MidnightLib Konfiguration",
"midnightlib.midnightconfig.midnightlib_description":"§nMidnightLib",
"midnightlib.midnightconfig.config_screen_list":"Konfigurationsübersicht", "midnightlib.midnightconfig.config_screen_list":"Konfigurationsübersicht",
"midnightlib.midnightconfig.background_texture":"Textur der Konfigurationsbildschirme", "modmenu.descriptionTranslation.midnightlib": "Code-Bibliothek für einfache Konfiguration.\nStellt eine Konfigurationsschnittstelle, automatische Kompatibilität und oft genutzten Code bereit.",
"midnightlib.midnightconfig.midnighthats_description":"§nMidnightHats", "modmenu.summaryTranslation.midnightlib": "Code-Bibliothek für einfache Konfiguration."
"midnightlib.midnightconfig.special_hats":"Unterstützer-Hüte",
"modmenu.descriptionTranslation.midnightlib": "Code-Bibliothek für Mods von MidnightDust.\nStellt eine Konfigurationsschnittstelle, automatische Kompatibilität, oft genutzten Code und Hüte für Unterstützer bereit.",
"modmenu.summaryTranslation.midnightlib": "Code-Bibliothek für Mods von MidnightDust."
} }

View File

@@ -1,17 +1,13 @@
{ {
"midnightlib.overview.title":"MidnightConfig Overview", "midnightlib.overview.title":"MidnightConfig Overview",
"midnightlib.midnightconfig.title":"MidnightLib Config", "midnightlib.midnightconfig.title":"MidnightLib Config",
"midnightlib.midnightconfig.midnightlib_description":"§nMidnightLib",
"midnightlib.midnightconfig.config_screen_list":"Enable Config Screen List", "midnightlib.midnightconfig.config_screen_list":"Enable Config Screen List",
"midnightlib.midnightconfig.enum.ConfigButton.TRUE":"§aYes", "midnightlib.midnightconfig.enum.ConfigButton.TRUE":"§aYes",
"midnightlib.midnightconfig.enum.ConfigButton.FALSE":"§cNo", "midnightlib.midnightconfig.enum.ConfigButton.FALSE":"§cNo",
"midnightlib.midnightconfig.enum.ConfigButton.MODMENU":"§bModMenu", "midnightlib.midnightconfig.enum.ConfigButton.MODMENU":"§bModMenu",
"midnightlib.midnightconfig.background_texture":"Texture of config screen backgrounds",
"midnightlib.midnightconfig.midnighthats_description":"§nMidnightHats",
"midnightlib.midnightconfig.special_hats":"Enable Supporter Hats",
"midnightlib.modrinth":"Modrinth", "midnightlib.modrinth":"Modrinth",
"midnightlib.curseforge":"CurseForge", "midnightlib.curseforge":"CurseForge",
"midnightlib.wiki":"Wiki", "midnightlib.wiki":"Wiki",
"modmenu.descriptionTranslation.midnightlib": "Common Library for Team MidnightDust's mods.\nProvides a config api, automatic integration with other mods, common utils, and cosmetics.", "modmenu.descriptionTranslation.midnightlib": "Common Library for easy configuration.\nProvides a config api, automatic integration with other mods and common utils.",
"modmenu.summaryTranslation.midnightlib": "Common Library for Team MidnightDust's mods." "modmenu.summaryTranslation.midnightlib": "Common Library for easy configuration."
} }

View File

@@ -0,0 +1,9 @@
{
"midnightlib.overview.title":"Vue d'ensemble de MidnightConfig",
"midnightlib.midnightconfig.title":"Configuration de MidnightLib",
"midnightlib.midnightconfig.config_screen_list":"Activer la liste de l'écran de configuration",
"midnightlib.midnightconfig.enum.ConfigButton.TRUE":"§aOui",
"midnightlib.midnightconfig.enum.ConfigButton.FALSE":"§cNon",
"modmenu.descriptionTranslation.midnightlib": "Bibliothèque commune pour les mods de la Team MidnightDust.\nFournit une API de configuration, une intégration automatique avec d'autres mods et des utilitaires courants.",
"modmenu.summaryTranslation.midnightlib": "Bibliothèque commune pour les mods de la Team MidnightDust."
}

View File

@@ -1,17 +1,9 @@
{ {
"midnightlib.overview.title":"Visão geral do MidnightConfig", "midnightlib.overview.title":"Visão geral do MidnightConfig",
"midnightlib.midnightconfig.title":"Configuração MidnightLib", "midnightlib.midnightconfig.title":"Configuração MidnightLib",
"midnightlib.midnightconfig.midnightlib_description":"§nMidnightLib",
"midnightlib.midnightconfig.config_screen_list":"Ativar lista de telas de configuração", "midnightlib.midnightconfig.config_screen_list":"Ativar lista de telas de configuração",
"midnightlib.midnightconfig.enum.ConfigButton.TRUE":"§aVerdadeiro", "midnightlib.midnightconfig.enum.ConfigButton.TRUE":"§aVerdadeiro",
"midnightlib.midnightconfig.enum.ConfigButton.FALSE":"§cFalso", "midnightlib.midnightconfig.enum.ConfigButton.FALSE":"§cFalso",
"midnightlib.midnightconfig.enum.ConfigButton.MODMENU":"§bModMenu", "modmenu.descriptionTranslation.midnightlib": "Biblioteca comum para mods do Team MidnightDust.\nFornece uma API de configuração, integração automática com outros mods e utilitários comuns.",
"midnightlib.midnightconfig.background_texture":"Textura dos fundos da tela de configuração",
"midnightlib.midnightconfig.midnighthats_description":"§nMidnightHats",
"midnightlib.midnightconfig.special_hats":"Ativar chapéus de torcedor",
"midnightlib.modrinth":"Modrinth",
"midnightlib.curseforge":"CurseForge",
"midnightlib.wiki":"Wiki",
"modmenu.descriptionTranslation.midnightlib": "Biblioteca comum para mods do Team MidnightDust.\nFornece uma API de configuração, integração automática com outros mods, utilitários comuns e cosméticos.",
"modmenu.summaryTranslation.midnightlib": "Biblioteca comum para mods do Team MidnightDust." "modmenu.summaryTranslation.midnightlib": "Biblioteca comum para mods do Team MidnightDust."
} }

View File

@@ -0,0 +1,10 @@
{
"midnightlib.overview.title":"MidnightConfig күзәтү",
"midnightlib.midnightconfig.title":"MidnightLib көйләүләре",
"midnightlib.midnightconfig.config_screen_list":"Көйләүләр экранының исемлеген кушу",
"midnightlib.midnightconfig.enum.ConfigButton.TRUE":"§aӘйе",
"midnightlib.midnightconfig.enum.ConfigButton.FALSE":"§cЮк",
"midnightlib.wiki":"Вики",
"modmenu.descriptionTranslation.midnightlib": "MidnightDust төркеменең модлары өчен гомуми китапханә.\nКөйләүләр API-ын, башка модлар белән автоматик интеграцияне, гомуми хезмәти программаларны һәм бизәнүләрне тәэмин ителә.",
"modmenu.summaryTranslation.midnightlib": "MidnightDust төркеменең модлары өчен гомуми китапханә."
}

View File

@@ -1,16 +1,7 @@
{ {
"midnightlib.overview.title":"Огляд MidnightConfig", "midnightlib.overview.title":"Огляд MidnightConfig",
"midnightlib.midnightconfig.title":"Конфігурація MidnightLib", "midnightlib.midnightconfig.title":"Конфігурація MidnightLib",
"midnightlib.midnightconfig.midnightlib_description":"§nMidnightLib",
"midnightlib.midnightconfig.config_screen_list":"Увімкнути список екрана конфігурації", "midnightlib.midnightconfig.config_screen_list":"Увімкнути список екрана конфігурації",
"midnightlib.midnightconfig.enum.ConfigButton.TRUE":"§aTrue",
"midnightlib.midnightconfig.enum.ConfigButton.FALSE":"§cFalse",
"midnightlib.midnightconfig.enum.ConfigButton.MODMENU":"§bModMenu",
"midnightlib.midnightconfig.background_texture":"Текстура фону екрана конфігурації",
"midnightlib.midnightconfig.midnighthats_description":"§nMidnightHats",
"midnightlib.midnightconfig.special_hats":"Увімкнути капелюхи спонсорів",
"midnightlib.modrinth":"Modrinth",
"midnightlib.curseforge":"CurseForge",
"midnightlib.wiki":"Вікі", "midnightlib.wiki":"Вікі",
"modmenu.descriptionTranslation.midnightlib": "Загальна бібліотека для модів команди MidnightDust.\nНадає конфігураційний API, автоматичну інтеграцію з іншими модами, загальні утиліти та косметику.", "modmenu.descriptionTranslation.midnightlib": "Загальна бібліотека для модів команди MidnightDust.\nНадає конфігураційний API, автоматичну інтеграцію з іншими модами, загальні утиліти та косметику.",
"modmenu.summaryTranslation.midnightlib": "Загальна бібліотека для модів команди MidnightDust." "modmenu.summaryTranslation.midnightlib": "Загальна бібліотека для модів команди MidnightDust."

View File

@@ -0,0 +1,11 @@
{
"midnightlib.overview.title":"MidnightConfig 概述",
"midnightlib.midnightconfig.title":"MidnightLib 設定",
"midnightlib.midnightconfig.config_screen_list":"啟用設定畫面列表",
"midnightlib.midnightconfig.enum.ConfigButton.TRUE":"§a是",
"midnightlib.midnightconfig.enum.ConfigButton.FALSE":"§c否",
"midnightlib.midnightconfig.enum.ConfigButton.MODMENU":"§b模組選單",
"midnightlib.wiki":"維基",
"modmenu.descriptionTranslation.midnightlib": "MidnightDust 團隊的常用程式庫模組。\n提供設定 API、與其他模組自動整合、常用工具和美觀。",
"modmenu.summaryTranslation.midnightlib": "MidnightDust 團隊的常用程式庫模組。"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 B

View File

@@ -1,13 +1 @@
{ {"required": true,"minVersion": "0.8","package": "eu.midnightdust.core.mixin","compatibilityLevel": "JAVA_17","client": ["MixinOptionsScreen"],"injectors": {"defaultRequire": 1}}
"required": true,
"minVersion": "0.8",
"package": "eu.midnightdust.core.mixin",
"compatibilityLevel": "JAVA_17",
"client": [
"MixinOptionsScreen",
"MixinPlayerEntityRenderer"
],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -11,9 +11,7 @@ loom {
dependencies { dependencies {
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
// Remove the next line if you don't want to depend on the API
modApi "dev.architectury:architectury-fabric:${rootProject.architectury_version}"
modImplementation ("com.terraformersmc:modmenu:${rootProject.mod_menu_version}") modImplementation ("com.terraformersmc:modmenu:${rootProject.mod_menu_version}")
compileClasspath(project(path: ":common", configuration: "namedElements")) { transitive false } compileOnly(project(path: ":common", configuration: "namedElements")) { transitive false }
} }

View File

@@ -2,7 +2,7 @@ package eu.midnightdust.lib.config;
import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi; import com.terraformersmc.modmenu.api.ModMenuApi;
import eu.midnightdust.core.MidnightLibClient; import eu.midnightdust.core.MidnightLib;
import eu.midnightdust.core.config.MidnightLibConfig; import eu.midnightdust.core.config.MidnightLibConfig;
import java.util.HashMap; import java.util.HashMap;
@@ -19,7 +19,7 @@ public class AutoModMenu implements ModMenuApi {
public Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() { public Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() {
HashMap<String, ConfigScreenFactory<?>> map = new HashMap<>(); HashMap<String, ConfigScreenFactory<?>> map = new HashMap<>();
MidnightConfig.configClass.forEach((modid, cClass) -> { MidnightConfig.configClass.forEach((modid, cClass) -> {
if (!MidnightLibClient.hiddenMods.contains(modid)) if (!MidnightLib.hiddenMods.contains(modid))
map.put(modid, parent -> MidnightConfig.getScreen(parent, modid)); map.put(modid, parent -> MidnightConfig.getScreen(parent, modid));
} }
); );

View File

@@ -1,5 +1,9 @@
plugins { plugins {
id "com.github.johnrengelman.shadow" version "7.1.2" id "com.github.johnrengelman.shadow" version "7.1.2"
id "me.shedaniel.unified-publishing"
}
repositories {
maven { url "https://maven.terraformersmc.com/releases" }
} }
architectury { architectury {
@@ -12,7 +16,7 @@ loom {
configurations { configurations {
common common
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this. shadowCommon // Don't use shadow from the shadow plugin since it *excludes* files.
compileClasspath.extendsFrom common compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common runtimeClasspath.extendsFrom common
developmentFabric.extendsFrom common developmentFabric.extendsFrom common
@@ -22,11 +26,10 @@ configurations {
dependencies { dependencies {
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
modCompileOnly ("com.terraformersmc:modmenu:${rootProject.mod_menu_version}")
common(project(path: ":common", configuration: "namedElements")) { transitive false } common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false } shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false }
common(project(path: ":fabric-like", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":fabric-like", configuration: "transformProductionFabric")) { transitive false }
} }
processResources { processResources {
@@ -41,17 +44,12 @@ shadowJar {
exclude "architectury.common.json" exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon] configurations = [project.configurations.shadowCommon]
classifier "dev-shadow" archiveClassifier = "dev-shadow"
} }
remapJar { remapJar {
input.set shadowJar.archiveFile input.set shadowJar.archiveFile
dependsOn shadowJar dependsOn shadowJar
classifier null
}
jar {
classifier "dev"
} }
sourcesJar { sourcesJar {
@@ -66,16 +64,38 @@ components.java {
} }
} }
publishing { unifiedPublishing {
publications { project {
mavenFabric(MavenPublication) { displayName = "MidnightLib v$project.version - Fabric $project.minecraft_version"
artifactId = rootProject.archives_base_name + "-" + project.name releaseType = "$project.release_type"
from components.java changelog = releaseChangelog()
gameVersions = []
gameLoaders = ["fabric","quilt"]
mainPublication remapJar
relations {
depends {
curseforge = "fabric-api"
modrinth = "fabric-api"
}
}
var CURSEFORGE_TOKEN = project.findProperty("CURSEFORGE_TOKEN") ?: System.getenv("CURSEFORGE_TOKEN")
if (CURSEFORGE_TOKEN != null) {
curseforge {
token = CURSEFORGE_TOKEN
id = rootProject.curseforge_id
gameVersions.addAll "Java 21", project.minecraft_version
}
}
var MODRINTH_TOKEN = project.findProperty("MODRINTH_TOKEN") ?: System.getenv("MODRINTH_TOKEN")
if (MODRINTH_TOKEN != null) {
modrinth {
token = MODRINTH_TOKEN
id = rootProject.modrinth_id
version = "$project.version-$project.name"
gameVersions.addAll project.minecraft_version
}
} }
} }
}
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
repositories {
// Add repositories to publish to here.
}
}

View File

@@ -1,19 +0,0 @@
package eu.midnightdust.fabric.core;
import eu.midnightdust.core.MidnightLibClient;
import eu.midnightdust.hats.witch.WitchHatFeatureRenderer;
import eu.midnightdust.lib.util.MidnightColorUtil;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry;
public class MidnightLibClientFabric implements ClientModInitializer {
@Override
public void onInitializeClient() {
EntityModelLayerRegistry.registerModelLayer(WitchHatFeatureRenderer.WITCH_HAT_MODEL_LAYER, WitchHatFeatureRenderer::getTexturedModelData);
MidnightLibClient.onInitializeClient();
ClientTickEvents.END_CLIENT_TICK.register(
client -> MidnightColorUtil.tick()
);
}
}

View File

@@ -0,0 +1,14 @@
package eu.midnightdust.fabric.core;
import eu.midnightdust.core.MidnightLib;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.DedicatedServerModInitializer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
public class MidnightLibFabric implements ClientModInitializer, DedicatedServerModInitializer {
@Override @Environment(EnvType.CLIENT)
public void onInitializeClient() {MidnightLib.onInitializeClient();}
@Override @Environment(EnvType.SERVER)
public void onInitializeServer() {MidnightLib.onInitializeServer();}
}

View File

@@ -1,11 +0,0 @@
package eu.midnightdust.fabric.core;
import eu.midnightdust.core.MidnightLibServer;
import net.fabricmc.api.DedicatedServerModInitializer;
public class MidnightLibServerFabric implements DedicatedServerModInitializer {
@Override
public void onInitializeServer() {
MidnightLibServer.onInitializeServer();
}
}

View File

@@ -0,0 +1,28 @@
package eu.midnightdust.lib.config;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import eu.midnightdust.core.MidnightLib;
import eu.midnightdust.core.config.MidnightLibConfig;
import java.util.HashMap;
import java.util.Map;
public class AutoModMenu implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return parent -> MidnightLibConfig.getScreen(parent,"midnightlib");
}
@Override
public Map<String, ConfigScreenFactory<?>> getProvidedConfigScreenFactories() {
HashMap<String, ConfigScreenFactory<?>> map = new HashMap<>();
MidnightConfig.configClass.forEach((modid, cClass) -> {
if (!MidnightLib.hiddenMods.contains(modid))
map.put(modid, parent -> MidnightConfig.getScreen(parent, modid));
}
);
return map;
}
}

View File

@@ -21,15 +21,19 @@
"environment": "*", "environment": "*",
"entrypoints": { "entrypoints": {
"client": [ "client": [
"eu.midnightdust.fabric.core.MidnightLibClientFabric" "eu.midnightdust.fabric.core.MidnightLibFabric"
], ],
"server": [ "server": [
"eu.midnightdust.fabric.core.MidnightLibServerFabric" "eu.midnightdust.fabric.core.MidnightLibFabric"
], ],
"modmenu": [ "modmenu": [
"eu.midnightdust.lib.config.AutoModMenu" "eu.midnightdust.lib.config.AutoModMenu"
] ]
}, },
"depends": {
"fabric-resource-loader-v0": "*",
"minecraft": ">=1.20.4"
},
"mixins": [ "mixins": [
"midnightlib.mixins.json" "midnightlib.mixins.json"

View File

@@ -1 +0,0 @@
loom.platform=forge

View File

@@ -1,37 +0,0 @@
package eu.midnightdust.forge;
import eu.midnightdust.hats.witch.WitchHatFeatureRenderer;
import eu.midnightdust.lib.config.MidnightConfig;
import eu.midnightdust.lib.util.MidnightColorUtil;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.ConfigScreenHandler;
import net.minecraftforge.client.event.EntityRenderersEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent;
@Mod.EventBusSubscriber(modid = "midnightlib", bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public class MidnightLibClientEvents {
@SubscribeEvent
public static void registerLayerDefinition(EntityRenderersEvent.RegisterLayerDefinitions event) {
event.registerLayerDefinition(WitchHatFeatureRenderer.WITCH_HAT_MODEL_LAYER, WitchHatFeatureRenderer::getTexturedModelData);
}
@SubscribeEvent
public void registerClientTick(TickEvent.ClientTickEvent event) {
MidnightColorUtil.tick();
}
@SubscribeEvent
public void onPostInit(FMLLoadCompleteEvent event) {
ModList.get().applyForEachModContainer(modContainer -> {
System.out.println(modContainer.getModId() + " yes");
if (MidnightConfig.configClass.containsKey(modContainer.getModId())) {
modContainer.registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () ->
new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> MidnightConfig.getScreen(parent, modContainer.getModId())));
}
return true;
});
}
}

View File

@@ -1,24 +0,0 @@
package eu.midnightdust.forge;
import eu.midnightdust.core.MidnightLibClient;
import eu.midnightdust.core.MidnightLibServer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.IExtensionPoint;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.network.NetworkConstants;
@Mod("midnightlib")
public class MidnightLibForge {
public MidnightLibForge() {
ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> NetworkConstants.IGNORESERVERONLY, (remote, server) -> true));
DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> MidnightLibClient::onInitializeClient);
DistExecutor.safeRunWhenOn(Dist.DEDICATED_SERVER, () -> MidnightLibServer::onInitializeServer);
//ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () ->
// new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> MidnightConfig.getScreen(parent, "midnightlib")));
MinecraftForge.EVENT_BUS.register(new MidnightLibClientEvents());
MinecraftForge.EVENT_BUS.register(new MidnightLibServerEvents());
}
}

View File

@@ -1,19 +0,0 @@
package eu.midnightdust.forge;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import eu.midnightdust.lib.config.AutoCommand;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(modid = "midnightlib", bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.DEDICATED_SERVER)
public class MidnightLibServerEvents {
@SubscribeEvent
public void registerCommands(RegisterCommandsEvent event) {
for (LiteralArgumentBuilder<ServerCommandSource> command : AutoCommand.commands){
event.getDispatcher().register(command);
}
}
}

View File

@@ -1,19 +1,21 @@
org.gradle.jvmargs=-Xmx4096M org.gradle.jvmargs=-Xmx4096M
minecraft_version=1.19.3-rc1 minecraft_version=1.20.6
yarn_mappings=1.20.6+build.1
enabled_platforms=fabric enabled_platforms=fabric
archives_base_name=midnightlib archives_base_name=midnightlib
mod_version=1.1.0 mod_version=1.5.5
maven_group=eu.midnightdust maven_group=eu.midnightdust
release_type=release
curseforge_id=488090
modrinth_id=codAaoxh
architectury_version=6.2.43 fabric_loader_version=0.15.11
fabric_api_version=0.97.8+1.20.6
fabric_loader_version=0.14.11 neoforge_version=20.6.30-beta
fabric_api_version=0.68.1+1.19.3
forge_version=1.19.2-43.0.8 quilt_loader_version=0.19.0-beta.18
quilt_fabric_api_version=7.0.1+0.83.0-1.20
quilt_loader_version=0.18.1-beta.9 mod_menu_version = 9.0.0
quilt_fabric_api_version=4.0.0-beta.7+0.59.0-1.19.2
mod_menu_version = 5.0.0-alpha.4

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -1,16 +1,17 @@
plugins { plugins {
id "com.github.johnrengelman.shadow" version "7.1.2" id "com.github.johnrengelman.shadow" version "7.1.2"
} }
repositories{
maven {url "https://maven.neoforged.net/releases"}
}
architectury { architectury {
platformSetupLoomIde() platformSetupLoomIde()
forge() neoForge()
} }
loom { loom {
forge { accessWidenerPath = project(":common").loom.accessWidenerPath
mixinConfig "midnightlib.mixins.json"
}
} }
configurations { configurations {
@@ -19,14 +20,14 @@ configurations {
compileClasspath.extendsFrom common compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common runtimeClasspath.extendsFrom common
developmentForge.extendsFrom common developmentForge.extendsFrom common
archivesBaseName = rootProject.archives_base_name + "-forge" archivesBaseName = rootProject.archives_base_name + "-neoforge"
} }
dependencies { dependencies {
forge "net.minecraftforge:forge:${rootProject.forge_version}" neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
common(project(path: ":common", configuration: "namedElements")) { transitive false } common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionForge")) { transitive = false } shadowCommon(project(path: ":common", configuration: "transformProductionNeoForge")) { transitive = false }
} }
processResources { processResources {
@@ -42,17 +43,13 @@ shadowJar {
exclude "architectury.common.json" exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon] configurations = [project.configurations.shadowCommon]
classifier "dev-shadow" archiveClassifier = "dev-shadow"
} }
remapJar { remapJar {
atAccessWideners.add('midnightlib.accesswidener')
input.set shadowJar.archiveFile input.set shadowJar.archiveFile
dependsOn shadowJar dependsOn shadowJar
classifier null
}
jar {
classifier "dev"
} }
sourcesJar { sourcesJar {

View File

@@ -0,0 +1 @@
loom.platform=neoforge

View File

@@ -1,11 +1,11 @@
package eu.midnightdust.lib.util.forge; package eu.midnightdust.lib.util.neoforge;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import eu.midnightdust.lib.util.PlatformFunctions; import eu.midnightdust.lib.util.PlatformFunctions;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraftforge.fml.ModList; import net.neoforged.fml.ModList;
import net.minecraftforge.fml.loading.FMLEnvironment; import net.neoforged.fml.loading.FMLEnvironment;
import net.minecraftforge.fml.loading.FMLPaths; import net.neoforged.fml.loading.FMLPaths;
import java.nio.file.Path; import java.nio.file.Path;
@@ -23,6 +23,6 @@ public class PlatformFunctionsImpl {
return ModList.get().isLoaded(modid); return ModList.get().isLoaded(modid);
} }
public static void registerCommand(LiteralArgumentBuilder<ServerCommandSource> command) { public static void registerCommand(LiteralArgumentBuilder<ServerCommandSource> command) {
// Ignored here, see MidnightLibEvents#registerCommands // Ignored here, see MidnightLibNeoForge#registerCommands
} }
} }

View File

@@ -0,0 +1,51 @@
package eu.midnightdust.neoforge;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import eu.midnightdust.core.MidnightLib;
import eu.midnightdust.core.screen.MidnightConfigOverviewScreen;
import eu.midnightdust.lib.config.AutoCommand;
import eu.midnightdust.lib.config.MidnightConfig;
import net.minecraft.server.command.ServerCommandSource;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.IExtensionPoint;
import net.neoforged.fml.ModList;
import net.neoforged.fml.ModLoadingContext;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.fml.loading.FMLEnvironment;
import net.neoforged.neoforge.client.ConfigScreenHandler;
import net.neoforged.neoforge.client.event.ScreenEvent;
import net.neoforged.neoforge.event.RegisterCommandsEvent;
import static net.neoforged.fml.IExtensionPoint.DisplayTest.IGNORESERVERONLY;
@Mod("midnightlib")
public class MidnightLibNeoForge {
public MidnightLibNeoForge() {
ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> IGNORESERVERONLY, (remote, server) -> true));
if (FMLEnvironment.dist == Dist.CLIENT) MidnightLib.onInitializeClient(); else MidnightLib.onInitializeServer();
}
@Mod.EventBusSubscriber(modid = "midnightlib", bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public static class MidnightLibBusEvents {
@SubscribeEvent
public static void onPostInit(FMLClientSetupEvent event) {
ModList.get().forEachModContainer((modid, modContainer) -> {
if (MidnightConfig.configClass.containsKey(modid)) {
modContainer.registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () ->
new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> MidnightConfig.getScreen(parent, modid)));
}
});
}
}
@Mod.EventBusSubscriber(modid = "midnightlib", value = Dist.DEDICATED_SERVER)
public static class MidnightLibServerEvents {
@SubscribeEvent
public static void registerCommands(RegisterCommandsEvent event) {
for (LiteralArgumentBuilder<ServerCommandSource> command : AutoCommand.commands){
event.getDispatcher().register(command);
}
}
}
}

View File

@@ -1,5 +1,5 @@
modLoader = "javafml" modLoader = "javafml"
loaderVersion = "[43,)" loaderVersion = "[1,)"
#issueTrackerURL = "" #issueTrackerURL = ""
license = "MIT License" license = "MIT License"
@@ -15,15 +15,15 @@ Common Library for Team MidnightDust's mods.
#logoFile = "" #logoFile = ""
[[dependencies.midnightlib]] [[dependencies.midnightlib]]
modId = "forge" modId = "neoforge"
mandatory = true mandatory = true
versionRange = "[43,)" versionRange = "[20.3,)"
ordering = "NONE" ordering = "NONE"
side = "BOTH" side = "BOTH"
[[dependencies.midnightlib]] [[dependencies.midnightlib]]
modId = "minecraft" modId = "minecraft"
mandatory = true mandatory = true
versionRange = "[1.19.2,)" versionRange = "[1.20.3,)"
ordering = "NONE" ordering = "NONE"
side = "BOTH" side = "BOTH"

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,6 +1,6 @@
{ {
"pack": { "pack": {
"description": "MidnightLib", "description": "MidnightLib",
"pack_format": 9 "pack_format": 22
} }
} }

View File

@@ -5,7 +5,7 @@ import eu.midnightdust.lib.util.PlatformFunctions;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import org.quiltmc.loader.api.QuiltLoader; import org.quiltmc.loader.api.QuiltLoader;
import org.quiltmc.loader.impl.QuiltLoaderImpl; import org.quiltmc.loader.api.minecraft.MinecraftQuiltLoader;
import org.quiltmc.qsl.command.api.CommandRegistrationCallback; import org.quiltmc.qsl.command.api.CommandRegistrationCallback;
import java.nio.file.Path; import java.nio.file.Path;
@@ -18,7 +18,7 @@ public class PlatformFunctionsImpl {
return QuiltLoader.getConfigDir(); return QuiltLoader.getConfigDir();
} }
public static boolean isClientEnv() { public static boolean isClientEnv() {
return QuiltLoaderImpl.INSTANCE.getEnvironmentType() == EnvType.CLIENT; return MinecraftQuiltLoader.getEnvironmentType() == EnvType.CLIENT;
} }
public static boolean isModLoaded(String modid) { public static boolean isModLoaded(String modid) {
return QuiltLoader.isModLoaded(modid); return QuiltLoader.isModLoaded(modid);

View File

@@ -1,9 +1,7 @@
package eu.midnightdust.quilt.core; package eu.midnightdust.quilt.core;
import eu.midnightdust.core.MidnightLibClient; import eu.midnightdust.core.MidnightLibClient;
import eu.midnightdust.hats.witch.WitchHatFeatureRenderer;
import eu.midnightdust.lib.util.MidnightColorUtil; import eu.midnightdust.lib.util.MidnightColorUtil;
import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry;
import org.quiltmc.loader.api.ModContainer; import org.quiltmc.loader.api.ModContainer;
import org.quiltmc.qsl.base.api.entrypoint.client.ClientModInitializer; import org.quiltmc.qsl.base.api.entrypoint.client.ClientModInitializer;
import org.quiltmc.qsl.lifecycle.api.client.event.ClientTickEvents; import org.quiltmc.qsl.lifecycle.api.client.event.ClientTickEvents;
@@ -11,10 +9,6 @@ import org.quiltmc.qsl.lifecycle.api.client.event.ClientTickEvents;
public class MidnightLibClientQuilt implements ClientModInitializer { public class MidnightLibClientQuilt implements ClientModInitializer {
@Override @Override
public void onInitializeClient(ModContainer mod) { public void onInitializeClient(ModContainer mod) {
EntityModelLayerRegistry.registerModelLayer(WitchHatFeatureRenderer.WITCH_HAT_MODEL_LAYER, WitchHatFeatureRenderer::getTexturedModelData);
MidnightLibClient.onInitializeClient(); MidnightLibClient.onInitializeClient();
ClientTickEvents.END.register(
client -> MidnightColorUtil.tick()
);
} }
} }

View File

@@ -4,21 +4,7 @@
"group": "${group}", "group": "${group}",
"id": "midnightlib", "id": "midnightlib",
"version": "${version}", "version": "${version}",
"name": "MidnightLib",
"description": "Common Library for Team MidnightDust's mods.",
"authors": [
"TeamMidnightDust",
"Motschen"
],
"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",
"intermediate_mappings": "net.fabricmc:intermediary", "intermediate_mappings": "net.fabricmc:intermediary",
"environment": "*",
"entrypoints": { "entrypoints": {
"client_init": [ "client_init": [
"eu.midnightdust.quilt.core.MidnightLibClientQuilt" "eu.midnightdust.quilt.core.MidnightLibClientQuilt"
@@ -38,11 +24,17 @@
{ {
"id": "quilt_base", "id": "quilt_base",
"version": "*" "version": "*"
},
{
"id": "minecraft",
"version": ">=1.19.4"
} }
], ],
"metadata": { "metadata": {
"name": "MidnightLib (Quilt)", "name": "MidnightLib (Quilt)",
"description": "Common Library for Team MidnightDust's mods.\nProvides a config api, automatic integration with other mods, common utils, and cosmetics.", "description": "Common Library for Team MidnightDust's mods. Provides a config api, automatic integration with other mods, common utils, and cosmetics.",
"license": "MIT",
"environment": "*",
"contributors": { "contributors": {
"Motschen": "Author", "Motschen": "Author",
"TeamMidnightDust": "Mascot" "TeamMidnightDust": "Mascot"

View File

@@ -2,7 +2,7 @@ pluginManagement {
repositories { repositories {
maven { url "https://maven.fabricmc.net/" } maven { url "https://maven.fabricmc.net/" }
maven { url "https://maven.architectury.dev/" } maven { url "https://maven.architectury.dev/" }
maven { url "https://maven.minecraftforge.net/" } maven { url "https://maven.neoforged.net/releases" }
gradlePluginPortal() gradlePluginPortal()
} }
} }
@@ -11,6 +11,6 @@ include("common")
include("fabric-like") include("fabric-like")
include("fabric") include("fabric")
//include("quilt") //include("quilt")
//include("forge") //include("neoforge")
rootProject.name = "midnightlib" rootProject.name = "midnightlib"