Use cloth lite and proguard

This commit is contained in:
JFronny 2021-04-11 20:23:52 +02:00
parent fdcdb6d9fa
commit 71dd92703e
No known key found for this signature in database
GPG Key ID: BEC5ACBBD4EE17E5
15 changed files with 125 additions and 304 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@
*.iws
# IntelliJ
out.map
out/
# mpeltonen/sbt-idea plugin
.idea_modules/

View File

@ -1,3 +1,20 @@
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import proguard.gradle.ProGuardTask
import net.fabricmc.loom.task.RunClientTask
import net.fabricmc.loom.task.RunServerTask
buildscript {
repositories {
mavenLocal()
google()
}
dependencies {
classpath 'com.guardsquare:proguard-gradle:7.0.1'
}
}
plugins {
id 'fabric-loom' version '0.7-SNAPSHOT'
id 'maven-publish'
@ -12,6 +29,22 @@ group = project.maven_group
repositories {
maven { url = 'https://maven.terraformersmc.com/'; name = "ModMenu" }
maven { url "https://maven.shedaniel.me/" }
}
sourceSets {
testmod {
compileClasspath += main.compileClasspath + main.output
runtimeClasspath += main.runtimeClasspath + main.output
}
}
task runTestmodClient(type: RunClientTask) {
classpath sourceSets.testmod.runtimeClasspath
}
task runTestmodServer(type: RunServerTask) {
classpath sourceSets.testmod.runtimeClasspath
}
dependencies {
@ -24,6 +57,7 @@ dependencies {
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
// You may need to force-disable transitiveness on them.
modImplementation "com.terraformersmc:modmenu:1.16.9"
include modImplementation("me.shedaniel.cloth:cloth-config-lite-fabric:1.0.4")
}
processResources {
@ -37,6 +71,29 @@ processResources {
from(sourceSets.main.resources.srcDirs) {
exclude "fabric.mod.json"
}
doLast {
fileTree(dir: outputs.files.asPath, include: "**/*.json").each {
File file -> file.text = JsonOutput.toJson(new JsonSlurper().parse(file))
}
}
}
def proguardJarOut = file(jar.archiveFile.get().getAsFile().absolutePath.replace(".jar", "-min.jar"))
task proguardJar(type: ProGuardTask, dependsOn: jar) {
configuration './proguard.conf'
verbose
injars jar.archiveFile.get().getAsFile()
outjars proguardJarOut
libraryjars files(configurations.compileClasspath)
printmapping 'out.map'
}
tasks.remapJar {
input.set proguardJarOut
archiveClassifier.set null
dependsOn proguardJar
}
// ensure that the encoding is set to UTF-8, no matter what the system default is

11
proguard.conf Normal file
View File

@ -0,0 +1,11 @@
-libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class)
-keep public class io.gitlab.jfronny.libjf.config.JfConfig {
public protected *;
}
-keep public class io.gitlab.jfronny.libjf.Libjf
-keep public class io.gitlab.jfronny.libjf.config.ModMenu
-repackageclasses 'jf.lib'
-allowaccessmodification
-overloadaggressively
-optimizationpasses 5
-optimizations '*'

View File

@ -1,36 +0,0 @@
package io.gitlab.jfronny.libjf;
import io.gitlab.jfronny.libjf.config.Entry;
import io.gitlab.jfronny.libjf.config.EntryInfo;
import io.gitlab.jfronny.libjf.config.JfConfig;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import java.util.Collections;
import java.util.List;
/*from https://github.com/Minenash/TinyConfig*/
public class ExampleConfig implements JfConfig {
@Entry
public static boolean boolTest = false;
@Entry(min = 5)
public static int intTest = 20;
@Entry
public static double decimalTest = 20;
@Entry(dynamicTooltip = "dieStrTooltip", max = 5)
public static String dieStr = "lolz";
@Entry
public static Test enumTest = Test.Test;
private static List<Text> dieStrTooltip(List<EntryInfo> infos) {
return Collections.singletonList(new LiteralText("safbjkasf"));
}
public enum Test {
Test, ER
}
}

View File

@ -27,7 +27,6 @@ public class Libjf implements PreLaunchEntrypoint {
@Override
public void onPreLaunch() {
registerConfig(MOD_ID, ExampleConfig.class);
for (EntrypointContainer<JfConfig> entrypointContainer : FabricLoader.getInstance().getEntrypointContainers(MOD_ID + ":config", JfConfig.class)) {
String id = entrypointContainer.getProvider().getMetadata().getId();
Libjf.registerConfig(id, entrypointContainer.getEntrypoint().getClass());

View File

@ -2,30 +2,14 @@ package io.gitlab.jfronny.libjf.config;
import io.gitlab.jfronny.libjf.Libjf;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.*;
import net.minecraft.util.Formatting;
import java.lang.reflect.Field;
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;
/* Based on https://github.com/TeamMidnightDust/MidnightLib
* see https://github.com/TeamMidnightDust/MidnightLib/blob/main/LICENSE
*/
@SuppressWarnings("rawtypes")
public class Config {
private static final Pattern INTEGER_ONLY = Pattern.compile("(-?[0-9]*)");
private static final Pattern DECIMAL_ONLY = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
public Class configClass;
public Class<?> configClass;
public String translationPrefix;
public Path path;
public final List<EntryInfo> entries = new ArrayList<>();
@ -36,49 +20,13 @@ public class Config {
configClass = config;
for (Field field : config.getFields()) {
Class<?> type = field.getType();
EntryInfo info = new EntryInfo();
Entry e;
try { e = field.getAnnotation(Entry.class); }
catch (Exception ignored) { continue; }
info.width = e.width();
info.field = field;
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 == float.class) textField(info, Float::parseFloat, 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 == 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(translationPrefix + "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);
}
else
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 { Libjf.GSON.fromJson(Files.newBufferedReader(path), config); }
@ -87,48 +35,15 @@ public class Config {
for (EntryInfo info : entries) {
try {
info.value = info.field.get(null);
info.tempValue = info.value.toString();
}
catch (IllegalAccessException ignored) {}
}
}
private 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 void write() {
try {
if (!Files.exists(path)) Files.createFile(path);
Files.write(path, Libjf.GSON.toJson(configClass.newInstance()).getBytes());
Files.write(path, Libjf.GSON.toJson(configClass.getDeclaredConstructor().newInstance()).getBytes());
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -1,132 +0,0 @@
package io.gitlab.jfronny.libjf.config;
import io.gitlab.jfronny.libjf.Libjf;
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.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.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
public class ConfigScreen extends Screen {
public ConfigScreen(Screen parent, Config config) {
super(new TranslatableText(config.translationPrefix + "title"));
this.parent = parent;
this.config = config;
}
private final Screen parent;
private final Config config;
// Real Time config update //
@Override
public void tick() {
for (EntryInfo info : config.entries)
try { info.field.set(null, info.value); }
catch (IllegalAccessException ignore) {}
}
@Override
protected void init() {
super.init();
this.addButton(new ButtonWidget(this.width / 2 - 154, this.height - 28, 150, 20, ScreenTexts.CANCEL, button -> {
try { Libjf.GSON.fromJson(Files.newBufferedReader(config.path), config.configClass); }
catch (Exception e) { config.write(); }
for (EntryInfo info : config.entries) {
try {
info.value = info.field.get(null);
info.tempValue = info.value.toString();
}
catch (IllegalAccessException ignored) {}
}
Objects.requireNonNull(client).openScreen(parent);
}));
ButtonWidget done = this.addButton(new ButtonWidget(this.width / 2 + 4, this.height - 28, 150, 20, ScreenTexts.DONE, (button) -> {
for (EntryInfo info : config.entries)
try { info.field.set(null, info.value); }
catch (IllegalAccessException ignore) {}
config.write();
Objects.requireNonNull(client).openScreen(parent);
}));
int y = 45;
for (EntryInfo info : config.entries) {
addButton(new ButtonWidget(width - 155, y, 40,20, new LiteralText("Reset").formatted(Formatting.RED), (button -> {
info.value = info.defaultValue;
info.tempValue = info.value.toString();
Objects.requireNonNull(client).openScreen(this);
})));
if (info.widget instanceof Map.Entry) {
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()));
}
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
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices);
if (aniX < this.width / 2) {
aniX = aniX +40;
}
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);
drawCenteredText(matrices, textRenderer, title, width/2, 15, 0xFFFFFF);
int y = 40;
for (EntryInfo info : config.entries) {
drawTextWithShadow(matrices, textRenderer, new TranslatableText(config.translationPrefix + info.field.getName()), 12, y + 10, 0xFFFFFF);
if (info.error != null && info.error.getKey().isMouseOver(mouseX,mouseY))
renderTooltip(matrices, info.error.getValue(), mouseX, mouseY);
else if (mouseY >= y && mouseY < (y + 25)) {
if (info.dynamicTooltip != null) {
try {
renderTooltip(matrices, (List<Text>) info.dynamicTooltip.invoke(null, config.entries), mouseX, mouseY);
y += 25;
continue;
} catch (Exception e) { e.printStackTrace(); }
}
String key = config.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;
}
}
}

View File

@ -1,15 +0,0 @@
package io.gitlab.jfronny.libjf.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Entry {
String dynamicTooltip() default "";
int width() default 100;
double min() default Double.MIN_NORMAL;
double max() default Double.MAX_VALUE;
}

View File

@ -1,20 +1,9 @@
package io.gitlab.jfronny.libjf.config;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.Text;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
public class EntryInfo {
Field field;
Object widget;
int width;
Method dynamicTooltip;
Map.Entry<TextFieldWidget, Text> error;
Object defaultValue;
Object value;
String tempValue;
boolean inLimits = true;
}

View File

@ -3,6 +3,8 @@ package io.gitlab.jfronny.libjf.config;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import io.gitlab.jfronny.libjf.Libjf;
import me.shedaniel.clothconfiglite.api.ConfigScreen;
import net.minecraft.text.TranslatableText;
import java.util.HashMap;
import java.util.Map;
@ -13,18 +15,22 @@ public class ModMenu implements ModMenuApi {
Map<String, ConfigScreenFactory<?>> factories = new HashMap<>();
for (Map.Entry<String, Config> entry : Libjf.getConfigs().entrySet()) {
if (!Libjf.MOD_ID.equals(entry.getKey()))
factories.put(entry.getKey(), s -> new ConfigScreen(s, entry.getValue()));
factories.put(entry.getKey(), buildFactory(entry.getValue()));
}
return factories;
}
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
for (Map.Entry<String, Config> entry : Libjf.getConfigs().entrySet()) {
if (Libjf.MOD_ID.equals(entry.getKey()))
return s -> new ConfigScreen(s, entry.getValue());
}
new Exception("Could not find own config screen, this is bad").printStackTrace();
return null;
private static ConfigScreenFactory<?> buildFactory(Config config) {
return s -> {
ConfigScreen c = ConfigScreen.create(new TranslatableText(config.translationPrefix + "title"), s);
for (EntryInfo entry : config.entries) {
c.add(new TranslatableText(config.translationPrefix + entry.field.getName()),
entry.value, () -> entry.defaultValue, v -> {
entry.value = v;
config.write();
});
}
return c.get();
};
}
}

View File

@ -1,10 +0,0 @@
{
"libjf.jfconfig.title": "JfConfig example",
"libjf.jfconfig.boolTest": "Bool Test",
"libjf.jfconfig.intTest": "Int Test",
"libjf.jfconfig.decimalTest": "Decimal Test",
"libjf.jfconfig.dieStr": "String Test",
"libjf.jfconfig.enumTest": "Enum Test",
"libjf.jfconfig.enum.Test.Test": "Test",
"libjf.jfconfig.enum.Test.ER": "ER"
}

View File

@ -20,9 +20,6 @@
],
"modmenu": [
"io.gitlab.jfronny.libjf.config.ModMenu"
],
"libjf:config": [
"io.gitlab.jfronny.libjf.ExampleConfig"
]
},
"mixins": [
@ -31,5 +28,10 @@
"depends": {
"fabricloader": ">=0.11.3",
"minecraft": "1.16.5"
},
"custom": {
"modmenu": {
"badges": ["library"]
}
}
}

View File

@ -0,0 +1,15 @@
package io.gitlab.jfronny.libjf.test;
import io.gitlab.jfronny.libjf.config.JfConfig;
public class TestMod implements JfConfig {
public static boolean boolTest = false;
public static int intTest = 20;
public static double decimalTest = 20;
public static String dieStr = "lolz";
public static Test enumTest = Test.Test;
public enum Test {
Test, ER
}
}

View File

@ -0,0 +1,8 @@
{
"libjf-testmod.jfconfig.title": "JfConfig example",
"libjf-testmod.jfconfig.boolTest": "Bool Test",
"libjf-testmod.jfconfig.intTest": "Int Test",
"libjf-testmod.jfconfig.decimalTest": "Decimal Test",
"libjf-testmod.jfconfig.dieStr": "String Test",
"libjf-testmod.jfconfig.enumTest": "Enum Test"
}

View File

@ -0,0 +1,11 @@
{
"schemaVersion": 1,
"id": "libjf-testmod",
"version": "${version}",
"environment": "*",
"entrypoints": {
"libjf:config": [
"io.gitlab.jfronny.libjf.test.TestMod"
]
}
}