Compare commits

...

27 Commits

Author SHA1 Message Date
Motschen
eaa2b1543e MidnightLib 1.1.0 - Port to 1.19.3
- Port to 1.19.3 (temporarily disabled forge and quilt until they're available)
- Removed custom button tooltip system in favor of the new vanilla one
2022-12-03 16:33:34 +01:00
Motschen
c751859f90 Fix quilt.mod.json 2022-10-31 12:33:38 +01:00
Motschen
0cb16cbf3f Update the example config class 2022-10-31 11:56:53 +01:00
Motschen
5b941204f9 Fix #16 using the suggested fix
Thanks @MasterToster
2022-10-31 10:18:36 +01:00
Motschen
42414c103e Fix MidnightConfig command on Forge 2022-10-31 10:12:09 +01:00
Motschen
0e7478b5e5 Various renames and fixes 2022-10-31 00:03:25 +01:00
Motschen
0c23fa4f53 Port to Architectury
Yes, that also means Forge!
And yes, this was pain.
And no, the file size has not increased much!
2022-10-30 23:49:58 +01:00
Martin Prokoph
f70460ff65 Merge pull request #17 from FITFC/main
added pt_br
2022-10-30 22:38:31 +01:00
Motschen
c63cf9c515 Add support for sliders (int, float and double) 2022-10-30 17:10:22 +01:00
FITFC
38396c1886 added pt_br 2022-10-30 01:58:10 -05:00
Motschen
ac1516293c MidnightLib 0.6.1 - Fix reset button for color fields
- Fix reset button never being inactive for color config options
- Always make color button non-interactive
2022-09-21 20:52:56 +02:00
Motschen
383de29f93 MidnightLib 0.6.0 - Centered Comments, Inactive Reset Buttons, Hidden Entries
- Comments can now be centered via a property in the Annotation
- Entries can now be completely hidden using the respective annotation (allows for things like config versions being saved)
- Reset buttons now get deactivated when the value matches the default
- The MidnightConfigOverview list is now sorted alphabetically
- Make more fields publicly accessible
- Ukrainian translation by @Altegar
2022-08-22 18:42:48 +02:00
Martin Prokoph
71c16ffbb3 Merge pull request #13 from Altegar/patch-1
Create uk_ua.json
2022-08-16 12:43:56 +02:00
Sushomeister
76166aed49 Create uk_ua.json 2022-07-26 16:11:35 +03:00
Motschen
d6e1a5e558 Some more fixes... 2022-06-07 21:13:26 +02:00
Motschen
191120393c MidnightLib 0.5.2 - Fix AutoModMenu opt-out... again
Closes #10
2022-06-07 21:03:45 +02:00
Motschen
1be14dc3ac MidnightLib 1.5.1 - Fix AutoModMenu opt-out 2022-06-06 18:48:32 +02:00
Motschen
7e1de67a5e MidnightLib 0.5.0 - Same as 0.4.2 but 1.19 2022-06-06 18:13:39 +02:00
Motschen
da4e59ef3a MidnightLib 0.4.1 - Update to 1.19 2022-05-18 20:21:31 +02:00
Motschen
da2c76ed5f Update MidnightConfigExample.java 2022-04-12 17:56:08 +02:00
Motschen
8c1c00f6e2 Update Documentation 2022-02-22 12:49:09 +01:00
Motschen
5183b54285 Ditch Log4j for future-proofing 2022-02-22 12:44:28 +01:00
Motschen
a9190f2a0d MidnightLib 0.4.0 - Color support, Client and Server-only config options, cleanup 2022-02-22 12:30:55 +01:00
Motschen
794586362d MidnightLib 0.3.1 - Remove debug info 2021-11-20 11:21:40 +01:00
Motschen
1bdbde0af6 Merge pull request #5 from wafflecoffee/patch-1
Remove debug printlns in MidnightConfig
2021-11-20 10:17:57 +00:00
Emma
c1815c25d8 Remove debug printlns 2021-11-14 17:43:12 -05:00
Motschen
5dc707a6d8 MidnightLib 0.3.0 - String-List ingame support
- String Lists can now be edited in MidnightLib config screens
- Remove some pointless clutter
2021-10-31 15:46:34 +01:00
64 changed files with 1448 additions and 774 deletions

32
.gitignore vendored Executable file → Normal file
View File

@@ -1,25 +1,19 @@
# gradle
.gradle/
out/
classes/
build/ build/
# idea
.idea/
*.iml
*.ipr *.ipr
run/
*.iws *.iws
out/
# vscode *.iml
.gradle/
.settings/ output/
.vscode/
bin/ bin/
libs/
.classpath .classpath
.project .project
.idea/
# fabric classes/
.metadata
run/ .vscode
.settings
*.launch

View File

@@ -1,4 +1,8 @@
package eu.midnightdust.lib.config; package eu.midnightdust.core.config;
import eu.midnightdust.lib.config.MidnightConfig;
import java.util.List;
/** MidnightConfig documentation & examples: /** MidnightConfig documentation & examples:
* Thanks for choosing MidnightConfig - the fancy, tiny and lightweight config library. * Thanks for choosing MidnightConfig - the fancy, tiny and lightweight config library.
@@ -9,16 +13,21 @@ package eu.midnightdust.lib.config;
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 public static Comment text1; // Comments are rendered like an option without a button and are excluded from the config file
@Entry public static int fabric = 16777215; // Example for a int option @Comment(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
@Entry public static double world = 1.4D; // Example for a double option @Entry public static double world = 1.4D; // Example for a double option
@Entry public static boolean showInfo = true; // Example for a boolean option @Entry public static boolean showInfo = true; // Example for a boolean option
@Entry public static String name = "Hi"; // Example for a string option @Entry public static String name = "Hello World!"; // Example for a string option
@Entry public static TestEnum testEnum = TestEnum.FABRIC; // Example for a enum option @Entry public static TestEnum testEnum = TestEnum.FABRIC; // Example for an enum option
public static 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 QUILT, FABRIC, FORGE
} }
@Entry(min=10,max=30) public static int hello = 15675965; // - The entered number has to be larger than 10 and smaller than 30 @Entry(min=69,max=420) public static int hello = 420; // - The entered number has to be larger than 69 and smaller than 420
@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(name = "I am an array list!") public static List<String> arrayList = List.of("String1", "String2"); // Array String Lists are also supported
@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(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
// 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
@@ -27,29 +36,28 @@ public class MidnightConfigExample extends MidnightConfig {
{ {
"modid.midnightconfig.title":"I am a title", // "*.midnightconfig.title" defines the title of the screen "modid.midnightconfig.title":"I am a title", // "*.midnightconfig.title" defines the title of the screen
"modid.midnightconfig.text1":"I am a comment *u*", // Translation for the comment "text1" defined in the example config "modid.midnightconfig.text1":"I am a comment *u*", // Translation for the comment "text1" defined in the example config
"modid.midnightconfig.name":"Pet Name", // Translation for the field "name" defined in the example config "modid.midnightconfig.text2":"I am a centered comment (╯°□°)╯︵ ┻━┻",
"modid.midnightconfig.name":"I am a string!", // Translation for the field "name" defined in the example config
"modid.midnightconfig.name.tooltip":"Name your Pet! \n I am a new line uwu", "modid.midnightconfig.name.tooltip":"I am a tooltip uwu \nI am a new line",
// When hovering over the option "showInfo", // When hovering over the option "showInfo",
// this text will appear as a tooltip. // this text will appear as a tooltip.
// "\n" inserts a line break. // "\n" inserts a line break.
"modid.midnightconfig.fabric":"I am an int", "modid.midnightconfig.fabric":"I am an int",
"modid.midnightconfig.world":"I am a double", "modid.midnightconfig.world":"I am a double",
"modid.midnightconfig.showInfo":"I am a boolean", "modid.midnightconfig.showInfo":"I am a boolean",
"modid.midnightconfig.hello":"I am a limited int!", "modid.midnightconfig.hello":"I am a limited int!",
"modid.midnightconfig.testEnum":"I am an enum!", "modid.midnightconfig.testEnum":"I am an enum!",
"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"
} }
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");"
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() {
return parent -> MidnightConfig.getScreen(parent, "modid"); return parent -> MidnightConfig.getScreen(parent, "modid");
} }
*/ */
} }

114
build.gradle Executable file → Normal file
View File

