MidnightLib v0.2.0 for 21w19a

- MidnightConfig screens can be viewed from a new screen in the minecraft options
- Code cleanup
- Examples & Documentation
- New Methods
- Upgrade to 21w19a and Java 16

MidnightConfig v1.0.0:
 - The config screen no longer shows the entries of all instances of MidnightConfig
 - Compatible with servers!
 - Scrollable!
 - Comment support!
 - Fresh new design
This commit is contained in:
Motschen
2021-05-14 22:20:20 +02:00
parent a4be637128
commit 235042f30e
48 changed files with 563 additions and 313 deletions

0
.gitignore vendored Normal file → Executable file
View File

0
LICENSE Normal file → Executable file
View File

0
README.md Normal file → Executable file
View File

58
build.gradle Normal file → Executable file
View File

@@ -1,10 +1,10 @@
plugins { plugins {
id 'fabric-loom' version '0.6-SNAPSHOT' id 'fabric-loom' version '0.8-SNAPSHOT'
id 'maven-publish' id 'maven-publish'
} }
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_16
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_16
archivesBaseName = project.archives_base_name archivesBaseName = project.archives_base_name
version = project.mod_version version = project.mod_version
@@ -14,7 +14,7 @@ minecraft {
} }
repositories { repositories {
maven { url "https://maven.shedaniel.me/" } maven { url "https://maven.terraformersmc.com/releases" }
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
} }
@@ -22,43 +22,43 @@ dependencies {
//to change the versions see the gradle.properties file //to change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}" minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modCompile "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modImplementation ("io.github.prospector:modmenu:${project.mod_menu_version}") modImplementation ("com.terraformersmc:modmenu:${project.mod_menu_version}")
} }
processResources { processResources {
inputs.property "version", project.version inputs.property "version", project.version
from(sourceSets.main.resources.srcDirs) { filesMatching("fabric.mod.json") {
include "fabric.mod.json"
expand "version": project.version expand "version": project.version
} }
from(sourceSets.main.resources.srcDirs) {
exclude "fabric.mod.json"
}
} }
// ensure that the encoding is set to UTF-8, no matter what the system default is tasks.withType(JavaCompile).configureEach {
// this fixes some edge cases with special characters not displaying correctly // ensure that the encoding is set to UTF-8, no matter what the system default is
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html // this fixes some edge cases with special characters not displaying correctly
tasks.withType(JavaCompile) { // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
options.encoding = "UTF-8" // If Javadoc is generated, this must be specified in that task too.
it.options.encoding = "UTF-8"
// Minecraft 1.17 (21w19a) upwards uses Java 16.
it.options.release = 16
} }
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task java {
// if it is present. // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
// If you remove this task, sources will not be generated. // if it is present.
task sourcesJar(type: Jar, dependsOn: classes) { // If you remove this line, sources will not be generated.
classifier = "sources" withSourcesJar()
from sourceSets.main.allSource
} }
jar { jar {
from "LICENSE" from("LICENSE") {
rename { "${it}_${project.archivesBaseName}"}
}
} }
// configure the maven publication // configure the maven publication
@@ -75,9 +75,11 @@ publishing {
} }
} }
// select the repositories you want to publish to // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
repositories { repositories {
// uncomment to publish to the local maven // Add repositories to publish to here.
// mavenLocal() // 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.
} }
} }

12
gradle.properties Normal file → Executable file
View File

@@ -3,16 +3,16 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties # Fabric Properties
# check these on https://fabricmc.net/use # check these on https://fabricmc.net/use
minecraft_version=21w08b minecraft_version=21w19a
yarn_mappings=21w08b+build.5 yarn_mappings=21w19a+build.9
loader_version=0.11.2 loader_version=0.11.3
# Mod Properties # Mod Properties
mod_version = 0.1.0 mod_version = 0.2.0
maven_group = eu.midnightdust maven_group = eu.midnightdust
archives_base_name = midnightlib archives_base_name = midnightlib
# Dependencies # Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.31.1+1.17 fabric_version=0.34.4+1.17
mod_menu_version = 2.0.0-beta.1+build.2 mod_menu_version = 2.0.0-beta.4

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file → Executable file

Binary file not shown.

2
gradle/wrapper/gradle-wrapper.properties vendored Normal file → Executable file
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-5.5.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

35
gradlew vendored Normal file → Executable file
View File

@@ -82,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -125,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi fi
# For Cygwin, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if $cygwin ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath
@@ -154,19 +156,19 @@ if $cygwin ; then
else else
eval `echo args$i`="\"$arg\"" eval `echo args$i`="\"$arg\""
fi fi
i=$((i+1)) i=`expr $i + 1`
done done
case $i in case $i in
(0) set -- ;; 0) set -- ;;
(1) set -- "$args0" ;; 1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;; 2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;; 3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
@@ -175,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " " echo " "
} }
APP_ARGS=$(save "$@") APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules # Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

25
gradlew.bat vendored Normal file → Executable file
View File

@@ -29,6 +29,9 @@ 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.
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"
@@ -37,7 +40,7 @@ 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 init if "%ERRORLEVEL%" == "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.
@@ -51,7 +54,7 @@ goto fail
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 init 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%
@@ -61,28 +64,14 @@ echo location of your Java installation.
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
: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 %CMD_LINE_ARGS% "%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

0
logs/latest.log Normal file → Executable file
View File

0
settings.gradle Normal file → Executable file
View File

View File

@@ -1,28 +1,29 @@
package eu.midnightdust.hats; package eu.midnightdust.core;
import eu.midnightdust.hats.bunny.BunnyEarsFeatureRenderer; import eu.midnightdust.hats.bunny.BunnyEarsFeatureRenderer;
import eu.midnightdust.hats.christmas.ChristmasHatFeatureRenderer; import eu.midnightdust.hats.christmas.ChristmasHatFeatureRenderer;
import eu.midnightdust.hats.config.HatsConfig; import eu.midnightdust.core.config.MidnightLibConfig;
import eu.midnightdust.hats.tater.TinyPotatoFeatureRenderer; import eu.midnightdust.hats.tater.TinyPotatoFeatureRenderer;
import eu.midnightdust.hats.web.HatLoader; 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 net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityModelLayerRegistry; import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityModelLayerRegistry;
@SuppressWarnings({"deprecation", "UnstableApiUsage"}) @SuppressWarnings({"deprecation", "UnstableApiUsage"})
public class HatsClient implements ClientModInitializer { public class MidnightLibClient implements ClientModInitializer {
public static final String MOD_ID = "midnightlib"; public static final String MOD_ID = "midnightlib";
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
HatsConfig.init("midnightlib", HatsConfig.class); MidnightConfig.init("midnightlib", MidnightLibConfig.class);
EntityModelLayerRegistry.registerModelLayer(BunnyEarsFeatureRenderer.RABBIT_EARS_MODEL_LAYER, BunnyEarsFeatureRenderer::getTexturedModelData); EntityModelLayerRegistry.registerModelLayer(BunnyEarsFeatureRenderer.RABBIT_EARS_MODEL_LAYER, BunnyEarsFeatureRenderer::getTexturedModelData);
EntityModelLayerRegistry.registerModelLayer(ChristmasHatFeatureRenderer.CHRISTMAS_HAT_MODEL_LAYER, ChristmasHatFeatureRenderer::getTexturedModelData); EntityModelLayerRegistry.registerModelLayer(ChristmasHatFeatureRenderer.CHRISTMAS_HAT_MODEL_LAYER, ChristmasHatFeatureRenderer::getTexturedModelData);
EntityModelLayerRegistry.registerModelLayer(TinyPotatoFeatureRenderer.TINY_POTATO_MODEL_LAYER, TinyPotatoFeatureRenderer::getTexturedModelData); EntityModelLayerRegistry.registerModelLayer(TinyPotatoFeatureRenderer.TINY_POTATO_MODEL_LAYER, TinyPotatoFeatureRenderer::getTexturedModelData);
EntityModelLayerRegistry.registerModelLayer(WitchHatFeatureRenderer.WITCH_HAT_MODEL_LAYER, WitchHatFeatureRenderer::getTexturedModelData); EntityModelLayerRegistry.registerModelLayer(WitchHatFeatureRenderer.WITCH_HAT_MODEL_LAYER, WitchHatFeatureRenderer::getTexturedModelData);
if (HatsConfig.special_hats) { if (MidnightLibConfig.special_hats) {
HatLoader.init(); HatLoader.init();
} }
} }