@@ -1,85 +1,47 @@
plugins { plugins {
id 'fabric-loom' version '0.8-SNAPSHOT' id "architectury-plugin" version "3.4-SNAPSHOT"
id 'maven-publish' id "dev.architectury.loom" version "1.0-SNAPSHOT" apply false
} }
sourceCompatibility = JavaVersion.VERSION_16 architectury {
targetCompatibility = JavaVersion.VERSION_16 minecraft = rootProject.minecraft_version
archivesBaseName = project.archives_base_name
version = project.mod_version
group = project.maven_group
minecraft {
} }
repositories { subprojects {
maven { url "https://maven.terraformersmc.com/releases" } apply plugin: "dev.architectury.loom"
maven { url "https://jitpack.io" }
dependencies {
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.
mappings "net.fabricmc:yarn:1.19.3-rc1+build.2:v2"
}
} }
dependencies { allprojects {
//to change the versions see the gradle.properties file apply plugin: "java"
minecraft "com.mojang:minecraft:${project.minecraft_version}" apply plugin: "architectury-plugin"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" apply plugin: "maven-publish"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" archivesBaseName = rootProject.archives_base_name
version = rootProject.mod_version
modImplementation ("com.terraformersmc:modmenu:${project.mod_menu_version}") group = rootProject.maven_group
}
repositories {
processResources { // Add repositories to retrieve artifacts from in here.
inputs.property "version", project.version // You should only use this when depending on other mods because
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
filesMatching("fabric.mod.json") { // See https://docs.gradle.org/current/userguide/declaring_repositories.html
expand "version": project.version // for more information about repositories.
} }
}
tasks.withType(JavaCompile) {
tasks.withType(JavaCompile).configureEach { options.encoding = "UTF-8"
// ensure that the encoding is set to UTF-8, no matter what the system default is options.release = 17
// this fixes some edge cases with special characters not displaying correctly }
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
// If Javadoc is generated, this must be specified in that task too. java {
it.options.encoding = "UTF-8" withSourcesJar()
}
// Minecraft 1.17 (21w19a) upwards uses Java 16.
it.options.release = 16
}
java {
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
// if it is present.
// If you remove this line, sources will not be generated.
withSourcesJar()
}
jar {
from("LICENSE") {
rename { "${it}_${project.archivesBaseName}"}
}
}
// configure the maven publication
publishing {
publications {
mavenJava(MavenPublication) {
// add all the jars that should be included when publishing to maven
artifact(remapJar) {
builtBy remapJar
}
artifact(sourcesJar) {
builtBy remapSourcesJar
}
}
}
// 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.
// Notice: This block does NOT have the same function as the block in the top level.
// The repositories here will be used for publishing your artifact, not for
// retrieving dependencies.
}
} }

26
common/build.gradle Normal file
View File

@@ -0,0 +1,26 @@
architectury {
common(rootProject.enabled_platforms.split(","))
}
loom {
}
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
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
}
publishing {
publications {
mavenCommon(MavenPublication) {
artifactId = rootProject.archives_base_name
from components.java
}
}
// 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

@@ -0,0 +1,21 @@
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

@@ -2,17 +2,15 @@ package eu.midnightdust.core;
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.DedicatedServerModInitializer;
import java.lang.reflect.Field; import java.lang.reflect.Field;
public class MidnightLibServer implements DedicatedServerModInitializer { public class MidnightLibServer {
@Override public static void onInitializeServer() {
public void onInitializeServer() {
MidnightConfig.configClass.forEach((modid, config) -> { MidnightConfig.configClass.forEach((modid, config) -> {
for (Field field : config.getFields()) { for (Field field : config.getFields()) {
if (field.isAnnotationPresent(MidnightConfig.Entry.class)) if (field.isAnnotationPresent(MidnightConfig.Entry.class) && !field.isAnnotationPresent(MidnightConfig.Client.class) && !field.isAnnotationPresent(MidnightConfig.Hidden.class))
new AutoCommand(field, modid).register(); new AutoCommand(field, modid).register();
} }
}); });

View File

@@ -0,0 +1,17 @@
package eu.midnightdust.core.config;
import eu.midnightdust.lib.config.MidnightConfig;
import eu.midnightdust.lib.util.PlatformFunctions;
public class MidnightLibConfig extends MidnightConfig {
@Comment(centered = true) public static Comment midnightlib_description;
@Entry // Enable or disable the MidnightConfig overview screen button
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 {
TRUE,FALSE,MODMENU
}
}

View File

@@ -2,12 +2,11 @@ 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.screen.TexturedOverlayButtonWidget; import eu.midnightdust.lib.util.screen.TexturedOverlayButtonWidget;
import net.fabricmc.loader.api.FabricLoader;
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.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@@ -25,7 +24,7 @@ public class MixinOptionsScreen extends Screen {
@Inject(at = @At("HEAD"),method = "init") @Inject(at = @At("HEAD"),method = "init")
private void midnightlib$init(CallbackInfo ci) { private void midnightlib$init(CallbackInfo ci) {
if (MidnightLibConfig.config_screen_list.equals(MidnightLibConfig.ConfigButton.TRUE) || MidnightLibConfig.config_screen_list.equals(MidnightLibConfig.ConfigButton.MODMENU) && FabricLoader.getInstance().isModLoaded("modmenu")) if (MidnightLibConfig.config_screen_list.equals(MidnightLibConfig.ConfigButton.TRUE) || (MidnightLibConfig.config_screen_list.equals(MidnightLibConfig.ConfigButton.MODMENU) && !PlatformFunctions.isModLoaded("modmenu")))
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)), new TranslatableText("midnightlib.overview.title"))); 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")));
} }
} }

View File

@@ -1,5 +1,6 @@
package eu.midnightdust.core.screen; package eu.midnightdust.core.screen;
import eu.midnightdust.core.MidnightLibClient;
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;
@@ -8,9 +9,9 @@ import net.minecraft.client.font.TextRenderer;
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.screen.ScreenTexts;
import net.minecraft.client.gui.widget.*; import net.minecraft.client.gui.widget.*;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.*; import net.minecraft.text.*;
import java.util.*; import java.util.*;
@@ -18,7 +19,7 @@ import java.util.*;
public class MidnightConfigOverviewScreen extends Screen { public class MidnightConfigOverviewScreen extends Screen {
public MidnightConfigOverviewScreen(Screen parent) { public MidnightConfigOverviewScreen(Screen parent) {
super(new TranslatableText( "midnightlib.overview.title")); super(Text.translatable( "midnightlib.overview.title"));
this.parent = parent; this.parent = parent;
} }
private final Screen parent; private final Screen parent;
@@ -26,24 +27,26 @@ public class MidnightConfigOverviewScreen extends Screen {
@Override @Override
protected void init() { protected void init() {
this.addDrawableChild(new ButtonWidget(this.width / 2 - 100, this.height - 28, 200, 20, ScreenTexts.DONE, (button) -> Objects.requireNonNull(client).setScreen(parent))); this.addDrawableChild(ButtonWidget.builder(ScreenTexts.DONE, (button) -> Objects.requireNonNull(client).setScreen(parent)).dimensions(this.width / 2 - 100, this.height - 28, 200, 20).build());
this.list = new MidnightOverviewListWidget(this.client, this.width, this.height, 32, this.height - 32, 25); this.list = new MidnightOverviewListWidget(this.client, this.width, this.height, 32, this.height - 32, 25);
if (this.client != null && this.client.world != null) this.list.setRenderBackground(false); if (this.client != null && this.client.world != null) this.list.setRenderBackground(false);
this.addSelectableChild(this.list); this.addSelectableChild(this.list);
MidnightConfig.configClass.forEach((modid, configClass) -> List<String> sortedMods = new ArrayList<>(MidnightConfig.configClass.keySet());
list.addButton(new ButtonWidget(this.width / 2 - 100, this.height - 28, 200, 20, new TranslatableText(modid +".midnightconfig.title"), (button) -> Collections.sort(sortedMods);
Objects.requireNonNull(client).setScreen(MidnightConfig.getScreen(this,modid))))); sortedMods.forEach((modid) -> {
if (!MidnightLibClient.hiddenMods.contains(modid)) {
list.addButton(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());
}
});
super.init(); super.init();
} }
@Override @Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices); this.renderBackground(matrices);
this.list.render(matrices, mouseX, mouseY, delta); this.list.render(matrices, mouseX, mouseY, delta);
drawCenteredText(matrices, textRenderer, title, width / 2, 15, 0xFFFFFF);
int stringWidth = title.getString().length() + 47;
renderTooltip(matrices, title, width/2 - stringWidth, 27);
//drawCenteredText(matrices, textRenderer, title, width / 2, 15, 0xFFFFFF);
super.render(matrices, mouseX, mouseY, delta); super.render(matrices, mouseX, mouseY, delta);
} }
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
@@ -56,7 +59,7 @@ public class MidnightConfigOverviewScreen extends Screen {
textRenderer = minecraftClient.textRenderer; textRenderer = minecraftClient.textRenderer;
} }
@Override @Override
public int getScrollbarPositionX() { return this.width -7; } public int getScrollbarPositionX() {return this.width -7;}
public void addButton(ClickableWidget button) { public void addButton(ClickableWidget button) {
this.addEntry(OverviewButtonEntry.create(button)); this.addEntry(OverviewButtonEntry.create(button));
@@ -65,26 +68,19 @@ public class MidnightConfigOverviewScreen extends Screen {
public int getRowWidth() { return 400; } public int getRowWidth() { return 400; }
} }
public static class OverviewButtonEntry extends ElementListWidget.Entry<OverviewButtonEntry> { public static class OverviewButtonEntry extends ElementListWidget.Entry<OverviewButtonEntry> {
private final List<ClickableWidget> buttons = new ArrayList<>(); private final ClickableWidget button;
private final List<ClickableWidget> buttonList = new ArrayList<>();
private OverviewButtonEntry(ClickableWidget button) { private OverviewButtonEntry(ClickableWidget button) {
this.buttons.add(button); this.button = button;
} this.buttonList.add(button);
public static OverviewButtonEntry create(ClickableWidget button) {
return new OverviewButtonEntry(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) { public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
this.buttons.forEach((button) -> { button.setY(y);
button.y = y; button.render(matrices, mouseX, mouseY, tickDelta);
button.render(matrices, mouseX, mouseY, tickDelta);
});
}
public List<? extends Element> children() {
return buttons;
}
public List<? extends Selectable> selectableChildren() {
return buttons;
} }
public List<? extends Element> children() {return buttonList;}
public List<? extends Selectable> selectableChildren() {return buttonList;}
} }
} }

View File

@@ -4,9 +4,6 @@ import com.google.common.reflect.TypeToken;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@@ -14,11 +11,14 @@ import java.io.Reader;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.*; import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@SuppressWarnings("UnstableApiUsage")
public class HatLoader { public class HatLoader {
public static final Logger logger = LogManager.getLogger("MidnightLib"); public static final System.Logger logger = System.getLogger("MidnightLib");
private final static String HATS_URL = "https://raw.githubusercontent.com/TeamMidnightDust/MidnightHats/master/hats.json"; 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 final Type HAT_TYPE = new TypeToken<Map<UUID, PlayerHatData>>(){}.getType();
public static Map<UUID, PlayerHatData> PLAYER_HATS; public static Map<UUID, PlayerHatData> PLAYER_HATS;
@@ -30,19 +30,19 @@ public class HatLoader {
try (Reader reader = new InputStreamReader(new URL(HATS_URL).openStream())) { try (Reader reader = new InputStreamReader(new URL(HATS_URL).openStream())) {
return GSON.<Map<UUID, PlayerHatData>>fromJson(reader, HAT_TYPE); return GSON.<Map<UUID, PlayerHatData>>fromJson(reader, HAT_TYPE);
} catch (MalformedURLException error) { } catch (MalformedURLException error) {
logger.log(Level.ERROR, "Unable to load player hats because of connection problems: " + error.getMessage()); logger.log(System.Logger.Level.ERROR, "Unable to load player hats because of connection problems: " + error.getMessage());
} catch (IOException error) { } catch (IOException error) {
logger.log(Level.ERROR, "Unable to load player hats because of an I/O Exception: " + error.getMessage()); logger.log(System.Logger.Level.ERROR, "Unable to load player hats because of an I/O Exception: " + error.getMessage());
} }
return null; return null;
}).thenAcceptAsync(playerData -> { }).thenAcceptAsync(playerData -> {
if (playerData != null) { if (playerData != null) {
PLAYER_HATS = playerData; PLAYER_HATS = playerData;
logger.log(Level.INFO, "Player hats successfully loaded!"); System.out.println("(MidnightLib) Player hats successfully loaded!");
} else { } else {
PLAYER_HATS = Collections.emptyMap(); PLAYER_HATS = Collections.emptyMap();
logger.log(Level.WARN, "A problem with the database occurred, the hats could not be initialized."); logger.log(System.Logger.Level.WARNING, "A problem with the database occurred, the hats could not be initialized.");
} }
}, MinecraftClient.getInstance()); }, MinecraftClient.getInstance());
} }

View File

@@ -68,15 +68,14 @@ public class WitchHatFeatureRenderer<T extends LivingEntity, M extends EntityMod
if (uuid.equals(MOTSCHEN)) { if (uuid.equals(MOTSCHEN)) {
return MOTSCHEN_COLOR; return MOTSCHEN_COLOR;
} else if (HatLoader.PLAYER_HATS != null && HatLoader.PLAYER_HATS.containsKey(uuid)) { } else if (HatLoader.PLAYER_HATS != null && HatLoader.PLAYER_HATS.containsKey(uuid)) {
switch (HatLoader.PLAYER_HATS.get(uuid).getHatType()) { return switch (HatLoader.PLAYER_HATS.get(uuid).getHatType()) {
case "adopter": return ADOPTER_COLOR; case "adopter" -> ADOPTER_COLOR;
case "contributer": // old name case "contributer", "modder" -> MODDER_COLOR;
case "modder": return MODDER_COLOR; case "friend" -> FRIEND_COLOR;
case "friend": return FRIEND_COLOR; case "donator", "donor" -> DONOR_COLOR;
case "donator": // old name case "social" -> SOCIAL_COLOR;
case "donor": return DONOR_COLOR; default -> MidnightColorUtil.hex2Rgb(HatLoader.PLAYER_HATS.get(uuid).getHatType());
case "social": return SOCIAL_COLOR; };
}
} }
return null; return null;
} }

View File

@@ -7,7 +7,7 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
public class WitchHatModel<T extends LivingEntity> extends SinglePartEntityModel<T> { public class WitchHatModel<T extends LivingEntity> extends SinglePartEntityModel<T> {
private final ModelPart headwear; private final ModelPart headwear;
public WitchHatModel(ModelPart root) { public WitchHatModel(ModelPart root) {
headwear = root; headwear = root;
@@ -37,13 +37,13 @@ public class WitchHatModel<T extends LivingEntity> extends SinglePartEntityModel
return modelData; return modelData;
} }
@Override @Override
public void setAngles(T entity, float limbAngle, float limbDistance, float animationProgress, float headYaw, float headPitch) { public void setAngles(T entity, float limbAngle, float limbDistance, float animationProgress, float headYaw, float headPitch) {
} }
@Override @Override
public void render(MatrixStack matrixStack, VertexConsumer buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha){ 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); headwear.render(matrixStack, buffer, packedLight, packedOverlay, red, green, blue, alpha);
} }
@Override @Override
@@ -51,9 +51,9 @@ public class WitchHatModel<T extends LivingEntity> extends SinglePartEntityModel
return headwear; return headwear;
} }
public void setRotationAngle(ModelPart bone, float x, float y, float z) { public void setRotationAngle(ModelPart bone, float x, float y, float z) {
bone.pitch = x; bone.pitch = x;
bone.yaw = y; bone.yaw = y;
bone.roll = z; bone.roll = z;
} }
} }

View File