View File

@@ -0,0 +1,16 @@
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 boolean config_screen_list = !FabricLoader.getInstance().isModLoaded("modmenu");
@Comment public static Comment midnighthats_description;
@Entry // Enable or disable event hats
public static boolean event_hats = true;
@Entry // Enable or disable hats for contributors, friends and donors.
public static boolean special_hats = true;
}

View File

@@ -0,0 +1,30 @@
package eu.midnightdust.core.mixin;
import eu.midnightdust.core.config.MidnightLibConfig;
import eu.midnightdust.core.screen.MidnightConfigOverviewScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.option.OptionsScreen;
import net.minecraft.client.gui.widget.TexturedButtonWidget;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
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.Objects;
@Mixin(OptionsScreen.class)
public class MixinOptionsScreen extends Screen {
private static final Identifier MIDNIGHTLIB_ICON_TEXTURE = new Identifier("midnightlib","textures/gui/midnightlib_button.png");
protected MixinOptionsScreen(Text title) {
super(title);
}
@Inject(at = @At("HEAD"),method = "init")
private void midnightlib$init(CallbackInfo ci) {
if (MidnightLibConfig.config_screen_list)
this.addButton(new TexturedButtonWidget(this.width / 2 + 158, this.height / 6 - 12, 20, 20, 0, 0, 20, MIDNIGHTLIB_ICON_TEXTURE, 32, 64, (buttonWidget) -> Objects.requireNonNull(client).openScreen(new MidnightConfigOverviewScreen(this)), new TranslatableText("narrator.button.midnightlib")));
}
}

View File

@@ -0,0 +1,89 @@
package eu.midnightdust.core.screen;
import eu.midnightdust.lib.config.MidnightConfig;
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.Element;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ScreenTexts;
import net.minecraft.client.gui.widget.*;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.*;
import java.util.*;
@Environment(EnvType.CLIENT)
public class MidnightConfigOverviewScreen extends Screen {
public MidnightConfigOverviewScreen(Screen parent) {
super(new TranslatableText( "midnightlib.overview.title"));
this.parent = parent;
}
private final Screen parent;
private MidnightOverviewListWidget list;
@Override
protected void init() {
super.init();
this.addButton(new ButtonWidget(this.width / 2 - 100, this.height - 28, 200, 20, ScreenTexts.DONE, (button) -> {
Objects.requireNonNull(client).openScreen(parent);
}));
this.list = new MidnightOverviewListWidget(this.client, this.width, this.height, 32, this.height - 32, 25);
this.children.add(this.list);
MidnightConfig.configClass.forEach((modid, configClass) -> {
list.addButton(new ButtonWidget(this.width / 2 - 100, this.height - 28, 200, 20, new TranslatableText(modid +".midnightconfig.title"), (button) -> {
Objects.requireNonNull(client).openScreen(MidnightConfig.getScreen(this,modid));
}));
});
}
@Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices);
this.list.render(matrices, mouseX, mouseY, delta);
int stringWidth = title.getString().length() + 47;
super.render(matrices, mouseX, mouseY, delta);
if (MidnightConfig.useTooltipForTitle) renderTooltip(matrices, title, width/2 - stringWidth, 27);
else drawCenteredText(matrices, textRenderer, title, width / 2, 15, 0xFFFFFF);
}
@Environment(EnvType.CLIENT)
public static class MidnightOverviewListWidget extends ElementListWidget<OverviewButtonEntry> {
TextRenderer textRenderer;
public MidnightOverviewListWidget(MinecraftClient minecraftClient, int i, int j, int k, int l, int m) {
super(minecraftClient, i, j, k, l, m);
this.centerListVertically = false;
textRenderer = minecraftClient.textRenderer;
}
@Override
public int getScrollbarPositionX() { return this.width -7; }
public void addButton(AbstractButtonWidget button) {
this.addEntry(OverviewButtonEntry.create(button));
}
@Override
public int getRowWidth() { return 400; }
}
public static class OverviewButtonEntry extends ElementListWidget.Entry<OverviewButtonEntry> {
private final List<AbstractButtonWidget> buttons = new ArrayList<>();
private OverviewButtonEntry(AbstractButtonWidget button) {
this.buttons.add(button);
}
public static OverviewButtonEntry create(AbstractButtonWidget 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) {
this.buttons.forEach((button) -> {
button.y = y;
button.render(matrices, mouseX, mouseY, tickDelta);
});
}
public List<? extends Element> children() {
return buttons;
}
}
}

View File

@@ -1,7 +1,7 @@
package eu.midnightdust.hats.bunny; package eu.midnightdust.hats.bunny;
import eu.midnightdust.hats.HatsClient; import eu.midnightdust.core.MidnightLibClient;
import eu.midnightdust.hats.config.AreEventHatsEnabled; import eu.midnightdust.core.config.MidnightLibConfig;
import eu.midnightdust.hats.web.HatLoader; import eu.midnightdust.hats.web.HatLoader;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
@@ -25,7 +25,7 @@ import java.util.UUID;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public class BunnyEarsFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> { public class BunnyEarsFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> {
private static final String MOD_ID = HatsClient.MOD_ID; private static final String MOD_ID = MidnightLibClient.MOD_ID;
public static final EntityModelLayer RABBIT_EARS_MODEL_LAYER = new EntityModelLayer(new Identifier("midnight-hats","bunny_ears"), "main"); public static final EntityModelLayer RABBIT_EARS_MODEL_LAYER = new EntityModelLayer(new Identifier("midnight-hats","bunny_ears"), "main");
private static final UUID MOTSCHEN = UUID.fromString("a44c2660-630f-478f-946a-e518669fcf0c"); private static final UUID MOTSCHEN = UUID.fromString("a44c2660-630f-478f-946a-e518669fcf0c");
@@ -49,13 +49,10 @@ public class BunnyEarsFeatureRenderer<T extends LivingEntity, M extends EntityMo
if (livingEntity != null) { if (livingEntity != null) {
if (Calendar.getInstance().get(Calendar.MONTH) == Calendar.APRIL && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) <= 4) { if (Calendar.getInstance().get(Calendar.MONTH) == Calendar.APRIL && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) <= 4) {
if (FabricLoader.getInstance().isModLoaded("cloth-config2")) { if (MidnightLibConfig.event_hats) {
if (AreEventHatsEnabled.areEventHatsEnabled()) { hat_type = RABBIT;
hat_type = RABBIT;
}
else hat_type = DEACTIVATED;
} }
else hat_type = RABBIT; else hat_type = DEACTIVATED;
}else { }else {
hat_type = DEACTIVATED; hat_type = DEACTIVATED;
} }

View File

@@ -11,10 +11,8 @@ public class BunnyEarsModel<T extends LivingEntity> extends SinglePartEntityMode
public BunnyEarsModel(ModelPart root) { public BunnyEarsModel(ModelPart root) {
this.right_ear = root; this.right_ear = root;
right_ear.setPivot(0.0F, -3.0F, -1.0F); right_ear.setPivot(0.0F, -3.0F, -1.0F);
}
}
public static ModelData getModelData(){ public static ModelData getModelData(){
ModelData modelData = new ModelData(); ModelData modelData = new ModelData();
ModelPartData modelPartData = modelData.getRoot(); ModelPartData modelPartData = modelData.getRoot();
@@ -35,10 +33,4 @@ public class BunnyEarsModel<T extends LivingEntity> extends SinglePartEntityMode
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){
right_ear.render(matrixStack, buffer, packedLight, packedOverlay); right_ear.render(matrixStack, buffer, packedLight, packedOverlay);
} }
public void setRotationAngle(ModelPart bone, float x, float y, float z) {
bone.pitch = x;
bone.yaw = y;
bone.roll = z;
}
} }