@@ -4,15 +4,18 @@ import com.mojang.brigadier.arguments.DoubleArgumentType;
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;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import eu.midnightdust.lib.util.PlatformFunctions;
import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.LiteralText; import net.minecraft.text.Text;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
public class AutoCommand { public class AutoCommand {
public static List<LiteralArgumentBuilder<ServerCommandSource>> commands = new ArrayList<>();
private LiteralArgumentBuilder<ServerCommandSource> command; private LiteralArgumentBuilder<ServerCommandSource> command;
final Field entry; final Field entry;
final String modid; final String modid;
@@ -27,7 +30,7 @@ public class AutoCommand {
command(); command();
LiteralArgumentBuilder<ServerCommandSource> finalized = CommandManager.literal("midnightconfig").requires(source -> source.hasPermissionLevel(2)).then(command); LiteralArgumentBuilder<ServerCommandSource> finalized = CommandManager.literal("midnightconfig").requires(source -> source.hasPermissionLevel(2)).then(command);
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(finalized)); PlatformFunctions.registerCommand(finalized); commands.add(finalized);
} }
private void command() { private void command() {
@@ -61,10 +64,10 @@ public class AutoCommand {
} }
} }
else 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")))
)); ));
} }
private int setValue(ServerCommandSource source, Object value) { private int setValue(ServerCommandSource source, Object value) {
@@ -73,16 +76,16 @@ public class AutoCommand {
MidnightConfig.write(modid); MidnightConfig.write(modid);
} }
catch (Exception e) { catch (Exception e) {
source.sendError(new LiteralText("Could not set "+entry.getName()+" to value "+value+": " + e)); source.sendError(Text.literal("Could not set "+entry.getName()+" to value "+value+": " + e));
return 0; return 0;
} }
source.sendFeedback(new LiteralText("Successfully set " + entry.getName()+" to "+value), true); source.sendFeedback(Text.literal("Successfully set " + entry.getName()+" to "+value), true);
return 1; return 1;
} }
private int getValue(ServerCommandSource source) { private int getValue(ServerCommandSource source) {
try { try {
source.sendFeedback(new LiteralText("The value of "+entry.getName()+" is "+entry.get(null)), false); source.sendFeedback(Text.literal("The value of "+entry.getName()+" is "+entry.get(null)), false);
return 1; return 1;
} }
catch (IllegalAccessException ignored) {} catch (IllegalAccessException ignored) {}

View File

@@ -0,0 +1,430 @@
package eu.midnightdust.lib.config;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import eu.midnightdust.lib.util.PlatformFunctions;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.Selectable;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.tooltip.Tooltip;
import net.minecraft.client.gui.widget.*;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import java.awt.Color;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
/** MidnightConfig v2.4.0 by TeamMidnightDust & Motschen
* Single class config library - feel free to copy!
* Based on https://github.com/Minenash/TinyConfig
* Credits to Minenash */
@SuppressWarnings("unchecked")
public abstract class MidnightConfig {
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 HEXADECIMAL_ONLY = Pattern.compile("(-?[#0-9a-fA-F]*)");
private static final List<EntryInfo> entries = new ArrayList<>();
protected static class EntryInfo {
Field field;
Object widget;
int width;
int max;
boolean centered;
Map.Entry<TextFieldWidget,Text> error;
Object defaultValue;
Object value;
String tempValue;
boolean inLimits = true;
String id;
Text name;
int index;
ClickableWidget colorButton;
}
public static final Map<String,Class<?>> configClass = new HashMap<>();
private static Path path;
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) {
path = PlatformFunctions.getConfigDirectory().resolve(modid + ".json");
configClass.put(modid, config);
for (Field field : config.getFields()) {
EntryInfo info = new EntryInfo();
if ((field.isAnnotationPresent(Entry.class) || field.isAnnotationPresent(Comment.class)) && !field.isAnnotationPresent(Server.class) && !field.isAnnotationPresent(Hidden.class))
if (PlatformFunctions.isClientEnv()) initClient(modid, field, info);
if (field.isAnnotationPresent(Comment.class)) info.centered = field.getAnnotation(Comment.class).centered();
if (field.isAnnotationPresent(Entry.class))
try {
info.defaultValue = field.get(null);
} catch (IllegalAccessException ignored) {}
}
try { gson.fromJson(Files.newBufferedReader(path), config); }
catch (Exception e) { write(modid); }
for (EntryInfo info : entries) {
if (info.field.isAnnotationPresent(Entry.class))
try {
info.value = info.field.get(null);
info.tempValue = info.value.toString();
} catch (IllegalAccessException ignored) {}
}
}
@Environment(EnvType.CLIENT)
private static void initClient(String modid, Field field, EntryInfo info) {
Class<?> type = field.getType();
Entry e = field.getAnnotation(Entry.class);
info.width = e != null ? e.width() : 0;
info.field = field;
info.id = modid;
if (e != null) {
if (!e.name().equals("")) info.name = Text.translatable(e.name());
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 == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(), false);
else if (type == String.class || type == List.class) {
info.max = e.max() == Double.MAX_VALUE ? Integer.MAX_VALUE : (int) e.max();
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);
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
info.value = !(Boolean) info.value;
button.setMessage(func.apply(info.value));
}, func);
} else if (type.isEnum()) {
List<?> values = Arrays.asList(field.getType().getEnumConstants());
Function<Object, Text> func = value -> Text.translatable(modid + ".midnightconfig." + "enum." + type.getSimpleName() + "." + info.value.toString());
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
int index = values.indexOf(info.value) + 1;
info.value = values.get(index >= values.size() ? 0 : index);
button.setMessage(func.apply(info.value));
}, func);
}
}
entries.add(info);
}
private static void textField(EntryInfo info, Function<String,Number> f, Pattern pattern, double min, double max, boolean cast) {
boolean isNumber = pattern != null;
info.widget = (BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) (t, b) -> s -> {
s = s.trim();
if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches())) return false;
Number value = 0;
boolean inLimits = false;
info.error = null;
if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) {
try { value = f.apply(s); } catch(NumberFormatException e){ return false; }
inLimits = value.doubleValue() >= min && value.doubleValue() <= max;
info.error = inLimits? null : new AbstractMap.SimpleEntry<>(t, Text.literal(value.doubleValue() < min ?
"§cMinimum " + (isNumber? "value" : "length") + (cast? " is " + (int)min : " is " + min) :
"§cMaximum " + (isNumber? "value" : "length") + (cast? " is " + (int)max : " is " + max)));
}
info.tempValue = s;
t.setEditableColor(inLimits? 0xFFFFFFFF : 0xFFFF7777);
info.inLimits = inLimits;
b.active = entries.stream().allMatch(e -> e.inLimits);
if (inLimits && info.field.getType() != List.class)
info.value = isNumber? value : s;
else if (inLimits) {
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));
}
if (info.field.getAnnotation(Entry.class).isColor()) {
if (!s.contains("#")) s = '#' + s;
if (!HEXADECIMAL_ONLY.matcher(s).matches()) return false;
try {
info.colorButton.setMessage(Text.literal("").setStyle(Style.EMPTY.withColor(Color.decode(info.tempValue).getRGB())));
} catch (Exception ignored) {}
}
return true;
};
}
public static void write(String modid) {
path = PlatformFunctions.getConfigDirectory().resolve(modid + ".json");
try {
if (!Files.exists(path)) Files.createFile(path);
Files.write(path, gson.toJson(configClass.get(modid).getDeclaredConstructor().newInstance()).getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
@Environment(EnvType.CLIENT)
public static Screen getScreen(Screen parent, String modid) {
return new MidnightConfigScreen(parent, modid);
}
@Environment(EnvType.CLIENT)
public static class MidnightConfigScreen extends Screen {
protected MidnightConfigScreen(Screen parent, String modid) {
super(Text.translatable(modid + ".midnightconfig." + "title"));
this.parent = parent;
this.modid = modid;
this.translationPrefix = modid + ".midnightconfig.";
}
public final String translationPrefix;
public final Screen parent;
public final String modid;
public MidnightConfigListWidget list;
public boolean reload = false;
// Real Time config update //
@Override
public void tick() {
super.tick();
for (EntryInfo info : entries) {
try {info.field.set(null, info.value);} catch (IllegalAccessException ignored) {}
}
updateResetButtons();
}
public void updateResetButtons() {
if (this.list != null) {
for (ButtonEntry entry : this.list.children()) {
if (entry.buttons != null && entry.buttons.size() > 1 && entry.buttons.get(1) instanceof ButtonWidget button) {
button.active = !Objects.equals(entry.info.value.toString(), entry.info.defaultValue.toString());
}
}
}
}
public void loadValues() {
try { gson.fromJson(Files.newBufferedReader(path), configClass.get(modid)); }
catch (Exception e) { write(modid); }
for (EntryInfo info : entries) {
if (info.field.isAnnotationPresent(Entry.class))
try {
info.value = info.field.get(null);
info.tempValue = info.value.toString();
} catch (IllegalAccessException ignored) {}
}
}
public Tooltip getTooltip(EntryInfo info) {
return Tooltip.of(I18n.hasTranslation(translationPrefix+info.field.getName()+".tooltip") ? Text.translatable(translationPrefix+info.field.getName()+".tooltip") : Text.empty());
}
@Override
public void init() {
super.init();
if (!reload) loadValues();
this.addDrawableChild(ButtonWidget.builder(ScreenTexts.CANCEL, button -> {
loadValues();
Objects.requireNonNull(client).setScreen(parent);
}).dimensions(this.width / 2 - 154, this.height - 28, 150, 20).build());
ButtonWidget done = this.addDrawableChild(ButtonWidget.builder(ScreenTexts.DONE, (button) -> {
for (EntryInfo info : entries)
if (info.id.equals(modid)) {
try {
info.field.set(null, info.value);
} catch (IllegalAccessException ignored) {}
}
write(modid);
Objects.requireNonNull(client).setScreen(parent);
}).dimensions(this.width / 2 + 4, this.height - 28, 150, 20).build());
this.list = new MidnightConfigListWidget(this.client, this.width, this.height, 32, this.height - 32, 25);
if (this.client != null && this.client.world != null) this.list.setRenderBackground(false);
this.addSelectableChild(this.list);
for (EntryInfo info : entries) {
if (info.id.equals(modid)) {
Text name = Objects.requireNonNullElseGet(info.name, () -> Text.translatable(translationPrefix + info.field.getName()));
ButtonWidget resetButton = ButtonWidget.builder(Text.literal("Reset").formatted(Formatting.RED), (button -> {
info.value = info.defaultValue;
info.tempValue = info.defaultValue.toString();
info.index = 0;
double scrollAmount = list.getScrollAmount();
this.reload = true;
Objects.requireNonNull(client).setScreen(this);
list.setScrollAmount(scrollAmount);
})).dimensions(width - 205, 0, 40, 20).build();
if (info.widget instanceof Map.Entry) {
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()));
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) {
if (!reload) info.index = 0;
TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 160, 0, 150, 20, Text.empty());
widget.setMaxLength(info.width);
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);
widget.setTextPredicate(processor);
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 -> {
((List<String>)info.value).remove("");
double scrollAmount = list.getScrollAmount();
this.reload = true;
info.index = info.index + 1;
if (info.index > ((List<String>)info.value).size()) info.index = 0;
Objects.requireNonNull(client).setScreen(this);
list.setScrollAmount(scrollAmount);
})).dimensions(width - 185, 0, 20, 20).build();
widget.setTooltip(getTooltip(info));
this.list.addButton(List.of(widget, resetButton, cycleButton), name, info);
} else if (info.widget != null) {
ClickableWidget widget;
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);
else widget = new TextFieldWidget(textRenderer, width - 160, 0, 150, 20, null, Text.of(info.tempValue));
if (widget instanceof TextFieldWidget textField) {
textField.setMaxLength(info.width);
textField.setText(info.tempValue);
Predicate<String> processor = ((BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) info.widget).apply(textField, done);
textField.setTextPredicate(processor);
}
widget.setTooltip(getTooltip(info));
if (e.isColor()) {
resetButton.setWidth(20);
resetButton.setMessage(Text.literal("R").formatted(Formatting.RED));
ButtonWidget colorButton = ButtonWidget.builder(Text.literal(""), (button -> {})).dimensions(width - 185, 0, 20, 20).build();
try {colorButton.setMessage(Text.literal("").setStyle(Style.EMPTY.withColor(Color.decode(info.tempValue).getRGB())));} catch (Exception ignored) {}
info.colorButton = colorButton;
colorButton.active = false;
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(),name, info);
}
}
updateResetButtons();
}
}
@Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices);
this.list.render(matrices, mouseX, mouseY, delta);
drawCenteredText(matrices, textRenderer, title, width / 2, 15, 0xFFFFFF);
super.render(matrices,mouseX,mouseY,delta);
}
}
@Environment(EnvType.CLIENT)
public static class MidnightConfigListWidget extends ElementListWidget<ButtonEntry> {
TextRenderer textRenderer;
public MidnightConfigListWidget(MinecraftClient minecraftClient, int i, int j, int k, int l, int m) {
super(minecraftClient, i, j, k, l, m);
this.centerListVertically = false;
textRenderer = minecraftClient.textRenderer;
}
@Override
public int getScrollbarPositionX() { return this.width -7; }
public void addButton(List<ClickableWidget> buttons, Text text, EntryInfo info) {
this.addEntry(new ButtonEntry(buttons, text, info));
}
@Override
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> {
private static final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
public final List<ClickableWidget> buttons;
private final Text text;
public final EntryInfo info;
private final List<ClickableWidget> children = new ArrayList<>();
public static final Map<ClickableWidget, Text> buttonsWithText = new HashMap<>();
private ButtonEntry(List<ClickableWidget> buttons, Text text, EntryInfo info) {
if (!buttons.isEmpty()) buttonsWithText.put(buttons.get(0),text);
this.buttons = buttons;
this.text = text;
this.info = info;
children.addAll(buttons);
}
public void render(MatrixStack matrices, 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); });
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);
else DrawableHelper.drawTextWithShadow(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF);
}
}
public List<? extends Element> children() {return children;}
public List<? extends Selectable> selectableChildren() {return children;}
}
private static class MidnightSliderWidget extends SliderWidget {
private final EntryInfo info; private final Entry e;
public MidnightSliderWidget(int x, int y, int width, int height, Text text, double value, EntryInfo info) {
super(x, y, width, height, text, value);
this.e = info.field.getAnnotation(Entry.class);
this.info = info;
}
@Override
protected void updateMessage() {
this.setMessage(Text.of(info.tempValue));
}
@Override
protected void applyValue() {
if (info.field.getType() == int.class) info.value = ((Number) (e.min() + value * (e.max() - e.min()))).intValue();
else if (info.field.getType() == double.class) info.value = Math.round((e.min() + value * (e.max() - e.min())) * (double) e.precision()) / (double) e.precision();
else if (info.field.getType() == float.class) info.value = Math.round((e.min() + value * (e.max() - e.min())) * (float) e.precision()) / (float) e.precision();
info.tempValue = String.valueOf(info.value);
}
}
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Entry {
int width() default 100;
double min() default Double.MIN_NORMAL;
double max() default Double.MAX_VALUE;
String name() default "";
boolean isColor() default false;
boolean isSlider() default false;
int precision() default 100;
}
@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 Hidden {}
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Comment {
boolean centered() default false;
}
public static class HiddenAnnotationExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipClass(Class<?> clazz) { return false; }
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
return fieldAttributes.getAnnotation(Entry.class) == null;
}
}
}

View File

@@ -10,15 +10,14 @@ public class MidnightColorUtil {
} }
/** /**
* @credit https://stackoverflow.com/questions/4129666/how-to-convert-hex-to-rgb-using-java * @param colorStr e.g. "FFFFFF" or "#FFFFFF"
* @param colorStr e.g. "FFFFFF"
* @return Color as RGB * @return Color as RGB
*/ */
public static Color hex2Rgb(String colorStr) { public static Color hex2Rgb(String colorStr) {
return new Color( try {
Integer.valueOf( colorStr.substring( 0, 2 ), 16 ), return Color.decode("#" + colorStr.replace("#", ""));
Integer.valueOf( colorStr.substring( 2, 4 ), 16 ), } catch (Exception ignored) {}
Integer.valueOf( colorStr.substring( 4, 6 ), 16 )); return Color.BLACK;
} }
public static Color radialRainbow(float saturation, float brightness) { public static Color radialRainbow(float saturation, float brightness) {

View File

@@ -0,0 +1,30 @@
package eu.midnightdust.lib.util;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import dev.architectury.injectables.annotations.ExpectPlatform;
import net.minecraft.server.command.ServerCommandSource;
import java.nio.file.Path;
public class PlatformFunctions {
@ExpectPlatform
public static Path getConfigDirectory() {
// Just throw an error, the content should get replaced at runtime.
throw new AssertionError();
}
@ExpectPlatform
public static boolean isClientEnv() {
// Just throw an error, the content should get replaced at runtime.
throw new AssertionError();
}
@ExpectPlatform
public static boolean isModLoaded(String modid) {
// Just throw an error, the content should get replaced at runtime.
throw new AssertionError();
}
@ExpectPlatform
public static void registerCommand(LiteralArgumentBuilder<ServerCommandSource> command) {
// Just throw an error, the content should get replaced at runtime.
throw new AssertionError();
}
}

View File

@@ -8,9 +8,15 @@ import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class TexturedOverlayButtonWidget extends TexturedButtonWidget { public class TexturedOverlayButtonWidget extends TexturedButtonWidget {
public TexturedOverlayButtonWidget(int x, int y, int width, int height, int u, int v, Identifier texture, PressAction pressAction) { 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); 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) { 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); super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction);
} }
@@ -19,21 +25,17 @@ public class TexturedOverlayButtonWidget extends TexturedButtonWidget {
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, text); super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, text);
} }
public TexturedOverlayButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, Identifier texture, int textureWidth, int textureHeight, PressAction pressAction, TooltipSupplier tooltipSupplier, Text text) {
super(x,y,width,height, u,v,hoveredVOffset,texture,textureWidth,textureHeight,pressAction,tooltipSupplier,text);
}
@Override @Override
public void renderButton(MatrixStack matrices, int mouseX, int mouseY, float delta) { public void renderButton(MatrixStack matrices, int mouseX, int mouseY, float delta) {
RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShader(GameRenderer::getPositionTexProgram);
RenderSystem.setShaderTexture(0, WIDGETS_TEXTURE); RenderSystem.setShaderTexture(0, WIDGETS_TEXTURE);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha);
int i = this.getYImage(this.isHovered()); int i = this.getYImage(this.isHovered());
RenderSystem.enableBlend(); RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc(); RenderSystem.defaultBlendFunc();
RenderSystem.enableDepthTest(); RenderSystem.enableDepthTest();
this.drawTexture(matrices, this.x, this.y, 0, 46 + i * 20, this.width / 2, this.height); this.drawTexture(matrices, this.getX(), this.getY(), 0, 46 + i * 20, this.width / 2, this.height);
this.drawTexture(matrices, this.x + this.width / 2, this.y, 200 - this.width / 2, 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); super.renderButton(matrices, mouseX, mouseY, delta);
} }

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -3,8 +3,8 @@
"midnightlib.midnightconfig.title":"MidnightLib Config", "midnightlib.midnightconfig.title":"MidnightLib Config",
"midnightlib.midnightconfig.midnightlib_description":"§nMidnightLib", "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":"§aTrue", "midnightlib.midnightconfig.enum.ConfigButton.TRUE":"§aYes",
"midnightlib.midnightconfig.enum.ConfigButton.FALSE":"§cFalse", "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.background_texture":"Texture of config screen backgrounds",
"midnightlib.midnightconfig.midnighthats_description":"§nMidnightHats", "midnightlib.midnightconfig.midnighthats_description":"§nMidnightHats",

View File

@@ -0,0 +1,17 @@
{
"midnightlib.overview.title":"Visão geral do MidnightConfig",
"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.enum.ConfigButton.TRUE":"§aVerdadeiro",
"midnightlib.midnightconfig.enum.ConfigButton.FALSE":"§cFalso",
"midnightlib.midnightconfig.enum.ConfigButton.MODMENU":"§bModMenu",
"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."
}

View File

@@ -0,0 +1,17 @@
{
"midnightlib.overview.title":"Огляд MidnightConfig",
"midnightlib.midnightconfig.title":"Конфігурація MidnightLib",
"midnightlib.midnightconfig.midnightlib_description":"§nMidnightLib",
"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":"Вікі",
"modmenu.descriptionTranslation.midnightlib": "Загальна бібліотека для модів команди MidnightDust.\nНадає конфігураційний API, автоматичну інтеграцію з іншими модами, загальні утиліти та косметику.",
"modmenu.summaryTranslation.midnightlib": "Загальна бібліотека для модів команди MidnightDust."
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

View File

Before

Width:  |  Height:  |  Size: 217 B

After

Width:  |  Height:  |  Size: 217 B

View File

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

19
fabric-like/build.gradle Normal file
View File

@@ -0,0 +1,19 @@
architectury {
common(rootProject.enabled_platforms.split(","))
}
repositories {
maven { url "https://maven.terraformersmc.com/releases" }
}
loom {
}
dependencies {
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_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}")
compileClasspath(project(path: ":common", configuration: "namedElements")) { transitive false }
}

View File

@@ -2,12 +2,14 @@ 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.config.MidnightLibConfig; import eu.midnightdust.core.config.MidnightLibConfig;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class AutoModMenu implements ModMenuApi { public class AutoModMenu implements ModMenuApi {
@Override @Override
public ConfigScreenFactory<?> getModConfigScreenFactory() { public ConfigScreenFactory<?> getModConfigScreenFactory() {
return parent -> MidnightLibConfig.getScreen(parent,"midnightlib"); return parent -> MidnightLibConfig.getScreen(parent,"midnightlib");
@@ -16,7 +18,11 @@ public class AutoModMenu implements ModMenuApi {
@Override @Override
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) -> map.put(modid, parent -> MidnightConfig.getScreen(parent, modid))); MidnightConfig.configClass.forEach((modid, cClass) -> {
if (!MidnightLibClient.hiddenMods.contains(modid))
map.put(modid, parent -> MidnightConfig.getScreen(parent, modid));
}
);
return map; return map;
} }
} }

81
fabric/build.gradle Normal file
View File