View File

@@ -1,11 +1,10 @@
package eu.midnightdust.hats.christmas; package eu.midnightdust.hats.christmas;
import eu.midnightdust.hats.HatsClient; import eu.midnightdust.core.MidnightLibClient;
import eu.midnightdust.hats.config.AreEventHatsEnabled; import eu.midnightdust.core.config.MidnightLibConfig;
import eu.midnightdust.hats.web.HatLoader; import eu.midnightdust.hats.web.HatLoader;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.model.TexturedModelData; import net.minecraft.client.model.TexturedModelData;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.OverlayTexture;
@@ -28,7 +27,7 @@ import java.util.UUID;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public class ChristmasHatFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> { public class ChristmasHatFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> {
private static final String MOD_ID = HatsClient.MOD_ID; private static final String MOD_ID = MidnightLibClient.MOD_ID;
public static final EntityModelLayer CHRISTMAS_HAT_MODEL_LAYER = new EntityModelLayer(new Identifier("midnight-hats","christmas_hat"), "main"); public static final EntityModelLayer CHRISTMAS_HAT_MODEL_LAYER = new EntityModelLayer(new Identifier("midnight-hats","christmas_hat"), "main");
private static final UUID MOTSCHEN = UUID.fromString("a44c2660-630f-478f-946a-e518669fcf0c"); private static final UUID MOTSCHEN = UUID.fromString("a44c2660-630f-478f-946a-e518669fcf0c");
@@ -38,7 +37,7 @@ public class ChristmasHatFeatureRenderer<T extends LivingEntity, M extends Entit
public ChristmasHatFeatureRenderer(FeatureRendererContext<T, M> featureRendererContext, EntityModelLoader entityModelLoader) { public ChristmasHatFeatureRenderer(FeatureRendererContext<T, M> featureRendererContext, EntityModelLoader entityModelLoader) {
super(featureRendererContext); super(featureRendererContext);
this.christmasHat = new ChristmasHatModel(entityModelLoader.getModelPart(CHRISTMAS_HAT_MODEL_LAYER)); this.christmasHat = new ChristmasHatModel<>(entityModelLoader.getModelPart(CHRISTMAS_HAT_MODEL_LAYER));
} }
public static TexturedModelData getTexturedModelData() { public static TexturedModelData getTexturedModelData() {
@@ -51,13 +50,10 @@ public class ChristmasHatFeatureRenderer<T extends LivingEntity, M extends Entit
Identifier hat_type; Identifier hat_type;
if (livingEntity != null) { if (livingEntity != null) {
if (Calendar.getInstance().get(Calendar.MONTH) == Calendar.DECEMBER && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) >= 23 && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) <= 26) { if (Calendar.getInstance().get(Calendar.MONTH) == Calendar.DECEMBER && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) >= 23 && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) <= 26) {
if (FabricLoader.getInstance().isModLoaded("cloth-config2")) { if (MidnightLibConfig.event_hats) {
if (AreEventHatsEnabled.areEventHatsEnabled()) { hat_type = CHRISTMAS;
hat_type = CHRISTMAS;
}
else hat_type = DEACTIVATED;
} }
else hat_type = CHRISTMAS; else hat_type = DEACTIVATED;
}else { }else {
hat_type = DEACTIVATED; hat_type = DEACTIVATED;
} }

View File

@@ -8,33 +8,30 @@ import net.minecraft.entity.LivingEntity;
public class ChristmasHatModel<T extends LivingEntity> extends SinglePartEntityModel<T> { public class ChristmasHatModel<T extends LivingEntity> extends SinglePartEntityModel<T> {
private final ModelPart headwear; private final ModelPart headwear;
private final ModelPart bone;
private final ModelPart bone2;
private final ModelPart bone3;
public ChristmasHatModel(ModelPart root) { public ChristmasHatModel(ModelPart root) {
headwear = root; headwear = root;
root.setPivot(5.0F, -9.0F, -5.0F); root.setPivot(5.0F, -9.0F, -5.0F);
bone = headwear.getChild("bone"); ModelPart bone = headwear.getChild("bone");
bone.setPivot(-8.5F, -0.1F, 1.5F); bone.setPivot(-8.5F, -0.1F, 1.5F);
setRotationAngle(bone, -0.0524F, 0.0F, 0.0349F); setRotationAngle(bone, -0.0524F, 0.0F, 0.0349F);
bone2 = bone.getChild("bone2"); ModelPart bone2 = bone.getChild("bone2");
bone2.setPivot(1.5F, -4.0F, 1.5F); bone2.setPivot(1.5F, -4.0F, 1.5F);
setRotationAngle(bone2, -0.1222F, 0.0F, 0.0698F); setRotationAngle(bone2, -0.1222F, 0.0F, 0.0698F);
bone3 = bone2.getChild("bone3"); ModelPart bone3 = bone2.getChild("bone3");
bone3.setPivot(1.5F, -4.0F, 1.5F); bone3.setPivot(1.5F, -4.0F, 1.5F);
setRotationAngle(bone3, -0.2618F, 0.0F, 0.1047F); setRotationAngle(bone3, -0.2618F, 0.0F, 0.1047F);
} }
public static ModelData getModelData(){ public static ModelData getModelData(){
ModelData modelData = new ModelData(); ModelData modelData = new ModelData();
ModelPartData modelPartData = modelData.getRoot(); ModelPartData modelPartData = modelData.getRoot();
modelPartData.addChild("headwear", ModelPartBuilder.create().uv(0, 0).cuboid(-10.0F, -0.1F, 0.0F, 10.0F, 2.0F, 10.0F), ModelTransform.NONE); modelPartData.addChild("headwear", ModelPartBuilder.create().uv(0, 0).cuboid(-10.0F, -0.1F, 0.0F, 10.0F, 2.0F, 10.0F), ModelTransform.NONE);
ModelPartData modelPartData2 = modelPartData.addChild("bone", ModelPartBuilder.create().uv(0, 12).cuboid(0.0F, -4.0F, 0.0F, 7.0F, 4.0F, 7.0F), ModelTransform.rotation(-0.0524F, 0.0F, 0.0349F)); ModelPartData modelPartData2 = modelPartData.addChild("bone", ModelPartBuilder.create().uv(0, 12).cuboid(0.0F, -4.0F, 0.0F, 7.0F, 4.0F, 7.0F), ModelTransform.rotation(-0.0524F, 0.0F, 0.0349F));
ModelPartData modelPartData3 = modelPartData2.addChild("bone2", ModelPartBuilder.create().uv(0, 23).cuboid(0.0F, -4.0F, 0.0F, 4.0F, 4.0F, 4.0F), ModelTransform.rotation(-0.1222F, 0.0F, 0.0698F)); ModelPartData modelPartData3 = modelPartData2.addChild("bone2", ModelPartBuilder.create().uv(0, 23).cuboid(0.0F, -4.0F, 0.0F, 4.0F, 4.0F, 4.0F), ModelTransform.rotation(-0.1222F, 0.0F, 0.0698F));
ModelPartData modelPartData4 = modelPartData3.addChild("bone3", ModelPartBuilder.create().uv(21, 12).cuboid(0.0F, -3.0F, 0.0F, 3.0F, 3.0F, 3.0F), ModelTransform.rotation(-0.2618F, 0.0F, 0.1047F)); modelPartData3.addChild("bone3", ModelPartBuilder.create().uv(21, 12).cuboid(0.0F, -3.0F, 0.0F, 3.0F, 3.0F, 3.0F), ModelTransform.rotation(-0.2618F, 0.0F, 0.1047F));
return modelData; return modelData;
} }

View File

@@ -1,8 +0,0 @@
package eu.midnightdust.hats.config;
public class AreEventHatsEnabled {
public static boolean areEventHatsEnabled() {
return HatsConfig.event_hats;
}
}

View File

@@ -1,12 +0,0 @@
package eu.midnightdust.hats.config;
import eu.midnightdust.lib.config.MidnightConfig;
public class HatsConfig extends MidnightConfig {
@Entry // Enable or disable event hats
public static boolean event_hats = true;
@Entry // Enable or disable hats for contributors, friends and donors.
public static boolean special_hats = true;
}

View File

@@ -1,7 +1,8 @@
package eu.midnightdust.hats.config; package eu.midnightdust.hats.config;
import io.github.prospector.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import io.github.prospector.modmenu.api.ModMenuApi; import com.terraformersmc.modmenu.api.ModMenuApi;
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;
@@ -10,6 +11,6 @@ public class ModMenuIntegration implements ModMenuApi {
@Override @Override
public ConfigScreenFactory<?> getModConfigScreenFactory() { public ConfigScreenFactory<?> getModConfigScreenFactory() {
return parent -> new HatsConfig().getScreen(parent); return parent -> MidnightConfig.getScreen(parent, "midnightlib");
} }
} }

View File

@@ -1,11 +1,10 @@
package eu.midnightdust.hats.tater; package eu.midnightdust.hats.tater;
import eu.midnightdust.hats.HatsClient; import eu.midnightdust.core.MidnightLibClient;
import eu.midnightdust.hats.config.AreEventHatsEnabled; import eu.midnightdust.core.config.MidnightLibConfig;
import eu.midnightdust.hats.web.HatLoader; import eu.midnightdust.hats.web.HatLoader;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.model.TexturedModelData; import net.minecraft.client.model.TexturedModelData;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.OverlayTexture;
@@ -28,7 +27,7 @@ import java.util.UUID;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public class TinyPotatoFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> { public class TinyPotatoFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> {
private static final String MOD_ID = HatsClient.MOD_ID; private static final String MOD_ID = MidnightLibClient.MOD_ID;
public static final EntityModelLayer TINY_POTATO_MODEL_LAYER = new EntityModelLayer(new Identifier("midnight-hats","tiny_potato"), "main"); public static final EntityModelLayer TINY_POTATO_MODEL_LAYER = new EntityModelLayer(new Identifier("midnight-hats","tiny_potato"), "main");
private static final UUID MOTSCHEN = UUID.fromString("a44c2660-630f-478f-946a-e518669fcf0c"); private static final UUID MOTSCHEN = UUID.fromString("a44c2660-630f-478f-946a-e518669fcf0c");
@@ -38,7 +37,7 @@ public class TinyPotatoFeatureRenderer<T extends LivingEntity, M extends EntityM
public TinyPotatoFeatureRenderer(FeatureRendererContext<T, M> featureRendererContext, EntityModelLoader entityModelLoader) { public TinyPotatoFeatureRenderer(FeatureRendererContext<T, M> featureRendererContext, EntityModelLoader entityModelLoader) {
super(featureRendererContext); super(featureRendererContext);
this.tinyPotato = new TinyPotatoModel(entityModelLoader.getModelPart(TINY_POTATO_MODEL_LAYER)); this.tinyPotato = new TinyPotatoModel<>(entityModelLoader.getModelPart(TINY_POTATO_MODEL_LAYER));
} }
public static TexturedModelData getTexturedModelData() { public static TexturedModelData getTexturedModelData() {
@@ -50,15 +49,11 @@ public class TinyPotatoFeatureRenderer<T extends LivingEntity, M extends EntityM
AbstractClientPlayerEntity abstractClientPlayerEntity = (AbstractClientPlayerEntity)livingEntity; AbstractClientPlayerEntity abstractClientPlayerEntity = (AbstractClientPlayerEntity)livingEntity;
Identifier hat_type; Identifier hat_type;
if (livingEntity != null) { if (livingEntity != null) {
if (Calendar.getInstance().get(Calendar.MONTH) == Calendar.DECEMBER && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) == 10) { if (Calendar.getInstance().get(Calendar.MONTH) == Calendar.DECEMBER && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) == 10) {
if (FabricLoader.getInstance().isModLoaded("cloth-config2")) { if (MidnightLibConfig.event_hats) {
if (AreEventHatsEnabled.areEventHatsEnabled()) { hat_type = TATER;
hat_type = TATER;
}
else hat_type = DEACTIVATED;
} }
else hat_type = TATER; else hat_type = DEACTIVATED;
}else { }else {
hat_type = DEACTIVATED; hat_type = DEACTIVATED;
} }

View File

@@ -33,10 +33,4 @@ public class TinyPotatoModel <T extends LivingEntity> extends SinglePartEntityMo
tater.render(matrixStack, buffer, packedLight, packedOverlay); tater.render(matrixStack, buffer, packedLight, packedOverlay);
} }
public void setRotationAngle(ModelPart bone, float x, float y, float z) {
bone.pitch = x;
bone.yaw = y;
bone.roll = z;
}
} }

3
src/main/java/eu/midnightdust/hats/web/HatLoader.java Normal file → Executable file
View File

@@ -26,8 +26,7 @@ public class HatLoader {
public static void init() { public static void init() {
CompletableFuture.supplyAsync(() -> { CompletableFuture.supplyAsync(() -> {
try (Reader reader = new InputStreamReader(new URL(HATS_URL).openStream())) { try (Reader reader = new InputStreamReader(new URL(HATS_URL).openStream())) {
Map<UUID, PlayerHatData> playerData = GSON.fromJson(reader, HAT_TYPE); return GSON.<Map<UUID, PlayerHatData>>fromJson(reader, HAT_TYPE);
return playerData;
} catch (MalformedURLException error) { } catch (MalformedURLException error) {
logger.log(Level.ERROR, "Unable to load player hats because of connection problems: " + error.getMessage()); logger.log(Level.ERROR, "Unable to load player hats because of connection problems: " + error.getMessage());
} catch (IOException error) { } catch (IOException error) {

View File

View File

@@ -1,11 +1,10 @@
package eu.midnightdust.hats.witch; package eu.midnightdust.hats.witch;
import eu.midnightdust.hats.HatsClient; import eu.midnightdust.core.MidnightLibClient;
import eu.midnightdust.hats.config.AreEventHatsEnabled; import eu.midnightdust.core.config.MidnightLibConfig;
import eu.midnightdust.hats.web.HatLoader; import eu.midnightdust.hats.web.HatLoader;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.model.TexturedModelData; import net.minecraft.client.model.TexturedModelData;
import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.OverlayTexture;
@@ -28,7 +27,7 @@ import java.util.UUID;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public class WitchHatFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> { public class WitchHatFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> {
private static final String MOD_ID = HatsClient.MOD_ID; private static final String MOD_ID = MidnightLibClient.MOD_ID;
public static final EntityModelLayer WITCH_HAT_MODEL_LAYER = new EntityModelLayer(new Identifier("midnight-hats","witch_hat"), "main"); public static final EntityModelLayer WITCH_HAT_MODEL_LAYER = new EntityModelLayer(new Identifier("midnight-hats","witch_hat"), "main");
private static final UUID MOTSCHEN = UUID.fromString("a44c2660-630f-478f-946a-e518669fcf0c"); private static final UUID MOTSCHEN = UUID.fromString("a44c2660-630f-478f-946a-e518669fcf0c");
@@ -44,7 +43,7 @@ public class WitchHatFeatureRenderer<T extends LivingEntity, M extends EntityMod
public WitchHatFeatureRenderer(FeatureRendererContext<T, M> featureRendererContext, EntityModelLoader entityModelLoader) { public WitchHatFeatureRenderer(FeatureRendererContext<T, M> featureRendererContext, EntityModelLoader entityModelLoader) {
super(featureRendererContext); super(featureRendererContext);
this.witchHat = new WitchHatModel(entityModelLoader.getModelPart(WITCH_HAT_MODEL_LAYER)); this.witchHat = new WitchHatModel<>(entityModelLoader.getModelPart(WITCH_HAT_MODEL_LAYER));
} }
public static TexturedModelData getTexturedModelData() { public static TexturedModelData getTexturedModelData() {
@@ -54,40 +53,35 @@ public class WitchHatFeatureRenderer<T extends LivingEntity, M extends EntityMod
public void render(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, T livingEntity, float f, float g, float h, float j, float k, float l) { public void render(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, T livingEntity, float f, float g, float h, float j, float k, float l) {
{ {
Identifier hat_type = DEACTIVATED; Identifier hat_type = DEACTIVATED;
if (livingEntity instanceof AbstractClientPlayerEntity) { if (livingEntity instanceof AbstractClientPlayerEntity abstractClientPlayerEntity) {
AbstractClientPlayerEntity abstractClientPlayerEntity = (AbstractClientPlayerEntity)livingEntity;
if (abstractClientPlayerEntity.getUuid().equals(MOTSCHEN)) { if (abstractClientPlayerEntity.getUuid().equals(MOTSCHEN)) {
hat_type = MOTSCHEN_SKIN; hat_type = MOTSCHEN_SKIN;
}else if (HatLoader.PLAYER_HATS.containsKey(abstractClientPlayerEntity.getUuid()) && HatLoader.PLAYER_HATS.get(abstractClientPlayerEntity.getUuid()).getHatType().contains("contributer")) { } else if (HatLoader.PLAYER_HATS.containsKey(abstractClientPlayerEntity.getUuid()) && HatLoader.PLAYER_HATS.get(abstractClientPlayerEntity.getUuid()).getHatType().contains("contributer")) {
hat_type = CONTRIBUTER_SKIN; hat_type = CONTRIBUTER_SKIN;
}else if (HatLoader.PLAYER_HATS.containsKey(abstractClientPlayerEntity.getUuid()) && HatLoader.PLAYER_HATS.get(abstractClientPlayerEntity.getUuid()).getHatType().contains("friend")) { } else if (HatLoader.PLAYER_HATS.containsKey(abstractClientPlayerEntity.getUuid()) && HatLoader.PLAYER_HATS.get(abstractClientPlayerEntity.getUuid()).getHatType().contains("friend")) {
hat_type = FRIEND_SKIN; hat_type = FRIEND_SKIN;
}else if (HatLoader.PLAYER_HATS.containsKey(abstractClientPlayerEntity.getUuid()) && HatLoader.PLAYER_HATS.get(abstractClientPlayerEntity.getUuid()).getHatType().contains("donator")) { } else if (HatLoader.PLAYER_HATS.containsKey(abstractClientPlayerEntity.getUuid()) && HatLoader.PLAYER_HATS.get(abstractClientPlayerEntity.getUuid()).getHatType().contains("donator")) {
hat_type = DONATOR_SKIN; hat_type = DONATOR_SKIN;
}else if (HatLoader.PLAYER_HATS.containsKey(abstractClientPlayerEntity.getUuid()) && HatLoader.PLAYER_HATS.get(abstractClientPlayerEntity.getUuid()).getHatType().contains("social")) { } else if (HatLoader.PLAYER_HATS.containsKey(abstractClientPlayerEntity.getUuid()) && HatLoader.PLAYER_HATS.get(abstractClientPlayerEntity.getUuid()).getHatType().contains("social")) {
hat_type = SOCIAL_SKIN; hat_type = SOCIAL_SKIN;
}else if (HatLoader.PLAYER_HATS.containsKey(abstractClientPlayerEntity.getUuid()) && HatLoader.PLAYER_HATS.get(abstractClientPlayerEntity.getUuid()).getHatType().contains("pride")) { } else if (HatLoader.PLAYER_HATS.containsKey(abstractClientPlayerEntity.getUuid()) && HatLoader.PLAYER_HATS.get(abstractClientPlayerEntity.getUuid()).getHatType().contains("pride")) {
hat_type = PRIDE_SKIN; hat_type = PRIDE_SKIN;
}else if (Calendar.getInstance().get(Calendar.MONTH) == Calendar.OCTOBER && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) >= 30) { } else if (Calendar.getInstance().get(Calendar.MONTH) == Calendar.OCTOBER && Calendar.getInstance().get(Calendar.DAY_OF_MONTH) >= 30) {
if (FabricLoader.getInstance().isModLoaded("cloth-config2")) { if (MidnightLibConfig.event_hats) {
if (AreEventHatsEnabled.areEventHatsEnabled()) { hat_type = WITCH;
hat_type = WITCH;
}
else hat_type = DEACTIVATED;
} }
else hat_type = WITCH; }
}else hat_type = DEACTIVATED;
} else { hat_type = DEACTIVATED; }
if (!(hat_type == DEACTIVATED)) { if (!(hat_type == DEACTIVATED)) {
matrixStack.push(); matrixStack.push();
((ModelWithHead) this.getContextModel()).getHead().rotate(matrixStack); ((ModelWithHead) this.getContextModel()).getHead().rotate(matrixStack);
VertexConsumer vertexConsumer = ItemRenderer.getArmorGlintConsumer(vertexConsumerProvider, RenderLayer.getEntityCutoutNoCull(hat_type), false, false); VertexConsumer vertexConsumer = ItemRenderer.getArmorGlintConsumer(vertexConsumerProvider, RenderLayer.getEntityCutoutNoCull(hat_type), false, false);
this.witchHat.render(matrixStack, vertexConsumer, i, OverlayTexture.DEFAULT_UV, 1.0F, 1.0F, 1.0F, 1.0F); this.witchHat.render(matrixStack, vertexConsumer, i, OverlayTexture.DEFAULT_UV, 1.0F, 1.0F, 1.0F, 1.0F);
matrixStack.pop(); matrixStack.pop();
}
} }
} }
} }

View File

@@ -35,7 +35,7 @@ public class WitchHatModel<T extends LivingEntity> extends SinglePartEntityModel
modelPartData.addChild("headwear", ModelPartBuilder.create().uv(0, 64).cuboid(-10.0F, -0.1F, 0.0F, 10.0F, 2.0F, 10.0F), ModelTransform.NONE); modelPartData.addChild("headwear", ModelPartBuilder.create().uv(0, 64).cuboid(-10.0F, -0.1F, 0.0F, 10.0F, 2.0F, 10.0F), ModelTransform.NONE);
ModelPartData modelPartData2 = modelPartData.addChild("bone", ModelPartBuilder.create().uv(0, 76).cuboid(0.0F, -4.0F, 0.0F, 7.0F, 4.0F, 7.0F), ModelTransform.rotation(-0.0524F, 0.0F, 0.0349F)); ModelPartData modelPartData2 = modelPartData.addChild("bone", ModelPartBuilder.create().uv(0, 76).cuboid(0.0F, -4.0F, 0.0F, 7.0F, 4.0F, 7.0F), ModelTransform.rotation(-0.0524F, 0.0F, 0.0349F));
ModelPartData modelPartData3 = modelPartData2.addChild("bone2", ModelPartBuilder.create().uv(0, 87).cuboid(0.0F, -4.0F, 0.0F, 4.0F, 4.0F, 4.0F), ModelTransform.rotation(-0.1222F, 0.0F, 0.0698F)); ModelPartData modelPartData3 = modelPartData2.addChild("bone2", ModelPartBuilder.create().uv(0, 87).cuboid(0.0F, -4.0F, 0.0F, 4.0F, 4.0F, 4.0F), ModelTransform.rotation(-0.1222F, 0.0F, 0.0698F));
ModelPartData modelPartData4 = modelPartData3.addChild("bone3", ModelPartBuilder.create().uv(0, 95).cuboid(0.0F, -2.0F, 0.0F, 1.0F, 2.0F, 1.0F), ModelTransform.rotation(-0.2618F, 0.0F, 0.1047F)); modelPartData3.addChild("bone3", ModelPartBuilder.create().uv(0, 95).cuboid(0.0F, -2.0F, 0.0F, 1.0F, 2.0F, 1.0F), ModelTransform.rotation(-0.2618F, 0.0F, 0.1047F));
return modelData; return modelData;
} }

View File

@@ -1,12 +1,19 @@
package eu.midnightdust.lib.config; package eu.midnightdust.lib.config;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.loader.api.FabricLoader; 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.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ScreenTexts; import net.minecraft.client.gui.screen.ScreenTexts;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.*;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.client.resource.language.I18n; import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.*; import net.minecraft.text.*;
@@ -14,7 +21,6 @@ import net.minecraft.util.Formatting;
import java.lang.annotation.*; import java.lang.annotation.*;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -24,14 +30,21 @@ import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
// MidnightConfig v0.1.0 // // MidnightConfig v1.0.0
// Single class config library - feel free to copy!
// Changelog:
// - The config screen no longer shows the entries of all instances of MidnightConfig
// - Compatible with servers!
// - Scrollable!
// - Comment support!
// - Fresh New Design
/* Based on https://github.com/Minenash/TinyConfig /** Based on https://github.com/Minenash/TinyConfig
Credits to Minenash - CC0-1.0 * Credits to Minenash */
You can copy this class to get a standalone version of MidnightConfig */
@SuppressWarnings("rawtypes") @SuppressWarnings("unchecked")
public class MidnightConfig { public class MidnightConfig {
public static boolean useTooltipForTitle = true; // Render title as tooltip or as simple text
private static final Pattern INTEGER_ONLY = Pattern.compile("(-?[0-9]*)"); private static final Pattern INTEGER_ONLY = Pattern.compile("(-?[0-9]*)");
private static final Pattern DECIMAL_ONLY = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)"); private static final Pattern DECIMAL_ONLY = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
@@ -42,40 +55,55 @@ public class MidnightConfig {
Field field; Field field;
Object widget; Object widget;
int width; int width;
Method dynamicTooltip;
Map.Entry<TextFieldWidget,Text> error; Map.Entry<TextFieldWidget,Text> error;
Object defaultValue; Object defaultValue;
Object value; Object value;
String tempValue; String tempValue;
boolean inLimits = true; boolean inLimits = true;
String id;
} }
private static Class configClass; public static final Map<String,Class<?>> configClass = new HashMap<>();
private static String translationPrefix;
private static Path path; private static Path path;
private static final Gson gson = new GsonBuilder() private static final Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).excludeFieldsWithModifiers(Modifier.PRIVATE).addSerializationExclusionStrategy(new HiddenAnnotationExclusionStrategy()).setPrettyPrinting().create();
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
.excludeFieldsWithModifiers(Modifier.PRIVATE)
.setPrettyPrinting()
.create();
public static void init(String modid, Class<?> config) { public static void init(String modid, Class<?> config) {
translationPrefix = modid + ".midnightconfig.";
path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json"); path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json");
configClass = config; configClass.put(modid, config);
for (Field field : config.getFields()) { for (Field field : config.getFields()) {
Class<?> type = field.getType();
EntryInfo info = new EntryInfo(); EntryInfo info = new EntryInfo();
if (field.isAnnotationPresent(Entry.class) || field.isAnnotationPresent(Comment.class))
try {
initClient(modid, field, info);
} catch (Exception e) {continue;}
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); }
Entry e; for (EntryInfo info : entries) {
try { e = field.getAnnotation(Entry.class); } if (info.field.isAnnotationPresent(Entry.class))
catch (Exception ignored) { continue; } try {
info.value = info.field.get(null);
info.width = e.width(); info.tempValue = info.value.toString();
info.field = field; } catch (IllegalAccessException ignored) {
}
}
}
@Environment(EnvType.CLIENT)
public 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 (type == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, e.min(), e.max(), true); 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 == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(),false);
else if (type == String.class) textField(info, String::length, null, Math.min(e.min(),0), Math.max(e.max(),1),true); else if (type == String.class) textField(info, String::length, null, Math.min(e.min(),0), Math.max(e.max(),1),true);
@@ -85,50 +113,23 @@ public class MidnightConfig {
info.value = !(Boolean) info.value; info.value = !(Boolean) info.value;
button.setMessage(func.apply(info.value)); button.setMessage(func.apply(info.value));
}, func); }, func);
} } else if (type.isEnum()) {
else if (type.isEnum()) {
List<?> values = Arrays.asList(field.getType().getEnumConstants()); List<?> values = Arrays.asList(field.getType().getEnumConstants());
Function<Object,Text> func = value -> new TranslatableText(translationPrefix + "enum." + type.getSimpleName() + "." + info.value.toString()); 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 -> { info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object,Text>>( button -> {
int index = values.indexOf(info.value) + 1; int index = values.indexOf(info.value) + 1;
info.value = values.get(index >= values.size()? 0 : index); info.value = values.get(index >= values.size()? 0 : index);
button.setMessage(func.apply(info.value)); button.setMessage(func.apply(info.value));
}, func); }, func);
} }
else entries.add(info);
continue;
entries.add(info);
try { info.defaultValue = field.get(null); }
catch (IllegalAccessException ignored) {}
try {
info.dynamicTooltip = config.getMethod(e.dynamicTooltip());
info.dynamicTooltip.setAccessible(true);
} catch (Exception ignored) {}
}
try { gson.fromJson(Files.newBufferedReader(path), config); }
catch (Exception e) { write(); }
for (EntryInfo info : entries) {
try {
info.value = info.field.get(null);
info.tempValue = info.value.toString();
}
catch (IllegalAccessException ignored) {}
}
} }
private static void textField(EntryInfo info, Function<String,Number> f, Pattern pattern, double min, double max, boolean cast) { private static void textField(EntryInfo info, Function<String,Number> f, Pattern pattern, double min, double max, boolean cast) {
boolean isNumber = pattern != null; boolean isNumber = pattern != null;
info.widget = (BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) (t, b) -> s -> { info.widget = (BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) (t, b) -> s -> {
s = s.trim(); s = s.trim();
if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches())) if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches())) return false;
return false;
Number value = 0; Number value = 0;
boolean inLimits = false; boolean inLimits = false;
@@ -155,134 +156,211 @@ public class MidnightConfig {
}; };
} }
public static void write() { public static void write(String modid) {
path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json");
try { try {
if (!Files.exists(path)) Files.createFile(path); if (!Files.exists(path)) Files.createFile(path);
Files.write(path, gson.toJson(configClass.newInstance()).getBytes()); Files.write(path, gson.toJson(configClass.get(modid).getDeclaredConstructor().newInstance()).getBytes());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
public Screen getScreen(Screen parent) { @Environment(EnvType.CLIENT)
return new TinyConfigScreen(parent); public static Screen getScreen(Screen parent, String modid) {
return new TinyConfigScreen(parent, modid);
} }
@Environment(EnvType.CLIENT)
private static class TinyConfigScreen extends Screen { private static class TinyConfigScreen extends Screen {
protected TinyConfigScreen(Screen parent) {
super(new TranslatableText(MidnightConfig.translationPrefix + "title")); protected TinyConfigScreen(Screen parent, String modid) {
super(new TranslatableText(modid + ".midnightconfig." + "title"));
this.parent = parent; this.parent = parent;
this.modid = modid;
this.translationPrefix = modid + ".midnightconfig.";
} }
private final String translationPrefix;
private final Screen parent; private final Screen parent;
private final String modid;
private MidnightConfigListWidget list;
// Real Time config update // // Real Time config update //
@Override @Override
public void tick() { public void tick() {
for (EntryInfo info : entries) for (EntryInfo info : entries)
try { info.field.set(null, info.value); } try { info.field.set(null, info.value); }
catch (IllegalAccessException ignore) {} catch (IllegalAccessException ignored) {}
} }
@Override @Override
protected void init() { protected void init() {
super.init(); super.init();
this.addButton(new ButtonWidget(this.width / 2 - 154, this.height - 28, 150, 20, ScreenTexts.CANCEL, button -> { this.addButton(new ButtonWidget(this.width / 2 - 154, this.height - 28, 150, 20, ScreenTexts.CANCEL, button -> {
try { gson.fromJson(Files.newBufferedReader(path), configClass); } try { gson.fromJson(Files.newBufferedReader(path), configClass.get(modid)); }
catch (Exception e) { write(); } catch (Exception e) { write(modid); }
for (EntryInfo info : entries) { for (EntryInfo info : entries) {
try { if (info.field.isAnnotationPresent(Entry.class)) {
info.value = info.field.get(null); try {
info.tempValue = info.value.toString(); info.value = info.field.get(null);
info.tempValue = info.value.toString();
} catch (IllegalAccessException ignored) {
}
} }
catch (IllegalAccessException ignored) {}
} }
Objects.requireNonNull(client).openScreen(parent); Objects.requireNonNull(client).openScreen(parent);
})); }));
ButtonWidget done = this.addButton(new ButtonWidget(this.width / 2 + 4, this.height - 28, 150, 20, ScreenTexts.DONE, (button) -> { ButtonWidget done = this.addButton(new ButtonWidget(this.width / 2 + 4, this.height - 28, 150, 20, ScreenTexts.DONE, (button) -> {
for (EntryInfo info : entries) for (EntryInfo info : entries)
try { info.field.set(null, info.value); } if (info.id.equals(modid)) {
catch (IllegalAccessException ignore) {} try {
write(); info.field.set(null, info.value);
} catch (IllegalAccessException ignored) {}
}
write(modid);
Objects.requireNonNull(client).openScreen(parent); Objects.requireNonNull(client).openScreen(parent);
})); }));
int y = 45; this.list = new MidnightConfigListWidget(this.client, this.width, this.height, 32, this.height - 32, 25);
this.children.add(this.list);
for (EntryInfo info : entries) { for (EntryInfo info : entries) {
addButton(new ButtonWidget(width - 155, y, 40,20, new LiteralText("Reset").formatted(Formatting.RED), (button -> { if (info.id.equals(modid)) {
info.value = info.defaultValue; TranslatableText name = new TranslatableText(translationPrefix + info.field.getName());
info.tempValue = info.value.toString(); ButtonWidget resetButton = new ButtonWidget(width - 155, 0, 40, 20, new LiteralText("Reset").formatted(Formatting.RED), (button -> {
Objects.requireNonNull(client).openScreen(this); info.value = info.defaultValue;
}))); info.tempValue = info.value.toString();
double scrollAmount = list.getScrollAmount();
Objects.requireNonNull(client).openScreen(this);
list.setScrollAmount(scrollAmount);
}));
if (info.widget instanceof Map.Entry) { if (info.widget instanceof Map.Entry) {
Map.Entry<ButtonWidget.PressAction,Function<Object,Text>> widget = (Map.Entry<ButtonWidget.PressAction, Function<Object, Text>>) info.widget; Map.Entry<ButtonWidget.PressAction, Function<Object, Text>> widget = (Map.Entry<ButtonWidget.PressAction, Function<Object, Text>>) info.widget;
addButton(new ButtonWidget(width-110,y,info.width,20, widget.getValue().apply(info.value), widget.getKey())); 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, info.width, 20, widget.getValue().apply(info.value), widget.getKey()),resetButton,name);
} else if (info.widget != null) {
TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 110, 0, info.width, 20, null);
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);
}
} }
else {
TextFieldWidget widget = addButton(new TextFieldWidget(textRenderer, width-110, y, info.width, 20, null));
widget.setText(info.tempValue);
Predicate<String> processor = ((BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) info.widget).apply(widget,done);
widget.setTextPredicate(processor);
children.add(widget);
}
y += 25;
} }
} }
int aniX = this.width / 2;
@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);
if (aniX < this.width / 2) {
aniX = aniX +40;
}
int stringWidth = (int) (title.getString().length() * 2.75f); int stringWidth = (int) (title.getString().length() * 2.75f);
this.fillGradient(matrices, this.width / 2 - stringWidth, 10, this.width /2 + stringWidth, 29, -1072689136, -804253680);
this.fillGradient(matrices, this.width / 2 - aniX, 35, width/2 + aniX, this.height - 40, -1072689136, -804253680);
super.render(matrices, mouseX, mouseY, delta); super.render(matrices, mouseX, mouseY, delta);
drawCenteredText(matrices, textRenderer, title, width/2, 15, 0xFFFFFF); if (useTooltipForTitle) renderTooltip(matrices, title, width/2 - stringWidth, 27);
else drawCenteredText(matrices, textRenderer, title, width / 2, 15, 0xFFFFFF);
int y = 40;
for (EntryInfo info : entries) { for (EntryInfo info : entries) {
drawTextWithShadow(matrices, textRenderer, new TranslatableText(translationPrefix + info.field.getName()), 12, y + 10, 0xFFFFFF); if (info.id.equals(modid)) {
if (list.getHoveredButton(mouseX,mouseY).isPresent()) {
AbstractButtonWidget 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 && info.error.getKey().isMouseOver(mouseX,mouseY)) if (info.error != null && text.equals(name)) renderTooltip(matrices, info.error.getValue(), mouseX, mouseY);
renderTooltip(matrices, info.error.getValue(), mouseX, mouseY); else if (I18n.hasTranslation(key) && text.equals(name)) {
else if (mouseY >= y && mouseY < (y + 25)) { List<Text> list = new ArrayList<>();
if (info.dynamicTooltip != null) { for (String str : I18n.translate(key).split("\n"))
try { list.add(new LiteralText(str));
renderTooltip(matrices, (List<Text>) info.dynamicTooltip.invoke(null, entries), mouseX, mouseY); renderTooltip(matrices, list, mouseX, mouseY);
y += 25; }
continue;
} catch (Exception e) { e.printStackTrace(); }
}
String key = translationPrefix + info.field.getName() + ".tooltip";
if (I18n.hasTranslation(key)) {
List<Text> list = new ArrayList<>();
for (String str : I18n.translate(key).split("\n"))
list.add(new LiteralText(str));
renderTooltip(matrices, list, mouseX, mouseY);
} }
} }
y += 25;
} }
} }
} }
@Environment(EnvType.CLIENT)
public static class MidnightConfigListWidget extends ElementListWidget<MidnightConfig.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(AbstractButtonWidget button, AbstractButtonWidget resetButton, Text text) {
this.addEntry(ButtonEntry.create(button, text, resetButton));
}
@Override
public int getRowWidth() { return 400; }
public Optional<AbstractButtonWidget> getHoveredButton(double mouseX, double mouseY) {
for (ButtonEntry buttonEntry : this.children()) {
for (AbstractButtonWidget abstractButtonWidget : buttonEntry.buttons) {
if (abstractButtonWidget.isMouseOver(mouseX, mouseY)) {
return Optional.of(abstractButtonWidget);
}
}
}
return Optional.empty();
}
}
public static class ButtonEntry extends ElementListWidget.Entry<ButtonEntry> {
private static final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
private final List<AbstractButtonWidget> buttons = new ArrayList<>();
private final List<AbstractButtonWidget> resetButtons = new ArrayList<>();
private final List<Text> texts = new ArrayList<>();
private final List<AbstractButtonWidget> buttonsWithResetButtons = new ArrayList<>();
public static final Map<AbstractButtonWidget, Text> buttonsWithText = new HashMap<>();
private ButtonEntry(AbstractButtonWidget button, Text text, AbstractButtonWidget 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(AbstractButtonWidget button, Text text, AbstractButtonWidget 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;
}
}
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) @Target(ElementType.FIELD)
public @interface Entry { public @interface Entry {
String dynamicTooltip() default "";
int width() default 100; int width() default 100;
double min() default Double.MIN_NORMAL; double min() default Double.MIN_NORMAL;
double max() default Double.MAX_VALUE; double max() default Double.MAX_VALUE;
} }
@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

@@ -0,0 +1,55 @@
package eu.midnightdust.lib.config;
/** MidnightConfig documentation & examples:
* Thanks for choosing MidnightConfig - the fancy, tiny and lightweight config library.
* If you want to use the lib in your mod, here are some examples and hints:
* Every option in a MidnightConfig class has to be public and static, so we can access it from other classes.
* The config class also has to extend 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
@Entry public static int fabric = 16777215; // Example for a int 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 String name = "Hi"; // Example for a string option
@Entry public static TestEnum testEnum = TestEnum.FABRIC; // Example for a enum option
public static enum TestEnum { // Enums allow the user to cycle through predefined options
QUILT, FABRIC
}
@Entry(min=10,max=30) public static int hello = 15675965; // - The entered number has to be larger than 10 and smaller than 30
public static int imposter = 16777215; // - Entries without an @Entry or @Comment annotation are ignored
/*
The .json language file for your config class could look similar to this:
{
"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.name":"Pet Name", // Translation for the field "name" defined in the example config
"modid.midnightconfig.name.tooltip":"Name your Pet! \n I am a new line uwu",
// When hovering over the option "showInfo",
// this text will appear as a tooltip.
// "\n" inserts a line break.
"modid.midnightconfig.fabric":"I am an int",
"modid.midnightconfig.world":"I am a double",
"modid.midnightconfig.showInfo":"I am a boolean",
"modid.midnightconfig.hello":"I am a limited int!",
"modid.midnightconfig.testEnum":"I am an enum!",
"modid.midnightconfig.enum.TestEnum.FABRIC":"Fancy",
"modid.midnightconfig.enum.TestEnum.QUILT":"Fabulous"
}
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");"
The code in your ModMenu integration class would look something like this:
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return parent -> MidnightConfig.getScreen(parent, "modid");
}
*/
}