@@ -0,0 +1,81 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.1.2"
}
architectury {
platformSetupLoomIde()
fabric()
}
loom {
}
configurations {
common
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentFabric.extendsFrom common
archivesBaseName = rootProject.archives_base_name + "-fabric"
}
dependencies {
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
common(project(path: ":common", configuration: "namedElements")) { 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 {
inputs.property "version", project.version
filesMatching("fabric.mod.json") {
expand "version": project.version
}
}
shadowJar {
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon]
classifier "dev-shadow"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
classifier null
}
jar {
classifier "dev"
}
sourcesJar {
def commonSources = project(":common").sourcesJar
dependsOn commonSources
from commonSources.archiveFile.map { zipTree(it) }
}
components.java {
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
}
publishing {
publications {
mavenFabric(MavenPublication) {
artifactId = rootProject.archives_base_name + "-" + project.name
from components.java
}
}
// 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,24 +1,17 @@
package eu.midnightdust.core; package eu.midnightdust.fabric.core;
import eu.midnightdust.core.config.MidnightLibConfig; import eu.midnightdust.core.MidnightLibClient;
import eu.midnightdust.hats.web.HatLoader;
import eu.midnightdust.hats.witch.WitchHatFeatureRenderer; import eu.midnightdust.hats.witch.WitchHatFeatureRenderer;
import eu.midnightdust.lib.config.MidnightConfig;
import eu.midnightdust.lib.util.MidnightColorUtil; import eu.midnightdust.lib.util.MidnightColorUtil;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry; import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry;
public class MidnightLibClient implements ClientModInitializer { public class MidnightLibClientFabric implements ClientModInitializer {
public static final String MOD_ID = "midnightlib";
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
MidnightConfig.init("midnightlib", MidnightLibConfig.class);
EntityModelLayerRegistry.registerModelLayer(WitchHatFeatureRenderer.WITCH_HAT_MODEL_LAYER, WitchHatFeatureRenderer::getTexturedModelData); EntityModelLayerRegistry.registerModelLayer(WitchHatFeatureRenderer.WITCH_HAT_MODEL_LAYER, WitchHatFeatureRenderer::getTexturedModelData);
if (MidnightLibConfig.special_hats) HatLoader.init(); MidnightLibClient.onInitializeClient();
ClientTickEvents.END_CLIENT_TICK.register( ClientTickEvents.END_CLIENT_TICK.register(
client -> MidnightColorUtil.tick() client -> MidnightColorUtil.tick()
); );

View File

@@ -0,0 +1,11 @@
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.util.fabric;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import eu.midnightdust.lib.util.PlatformFunctions;
import net.fabricmc.api.EnvType;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.server.command.ServerCommandSource;
import java.nio.file.Path;
public class PlatformFunctionsImpl {
/**
* This is our actual method to {@link PlatformFunctions#getConfigDirectory()}.
*/
public static Path getConfigDirectory() {
return FabricLoader.getInstance().getConfigDir();
}
public static boolean isClientEnv() {
return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT;
}
public static boolean isModLoaded(String modid) {
return FabricLoader.getInstance().isModLoaded(modid);
}
public static void registerCommand(LiteralArgumentBuilder<ServerCommandSource> command) {
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated, registrationEnvironment) -> dispatcher.register(command));
}
}

View File

@@ -21,10 +21,10 @@
"environment": "*", "environment": "*",
"entrypoints": { "entrypoints": {
"client": [ "client": [
"eu.midnightdust.core.MidnightLibClient" "eu.midnightdust.fabric.core.MidnightLibClientFabric"
], ],
"server": [ "server": [
"eu.midnightdust.core.MidnightLibServer" "eu.midnightdust.fabric.core.MidnightLibServerFabric"
], ],
"modmenu": [ "modmenu": [
"eu.midnightdust.lib.config.AutoModMenu" "eu.midnightdust.lib.config.AutoModMenu"
@@ -32,13 +32,9 @@
}, },
"mixins": [ "mixins": [
"midnightcore.mixins.json" "midnightlib.mixins.json"
], ],
"depends": {
"fabric-renderer-registries-v1": "*"
},
"custom": { "custom": {
"modmenu": { "modmenu": {
"links": { "links": {

82
forge/build.gradle Normal file
View File

@@ -0,0 +1,82 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.1.2"
}
architectury {
platformSetupLoomIde()
forge()
}
loom {
forge {
mixinConfig "midnightlib.mixins.json"
}
}
configurations {
common
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentForge.extendsFrom common
archivesBaseName = rootProject.archives_base_name + "-forge"
}
dependencies {
forge "net.minecraftforge:forge:${rootProject.forge_version}"
common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionForge")) { transitive = false }
}
processResources {
inputs.property "version", project.version
filesMatching("META-INF/mods.toml") {
expand "version": project.version
}
}
shadowJar {
exclude "fabric.mod.json"
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon]
classifier "dev-shadow"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
classifier null
}
jar {
classifier "dev"
}
sourcesJar {
def commonSources = project(":common").sourcesJar
dependsOn commonSources
from commonSources.archiveFile.map { zipTree(it) }
}
components.java {
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
}
publishing {
publications {
mavenForge(MavenPublication) {
artifactId = rootProject.archives_base_name + "-" + project.name
from components.java
}
}
// 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.
}
}

1
forge/gradle.properties Normal file
View File

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

View File

@@ -0,0 +1,37 @@
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

@@ -0,0 +1,24 @@
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

@@ -0,0 +1,19 @@
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

@@ -0,0 +1,28 @@
package eu.midnightdust.lib.util.forge;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import eu.midnightdust.lib.util.PlatformFunctions;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.FMLEnvironment;
import net.minecraftforge.fml.loading.FMLPaths;
import java.nio.file.Path;
public class PlatformFunctionsImpl {
/**
* This is our actual method to {@link PlatformFunctions#getConfigDirectory()}.
*/
public static Path getConfigDirectory() {
return FMLPaths.CONFIGDIR.get();
}
public static boolean isClientEnv() {
return FMLEnvironment.dist.isClient();
}
public static boolean isModLoaded(String modid) {
return ModList.get().isLoaded(modid);
}
public static void registerCommand(LiteralArgumentBuilder<ServerCommandSource> command) {
// Ignored here, see MidnightLibEvents#registerCommands
}
}

View File

@@ -0,0 +1,29 @@
modLoader = "javafml"
loaderVersion = "[43,)"
#issueTrackerURL = ""
license = "MIT License"
[[mods]]
modId = "midnightlib"
version = "${version}"
displayName = "MidnightLib"
logoFile = "midnightlib.png"
authors = "TeamMidnightDust, Motschen"
description = '''
Common Library for Team MidnightDust's mods.
'''
#logoFile = ""
[[dependencies.midnightlib]]
modId = "forge"
mandatory = true
versionRange = "[43,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.midnightlib]]
modId = "minecraft"
mandatory = true
versionRange = "[1.19.2,)"
ordering = "NONE"
side = "BOTH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

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

31
gradle.properties Executable file → Normal file
View File

@@ -1,18 +1,19 @@
# Done to increase the memory available to gradle. org.gradle.jvmargs=-Xmx4096M
org.gradle.jvmargs=-Xmx1G
# Fabric Properties minecraft_version=1.19.3-rc1
# check these on https://fabricmc.net/use enabled_platforms=fabric
minecraft_version=1.17.1
yarn_mappings=1.17.1+build.63
loader_version=0.11.7
# Mod Properties archives_base_name=midnightlib
mod_version = 0.2.9 mod_version=1.1.0
maven_group = eu.midnightdust maven_group=eu.midnightdust
archives_base_name = midnightlib
# Dependencies architectury_version=6.2.43
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.41.0+1.17 fabric_loader_version=0.14.11
mod_menu_version = 2.0.2 fabric_api_version=0.68.1+1.19.3
forge_version=1.19.2-43.0.8
quilt_loader_version=0.18.1-beta.9
quilt_fabric_api_version=4.0.0-beta.7+0.59.0-1.19.2
mod_menu_version = 5.0.0-alpha.4

Binary file not shown.

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.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

6
gradlew vendored
View File

@@ -205,6 +205,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \ org.gradle.wrapper.GradleWrapperMain \
"$@" "$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args. # Use "xargs" to parse quoted args.
# #
# With -n1 it outputs one arg per line, with the quotes and backslashes removed. # With -n1 it outputs one arg per line, with the quotes and backslashes removed.

180
gradlew.bat vendored
View File

@@ -1,89 +1,91 @@
@rem @rem
@rem Copyright 2015 the original author or authors. @rem Copyright 2015 the original author or authors.
@rem @rem
@rem Licensed under the Apache License, Version 2.0 (the "License"); @rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License. @rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at @rem You may obtain a copy of the License at
@rem @rem
@rem https://www.apache.org/licenses/LICENSE-2.0 @rem https://www.apache.org/licenses/LICENSE-2.0
@rem @rem
@rem Unless required by applicable law or agreed to in writing, software @rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS, @rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@rem @rem
@rem ########################################################################## @rem ##########################################################################
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter. @rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. echo location of your Java installation.
goto fail goto fail
:findJavaFromJavaHome :findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. echo location of your Java installation.
goto fail goto fail
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if %ERRORLEVEL% equ 0 goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 set EXIT_CODE=%ERRORLEVEL%
exit /b 1 if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
:mainEnd exit /b %EXIT_CODE%
if "%OS%"=="Windows_NT" endlocal
:mainEnd
:omega if "%OS%"=="Windows_NT" endlocal
:omega

View File

88
quilt/build.gradle Normal file
View File

@@ -0,0 +1,88 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.1.2"
}
repositories {
maven { url "https://maven.quiltmc.org/repository/release/" }
}
architectury {
platformSetupLoomIde()
loader("quilt")
}
loom {
}
configurations {
common
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentQuilt.extendsFrom common
archivesBaseName = rootProject.archives_base_name + "-quilt"
}
dependencies {
modImplementation "org.quiltmc:quilt-loader:${rootProject.quilt_loader_version}"
modApi "org.quiltmc.quilted-fabric-api:quilted-fabric-api:${rootProject.quilt_fabric_api_version}"
// Remove the next few lines if you don't want to depend on the API
common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionQuilt")) { transitive false }
common(project(path: ":fabric-like", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":fabric-like", configuration: "transformProductionQuilt")) { transitive false }
}
processResources {
inputs.property "group", rootProject.maven_group
inputs.property "version", project.version
filesMatching("quilt.mod.json") {
expand "group": rootProject.maven_group,
"version": project.version
}
}
shadowJar {
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon]
classifier "dev-shadow"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
classifier null
}
jar {
classifier "dev"
}
sourcesJar {
def commonSources = project(":common").sourcesJar
dependsOn commonSources
from commonSources.archiveFile.map { zipTree(it) }
}
components.java {
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
}
publishing {
publications {
mavenQuilt(MavenPublication) {
artifactId = rootProject.archives_base_name + "-" + project.name
from components.java
}
}
// 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.
}
}

1
quilt/gradle.properties Normal file
View File

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

View File

@@ -0,0 +1,29 @@
package eu.midnightdust.lib.util.fabric;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import eu.midnightdust.lib.util.PlatformFunctions;
import net.fabricmc.api.EnvType;
import net.minecraft.server.command.ServerCommandSource;
import org.quiltmc.loader.api.QuiltLoader;
import org.quiltmc.loader.impl.QuiltLoaderImpl;
import org.quiltmc.qsl.command.api.CommandRegistrationCallback;
import java.nio.file.Path;
public class PlatformFunctionsImpl {
/**
* This is our actual method to {@link PlatformFunctions#getConfigDirectory()}.
*/
public static Path getConfigDirectory() {
return QuiltLoader.getConfigDir();
}
public static boolean isClientEnv() {
return QuiltLoaderImpl.INSTANCE.getEnvironmentType() == EnvType.CLIENT;
}
public static boolean isModLoaded(String modid) {
return QuiltLoader.isModLoaded(modid);
}
public static void registerCommand(LiteralArgumentBuilder<ServerCommandSource> command) {
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated, registrationEnvironment) -> dispatcher.register(command));
}
}

View File

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

View File

@@ -0,0 +1,12 @@
package eu.midnightdust.quilt.core;
import eu.midnightdust.core.MidnightLibServer;
import org.quiltmc.loader.api.ModContainer;
import org.quiltmc.qsl.base.api.entrypoint.server.DedicatedServerModInitializer;
public class MidnightLibServerQuilt implements DedicatedServerModInitializer {
@Override
public void onInitializeServer(ModContainer mod) {
MidnightLibServer.onInitializeServer();
}
}

View File

@@ -0,0 +1,72 @@
{
"schema_version": 1,
"quilt_loader": {
"group": "${group}",
"id": "midnightlib",
"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",
"environment": "*",
"entrypoints": {
"client_init": [
"eu.midnightdust.quilt.core.MidnightLibClientQuilt"
],
"server_init": [
"eu.midnightdust.quilt.core.MidnightLibServerQuilt"
],
"modmenu": [
"eu.midnightdust.lib.config.AutoModMenu"
]
},
"depends": [
{
"id": "quilt_loader",
"version": "*"
},
{
"id": "quilt_base",
"version": "*"
}
],
"metadata": {
"name": "MidnightLib (Quilt)",
"description": "Common Library for Team MidnightDust's mods.\nProvides a config api, automatic integration with other mods, common utils, and cosmetics.",
"contributors": {
"Motschen": "Author",
"TeamMidnightDust": "Mascot"
},
"contact": {
"email": "mail@midnightdust.eu",
"homepage": "https://modrinth.com/mod/midnightlib",
"issues": "https://github.com/TeamMidnightDust/MidnightLib/issues",
"sources": "https://github.com/TeamMidnightDust/MidnightLib"
},
"icon": "assets/midnightlib/icon.png"
}
},
"mixin": [
"midnightlib.mixins.json"
],
"modmenu": {
"links": {
"modmenu.discord": "https://discord.midnightdust.eu/",
"modmenu.website": "https://www.midnightdust.eu/",
"midnightlib.curseforge": "https://www.curseforge.com/minecraft/mc-mods/midnightlib",
"midnightlib.modrinth": "https://modrinth.com/mod/midnightlib",
"midnightlib.wiki": "https://github.com/TeamMidnightDust/MidnightLib/wiki"
},
"badges": [ "library" ]
}
}

16
settings.gradle Executable file → Normal file
View File

@@ -1,10 +1,16 @@
pluginManagement { pluginManagement {
repositories { repositories {
jcenter() maven { url "https://maven.fabricmc.net/" }
maven { maven { url "https://maven.architectury.dev/" }
name = 'Fabric' maven { url "https://maven.minecraftforge.net/" }
url = 'https://maven.fabricmc.net/'
}
gradlePluginPortal() gradlePluginPortal()
} }
} }
include("common")
include("fabric-like")
include("fabric")
//include("quilt")
//include("forge")
rootProject.name = "midnightlib"

View File

@@ -1,19 +0,0 @@
package eu.midnightdust.core.config;
import eu.midnightdust.lib.config.MidnightConfig;
import net.fabricmc.loader.api.FabricLoader;
public class MidnightLibConfig extends MidnightConfig {
@Comment public static Comment midnightlib_description;
@Entry // Enable or disable the MidnightConfig overview screen button
public static ConfigButton config_screen_list = FabricLoader.getInstance().isModLoaded("modmenu") ? ConfigButton.MODMENU : ConfigButton.TRUE;
@Entry // Change the texture of the background in MidnightConfig
public static String background_texture = "minecraft:textures/block/deepslate.png";
@Comment public static Comment midnighthats_description;
@Entry // Enable or disable hats for contributors, friends and donors.
public static boolean special_hats = true;
public enum ConfigButton {
TRUE,FALSE,MODMENU
}
}

View File

@@ -1,23 +0,0 @@
package eu.midnightdust.core.mixin;
import com.mojang.blaze3d.systems.RenderSystem;
import eu.midnightdust.core.config.MidnightLibConfig;
import net.minecraft.client.gui.widget.EntryListWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
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;
import java.util.Locale;
@Mixin(EntryListWidget.class)
public abstract class MixinEntryListWidget {
@Inject(at = @At(value = "INVOKE",target = "Lcom/mojang/blaze3d/systems/RenderSystem;setShaderTexture(ILnet/minecraft/util/Identifier;)V",shift = At.Shift.AFTER), method = "render", cancellable = true)
private void custom_background(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) {
if (!MidnightLibConfig.background_texture.equals("") && this.getClass().toString().toLowerCase(Locale.ROOT).contains("midnight"))
RenderSystem.setShaderTexture(0, Identifier.tryParse(MidnightLibConfig.background_texture));
}
}

View File

@@ -1,380 +0,0 @@
package eu.midnightdust.lib.config;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
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.ScreenTexts;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.gui.widget.ElementListWidget;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
/** MidnightConfig v1.0.8 by TeamMidnightDust & Motschen
* Single class config library - feel free to copy!
*
* Based on https://github.com/Minenash/TinyConfig
* Credits to Minenash */
@SuppressWarnings("unchecked")
public abstract class MidnightConfig {
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 List<EntryInfo> entries = new ArrayList<>();
protected static class EntryInfo {
Field field;
Object widget;
int width;
int max;
Map.Entry<TextFieldWidget,Text> error;
Object defaultValue;
Object value;
String tempValue;
boolean inLimits = true;
String id;
TranslatableText name;
}
public static final Map<String,Class<?>> configClass = new HashMap<>();
private static Path path;
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) {
path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json");
configClass.put(modid, config);
for (Field field : config.getFields()) {
EntryInfo info = new EntryInfo();
if (field.isAnnotationPresent(Entry.class) || field.isAnnotationPresent(Comment.class))
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) initClient(modid, field, info);
if (field.isAnnotationPresent(Entry.class))
try {
info.defaultValue = field.get(null);
} catch (IllegalAccessException ignored) {}
}
try { gson.fromJson(Files.newBufferedReader(path), config); }
catch (Exception e) { write(modid); }
for (EntryInfo info : entries) {
if (info.field.isAnnotationPresent(Entry.class))
try {
info.value = info.field.get(null);
info.tempValue = info.value.toString();
} catch (IllegalAccessException ignored) {
}
}
}
@Environment(EnvType.CLIENT)
private static void initClient(String modid, Field field, EntryInfo info) {
Class<?> type = field.getType();
Entry e = field.getAnnotation(Entry.class);
info.width = e != null ? e.width() : 0;
info.field = field;
info.id = modid;
if (e != null) {
if (!e.name().equals("")) info.name = new TranslatableText(e.name());
if (type == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, e.min(), e.max(), true);
else if (type == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(), false);
else if (type == String.class) {
info.max = e.max() == Double.MAX_VALUE ? Integer.MAX_VALUE : (int) e.max();
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 -> new LiteralText((Boolean) value ? "True" : "False").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED);
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
info.value = !(Boolean) info.value;
button.setMessage(func.apply(info.value));
}, func);
} else if (type.isEnum()) {
List<?> values = Arrays.asList(field.getType().getEnumConstants());
Function<Object, Text> func = value -> new TranslatableText(modid + ".midnightconfig." + "enum." + type.getSimpleName() + "." + info.value.toString());
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
int index = values.indexOf(info.value) + 1;
info.value = values.get(index >= values.size() ? 0 : index);
button.setMessage(func.apply(info.value));
}, func);
}
}
entries.add(info);
}
private static void textField(EntryInfo info, Function<String,Number> f, Pattern pattern, double min, double max, boolean cast) {
boolean isNumber = pattern != null;
info.widget = (BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) (t, b) -> s -> {
s = s.trim();
if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches())) return false;
Number value = 0;
boolean inLimits = false;
System.out.println(((isNumber ^ s.isEmpty())));
System.out.println(!s.equals("-") && !s.equals("."));
info.error = null;
if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) {
value = f.apply(s);
inLimits = value.doubleValue() >= min && value.doubleValue() <= max;
info.error = inLimits? null : new AbstractMap.SimpleEntry<>(t, new LiteralText(value.doubleValue() < min ?
"§cMinimum " + (isNumber? "value" : "length") + (cast? " is " + (int)min : " is " + min) :
"§cMaximum " + (isNumber? "value" : "length") + (cast? " is " + (int)max : " is " + max)));
}
info.tempValue = s;
t.setEditableColor(inLimits? 0xFFFFFFFF : 0xFFFF7777);
info.inLimits = inLimits;
b.active = entries.stream().allMatch(e -> e.inLimits);
if (inLimits)
info.value = isNumber? value : s;
return true;
};
}
public static void write(String modid) {
path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json");
try {
if (!Files.exists(path)) Files.createFile(path);
Files.write(path, gson.toJson(configClass.get(modid).getDeclaredConstructor().newInstance()).getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
@Environment(EnvType.CLIENT)
public static Screen getScreen(Screen parent, String modid) {
return new MidnightConfigScreen(parent, modid);
}
@Environment(EnvType.CLIENT)
private static class MidnightConfigScreen extends Screen {
protected MidnightConfigScreen(Screen parent, String modid) {
super(new TranslatableText(modid + ".midnightconfig." + "title"));
this.parent = parent;
this.modid = modid;
this.translationPrefix = modid + ".midnightconfig.";
}
private final String translationPrefix;
private final Screen parent;
private final String modid;
private MidnightConfigListWidget list;
private boolean reload = false;
// Real Time config update //
@Override
public void tick() {
super.tick();
for (EntryInfo info : entries)
try { info.field.set(null, info.value); }
catch (IllegalAccessException ignored) {}
}
private void loadValues() {
try { gson.fromJson(Files.newBufferedReader(path), configClass.get(modid)); }
catch (Exception e) { write(modid); }
for (EntryInfo info : entries) {
if (info.field.isAnnotationPresent(Entry.class))
try {
info.value = info.field.get(null);
info.tempValue = info.value.toString();
} catch (IllegalAccessException ignored) {
}
}
}
@Override
protected void init() {
super.init();
if (!reload) loadValues();
this.addDrawableChild(new ButtonWidget(this.width / 2 - 154, this.height - 28, 150, 20, ScreenTexts.CANCEL, button -> {
loadValues();
Objects.requireNonNull(client).setScreen(parent);
}));
ButtonWidget done = this.addDrawableChild(new ButtonWidget(this.width / 2 + 4, this.height - 28, 150, 20, ScreenTexts.DONE, (button) -> {
for (EntryInfo info : entries)
if (info.id.equals(modid)) {
try {
info.field.set(null, info.value);
} catch (IllegalAccessException ignored) {}
}
write(modid);
Objects.requireNonNull(client).setScreen(parent);
}));
this.list = new MidnightConfigListWidget(this.client, this.width, this.height, 32, this.height - 32, 25);
if (this.client != null && this.client.world != null) this.list.setRenderBackground(false);
this.addSelectableChild(this.list);
for (EntryInfo info : entries) {
if (info.id.equals(modid)) {
TranslatableText name = Objects.requireNonNullElseGet(info.name, () -> new TranslatableText(translationPrefix + info.field.getName()));
ButtonWidget resetButton = new ButtonWidget(width - 155, 0, 40, 20, new LiteralText("Reset").formatted(Formatting.RED), (button -> {
info.value = info.defaultValue;
info.tempValue = info.value.toString();
double scrollAmount = list.getScrollAmount();
this.reload = true;
Objects.requireNonNull(client).setScreen(this);
list.setScrollAmount(scrollAmount);
}));
if (info.widget instanceof Map.Entry) {
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 -> new TranslatableText(translationPrefix + "enum." + info.field.getType().getSimpleName() + "." + info.value.toString()));
this.list.addButton(new ButtonWidget(width - 110, 0,100, 20, widget.getValue().apply(info.value), widget.getKey()),resetButton,name);
} else if (info.widget != null) {
TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 110, 0, 100, 20, null);
widget.setMaxLength(info.width);
widget.setText(info.tempValue);
Predicate<String> processor = ((BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) info.widget).apply(widget, done);
widget.setTextPredicate(processor);
this.list.addButton(widget, resetButton, name);
} else {
ButtonWidget dummy = new ButtonWidget(-10, 0, 0, 0, Text.of(""), null);
this.list.addButton(dummy,dummy,name);
}
}
}
}
@Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices);
this.list.render(matrices, mouseX, mouseY, delta);
int stringWidth = (int) (title.getString().length() * 2.75f);
renderTooltip(matrices, title, width/2 - stringWidth, 27);
//drawCenteredText(matrices, textRenderer, title, width / 2, 15, 0xFFFFFF);
for (EntryInfo info : entries) {
if (info.id.equals(modid)) {
if (list.getHoveredButton(mouseX,mouseY).isPresent()) {
ClickableWidget buttonWidget = list.getHoveredButton(mouseX,mouseY).get();
Text text = ButtonEntry.buttonsWithText.get(buttonWidget);
TranslatableText name = new TranslatableText(this.translationPrefix + info.field.getName());
String key = translationPrefix + info.field.getName() + ".tooltip";
if (info.error != null && text.equals(name)) renderTooltip(matrices, info.error.getValue(), mouseX, mouseY);
else if (I18n.hasTranslation(key) && text.equals(name)) {
List<Text> list = new ArrayList<>();
for (String str : I18n.translate(key).split("\n"))
list.add(new LiteralText(str));
renderTooltip(matrices, list, mouseX, mouseY);
}
}
}
}
super.render(matrices,mouseX,mouseY,delta);
}
}
@Environment(EnvType.CLIENT)
public static class MidnightConfigListWidget extends ElementListWidget<ButtonEntry> {
TextRenderer textRenderer;
public MidnightConfigListWidget(MinecraftClient minecraftClient, int i, int j, int k, int l, int m) {
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, ClickableWidget resetButton, Text text) {
this.addEntry(ButtonEntry.create(button, text, resetButton));
}
@Override
public int getRowWidth() { return 10000; }
public Optional<ClickableWidget> getHoveredButton(double mouseX, double mouseY) {
for (ButtonEntry buttonEntry : this.children()) {
for (ClickableWidget ClickableWidget : buttonEntry.buttons) {
if (ClickableWidget.isMouseOver(mouseX, mouseY)) {
return Optional.of(ClickableWidget);
}
}
}
return Optional.empty();
}
}
public static class ButtonEntry extends ElementListWidget.Entry<ButtonEntry> {
private static final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
private final List<ClickableWidget> buttons = new ArrayList<>();
private final List<ClickableWidget> resetButtons = new ArrayList<>();
private final List<Text> texts = new ArrayList<>();
private final List<ClickableWidget> buttonsWithResetButtons = new ArrayList<>();
public static final Map<ClickableWidget, Text> buttonsWithText = new HashMap<>();
private ButtonEntry(ClickableWidget button, Text text, ClickableWidget resetButton) {
buttonsWithText.put(button,text);
this.buttons.add(button);
this.resetButtons.add(resetButton);
this.texts.add(text);
this.buttonsWithResetButtons.add(button);
this.buttonsWithResetButtons.add(resetButton);
}
public static ButtonEntry create(ClickableWidget button, Text text, ClickableWidget resetButton) {
return new ButtonEntry(button, text, resetButton);
}
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
this.buttons.forEach(button -> {
button.y = y;
button.render(matrices, mouseX, mouseY, tickDelta);
});
this.texts.forEach(text -> DrawableHelper.drawTextWithShadow(matrices,textRenderer, text,12,y+5,0xFFFFFF));
this.resetButtons.forEach((button) -> {
button.y = y;
button.render(matrices, mouseX, mouseY, tickDelta);
});
}
public List<? extends Element> children() {
return buttonsWithResetButtons;
}
public List<? extends Selectable> selectableChildren() {
return buttonsWithResetButtons;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Entry {
int width() default 100;
double min() default Double.MIN_NORMAL;
double max() default Double.MAX_VALUE;
String name() default "";
}
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Comment {}
public static class HiddenAnnotationExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipClass(Class<?> clazz) { return false; }
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
return fieldAttributes.getAnnotation(Entry.class) == null;
}
}
}

View File

@@ -1,20 +0,0 @@
package eu.midnightdust.lib.util.render.entity;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.entity.feature.EyesFeatureRenderer;
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Identifier;
public class EmissiveOverlayRenderer<T extends LivingEntity> extends EyesFeatureRenderer<T, EntityModel<T>> {
private final RenderLayer SKIN;
public EmissiveOverlayRenderer(FeatureRendererContext<T, EntityModel<T>> featureRendererContext, Identifier texture) {
super(featureRendererContext);
SKIN = RenderLayer.getEyes(texture);
}
public RenderLayer getEyesTexture() {
return SKIN;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 B