View File

@@ -0,0 +1,17 @@
package eu.midnightdust.lib.util;
import java.awt.*;
public class MidnightColorUtil {
/**
* @credit https://stackoverflow.com/questions/4129666/how-to-convert-hex-to-rgb-using-java
* @param colorStr e.g. "FFFFFF"
* @return Color as RGB
*/
public static Color hex2Rgb(String colorStr) {
return new Color(
Integer.valueOf( colorStr.substring( 0, 2 ), 16 ),
Integer.valueOf( colorStr.substring( 2, 4 ), 16 ),
Integer.valueOf( colorStr.substring( 4, 6 ), 16 ));
}
}

View File

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

0
src/main/resources/assets/midnightlib/icon.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

10
src/main/resources/assets/midnightlib/lang/en_us.json Normal file → Executable file
View File

@@ -1,7 +1,13 @@
{ {
"midnightlib.overview.title":"MidnightConfig Overview",
"midnightlib.midnightconfig.title":"MidnightLib Config", "midnightlib.midnightconfig.title":"MidnightLib Config",
"midnightlib.midnightconfig.midnightlib_description":"MidnightLib",
"midnightlib.midnightconfig.config_screen_list":"Enable Config Screen List",
"midnightlib.midnightconfig.midnighthats_description":"MidnightHats",
"midnightlib.midnightconfig.event_hats":"Enable Event Hats", "midnightlib.midnightconfig.event_hats":"Enable Event Hats",
"midnightlib.midnightconfig.event_hats.tooltip":"Enable or disable event hats",
"midnightlib.midnightconfig.special_hats":"Enable Special Hats", "midnightlib.midnightconfig.special_hats":"Enable Special Hats",
"midnightlib.midnightconfig.special_hats.tooltip":"Enable or disable hats for contributors, friends and donors." "midnightlib.modrinth":"Modrinth",
"midnightlib.curseforge":"CurseForge",
"modmenu.descriptionTranslation.midnightlib": "Common Library for Team MidnightDust's mods.\nProvides a config api, common utils, and cosmetics.",
"modmenu.summaryTranslation.midnightlib": "Common Library for Team MidnightDust's mods."
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 649 B

After

Width:  |  Height:  |  Size: 649 B

View File

Before

Width:  |  Height:  |  Size: 629 B

After

Width:  |  Height:  |  Size: 629 B

View File

Before

Width:  |  Height:  |  Size: 139 B

After

Width:  |  Height:  |  Size: 139 B

View File

Before

Width:  |  Height:  |  Size: 621 B

After

Width:  |  Height:  |  Size: 621 B

View File

Before

Width:  |  Height:  |  Size: 622 B

After

Width:  |  Height:  |  Size: 622 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 622 B

After

Width:  |  Height:  |  Size: 622 B

View File

Before

Width:  |  Height:  |  Size: 639 B

After

Width:  |  Height:  |  Size: 639 B

15
src/main/resources/fabric.mod.json Normal file → Executable file
View File

@@ -4,7 +4,7 @@
"version": "${version}", "version": "${version}",
"name": "MidnightLib", "name": "MidnightLib",
"description": "Common Library for Team MidnightDust's mods.\nProvides a config api, common utils, and cosmetics.", "description": "Common Library for Team MidnightDust's mods.",
"authors": [ "authors": [
"Motschen", "Motschen",
"TeamMidnightDust" "TeamMidnightDust"
@@ -21,7 +21,7 @@
"environment": "*", "environment": "*",
"entrypoints": { "entrypoints": {
"client": [ "client": [
"eu.midnightdust.hats.HatsClient" "eu.midnightdust.core.MidnightLibClient"
], ],
"modmenu": [ "modmenu": [
"eu.midnightdust.hats.config.ModMenuIntegration" "eu.midnightdust.hats.config.ModMenuIntegration"
@@ -29,7 +29,8 @@
}, },
"mixins": [ "mixins": [
"midnight-hats.mixins.json" "midnighthats.mixins.json",
"midnightcore.mixins.json"
], ],
"depends": { "depends": {
@@ -37,6 +38,12 @@
}, },
"custom": { "custom": {
"modmenu:api": true "modmenu": {
"links": {
"modmenu.discord": "https://discord.gg/jAGnWYHm3r",
"modmenu.website": "https://www.midnightdust.eu/"
},
"badges": [ "library" ]
}
} }
} }

View File

@@ -0,0 +1,11 @@
{
"required": true,
"package": "eu.midnightdust.core.mixin",
"compatibilityLevel": "JAVA_8",
"client": [
"MixinOptionsScreen"
],
"injectors": {
"defaultRequire": 1
}
}