Use LibJF 2.0, make configs more powerful
This commit is contained in:
parent
18886c6635
commit
35bda8675b
|
@ -129,3 +129,8 @@ public/
|
|||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
.classpath
|
||||
bin
|
||||
.project
|
||||
.settings
|
||||
|
|
16
build.gradle
16
build.gradle
|
@ -13,6 +13,10 @@ repositories {
|
|||
includeGroup "net.oskarstrom"
|
||||
}
|
||||
}
|
||||
maven {
|
||||
url "https://gitlab.com/api/v4/projects/25805200/packages/maven"
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -20,14 +24,18 @@ dependencies {
|
|||
mappings "net.fabricmc:yarn:${project.minecraft_version}+${project.yarn_mappings}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:0.39.2+1.17"
|
||||
modImplementation "com.terraformersmc:modmenu:2.0.5"
|
||||
download("https://gitlab.com/jfmods/LibJF/-/jobs/artifacts/master/raw/latest-dev.jar?job=build_test", "libjf")
|
||||
modImplementation("net.fabricmc.fabric-api:fabric-api:${project.fabric_version}")
|
||||
modImplementation("com.terraformersmc:modmenu:2.0.5")
|
||||
include modImplementation("com.github.MeteorDevelopment:starscript:0.1.5")
|
||||
modApi("me.shedaniel.cloth:cloth-config-fabric:5.0.38")
|
||||
modCompileOnly "grondag:frex-mc117:+"
|
||||
include modImplementation("io.gitlab.jfronny.libjf:libjf-data-manipulation-v0:${project.jfapi_version}") {
|
||||
exclude(group: "net.fabricmc.fabric-api")
|
||||
}
|
||||
include("io.gitlab.jfronny.libjf:libjf-unsafe-v0:${project.jfapi_version}")
|
||||
include("io.gitlab.jfronny.libjf:libjf-base-v0:${project.jfapi_version}")
|
||||
|
||||
testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
|
||||
testImplementation('org.junit.jupiter:junit-jupiter:5.8.1')
|
||||
|
||||
//Canvas for FREX testing
|
||||
//modRuntime("grondag:canvas-mc117-1.17:+") {
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
# Advanced config entries
|
||||
|
||||
## Common info
|
||||
Every advanced entry will be represented as a json object.
|
||||
Every entry can contain the following properties, regardless of its type:
|
||||
| Name | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| type | yes | The type of the entries. Each one can contain specific info, more on that below |
|
||||
| default | yes | The default value for this entry. This is what you would specify in a normal config entry (except for enums, where this is just the default entries name) |
|
||||
| reloadType | no | `"Resource"` or `"Simple"`, specifies whether resources have to be reloaded if this is changed. Frex shaders will be reloaded anyways |
|
||||
|
||||
## Numbers
|
||||
There are two ways to display numbers: input boxes and sliders.
|
||||
Sliders can only be used to select whole numbers but are more intuitive for limited inputs.
|
||||
They also require a minimum and maximum value to be specified.
|
||||
|
||||
### Example:
|
||||
```json
|
||||
{
|
||||
"id": "examplePack",
|
||||
"version": 6,
|
||||
"capabilities": ["FileFilter", "DirFilter"],
|
||||
"conf": {
|
||||
"someOption": {
|
||||
"type": "slider", // can also be "number" for a normal number
|
||||
"default": 5,
|
||||
"min": 0,
|
||||
"max": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### Result:
|
||||
![configExampleSlider](./img/ExamplePackSlider.png)
|
||||
|
||||
## Booleans/Toggles
|
||||
These do not expose any additional options, look under `Common info`. Their type is `boolean`
|
||||
|
||||
## Enum entries/Selecting from a list
|
||||
The possible values for this entry will be under `values`, while the `default` value will just be a string.
|
||||
Their type is `enum`
|
||||
|
||||
### Example:
|
||||
```json
|
||||
{
|
||||
"id": "examplePack",
|
||||
"version": 6,
|
||||
"capabilities": ["FileFilter", "DirFilter"],
|
||||
"conf": {
|
||||
"someOption": {
|
||||
"type": "enum",
|
||||
"default": "Second",
|
||||
"values": ["First", "Second", "Third"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### Result:
|
||||
![configExampleSlider](./img/ExamplePackEnum2.png)
|
|
@ -15,7 +15,7 @@ You can add [translations](./Translations.md) to work around this in the UI show
|
|||
```json
|
||||
{
|
||||
"id": "<PackID>",
|
||||
"version": 5,
|
||||
"version": 6,
|
||||
"capabilities": ["FileFilter", "DirFilter"],
|
||||
"conf": {
|
||||
// Your config options here
|
||||
|
@ -37,7 +37,7 @@ To add a boolean entry, add code like this: `"entryName": <Default Option (true/
|
|||
```json
|
||||
{
|
||||
"id": "examplePack",
|
||||
"version": 5,
|
||||
"version": 6,
|
||||
"capabilities": ["FileFilter", "DirFilter"],
|
||||
"conf": {
|
||||
"someTexture": true,
|
||||
|
@ -58,7 +58,7 @@ A number box follows the same principle as a boolean: `"entryName": Default Numb
|
|||
```json
|
||||
{
|
||||
"id": "examplePack",
|
||||
"version": 5,
|
||||
"version": 6,
|
||||
"capabilities": ["FileFilter", "DirFilter"],
|
||||
"conf": {
|
||||
"someOption": 10
|
||||
|
@ -70,24 +70,7 @@ A number box follows the same principle as a boolean: `"entryName": Default Numb
|
|||
|
||||
## Adding a slider
|
||||
A slider is slightly more complicated as a minimum and a maximum need to be defined. Sliders also only support whole numbers.
|
||||
|
||||
### Example:
|
||||
```json
|
||||
{
|
||||
"id": "examplePack",
|
||||
"version": 5,
|
||||
"capabilities": ["FileFilter", "DirFilter"],
|
||||
"conf": {
|
||||
"someOption": {
|
||||
"min": 0,
|
||||
"default": 5,
|
||||
"max": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### Result:
|
||||
![configExampleSlider](./img/ExamplePackSlider.png)
|
||||
More information is available [here](AdvancedConfig.md)
|
||||
|
||||
## Select From a list
|
||||
To allow users to select one entry from a list, you can use a json array with string entries. *Numbers/etc are not supported*
|
||||
|
@ -96,7 +79,7 @@ To allow users to select one entry from a list, you can use a json array with st
|
|||
```json
|
||||
{
|
||||
"id": "examplePack",
|
||||
"version": 5,
|
||||
"version": 6,
|
||||
"capabilities": ["FileFilter", "DirFilter"],
|
||||
"conf": {
|
||||
"someOption": [
|
||||
|
@ -116,7 +99,7 @@ To allow users to select one entry from a list, you can use a json array with st
|
|||
```json
|
||||
{
|
||||
"id": "examplePack",
|
||||
"version": 5,
|
||||
"version": 6,
|
||||
"capabilities": ["FileFilter", "DirFilter"],
|
||||
"conf": {
|
||||
"someCategory": {
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -3,16 +3,19 @@ org.gradle.jvmargs=-Xmx1G
|
|||
# Fabric Properties
|
||||
# check these on https://fabricmc.net/versions.html
|
||||
minecraft_version=1.17.1
|
||||
yarn_mappings=build.43
|
||||
loader_version=0.11.6
|
||||
yarn_mappings=build.61
|
||||
loader_version=0.11.7
|
||||
# Mod Properties
|
||||
mod_version=2.7.1
|
||||
mod_version=2.7.2
|
||||
maven_group=io.gitlab.jfronny
|
||||
archives_base_name=respackopts
|
||||
# Dependencies
|
||||
fabric_version=0.40.1+1.17
|
||||
jfapi_version=2.0+381554148
|
||||
|
||||
modrinth_id=TiF5QWZY
|
||||
modrinth_required_dependencies=mzVbb1XI, dOW0jmMj
|
||||
modrinth_required_dependencies=3CD6YUw1
|
||||
modrinth_optional_dependencies=
|
||||
curseforge_id=430090
|
||||
curseforge_required_dependencies=cloth-config, modmenu, libjf
|
||||
curseforge_required_dependencies=cloth-config, modmenu
|
||||
curseforge_optional_dependencies=
|
||||
|
|
|
@ -12,6 +12,7 @@ nav:
|
|||
- 'README.md'
|
||||
- 'Setting up':
|
||||
- 'MainConfig.md'
|
||||
- 'AdvancedConfig.md'
|
||||
- 'Translations.md'
|
||||
- 'Select files':
|
||||
- 'ToggleFiles.md'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"id": "lumi",
|
||||
"version": 5,
|
||||
"version": 6,
|
||||
"capabilities": ["FileFilter", "DirFilter", "DirFilterAdditive"],
|
||||
"conf": {
|
||||
"tonemap": [
|
||||
|
@ -8,7 +8,11 @@
|
|||
"vibrant",
|
||||
"film"
|
||||
],
|
||||
"pbr": true,
|
||||
"pbr": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"reloadType": "Simple"
|
||||
},
|
||||
"debugMode": [
|
||||
"none",
|
||||
"normal",
|
||||
|
|
|
@ -1,21 +1,35 @@
|
|||
package io.gitlab.jfronny.respackopts;
|
||||
|
||||
import io.gitlab.jfronny.libjf.data.WrappedPack;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.gitlab.jfronny.respackopts.data.*;
|
||||
import io.gitlab.jfronny.respackopts.data.condition.Condition;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.ConfigSyncMode;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.PackCapability;
|
||||
import io.gitlab.jfronny.respackopts.filters.DirFilterEventImpl;
|
||||
import io.gitlab.jfronny.respackopts.gson.*;
|
||||
import io.gitlab.jfronny.respackopts.gson.entry.BooleanEntrySerializer;
|
||||
import io.gitlab.jfronny.respackopts.gson.entry.ConfigBranchSerializer;
|
||||
import io.gitlab.jfronny.respackopts.gson.entry.EnumEntrySerializer;
|
||||
import io.gitlab.jfronny.respackopts.gson.entry.NumericEntrySerializer;
|
||||
import io.gitlab.jfronny.respackopts.util.RpoCommand;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.*;
|
||||
import io.gitlab.jfronny.respackopts.filters.FileFilterEventImpl;
|
||||
import io.gitlab.jfronny.respackopts.util.GuiFactory;
|
||||
import meteordevelopment.starscript.Script;
|
||||
import meteordevelopment.starscript.StandardLib;
|
||||
import meteordevelopment.starscript.Starscript;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.gui.FabricGuiEntry;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.server.integrated.IntegratedServer;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
@ -34,28 +48,53 @@ public class Respackopts implements ClientModInitializer {
|
|||
public static final Map<String, PackMeta> PACK_METAS = new HashMap<>();
|
||||
public static final Map<String, String> DISPLAY_NAME_LOOKUP = new HashMap<>();
|
||||
public static final Map<String, String> PACK_NAME_LOOKUP = new HashMap<>();
|
||||
public static final Integer META_VERSION = 6;
|
||||
public static final String FILE_EXTENSION = ".rpo";
|
||||
public static final Gson GSON;
|
||||
|
||||
public static Starscript STAR_SCRIPT;
|
||||
public static final Identifier CONF_ID = new Identifier(RpoModInfo.ID, "conf.json");
|
||||
public static final String ID = "respackopts";
|
||||
public static final Logger LOGGER = LogManager.getFormatterLogger(ID);
|
||||
public static final Identifier CONF_ID = new Identifier(ID, "conf.json");
|
||||
public static final Set<Runnable> SAVE_ACTIONS = new HashSet<>();
|
||||
public static final GuiFactory GUI_FACTORY = new GuiFactory();
|
||||
|
||||
public static GuiFactory factory = new GuiFactory();
|
||||
public static boolean forcePackReload = false;
|
||||
|
||||
public static Path CONF_DIR;
|
||||
public static ConfigFile CONFIG;
|
||||
|
||||
static {
|
||||
GSON = new GsonBuilder()
|
||||
.registerTypeAdapter(ConfigEnumEntry.class, new EnumEntrySerializer())
|
||||
.registerTypeAdapter(ConfigNumericEntry.class, new NumericEntrySerializer())
|
||||
.registerTypeAdapter(ConfigBooleanEntry.class, new BooleanEntrySerializer())
|
||||
.registerTypeAdapter(ConfigBranch.class, new ConfigBranchSerializer())
|
||||
.registerTypeAdapter(Script.class, new ScriptDeserializer())
|
||||
.registerTypeAdapter(FileRpo.class, new FileRpoDeserializer())
|
||||
.registerTypeAdapter(DirRpo.class, new DirRpoDeserializer())
|
||||
.registerTypeAdapter(Condition.class, new ConditionDeserializer())
|
||||
.registerTypeAdapterFactory(new SingleElementSetTypeAdapterFactory())
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
try {
|
||||
CONF_DIR = FabricLoader.getInstance().getConfigDir().resolve(ID);
|
||||
CONFIG = ConfigFile.load();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Could not resolve config directory", e);
|
||||
}
|
||||
try {
|
||||
STAR_SCRIPT = new Starscript();
|
||||
} catch (Throwable e) {
|
||||
} catch (Exception e) {
|
||||
FabricGuiEntry.displayCriticalError(new Exception("Respackopts could not initialize Starscript. Expect issues with packs that use it", e), false);
|
||||
}
|
||||
StandardLib.init(STAR_SCRIPT);
|
||||
}
|
||||
|
||||
public static String getId(WrappedPack pack) {
|
||||
public static String getId(ResourcePack pack) {
|
||||
return PACK_NAME_LOOKUP.get(pack.getName());
|
||||
}
|
||||
|
||||
public static boolean hasCapability(WrappedPack pack, PackCapability capability) {
|
||||
public static boolean hasCapability(ResourcePack pack, PackCapability capability) {
|
||||
String id = getId(pack);
|
||||
if (id == null) return false;
|
||||
return PACK_METAS.get(id).capabilities.contains(capability);
|
||||
|
@ -64,12 +103,12 @@ public class Respackopts implements ClientModInitializer {
|
|||
@Override
|
||||
public void onInitializeClient() {
|
||||
try {
|
||||
Files.createDirectories(RpoModInfo.CONF_DIR);
|
||||
Files.createDirectories(CONF_DIR);
|
||||
} catch (IOException e) {
|
||||
RpoModInfo.LOGGER.error("Could not initialize config directory", e);
|
||||
LOGGER.error("Could not initialize config directory", e);
|
||||
}
|
||||
if (RpoModInfo.CONFIG.debugLogs)
|
||||
SAVE_ACTIONS.add(() -> RpoModInfo.LOGGER.info("Save"));
|
||||
if (CONFIG.debugLogs)
|
||||
SAVE_ACTIONS.add(() -> LOGGER.info("Save"));
|
||||
SAVE_ACTIONS.add(() -> {
|
||||
for (Map.Entry<String, ConfigBranch> e : CONFIG_BRANCH.entrySet()) {
|
||||
STAR_SCRIPT.set(sanitizeString(e.getKey()), () -> e.getValue().buildStarscript());
|
||||
|
@ -77,19 +116,19 @@ public class Respackopts implements ClientModInitializer {
|
|||
});
|
||||
DirFilterEventImpl.init();
|
||||
FileFilterEventImpl.init();
|
||||
if (RpoModInfo.CONFIG.debugCommands)
|
||||
if (CONFIG.debugCommands)
|
||||
RpoCommand.register();
|
||||
}
|
||||
|
||||
public static void save() {
|
||||
if (RpoModInfo.CONFIG.debugLogs)
|
||||
RpoModInfo.LOGGER.info("Saving configs");
|
||||
if (CONFIG.debugLogs)
|
||||
LOGGER.info("Saving configs");
|
||||
for (Map.Entry<String, ConfigBranch> e : CONFIG_BRANCH.entrySet()) {
|
||||
try (Writer writer = Files.newBufferedWriter(RpoModInfo.CONF_DIR.resolve(e.getKey() + ".json"))) {
|
||||
RpoModInfo.GSON.toJson(e.getValue(), writer);
|
||||
try (Writer writer = Files.newBufferedWriter(CONF_DIR.resolve(e.getKey() + ".json"))) {
|
||||
GSON.toJson(e.getValue(), writer);
|
||||
writer.flush();
|
||||
} catch (IOException ex) {
|
||||
RpoModInfo.LOGGER.error("Could not save config", ex);
|
||||
LOGGER.error("Could not save config", ex);
|
||||
}
|
||||
}
|
||||
for (Runnable action : SAVE_ACTIONS) {
|
||||
|
@ -98,17 +137,17 @@ public class Respackopts implements ClientModInitializer {
|
|||
}
|
||||
|
||||
public static void load(String id) {
|
||||
Path q = RpoModInfo.CONF_DIR.resolve(id + ".json");
|
||||
Path q = CONF_DIR.resolve(id + ".json");
|
||||
if (Files.exists(q)) {
|
||||
if (RpoModInfo.CONFIG.debugLogs)
|
||||
RpoModInfo.LOGGER.info("Loading configs for: " + id);
|
||||
if (CONFIG.debugLogs)
|
||||
LOGGER.info("Loading configs for: " + id);
|
||||
try (Reader reader = Files.newBufferedReader(q)) {
|
||||
ConfigBranch b = RpoModInfo.GSON.fromJson(reader, ConfigBranch.class);
|
||||
ConfigBranch b = GSON.fromJson(reader, ConfigBranch.class);
|
||||
if (CONFIG_BRANCH.containsKey(id))
|
||||
CONFIG_BRANCH.get(id).sync(b, SyncMode.CONF_LOAD);
|
||||
CONFIG_BRANCH.get(id).sync(b, ConfigSyncMode.CONF_LOAD);
|
||||
STAR_SCRIPT.set(sanitizeString(id), b::buildStarscript);
|
||||
} catch (IOException e) {
|
||||
RpoModInfo.LOGGER.error("Failed to load " + id, e);
|
||||
LOGGER.error("Failed to load " + id, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,8 +165,8 @@ public class Respackopts implements ClientModInitializer {
|
|||
}
|
||||
|
||||
public static CompletableFuture<Void> forceReloadResources() {
|
||||
if (RpoModInfo.CONFIG.debugLogs)
|
||||
RpoModInfo.LOGGER.info("Forcing resource reload");
|
||||
if (CONFIG.debugLogs)
|
||||
LOGGER.info("Forcing resource reload");
|
||||
return CompletableFuture.allOf(MinecraftClient.getInstance().reloadResources(),
|
||||
reloadData());
|
||||
}
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
package io.gitlab.jfronny.respackopts;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.gitlab.jfronny.respackopts.data.ConfigFile;
|
||||
import io.gitlab.jfronny.respackopts.data.DirRpo;
|
||||
import io.gitlab.jfronny.respackopts.data.FileRpo;
|
||||
import io.gitlab.jfronny.respackopts.data.condition.Condition;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigBooleanEntry;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigBranch;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigEnumEntry;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigNumericEntry;
|
||||
import io.gitlab.jfronny.respackopts.gson.*;
|
||||
import meteordevelopment.starscript.Script;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class RpoModInfo {
|
||||
public static final Integer META_VERSION = 5;
|
||||
public static final String ID = "respackopts";
|
||||
public static final Logger LOGGER = LogManager.getFormatterLogger(ID);
|
||||
public static final String FILE_EXTENSION = ".rpo";
|
||||
public static Path CONF_DIR;
|
||||
public static ConfigFile CONFIG;
|
||||
public static final Gson GSON;
|
||||
|
||||
static {
|
||||
GSON = new GsonBuilder()
|
||||
.registerTypeAdapter(ConfigEnumEntry.class, new EnumEntrySerializer())
|
||||
.registerTypeAdapter(ConfigNumericEntry.class, new NumericEntrySerializer())
|
||||
.registerTypeAdapter(ConfigBooleanEntry.class, new BooleanEntrySerializer())
|
||||
.registerTypeAdapter(ConfigBranch.class, new ConfigBranchSerializer())
|
||||
.registerTypeAdapter(Script.class, new ScriptDeserializer())
|
||||
.registerTypeAdapter(FileRpo.class, new FileRpoDeserializer())
|
||||
.registerTypeAdapter(DirRpo.class, new DirRpoDeserializer())
|
||||
.registerTypeAdapter(Condition.class, new ConditionDeserializer())
|
||||
.registerTypeAdapterFactory(new SingleElementSetTypeAdapterFactory())
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
try {
|
||||
CONF_DIR = FabricLoader.getInstance().getConfigDir().resolve(ID);
|
||||
CONFIG = ConfigFile.load();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Could not resolve config directory", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package io.gitlab.jfronny.respackopts.data;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
|
@ -12,32 +12,32 @@ public class ConfigFile {
|
|||
public boolean debugCommands = false;
|
||||
public boolean debugLogs = false;
|
||||
public boolean dashloaderCompat = true;
|
||||
private static final Path rpoPath = RpoModInfo.CONF_DIR.resolve("_respackopts.conf");
|
||||
private static final Path rpoPath = Respackopts.CONF_DIR.resolve("_respackopts.conf");
|
||||
|
||||
public static ConfigFile load() {
|
||||
if (!Files.exists(rpoPath))
|
||||
new ConfigFile().save();
|
||||
try (BufferedReader br = Files.newBufferedReader(rpoPath)) {
|
||||
return RpoModInfo.GSON.fromJson(br, ConfigFile.class);
|
||||
return Respackopts.GSON.fromJson(br, ConfigFile.class);
|
||||
} catch (IOException e) {
|
||||
RpoModInfo.LOGGER.error("Could not load config, using default", e);
|
||||
Respackopts.LOGGER.error("Could not load config, using default", e);
|
||||
return new ConfigFile();
|
||||
}
|
||||
}
|
||||
|
||||
public void save() {
|
||||
if (!Files.exists(RpoModInfo.CONF_DIR)) {
|
||||
if (!Files.exists(Respackopts.CONF_DIR)) {
|
||||
try {
|
||||
Files.createDirectories(RpoModInfo.CONF_DIR);
|
||||
Files.createDirectories(Respackopts.CONF_DIR);
|
||||
} catch (IOException e) {
|
||||
RpoModInfo.LOGGER.error("Could not create config dir", e);
|
||||
Respackopts.LOGGER.error("Could not create config dir", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try (BufferedWriter bw = Files.newBufferedWriter(rpoPath)) {
|
||||
RpoModInfo.GSON.toJson(this, bw);
|
||||
Respackopts.GSON.toJson(this, bw);
|
||||
} catch (IOException e) {
|
||||
RpoModInfo.LOGGER.error("Could not save", e);
|
||||
Respackopts.LOGGER.error("Could not save", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.gitlab.jfronny.respackopts.data;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigBranch;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.PackCapability;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
|
|
@ -31,6 +31,6 @@ public record RpoBooleanCondition(String name) implements Condition {
|
|||
}
|
||||
}
|
||||
}
|
||||
throw new RpoFormatException("Could not find pack with specified ID");
|
||||
throw new RpoFormatException("Could not find pack with specified ID: " + packId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
package io.gitlab.jfronny.respackopts.data.entry;
|
||||
|
||||
import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
|
||||
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
|
||||
import meteordevelopment.starscript.value.Value;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ConfigBooleanEntry extends ConfigEntry<Boolean> {
|
||||
public ConfigBooleanEntry(boolean v) {
|
||||
|
@ -35,11 +30,14 @@ public class ConfigBooleanEntry extends ConfigEntry<Boolean> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public AbstractConfigListEntry<?> buildEntry(ConfigEntryBuilder entryBuilder, Text name, Supplier<Optional<Text[]>> tooltipSupplier, String screenId, String entryName, String translationPrefix) {
|
||||
return entryBuilder.startBooleanToggle(name, getValue())
|
||||
public AbstractConfigListEntry<?> buildEntry(GuiEntryBuilderParam guiEntryBuilderParam) {
|
||||
return guiEntryBuilderParam.entryBuilder().startBooleanToggle(guiEntryBuilderParam.name(), getValue())
|
||||
.setDefaultValue(getDefault())
|
||||
.setSaveConsumer(this::setValue)
|
||||
.setTooltipSupplier(tooltipSupplier)
|
||||
.setSaveConsumer(value -> {
|
||||
if (getValue() != value) guiEntryBuilderParam.saveCallback();
|
||||
setValue(value);
|
||||
})
|
||||
.setTooltipSupplier(guiEntryBuilderParam.tooltipSupplier())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,19 +2,15 @@ package io.gitlab.jfronny.respackopts.data.entry;
|
|||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.ConfigSyncMode;
|
||||
import io.gitlab.jfronny.respackopts.util.RpoFormatException;
|
||||
import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
|
||||
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
|
||||
import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder;
|
||||
import meteordevelopment.starscript.value.Value;
|
||||
import meteordevelopment.starscript.value.ValueMap;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ConfigBranch extends ConfigEntry<Map<String, ConfigEntry<?>>> {
|
||||
public ConfigBranch() {
|
||||
|
@ -44,33 +40,33 @@ public class ConfigBranch extends ConfigEntry<Map<String, ConfigEntry<?>>> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void sync(ConfigEntry<Map<String, ConfigEntry<?>>> source, SyncMode mode) {
|
||||
public void sync(ConfigEntry<Map<String, ConfigEntry<?>>> source, ConfigSyncMode mode) {
|
||||
for (Map.Entry<String, ConfigEntry<?>> e : source.getValue().entrySet()) {
|
||||
if (!has(e.getKey())) {
|
||||
if (mode == SyncMode.RESPACK_LOAD)
|
||||
if (mode == ConfigSyncMode.RESPACK_LOAD)
|
||||
add(e.getKey(), e.getValue().clone());
|
||||
} else {
|
||||
ConfigEntry<?> current = get(e.getKey());
|
||||
if (e.getValue().getClass().equals(current.getClass())) {
|
||||
if (e.getValue().getEntryType().equals(current.getEntryType())) {
|
||||
syncSub(current, (ConfigEntry)e.getValue(), mode);
|
||||
}
|
||||
else {
|
||||
if (mode == SyncMode.RESPACK_LOAD) {
|
||||
RpoModInfo.LOGGER.warn("Type mismatch in config (" + getName() + "), overwriting");
|
||||
if (mode == ConfigSyncMode.RESPACK_LOAD) {
|
||||
Respackopts.LOGGER.warn("Type mismatch in config (" + getName() + "), overwriting");
|
||||
add(e.getKey(), e.getValue().clone());
|
||||
} else
|
||||
RpoModInfo.LOGGER.warn("Type mismatch in config (" + getName() + "), ignoring");
|
||||
Respackopts.LOGGER.warn("Type mismatch in config (" + getName() + "), ignoring");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode == SyncMode.RESPACK_LOAD)
|
||||
if (mode == ConfigSyncMode.RESPACK_LOAD)
|
||||
for (Map.Entry<String, ConfigEntry<?>> e : getValue().entrySet()) {
|
||||
if (!source.getValue().containsKey(e.getKey()))
|
||||
super.getValue().remove(e.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void syncSub(ConfigEntry<T> current, ConfigEntry<T> next, SyncMode mode) {
|
||||
private <T> void syncSub(ConfigEntry<T> current, ConfigEntry<T> next, ConfigSyncMode mode) {
|
||||
current.sync(next, mode);
|
||||
}
|
||||
|
||||
|
@ -118,10 +114,10 @@ public class ConfigBranch extends ConfigEntry<Map<String, ConfigEntry<?>>> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public AbstractConfigListEntry<?> buildEntry(ConfigEntryBuilder entryBuilder, Text name, Supplier<Optional<Text[]>> tooltipSupplier, String screenId, String entryName, String translationPrefix) {
|
||||
SubCategoryBuilder sc = entryBuilder.startSubCategory(name);
|
||||
Respackopts.factory.buildCategory(this, screenId, sc::add, entryBuilder, entryName);
|
||||
sc.setTooltipSupplier(tooltipSupplier);
|
||||
public AbstractConfigListEntry<?> buildEntry(GuiEntryBuilderParam guiEntryBuilderParam) {
|
||||
SubCategoryBuilder sc = guiEntryBuilderParam.entryBuilder().startSubCategory(guiEntryBuilderParam.name());
|
||||
Respackopts.GUI_FACTORY.buildCategory(this, guiEntryBuilderParam.screenId(), sc::add, guiEntryBuilderParam.agg(), guiEntryBuilderParam.entryBuilder(), guiEntryBuilderParam.entryName());
|
||||
sc.setTooltipSupplier(guiEntryBuilderParam.tooltipSupplier());
|
||||
return sc.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
package io.gitlab.jfronny.respackopts.data.entry;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.ConfigSyncMode;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.PackReloadType;
|
||||
import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
|
||||
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
|
||||
import meteordevelopment.starscript.value.Value;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public abstract class ConfigEntry<T> {
|
||||
private T defaultValue;
|
||||
private T value;
|
||||
private PackReloadType reloadType = PackReloadType.Resource;
|
||||
protected int version;
|
||||
protected ConfigBranch parent;
|
||||
|
||||
|
@ -34,7 +35,7 @@ public abstract class ConfigEntry<T> {
|
|||
public T getValue() {
|
||||
if (value == null) {
|
||||
if (defaultValue == null) {
|
||||
RpoModInfo.LOGGER.warn("No default value or current value set for entry, returning null in " + getName());
|
||||
Respackopts.LOGGER.warn("No default value or current value set for entry, returning null in " + getName());
|
||||
return null;
|
||||
}
|
||||
value = getDefault();
|
||||
|
@ -42,28 +43,30 @@ public abstract class ConfigEntry<T> {
|
|||
return value;
|
||||
}
|
||||
|
||||
public void setValue(T value) {
|
||||
public T setValue(T value) {
|
||||
if (value != null)
|
||||
this.value = value;
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public T getDefault() {
|
||||
if (defaultValue == null) {
|
||||
defaultValue = getValue();
|
||||
RpoModInfo.LOGGER.warn("No default value set for entry, using current in " + getName());
|
||||
Respackopts.LOGGER.warn("No default value set for entry, using current in " + getName());
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void setDefault(T value) {
|
||||
public T setDefault(T value) {
|
||||
if (value != null)
|
||||
defaultValue = value;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void sync(ConfigEntry<T> source, SyncMode mode) {
|
||||
if (mode == SyncMode.RESPACK_LOAD)
|
||||
public void sync(ConfigEntry<T> source, ConfigSyncMode mode) {
|
||||
if (mode == ConfigSyncMode.RESPACK_LOAD)
|
||||
setDefault(source.getDefault());
|
||||
if (mode == SyncMode.CONF_LOAD)
|
||||
if (mode == ConfigSyncMode.CONF_LOAD)
|
||||
setValue(source.getValue());
|
||||
}
|
||||
|
||||
|
@ -84,9 +87,21 @@ public abstract class ConfigEntry<T> {
|
|||
|
||||
public abstract Value buildStarscript();
|
||||
|
||||
public abstract AbstractConfigListEntry<?> buildEntry(ConfigEntryBuilder entryBuilder, Text name, Supplier<Optional<Text[]>> tooltipSupplier, String screenId, String entryName, String translationPrefix);
|
||||
public abstract AbstractConfigListEntry<?> buildEntry(GuiEntryBuilderParam guiEntryBuilderParam);
|
||||
|
||||
public String getEntryType() {
|
||||
return "field";
|
||||
}
|
||||
|
||||
public Type getValueType() {
|
||||
return new TypeToken<T>(){}.getType();
|
||||
}
|
||||
|
||||
public PackReloadType getReloadType() {
|
||||
return reloadType;
|
||||
}
|
||||
|
||||
public void setReloadType(PackReloadType reloadType) {
|
||||
this.reloadType = reloadType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
package io.gitlab.jfronny.respackopts.data.entry;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.ConfigSyncMode;
|
||||
import io.gitlab.jfronny.respackopts.util.GuiFactory;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
|
||||
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
|
||||
import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder;
|
||||
import meteordevelopment.starscript.value.Value;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ConfigEnumEntry extends ConfigEntry<String> {
|
||||
public List<String> values = new ArrayList<>();
|
||||
|
@ -51,10 +49,10 @@ public class ConfigEnumEntry extends ConfigEntry<String> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void sync(ConfigEntry<String> source, SyncMode mode) {
|
||||
public void sync(ConfigEntry<String> source, ConfigSyncMode mode) {
|
||||
super.sync(source, mode);
|
||||
ConfigEnumEntry n = (ConfigEnumEntry) source;
|
||||
if (mode == SyncMode.RESPACK_LOAD) {
|
||||
if (mode == ConfigSyncMode.RESPACK_LOAD) {
|
||||
if (n.values != null && !n.values.isEmpty())
|
||||
values = n.values;
|
||||
}
|
||||
|
@ -63,7 +61,7 @@ public class ConfigEnumEntry extends ConfigEntry<String> {
|
|||
setValue(values.get(n.nextValue));
|
||||
}
|
||||
else {
|
||||
RpoModInfo.LOGGER.error("Could not load default value for enum in " + getName());
|
||||
Respackopts.LOGGER.error("Could not load default value for enum in " + getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,16 +117,19 @@ public class ConfigEnumEntry extends ConfigEntry<String> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public AbstractConfigListEntry<?> buildEntry(ConfigEntryBuilder entryBuilder, Text name, Supplier<Optional<Text[]>> tooltipSupplier, String screenId, String entryName, String translationPrefix) {
|
||||
Function<String, Text> entryText = s -> GuiFactory.getText(s, ("".equals(translationPrefix) ? "" : translationPrefix + ".") + entryName);
|
||||
return entryBuilder.startDropdownMenu(name,
|
||||
public AbstractConfigListEntry<?> buildEntry(GuiEntryBuilderParam guiEntryBuilderParam) {
|
||||
Function<String, Text> entryText = s -> GuiFactory.getText(s, ("".equals(guiEntryBuilderParam.translationPrefix()) ? "" : guiEntryBuilderParam.translationPrefix() + ".") + guiEntryBuilderParam.entryName());
|
||||
return guiEntryBuilderParam.entryBuilder().startDropdownMenu(guiEntryBuilderParam.name(),
|
||||
DropdownMenuBuilder.TopCellElementBuilder.of(getValue(), s -> s, entryText),
|
||||
DropdownMenuBuilder.CellCreatorBuilder.of(entryText))
|
||||
.setSuggestionMode(false)
|
||||
.setDefaultValue(getDefault())
|
||||
.setSelections(() -> values.iterator())
|
||||
.setSaveConsumer(this::setValue)
|
||||
.setTooltipSupplier(tooltipSupplier)
|
||||
.setSaveConsumer(value -> {
|
||||
if (!Objects.equals(getValue(), value)) guiEntryBuilderParam.saveCallback();
|
||||
setValue(value);
|
||||
})
|
||||
.setTooltipSupplier(guiEntryBuilderParam.tooltipSupplier())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,38 @@
|
|||
package io.gitlab.jfronny.respackopts.data.entry;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.data.enums.ConfigSyncMode;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.NumericEntryType;
|
||||
import io.gitlab.jfronny.respackopts.gson.entry.NumericEntrySerializer;
|
||||
import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
|
||||
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
|
||||
import me.shedaniel.clothconfig2.impl.builders.DoubleFieldBuilder;
|
||||
import meteordevelopment.starscript.value.Value;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ConfigNumericEntry extends ConfigEntry<Double> {
|
||||
public Double min;
|
||||
public Double max;
|
||||
public Double min = null;
|
||||
public Double max = null;
|
||||
public final NumericEntryType type;
|
||||
|
||||
public ConfigNumericEntry() {
|
||||
public ConfigNumericEntry(NumericEntryType type) {
|
||||
this.type = type;
|
||||
setValue(0d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sync(ConfigEntry<Double> source, SyncMode mode) {
|
||||
public Double setDefault(Double value) {
|
||||
if ((min != null && value < min) || (max != null && value > max))
|
||||
throw new RuntimeException("Default value (" + value + ") out of range in number entry definition (" + min + "-" + max + ")");
|
||||
if (type == NumericEntryType.Slider && !NumericEntrySerializer.isWhole(value))
|
||||
throw new RuntimeException("Default number value must be a whole number");
|
||||
return super.setDefault(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sync(ConfigEntry<Double> source, ConfigSyncMode mode) {
|
||||
super.sync(source, mode);
|
||||
ConfigNumericEntry n = (ConfigNumericEntry) source;
|
||||
if (mode == SyncMode.RESPACK_LOAD) {
|
||||
if (mode == ConfigSyncMode.RESPACK_LOAD) {
|
||||
if (n.min != null)
|
||||
min = n.min;
|
||||
if (n.max != null)
|
||||
|
@ -42,7 +54,7 @@ public class ConfigNumericEntry extends ConfigEntry<Double> {
|
|||
|
||||
@Override
|
||||
public ConfigEntry<Double> clone() {
|
||||
ConfigNumericEntry ce = new ConfigNumericEntry();
|
||||
ConfigNumericEntry ce = new ConfigNumericEntry(type);
|
||||
ce.max = max;
|
||||
ce.min = min;
|
||||
ce.setValue(getValue());
|
||||
|
@ -64,21 +76,30 @@ public class ConfigNumericEntry extends ConfigEntry<Double> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public AbstractConfigListEntry<?> buildEntry(ConfigEntryBuilder entryBuilder, Text name, Supplier<Optional<Text[]>> tooltipSupplier, String screenId, String entryName, String translationPrefix) {
|
||||
if (min != null && max != null) {
|
||||
return entryBuilder.startIntSlider(name,
|
||||
public AbstractConfigListEntry<?> buildEntry(GuiEntryBuilderParam guiEntryBuilderParam) {
|
||||
if (type == NumericEntryType.Slider) {
|
||||
return guiEntryBuilderParam.entryBuilder().startIntSlider(guiEntryBuilderParam.name(),
|
||||
getValue().intValue(), min.intValue(), max.intValue())
|
||||
.setDefaultValue(getDefault().intValue())
|
||||
.setSaveConsumer(v -> setValue(v.doubleValue()))
|
||||
.setTooltipSupplier(tooltipSupplier)
|
||||
.setSaveConsumer(value -> {
|
||||
if (!Objects.equals(getValue(), value.doubleValue())) guiEntryBuilderParam.saveCallback();
|
||||
setValue(value.doubleValue());
|
||||
})
|
||||
.setTooltipSupplier(guiEntryBuilderParam.tooltipSupplier())
|
||||
.build();
|
||||
}
|
||||
else {
|
||||
return entryBuilder.startDoubleField(name, getValue())
|
||||
DoubleFieldBuilder builder = guiEntryBuilderParam.entryBuilder().startDoubleField(guiEntryBuilderParam.name(), getValue())
|
||||
.setDefaultValue(getDefault())
|
||||
.setSaveConsumer(this::setValue)
|
||||
.setTooltipSupplier(tooltipSupplier)
|
||||
.build();
|
||||
.setSaveConsumer(value -> {
|
||||
if (!Objects.equals(getValue(), value)) guiEntryBuilderParam.saveCallback();
|
||||
setValue(value);
|
||||
})
|
||||
.setTooltipSupplier(guiEntryBuilderParam.tooltipSupplier());
|
||||
if (min != null) builder.setMin(min);
|
||||
if (max != null) builder.setMax(max);
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package io.gitlab.jfronny.respackopts.data.entry;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.data.enums.PackReloadType;
|
||||
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record GuiEntryBuilderParam(ConfigEntryBuilder entryBuilder, Text name,
|
||||
Supplier<Optional<Text[]>> tooltipSupplier, String screenId, String entryName,
|
||||
String translationPrefix, Runnable onSave, Consumer<PackReloadType> agg) {
|
||||
public void saveCallback() {
|
||||
onSave.run();
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package io.gitlab.jfronny.respackopts.data.entry;
|
||||
|
||||
public enum SyncMode {
|
||||
RESPACK_LOAD, CONF_LOAD
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package io.gitlab.jfronny.respackopts.data.enums;
|
||||
|
||||
public enum ConfigSyncMode {
|
||||
RESPACK_LOAD, CONF_LOAD
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package io.gitlab.jfronny.respackopts.data.enums;
|
||||
|
||||
public enum NumericEntryType {
|
||||
Slider, Box
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package io.gitlab.jfronny.respackopts.data;
|
||||
package io.gitlab.jfronny.respackopts.data.enums;
|
||||
|
||||
public enum PackCapability {
|
||||
FileFilter, DirFilter, DirFilterAdditive
|
|
@ -0,0 +1,22 @@
|
|||
package io.gitlab.jfronny.respackopts.data.enums;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public enum PackReloadType {
|
||||
Resource, Simple;
|
||||
|
||||
public static class Aggregator implements Consumer<PackReloadType> {
|
||||
private PackReloadType reloadType = Simple;
|
||||
|
||||
@Override
|
||||
public void accept(PackReloadType packReloadType) {
|
||||
if (packReloadType == PackReloadType.Resource) {
|
||||
reloadType = PackReloadType.Resource;
|
||||
}
|
||||
}
|
||||
|
||||
public PackReloadType get() {
|
||||
return reloadType;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
package io.gitlab.jfronny.respackopts.filters;
|
||||
|
||||
import io.gitlab.jfronny.libjf.data.ResourcePath;
|
||||
import io.gitlab.jfronny.libjf.data.UserResourceEvents;
|
||||
import io.gitlab.jfronny.libjf.data.WrappedPack;
|
||||
import io.gitlab.jfronny.libjf.ResourcePath;
|
||||
import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.data.DirRpo;
|
||||
import io.gitlab.jfronny.respackopts.data.PackCapability;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.PackCapability;
|
||||
import io.gitlab.jfronny.respackopts.util.RpoFormatException;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import java.io.*;
|
||||
|
@ -87,12 +86,12 @@ public class DirFilterEventImpl {
|
|||
try {
|
||||
return !rpo.conditions.evaluate(packId);
|
||||
} catch (RpoFormatException e) {
|
||||
RpoModInfo.LOGGER.error("Couldn't parse dir conditions", e);
|
||||
Respackopts.LOGGER.error("Couldn't parse dir conditions", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static DirRpo findDirRpo(WrappedPack pack, String name) {
|
||||
private static DirRpo findDirRpo(ResourcePack pack, String name) {
|
||||
int li = name.lastIndexOf('/');
|
||||
if (li <= 0)
|
||||
return null;
|
||||
|
@ -107,15 +106,15 @@ public class DirFilterEventImpl {
|
|||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
if (pack.getUnderlying().contains(rp.getType(), rp.getId())) {
|
||||
try (InputStream stream = pack.getUnderlying().open(rp.getType(), rp.getId()); Reader w = new InputStreamReader(stream)) {
|
||||
drp = RpoModInfo.GSON.fromJson(w, DirRpo.class);
|
||||
if (UserResourceEvents.disable(() -> pack.contains(rp.getType(), rp.getId()))) {
|
||||
try (InputStream stream = UserResourceEvents.disable(() -> pack.open(rp.getType(), rp.getId())); Reader w = new InputStreamReader(stream)) {
|
||||
drp = Respackopts.GSON.fromJson(w, DirRpo.class);
|
||||
drp.path = name;
|
||||
if (drp.fallback != null && !drp.fallback.endsWith("/"))
|
||||
drp.fallback += "/";
|
||||
return drp;
|
||||
} catch (IOException e) {
|
||||
RpoModInfo.LOGGER.error("Couldn't open dir rpo", e);
|
||||
Respackopts.LOGGER.error("Couldn't open dir rpo", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package io.gitlab.jfronny.respackopts.filters;
|
||||
|
||||
import io.gitlab.jfronny.libjf.data.ResourcePath;
|
||||
import io.gitlab.jfronny.libjf.data.UserResourceEvents;
|
||||
import io.gitlab.jfronny.libjf.data.WrappedPack;
|
||||
import io.gitlab.jfronny.libjf.ResourcePath;
|
||||
import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.data.PackCapability;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.PackCapability;
|
||||
import io.gitlab.jfronny.respackopts.filters.util.FileExclusionProvider;
|
||||
import io.gitlab.jfronny.respackopts.filters.util.FileExpansionProvider;
|
||||
import io.gitlab.jfronny.respackopts.filters.util.FileFallbackProvider;
|
||||
import net.minecraft.resource.AbstractFileResourcePack;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
@ -50,7 +50,7 @@ public class FileFilterEventImpl {
|
|||
return true;
|
||||
}
|
||||
else {
|
||||
if (pack.getUnderlying().contains(type, new Identifier(id.getNamespace(), id.getPath() + ".rpo")) && FileFallbackProvider.fileVisible(pack, name)) {
|
||||
if (UserResourceEvents.disable(() -> pack.contains(type, new Identifier(id.getNamespace(), id.getPath() + ".rpo"))) && FileFallbackProvider.fileVisible(pack, name)) {
|
||||
containsFileWasFallback.set(true);
|
||||
return true;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ public class FileFilterEventImpl {
|
|||
});
|
||||
}
|
||||
|
||||
private static boolean skip(WrappedPack pack) {
|
||||
return !(pack.getUnderlying() instanceof AbstractFileResourcePack) || !Respackopts.hasCapability(pack, PackCapability.FileFilter);
|
||||
private static boolean skip(ResourcePack pack) {
|
||||
return !(pack instanceof AbstractFileResourcePack) || !Respackopts.hasCapability(pack, PackCapability.FileFilter);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
package io.gitlab.jfronny.respackopts.filters.util;
|
||||
|
||||
import io.gitlab.jfronny.libjf.data.WrappedPack;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.util.RpoFormatException;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
|
||||
public class FileExclusionProvider {
|
||||
public static boolean fileHidden(WrappedPack pack, String name) {
|
||||
public static boolean fileHidden(ResourcePack pack, String name) {
|
||||
return FileRpoSearchProvider.modifyWithRpo(name, pack, rpo -> {
|
||||
if (rpo.conditions == null)
|
||||
return false;
|
||||
try {
|
||||
return !rpo.conditions.evaluate(Respackopts.getId(pack));
|
||||
} catch (RpoFormatException e) {
|
||||
RpoModInfo.LOGGER.error("Could not evaluate condition " + name, e);
|
||||
Respackopts.LOGGER.error("Could not evaluate condition " + name, e);
|
||||
return false;
|
||||
}
|
||||
}, false);
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package io.gitlab.jfronny.respackopts.filters.util;
|
||||
|
||||
import io.gitlab.jfronny.libjf.data.WrappedPack;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import meteordevelopment.starscript.Script;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Map;
|
||||
|
@ -17,14 +16,14 @@ public class FileExpansionProvider {
|
|||
return new ByteArrayInputStream(s.getBytes());
|
||||
}
|
||||
|
||||
public static InputStream replace(InputStream inputStream, WrappedPack pack, String name) {
|
||||
public static InputStream replace(InputStream inputStream, ResourcePack pack, String name) {
|
||||
return FileRpoSearchProvider.modifyWithRpo(name, pack, rpo -> {
|
||||
if (rpo.expansions == null || rpo.expansions.isEmpty())
|
||||
return inputStream;
|
||||
try {
|
||||
return replace(inputStream, rpo.expansions);
|
||||
} catch (IOException e) {
|
||||
RpoModInfo.LOGGER.error("Could not perform file expansion on " + name, e);
|
||||
Respackopts.LOGGER.error("Could not perform file expansion on " + name, e);
|
||||
return inputStream;
|
||||
}
|
||||
}, inputStream);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.gitlab.jfronny.respackopts.filters.util;
|
||||
|
||||
import io.gitlab.jfronny.libjf.data.ResourcePath;
|
||||
import io.gitlab.jfronny.libjf.data.WrappedPack;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.libjf.ResourcePath;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
|
@ -10,7 +10,7 @@ import java.io.InputStream;
|
|||
import java.util.Collection;
|
||||
|
||||
public class FileFallbackProvider {
|
||||
public static boolean fileVisible(WrappedPack pack, String name) {
|
||||
public static boolean fileVisible(ResourcePack pack, String name) {
|
||||
return FileRpoSearchProvider.modifyWithRpo(name, pack, rpo -> {
|
||||
if (rpo.fallbacks != null) {
|
||||
for (String s : rpo.fallbacks) {
|
||||
|
@ -23,7 +23,7 @@ public class FileFallbackProvider {
|
|||
}, false);
|
||||
}
|
||||
|
||||
public static InputStream getReplacement(WrappedPack pack, String name) {
|
||||
public static InputStream getReplacement(ResourcePack pack, String name) {
|
||||
return FileRpoSearchProvider.modifyWithRpo(name, pack, rpo -> {
|
||||
try {
|
||||
if (rpo.fallbacks != null) {
|
||||
|
@ -33,21 +33,21 @@ public class FileFallbackProvider {
|
|||
return pack.open(tmp.getType(), tmp.getId());
|
||||
}
|
||||
}
|
||||
RpoModInfo.LOGGER.error("Could not determine replacement for " + name);
|
||||
Respackopts.LOGGER.error("Could not determine replacement for " + name);
|
||||
}
|
||||
catch (Exception e) {
|
||||
RpoModInfo.LOGGER.error("Could not determine replacement for " + name, e);
|
||||
Respackopts.LOGGER.error("Could not determine replacement for " + name, e);
|
||||
}
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
|
||||
public static void addFallbackResources(WrappedPack pack, Collection<Identifier> ret, String namespace, ResourceType type) {
|
||||
public static void addFallbackResources(ResourcePack pack, Collection<Identifier> ret, String namespace, ResourceType type) {
|
||||
// Warning: the Identifiers here DON'T CONTAIN THE TYPE! Therefore, it needs to be added when calling a method that generates a ResourcePath!
|
||||
for (Identifier identifier : ret) {
|
||||
String path = identifier.getPath();
|
||||
if (FileRpoSearchProvider.isRpo(path)) {
|
||||
String expectedTarget = path.substring(0, path.length() - RpoModInfo.FILE_EXTENSION.length());
|
||||
String expectedTarget = path.substring(0, path.length() - Respackopts.FILE_EXTENSION.length());
|
||||
if (ret.stream().noneMatch(s -> s.getPath().equals(expectedTarget)) && fileVisible(pack, type.getDirectory() + "/" + expectedTarget)) {
|
||||
ret.add(new Identifier(namespace, expectedTarget));
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.gitlab.jfronny.respackopts.filters.util;
|
||||
|
||||
import io.gitlab.jfronny.libjf.data.ResourcePath;
|
||||
import io.gitlab.jfronny.libjf.data.WrappedPack;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.libjf.ResourcePath;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.data.FileRpo;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -11,26 +11,26 @@ import java.io.Reader;
|
|||
|
||||
public class FileRpoSearchProvider {
|
||||
public static boolean isRpo(String fileName) {
|
||||
return fileName.endsWith(RpoModInfo.FILE_EXTENSION);
|
||||
return fileName.endsWith(Respackopts.FILE_EXTENSION);
|
||||
}
|
||||
|
||||
public static <T> T modifyWithRpo(String fileName, WrappedPack pack, ModifiedGenerator<T> getModified, T defaultValue) {
|
||||
public static <T> T modifyWithRpo(String fileName, ResourcePack pack, ModifiedGenerator<T> getModified, T defaultValue) {
|
||||
if (FileRpoSearchProvider.isRpo(fileName))
|
||||
return defaultValue;
|
||||
ResourcePath rpoPath;
|
||||
try {
|
||||
rpoPath = new ResourcePath(fileName + RpoModInfo.FILE_EXTENSION);
|
||||
rpoPath = new ResourcePath(fileName + Respackopts.FILE_EXTENSION);
|
||||
if (!pack.contains(rpoPath.getType(), rpoPath.getId()))
|
||||
return defaultValue;
|
||||
} catch (Throwable e) {
|
||||
RpoModInfo.LOGGER.error("Could not check file filter status", e);
|
||||
Respackopts.LOGGER.error("Could not check file filter status", e);
|
||||
return defaultValue;
|
||||
}
|
||||
try (InputStream stream = pack.open(rpoPath.getType(), rpoPath.getId()); Reader w = new InputStreamReader(stream)) {
|
||||
return getModified.getModified(RpoModInfo.GSON.fromJson(w, FileRpo.class));
|
||||
return getModified.getModified(Respackopts.GSON.fromJson(w, FileRpo.class));
|
||||
}
|
||||
catch (Exception e) {
|
||||
RpoModInfo.LOGGER.error("Could not generate replacement for " + rpoPath.getName() + " in " + pack.getName(), e);
|
||||
Respackopts.LOGGER.error("Could not generate replacement for " + rpoPath.getName() + " in " + pack.getName(), e);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
package io.gitlab.jfronny.respackopts.gson;
|
||||
|
||||
import com.google.gson.*;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.*;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigBranchSerializer implements JsonSerializer<ConfigBranch>, JsonDeserializer<ConfigBranch> {
|
||||
@Override
|
||||
public JsonElement serialize(ConfigBranch src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject o = new JsonObject();
|
||||
for (Map.Entry<String, ConfigEntry<?>> entry : src.getValue().entrySet()) {
|
||||
o.add(entry.getKey(), context.serialize(entry.getValue()));
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigBranch deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
if (!json.isJsonObject())
|
||||
throw new JsonSyntaxException("ConfigBranch is not an object");
|
||||
JsonObject o = json.getAsJsonObject();
|
||||
ConfigBranch cbNew = new ConfigBranch();
|
||||
for (Map.Entry<String, JsonElement> e : o.entrySet()) {
|
||||
JsonElement j = e.getValue();
|
||||
String s = e.getKey();
|
||||
if (NumericEntrySerializer.isSlider(j))
|
||||
cbNew.add(s, context.deserialize(j, ConfigNumericEntry.class));
|
||||
else if (j.isJsonPrimitive()) {
|
||||
JsonPrimitive p = j.getAsJsonPrimitive();
|
||||
if (p.isBoolean())
|
||||
cbNew.add(s, new ConfigBooleanEntry(p.getAsBoolean()));
|
||||
else if (p.isNumber())
|
||||
cbNew.add(s, context.deserialize(j, ConfigNumericEntry.class));
|
||||
else if (p.isString())
|
||||
cbNew.add(s, context.deserialize(j, ConfigEnumEntry.class));
|
||||
}
|
||||
else if (j.isJsonArray())
|
||||
cbNew.add(s, context.deserialize(j, ConfigEnumEntry.class));
|
||||
else if (j.isJsonObject())
|
||||
cbNew.add(s, context.deserialize(j, ConfigBranch.class));
|
||||
else if (j.isJsonNull())
|
||||
throw new JsonSyntaxException("Unexpected json null");
|
||||
else
|
||||
throw new JsonSyntaxException("Unexpected json object type");
|
||||
}
|
||||
return cbNew;
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package io.gitlab.jfronny.respackopts.gson;
|
||||
|
||||
import com.google.gson.*;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigNumericEntry;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class NumericEntrySerializer implements JsonSerializer<ConfigNumericEntry>, JsonDeserializer<ConfigNumericEntry> {
|
||||
@Override
|
||||
public JsonElement serialize(ConfigNumericEntry src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.getValue());
|
||||
}
|
||||
@Override
|
||||
public ConfigNumericEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
ConfigNumericEntry result = new ConfigNumericEntry();
|
||||
if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isNumber()) {
|
||||
result.setValue(json.getAsDouble());
|
||||
result.setDefault(json.getAsDouble());
|
||||
return result;
|
||||
}
|
||||
else if (isSlider(json)) {
|
||||
JsonObject o = json.getAsJsonObject();
|
||||
JsonElement def = o.get("default");
|
||||
JsonElement min = o.get("min");
|
||||
JsonElement max = o.get("max");
|
||||
if (def.isJsonPrimitive() && def.getAsJsonPrimitive().isNumber()
|
||||
&& min.isJsonPrimitive() && min.getAsJsonPrimitive().isNumber()
|
||||
&& max.isJsonPrimitive() && max.getAsJsonPrimitive().isNumber()) {
|
||||
double defV = def.getAsNumber().doubleValue();
|
||||
double minV = min.getAsNumber().doubleValue();
|
||||
double maxV = max.getAsNumber().doubleValue();
|
||||
if (defV < minV || defV > maxV) {
|
||||
throw new JsonSyntaxException("Default value out of range in slider definition");
|
||||
}
|
||||
if (isWhole(defV) && isWhole(minV) && isWhole(maxV)) {
|
||||
result.setValue(defV);
|
||||
result.setDefault(defV);
|
||||
result.min = minV;
|
||||
result.max = maxV;
|
||||
return result;
|
||||
}
|
||||
throw new JsonSyntaxException("Expected whole number in slider definition");
|
||||
}
|
||||
throw new JsonSyntaxException("Expected numeric values in slider definition");
|
||||
}
|
||||
throw new JsonSyntaxException("Could not deserialize numeric entry");
|
||||
}
|
||||
|
||||
public static boolean isSlider(JsonElement element) {
|
||||
return element.isJsonObject() && element.getAsJsonObject().entrySet().stream().allMatch(s -> "default".equals(s.getKey()) || "min".equals(s.getKey()) || "max".equals(s.getKey()));
|
||||
}
|
||||
|
||||
private boolean isWhole(double v) {
|
||||
return v == Math.floor(v) && !Double.isInfinite(v);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import com.google.gson.JsonDeserializationContext;
|
|||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import meteordevelopment.starscript.Script;
|
||||
import meteordevelopment.starscript.compiler.Compiler;
|
||||
import meteordevelopment.starscript.compiler.Parser;
|
||||
|
@ -26,7 +26,7 @@ public class ScriptDeserializer implements JsonDeserializer<Script> {
|
|||
Parser.Result result = Parser.parse(s);
|
||||
if (result.hasErrors()) {
|
||||
for (Error error : result.errors) {
|
||||
RpoModInfo.LOGGER.error(error);
|
||||
Respackopts.LOGGER.error(error);
|
||||
}
|
||||
throw new JsonParseException("Could not parse script: See errors above");
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import com.google.gson.reflect.TypeToken;
|
|||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
@ -20,8 +20,8 @@ public class SingleElementSetTypeAdapterFactory implements TypeAdapterFactory {
|
|||
if (typeToken.getRawType() != Set.class
|
||||
|| !(type instanceof ParameterizedType pt))
|
||||
return null;
|
||||
if (RpoModInfo.CONFIG.debugLogs)
|
||||
RpoModInfo.LOGGER.info("Using SingleElementSetTypeAdapter for " + typeToken.toString());
|
||||
if (Respackopts.CONFIG.debugLogs)
|
||||
Respackopts.LOGGER.info("Using SingleElementSetTypeAdapter for " + typeToken.toString());
|
||||
Type elementType = pt.getActualTypeArguments()[0];
|
||||
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
|
||||
return (TypeAdapter<T>) createAdapter(elementAdapter);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package io.gitlab.jfronny.respackopts.gson;
|
||||
package io.gitlab.jfronny.respackopts.gson.entry;
|
||||
|
||||
import com.google.gson.*;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigBooleanEntry;
|
||||
|
@ -8,7 +8,15 @@ import java.lang.reflect.Type;
|
|||
public class BooleanEntrySerializer implements JsonSerializer<ConfigBooleanEntry>, JsonDeserializer<ConfigBooleanEntry> {
|
||||
@Override
|
||||
public ConfigBooleanEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
return new ConfigBooleanEntry(json.getAsBoolean());
|
||||
if (json.isJsonPrimitive()) return new ConfigBooleanEntry(json.getAsBoolean());
|
||||
else if (json.isJsonObject()) {
|
||||
JsonObject o = json.getAsJsonObject();
|
||||
if (o.has("default"))
|
||||
return new ConfigBooleanEntry(o.get("default").getAsBoolean());
|
||||
else
|
||||
throw new JsonSyntaxException("Default value for boolean entry must be a boolean");
|
||||
}
|
||||
else throw new JsonSyntaxException("Invalid type for boolean entry");
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,78 @@
|
|||
package io.gitlab.jfronny.respackopts.gson.entry;
|
||||
|
||||
import com.google.gson.*;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.*;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.PackReloadType;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigBranchSerializer implements JsonSerializer<ConfigBranch>, JsonDeserializer<ConfigBranch> {
|
||||
@Override
|
||||
public JsonElement serialize(ConfigBranch src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject o = new JsonObject();
|
||||
for (Map.Entry<String, ConfigEntry<?>> entry : src.getValue().entrySet()) {
|
||||
o.add(entry.getKey(), context.serialize(entry.getValue()));
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigBranch deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
if (!json.isJsonObject())
|
||||
throw new JsonSyntaxException("ConfigBranch is not an object");
|
||||
JsonObject o = json.getAsJsonObject();
|
||||
ConfigBranch cbNew = new ConfigBranch();
|
||||
for (Map.Entry<String, JsonElement> e : o.entrySet()) {
|
||||
JsonElement j = e.getValue();
|
||||
String s = e.getKey();
|
||||
if (j.isJsonPrimitive()) {
|
||||
JsonPrimitive p = j.getAsJsonPrimitive();
|
||||
if (p.isBoolean())
|
||||
cbNew.add(s, new ConfigBooleanEntry(p.getAsBoolean()));
|
||||
else if (p.isNumber())
|
||||
cbNew.add(s, context.deserialize(j, ConfigNumericEntry.class));
|
||||
else if (p.isString())
|
||||
cbNew.add(s, context.deserialize(j, ConfigEnumEntry.class));
|
||||
}
|
||||
else if (j.isJsonArray())
|
||||
cbNew.add(s, context.deserialize(j, ConfigEnumEntry.class));
|
||||
else if (j.isJsonObject()) {
|
||||
JsonObject jo = j.getAsJsonObject();
|
||||
String type;
|
||||
if (jo.has("type")) {
|
||||
type = jo.get("type").getAsString();
|
||||
}
|
||||
else {
|
||||
if (jo.entrySet().stream().allMatch(entry -> "default".equals(entry.getKey()) || "min".equals(entry.getKey()) || "max".equals(entry.getKey()))) {
|
||||
Respackopts.LOGGER.info("No \"type\" property for non-branch entry object, assuming slider");
|
||||
type = "slider";
|
||||
}
|
||||
else {
|
||||
cbNew.add(s, context.deserialize(j, ConfigBranch.class));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ConfigEntry<?> entry = switch (type.toLowerCase()) {
|
||||
case "slider", "number", "numeric" -> context.deserialize(j, ConfigNumericEntry.class);
|
||||
case "boolean", "toggle" -> context.deserialize(j, ConfigBooleanEntry.class);
|
||||
case "enum", "select" -> context.deserialize(j, ConfigEnumEntry.class);
|
||||
default -> throw new JsonSyntaxException("Unknown entry type: " + type);
|
||||
};
|
||||
if (jo.has("default")) {
|
||||
entry.setDefault(context.deserialize(jo.get("default"), entry.getValueType()));
|
||||
entry.setValue(context.deserialize(jo.get("default"), entry.getValueType()));
|
||||
}
|
||||
if (jo.has("reloadType")) {
|
||||
entry.setReloadType(context.deserialize(jo.get("reloadType"), PackReloadType.class));
|
||||
}
|
||||
cbNew.add(s, entry);
|
||||
} else if (j.isJsonNull())
|
||||
throw new JsonSyntaxException("Unexpected json null");
|
||||
else
|
||||
throw new JsonSyntaxException("Unexpected json object type");
|
||||
}
|
||||
return cbNew;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package io.gitlab.jfronny.respackopts.gson;
|
||||
package io.gitlab.jfronny.respackopts.gson.entry;
|
||||
|
||||
import com.google.gson.*;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigEnumEntry;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
@ -38,11 +38,15 @@ public class EnumEntrySerializer implements JsonSerializer<ConfigEnumEntry>, Jso
|
|||
throw new JsonSyntaxException("Expected string entry in enum");
|
||||
}
|
||||
if (result.values.isEmpty())
|
||||
RpoModInfo.LOGGER.warn("Enum entry empty");
|
||||
Respackopts.LOGGER.warn("Enum entry empty");
|
||||
else
|
||||
result.setDefault(result.values.get(0));
|
||||
return result;
|
||||
}
|
||||
else if (json.isJsonObject()) {
|
||||
JsonObject o = json.getAsJsonObject();
|
||||
return deserialize(o.get("values"), typeOfT, context);
|
||||
}
|
||||
else
|
||||
throw new JsonSyntaxException("Expected primitive string key or string array for enum");
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package io.gitlab.jfronny.respackopts.gson.entry;
|
||||
|
||||
import com.google.gson.*;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigNumericEntry;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.NumericEntryType;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class NumericEntrySerializer implements JsonSerializer<ConfigNumericEntry>, JsonDeserializer<ConfigNumericEntry> {
|
||||
@Override
|
||||
public JsonElement serialize(ConfigNumericEntry src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.getValue());
|
||||
}
|
||||
@Override
|
||||
public ConfigNumericEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isNumber()) {
|
||||
ConfigNumericEntry result = new ConfigNumericEntry(NumericEntryType.Box);
|
||||
result.setValue(json.getAsDouble());
|
||||
result.setDefault(json.getAsDouble());
|
||||
return result;
|
||||
}
|
||||
else if (json.isJsonObject()) {
|
||||
JsonObject o = json.getAsJsonObject();
|
||||
boolean slider = o.has("type") && o.get("type").getAsString().equals("slider");
|
||||
ConfigNumericEntry result = new ConfigNumericEntry(slider ? NumericEntryType.Slider : NumericEntryType.Box);
|
||||
JsonElement min = o.get("min");
|
||||
JsonElement max = o.get("max");
|
||||
if (slider && (min == null || max == null))
|
||||
throw new JsonSyntaxException("min/max must not be null for slider");
|
||||
if (min != null) {
|
||||
if (min.isJsonPrimitive() && min.getAsJsonPrimitive().isNumber()) {
|
||||
result.min = min.getAsNumber().doubleValue();
|
||||
}
|
||||
else throw new JsonSyntaxException("Expected number as min of numeric entry");
|
||||
}
|
||||
if (max != null) {
|
||||
if (max.isJsonPrimitive() && max.getAsJsonPrimitive().isNumber()) {
|
||||
result.max = max.getAsNumber().doubleValue();
|
||||
}
|
||||
else throw new JsonSyntaxException("Expected number as max of numeric entry");
|
||||
}
|
||||
if (slider && (!isWhole(result.min) || !isWhole(result.max)))
|
||||
throw new JsonSyntaxException("Expected whole number in slider definition");
|
||||
return result;
|
||||
}
|
||||
throw new JsonSyntaxException("Could not deserialize numeric entry");
|
||||
}
|
||||
|
||||
public static boolean isWhole(double v) {
|
||||
return v == Math.floor(v) && !Double.isInfinite(v);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package io.gitlab.jfronny.respackopts.integration;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -11,40 +11,32 @@ import java.nio.file.SimpleFileVisitor;
|
|||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
public class DashLoaderCompat {
|
||||
public static final boolean modPresent = FabricLoader.getInstance().isModLoaded("dashloader");
|
||||
private static boolean forceReload = false;
|
||||
|
||||
// Called from ASM injected through mixin/AsmPlugin
|
||||
@SuppressWarnings("unused")
|
||||
public static void injection() {
|
||||
if (forceReload) {
|
||||
if (RpoModInfo.CONFIG.debugLogs)
|
||||
RpoModInfo.LOGGER.info("Attempting to force a dashloader reload by removing its data directory");
|
||||
try {
|
||||
Class<?> loaderClass = Class.forName("net.oskarstrom.dashloader.DashLoader");
|
||||
Object loaderInstance = loaderClass.getDeclaredMethod("getInstance").invoke(null);
|
||||
Path loaderPath = (Path) loaderClass.getDeclaredMethod("getModBoundDir").invoke(loaderInstance);
|
||||
Files.walkFileTree(loaderPath, new SimpleFileVisitor<>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
Files.delete(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
Files.delete(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
RpoModInfo.LOGGER.error("Failed to remove dashloader data", e);
|
||||
}
|
||||
}
|
||||
forceReload = false;
|
||||
}
|
||||
|
||||
public static void requestForceReload() {
|
||||
forceReload = true;
|
||||
if (!FabricLoader.getInstance().isModLoaded("dashloader"))
|
||||
return;
|
||||
if (!Respackopts.CONFIG.dashloaderCompat)
|
||||
return;
|
||||
try {
|
||||
if (Respackopts.CONFIG.debugLogs)
|
||||
Respackopts.LOGGER.info("Removing DashCache to force dashloader to reload");
|
||||
Class<?> loaderClass = Class.forName("net.oskarstrom.dashloader.DashLoader");
|
||||
Object loaderInstance = loaderClass.getDeclaredMethod("getInstance").invoke(null);
|
||||
Path loaderPath = (Path) loaderClass.getDeclaredMethod("getModBoundDir").invoke(loaderInstance);
|
||||
Files.walkFileTree(loaderPath, new SimpleFileVisitor<>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
Files.delete(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
Files.delete(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
Respackopts.LOGGER.error("Failed to remove dashloader data, try disabling dashloaderCompat if this keeps happening", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package io.gitlab.jfronny.respackopts.integration;
|
||||
|
||||
import grondag.frex.FrexInitializer;
|
||||
import grondag.frex.api.config.ShaderConfig;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigBranch;
|
||||
import io.vram.frex.api.config.ShaderConfig;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -13,8 +12,8 @@ public class FrexCompat implements FrexInitializer {
|
|||
boolean initial = true;
|
||||
@Override
|
||||
public void onInitalizeFrex() {
|
||||
ShaderConfig.registerShaderConfigSupplier(new Identifier(RpoModInfo.ID, "config_supplier"), FrexCompat::generateShader);
|
||||
RpoModInfo.LOGGER.info("enabled frex/canvas support");
|
||||
ShaderConfig.registerShaderConfigSupplier(new Identifier(Respackopts.ID, "config_supplier"), FrexCompat::generateShader);
|
||||
Respackopts.LOGGER.info("enabled frex/canvas support");
|
||||
Respackopts.SAVE_ACTIONS.add(() -> {
|
||||
try {
|
||||
if (!initial)
|
||||
|
@ -22,14 +21,14 @@ public class FrexCompat implements FrexInitializer {
|
|||
initial = false;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
RpoModInfo.LOGGER.error("Could not reload shader config", e);
|
||||
Respackopts.LOGGER.error("Could not reload shader config", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static String generateShader() {
|
||||
if (RpoModInfo.CONFIG.debugLogs)
|
||||
RpoModInfo.LOGGER.info("Generating FREX shader code");
|
||||
if (Respackopts.CONFIG.debugLogs)
|
||||
Respackopts.LOGGER.info("Generating FREX shader code");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("#define respackopts_loaded");
|
||||
for (Map.Entry<String, ConfigBranch> e : Respackopts.CONFIG_BRANCH.entrySet()) {
|
||||
|
|
|
@ -3,8 +3,8 @@ package io.gitlab.jfronny.respackopts.integration;
|
|||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.data.ConfigFile;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.PackReloadType;
|
||||
import me.shedaniel.clothconfig2.api.ConfigBuilder;
|
||||
import me.shedaniel.clothconfig2.api.ConfigCategory;
|
||||
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
|
||||
|
@ -21,38 +21,41 @@ public class ModMenuCompat implements ModMenuApi {
|
|||
.setParentScreen(parent)
|
||||
.setTitle(new TranslatableText("respackopts.mainconfig"));
|
||||
ConfigEntryBuilder entryBuilder = builder.entryBuilder();
|
||||
PackReloadType.Aggregator agg = new PackReloadType.Aggregator();
|
||||
builder.setSavingRunnable(() -> {
|
||||
RpoModInfo.CONFIG.save();
|
||||
Respackopts.CONFIG.save();
|
||||
Respackopts.save();
|
||||
DashLoaderCompat.requestForceReload();
|
||||
Respackopts.forceReloadResources();
|
||||
if (agg.get() == PackReloadType.Resource) {
|
||||
DashLoaderCompat.requestForceReload();
|
||||
Respackopts.forceReloadResources();
|
||||
}
|
||||
});
|
||||
//Respackopts config screen
|
||||
ConfigFile defaultConfig = new ConfigFile();
|
||||
ConfigCategory mainConfig = builder.getOrCreateCategory(new TranslatableText("respackopts.mainconfig"));
|
||||
mainConfig.addEntry(
|
||||
entryBuilder.startBooleanToggle(new TranslatableText("respackopts.mainconfig.debugCommands"), RpoModInfo.CONFIG.debugCommands)
|
||||
entryBuilder.startBooleanToggle(new TranslatableText("respackopts.mainconfig.debugCommands"), Respackopts.CONFIG.debugCommands)
|
||||
.setDefaultValue(defaultConfig.debugCommands)
|
||||
.setSaveConsumer(b -> RpoModInfo.CONFIG.debugCommands = b)
|
||||
.setSaveConsumer(b -> Respackopts.CONFIG.debugCommands = b)
|
||||
.build()
|
||||
);
|
||||
mainConfig.addEntry(
|
||||
entryBuilder.startBooleanToggle(new TranslatableText("respackopts.mainconfig.debugLogs"), RpoModInfo.CONFIG.debugLogs)
|
||||
entryBuilder.startBooleanToggle(new TranslatableText("respackopts.mainconfig.debugLogs"), Respackopts.CONFIG.debugLogs)
|
||||
.setDefaultValue(defaultConfig.debugLogs)
|
||||
.setSaveConsumer(b -> RpoModInfo.CONFIG.debugLogs = b)
|
||||
.setSaveConsumer(b -> Respackopts.CONFIG.debugLogs = b)
|
||||
.build()
|
||||
);
|
||||
mainConfig.addEntry(
|
||||
entryBuilder.startBooleanToggle(new TranslatableText("respackopts.mainconfig.dashloaderCompat"), RpoModInfo.CONFIG.dashloaderCompat)
|
||||
entryBuilder.startBooleanToggle(new TranslatableText("respackopts.mainconfig.dashloaderCompat"), Respackopts.CONFIG.dashloaderCompat)
|
||||
.requireRestart()
|
||||
.setDefaultValue(defaultConfig.dashloaderCompat)
|
||||
.setSaveConsumer(b -> RpoModInfo.CONFIG.dashloaderCompat = b)
|
||||
.setSaveConsumer(b -> Respackopts.CONFIG.dashloaderCompat = b)
|
||||
.build()
|
||||
);
|
||||
//Pack config screens
|
||||
Respackopts.CONFIG_BRANCH.forEach((id, conf) -> {
|
||||
ConfigCategory config = builder.getOrCreateCategory(new TranslatableText((Respackopts.PACK_METAS.get(id).version >= 5 ? "rpo." : "respackopts.title.") + id));
|
||||
Respackopts.factory.buildCategory(conf, id, config::addEntry, entryBuilder, "");
|
||||
Respackopts.GUI_FACTORY.buildCategory(conf, id, config::addEntry, agg, entryBuilder, "");
|
||||
});
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
package io.gitlab.jfronny.respackopts.mixin;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.integration.DashLoaderCompat;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
import org.spongepowered.asm.mixin.transformer.FabricMixinTransformerProxy;
|
||||
import org.spongepowered.asm.transformers.MixinClassWriter;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class AsmPlugin implements IMixinConfigPlugin {
|
||||
@Override
|
||||
public void onLoad(String mixinPackage) {
|
||||
if (RpoModInfo.CONFIG.dashloaderCompat && DashLoaderCompat.modPresent) {
|
||||
RpoModInfo.LOGGER.info("Injecting RPO into the mixin pipeline in order to facilitate dashloader integration. If respackopts is mentioned, try disabling this via the config before reporting (\"debugLogs\")");
|
||||
try {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
Class<?> classLoaderClass = classLoader.getClass();
|
||||
|
||||
Field delegateField = classLoaderClass.getDeclaredField("delegate");
|
||||
delegateField.setAccessible(true);
|
||||
Object delegate = delegateField.get(classLoader);
|
||||
Class<?> delegateClass = delegate.getClass();
|
||||
|
||||
Field mixinTransformerField = delegateClass.getDeclaredField("mixinTransformer");
|
||||
mixinTransformerField.setAccessible(true);
|
||||
|
||||
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
|
||||
Transformer mixinTransformer = (Transformer) unsafe.allocateInstance(Transformer.class);
|
||||
mixinTransformer.delegate = (FabricMixinTransformerProxy) mixinTransformerField.get(delegate);
|
||||
|
||||
mixinTransformerField.set(delegate, mixinTransformer);
|
||||
} catch (NoSuchFieldException | IllegalAccessException | InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRefMapperConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMixins() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
|
||||
}
|
||||
|
||||
private static class Transformer extends FabricMixinTransformerProxy {
|
||||
private FabricMixinTransformerProxy delegate;
|
||||
|
||||
@Override
|
||||
public byte[] transformClassBytes(String name, String transformedName, byte[] basicClass) {
|
||||
basicClass = delegate.transformClassBytes(name, transformedName, basicClass);
|
||||
|
||||
if (name.equals("net.oskarstrom.dashloader.DashLoader")) {
|
||||
ClassNode klass = new ClassNode();
|
||||
ClassReader reader = new ClassReader(basicClass);
|
||||
reader.accept(klass, ClassReader.EXPAND_FRAMES);
|
||||
|
||||
boolean found = false;
|
||||
for (MethodNode method : klass.methods) {
|
||||
if (method.name.equals("reload")) {
|
||||
method.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getInternalName(DashLoaderCompat.class), "injection", "()V"));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) RpoModInfo.LOGGER.error("Could not hack into dashloader");
|
||||
|
||||
ClassWriter writer = new MixinClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
klass.accept(writer);
|
||||
basicClass = writer.toByteArray();
|
||||
}
|
||||
|
||||
return basicClass;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.respackopts.mixin;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import net.minecraft.client.gui.screen.option.OptionsScreen;
|
||||
import net.minecraft.client.option.GameOptions;
|
||||
import net.minecraft.resource.ResourcePackManager;
|
||||
|
@ -20,8 +19,8 @@ public class OptionsScreenMixin {
|
|||
private void refreshResourcePacks(ResourcePackManager resourcePackManager, CallbackInfo info) {
|
||||
if (Respackopts.forcePackReload) {
|
||||
Respackopts.forcePackReload = false;
|
||||
if (RpoModInfo.CONFIG.debugLogs)
|
||||
RpoModInfo.LOGGER.info("Clearing loaded resource packs to enable a proper resource reload");
|
||||
if (Respackopts.CONFIG.debugLogs)
|
||||
Respackopts.LOGGER.info("Clearing loaded resource packs to enable a proper resource reload");
|
||||
this.settings.resourcePacks.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public abstract class ResourcePackEntryMixin {
|
|||
k = Respackopts.DISPLAY_NAME_LOOKUP.get(k);
|
||||
info.setReturnValue(true);
|
||||
MinecraftClient c = MinecraftClient.getInstance();
|
||||
c.setScreen(Respackopts.factory.buildGui(Respackopts.CONFIG_BRANCH.get(k), k, c.currentScreen));
|
||||
c.setScreen(Respackopts.GUI_FACTORY.buildGui(Respackopts.CONFIG_BRANCH.get(k), k, c.currentScreen));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package io.gitlab.jfronny.respackopts.mixin;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.ConfigSyncMode;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.PackCapability;
|
||||
import io.gitlab.jfronny.respackopts.util.MetadataLocateResult;
|
||||
import io.gitlab.jfronny.respackopts.data.PackCapability;
|
||||
import io.gitlab.jfronny.respackopts.data.PackMeta;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.SyncMode;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourcePackManager;
|
||||
import net.minecraft.resource.ResourcePackProfile;
|
||||
|
@ -31,15 +30,15 @@ public class ResourcePackManagerMixin {
|
|||
MetadataLocateResult scan = rpo$locateMetadata(v);
|
||||
if (scan.hasMeta()) {
|
||||
try (InputStream is = scan.pack().open(scan.type(), Respackopts.CONF_ID); InputStreamReader isr = new InputStreamReader(is)) {
|
||||
PackMeta conf = RpoModInfo.GSON.fromJson(isr, PackMeta.class);
|
||||
if (RpoModInfo.CONFIG.debugLogs)
|
||||
RpoModInfo.LOGGER.info("Discovered pack: " + conf.id);
|
||||
if (RpoModInfo.META_VERSION < conf.version) {
|
||||
RpoModInfo.LOGGER.error(s + " was not loaded as it specifies a newer respackopts version than is installed");
|
||||
PackMeta conf = Respackopts.GSON.fromJson(isr, PackMeta.class);
|
||||
if (Respackopts.CONFIG.debugLogs)
|
||||
Respackopts.LOGGER.info("Discovered pack: " + conf.id);
|
||||
if (Respackopts.META_VERSION < conf.version) {
|
||||
Respackopts.LOGGER.error(s + " was not loaded as it specifies a newer respackopts version than is installed");
|
||||
return;
|
||||
}
|
||||
if (RpoModInfo.META_VERSION > conf.version) {
|
||||
RpoModInfo.LOGGER.warn(s + " uses an outdated RPO format (" + conf.version + "). Although this is supported, using the latest version (" + RpoModInfo.META_VERSION + ") is recommended");
|
||||
if (Respackopts.META_VERSION > conf.version) {
|
||||
Respackopts.LOGGER.warn(s + " uses an outdated RPO format (" + conf.version + "). Although this is supported, using the latest version (" + Respackopts.META_VERSION + ") is recommended");
|
||||
}
|
||||
conf.conf.setVersion(conf.version);
|
||||
if (conf.version < 5)
|
||||
|
@ -47,13 +46,13 @@ public class ResourcePackManagerMixin {
|
|||
if (!Respackopts.CONFIG_BRANCH.containsKey(conf.id))
|
||||
Respackopts.CONFIG_BRANCH.put(conf.id, conf.conf);
|
||||
else
|
||||
Respackopts.CONFIG_BRANCH.get(conf.id).sync(conf.conf, SyncMode.RESPACK_LOAD);
|
||||
Respackopts.CONFIG_BRANCH.get(conf.id).sync(conf.conf, ConfigSyncMode.RESPACK_LOAD);
|
||||
Respackopts.DISPLAY_NAME_LOOKUP.put(v.getDisplayName().asString(), conf.id);
|
||||
Respackopts.PACK_NAME_LOOKUP.put(v.createResourcePack().getName(), conf.id);
|
||||
Respackopts.PACK_METAS.put(conf.id, conf);
|
||||
Respackopts.load(conf.id);
|
||||
} catch (Throwable e) {
|
||||
RpoModInfo.LOGGER.error("Could not initialize pack meta for " + s, e);
|
||||
Respackopts.LOGGER.error("Could not initialize pack meta for " + s, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package io.gitlab.jfronny.respackopts.util;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.integration.DashLoaderCompat;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigBranch;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigEntry;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.GuiEntryBuilderParam;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.PackReloadType;
|
||||
import io.gitlab.jfronny.respackopts.integration.DashLoaderCompat;
|
||||
import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
|
||||
import me.shedaniel.clothconfig2.api.ConfigBuilder;
|
||||
import me.shedaniel.clothconfig2.api.ConfigCategory;
|
||||
|
@ -20,26 +22,21 @@ import java.util.Optional;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
public class GuiFactory {
|
||||
public void buildCategory(ConfigBranch source, String screenId, Consumer<AbstractConfigListEntry<?>> config, ConfigEntryBuilder entryBuilder, String namePrefix) {
|
||||
public void buildCategory(ConfigBranch source, String screenId, Consumer<AbstractConfigListEntry<?>> config, Consumer<PackReloadType> reloadTypeAggregator, ConfigEntryBuilder entryBuilder, String namePrefix) {
|
||||
for (Map.Entry<String, ConfigEntry<?>> in : source.getValue().entrySet()) {
|
||||
ConfigEntry<?> entry = in.getValue();
|
||||
String entryName = ("".equals(namePrefix) ? "" : namePrefix + ".") + in.getKey();
|
||||
String translationPrefix = (source.getVersion() < 3 ? "respackopts." + entry.getEntryType() + "." : "rpo.") + screenId;
|
||||
config.accept(entry.buildEntry(entryBuilder,
|
||||
getText(entryName, translationPrefix),
|
||||
() -> {
|
||||
config.accept(entry.buildEntry(
|
||||
new GuiEntryBuilderParam(entryBuilder, getText(entryName, translationPrefix), () -> {
|
||||
String k = (source.getVersion() < 3 ? "respackopts.tooltip." : "rpo.tooltip.") + screenId + "." + entryName;
|
||||
if (Language.getInstance().hasTranslation(k)) {
|
||||
Text[] res = new Text[1];
|
||||
res[0] = new TranslatableText(k);
|
||||
return Optional.of(res);
|
||||
}
|
||||
else
|
||||
} else
|
||||
return Optional.empty();
|
||||
},
|
||||
screenId,
|
||||
entryName,
|
||||
translationPrefix));
|
||||
}, screenId, entryName, translationPrefix, () -> reloadTypeAggregator.accept(in.getValue().getReloadType()), reloadTypeAggregator)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,14 +54,17 @@ public class GuiFactory {
|
|||
.setParentScreen(parent)
|
||||
.setTitle(getText(packId, source.getVersion() < 4 ? "respackopts.title" : "rpo"));
|
||||
ConfigEntryBuilder entryBuilder = builder.entryBuilder();
|
||||
PackReloadType.Aggregator agg = new PackReloadType.Aggregator();
|
||||
builder.setSavingRunnable(() -> {
|
||||
Respackopts.save();
|
||||
Respackopts.forcePackReload = true;
|
||||
DashLoaderCompat.requestForceReload();
|
||||
Respackopts.reloadData();
|
||||
if (agg.get() == PackReloadType.Resource) {
|
||||
Respackopts.forcePackReload = true;
|
||||
DashLoaderCompat.requestForceReload();
|
||||
Respackopts.reloadData();
|
||||
}
|
||||
});
|
||||
ConfigCategory config = builder.getOrCreateCategory(getText(packId, source.getVersion() < 4 ? "respackopts.title" : "rpo"));
|
||||
buildCategory(source, packId, config::addEntry, entryBuilder, "");
|
||||
buildCategory(source, packId, config::addEntry, agg, entryBuilder, "");
|
||||
return builder.build();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.respackopts.util;
|
||||
|
||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||
import io.gitlab.jfronny.respackopts.RpoModInfo;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.ConfigBranch;
|
||||
import io.gitlab.jfronny.respackopts.integration.FrexCompat;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
@ -18,7 +17,7 @@ import java.util.Map;
|
|||
import static net.fabricmc.fabric.api.client.command.v1.ClientCommandManager.*;
|
||||
|
||||
public class RpoCommand {
|
||||
private static final ModContainer respackotps = FabricLoader.getInstance().getModContainer(RpoModInfo.ID).get();
|
||||
private static final ModContainer respackotps = FabricLoader.getInstance().getModContainer(Respackopts.ID).get();
|
||||
public static void register() {
|
||||
DISPATCHER.register(literal("rpo").then(literal("dump").then(literal("frex").executes(ctx -> {
|
||||
ctx.getSource().sendFeedback(dump(FrexCompat.generateShader(), "frex.glsl"));
|
||||
|
@ -37,11 +36,11 @@ public class RpoCommand {
|
|||
return 1;
|
||||
})));
|
||||
DISPATCHER.register(literal("rpo").then(literal("version").executes(ctx -> {
|
||||
ctx.getSource().sendFeedback(new TranslatableText("respackopts.versionText", respackotps.getMetadata().getVersion(), RpoModInfo.META_VERSION));
|
||||
ctx.getSource().sendFeedback(new TranslatableText("respackopts.versionText", respackotps.getMetadata().getVersion(), Respackopts.META_VERSION));
|
||||
return 1;
|
||||
})));
|
||||
DISPATCHER.register(literal("rpo").executes(ctx -> {
|
||||
ctx.getSource().sendFeedback(new TranslatableText("respackopts.versionText", respackotps.getMetadata().getVersion(), RpoModInfo.META_VERSION));
|
||||
ctx.getSource().sendFeedback(new TranslatableText("respackopts.versionText", respackotps.getMetadata().getVersion(), Respackopts.META_VERSION));
|
||||
return 1;
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"fabricloader": ">=0.10.8",
|
||||
"fabric": "*",
|
||||
"minecraft": "*",
|
||||
"libjf": ">=1.2.0"
|
||||
"libjf-data-manipulation-v0": ">=2.0",
|
||||
"libjf-base": ">=2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "io.gitlab.jfronny.respackopts.mixin",
|
||||
"plugin": "io.gitlab.jfronny.respackopts.mixin.AsmPlugin",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
],
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package io.gitlab.jfronny.respackopts;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import io.gitlab.jfronny.respackopts.data.ConfigFile;
|
||||
import io.gitlab.jfronny.respackopts.data.condition.Condition;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Set;
|
||||
|
||||
import static io.gitlab.jfronny.respackopts.Respackopts.SAVE_ACTIONS;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ConditionSerializationTest {
|
||||
@BeforeAll
|
||||
static void initialize() {
|
||||
Respackopts.LOGGER.info("Expected error end");
|
||||
Respackopts.CONF_DIR = Paths.get("./test");
|
||||
Respackopts.CONFIG = new ConfigFile();
|
||||
SAVE_ACTIONS.add(() -> Respackopts.LOGGER.info("Save"));
|
||||
Respackopts.LOGGER.info(Respackopts.CONF_DIR);
|
||||
}
|
||||
|
||||
@Test
|
||||
void gsonSetOrder() {
|
||||
String[] expected = new String[] {"one", "two", "three", "zero", "76"};
|
||||
String gson = "[\"one\", \"two\", \"three\", \"zero\", \"76\"]";
|
||||
Set<String> parsed = Respackopts.GSON.fromJson(gson, new TypeToken<Set<String>>(){}.getType());
|
||||
int i = 0;
|
||||
for (String s : parsed) {
|
||||
assertEquals(s, expected[i++]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void gsonSingleEntrySet() {
|
||||
String gson = "\"someText\"";
|
||||
Set<String> parsed = Respackopts.GSON.fromJson(gson, new TypeToken<Set<String>>(){}.getType());
|
||||
assertEquals(parsed.size(), 1);
|
||||
for (String s : parsed) {
|
||||
assertEquals(s, "someText");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void gsonConditionSimple() {
|
||||
assertTrue(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("true", Condition.class).evaluate("test")));
|
||||
assertTrue(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"not\": false}", Condition.class).evaluate("test")));
|
||||
assertTrue(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("[true, {\"not\": false}]", Condition.class).evaluate("test")));
|
||||
assertFalse(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("[true, {\"not\": true}]", Condition.class).evaluate("test")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void gsonConditionXor() {
|
||||
assertTrue(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"xor\": [true, false]}", Condition.class).evaluate("test")));
|
||||
assertFalse(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"xor\": [true, true]}", Condition.class).evaluate("test")));
|
||||
assertFalse(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"xor\": [false, false]}", Condition.class).evaluate("test")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void gsonConditionOr() {
|
||||
assertTrue(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"or\": [true, false]}", Condition.class).evaluate("test")));
|
||||
assertTrue(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"or\": [true, true]}", Condition.class).evaluate("test")));
|
||||
assertFalse(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"or\": [false, false]}", Condition.class).evaluate("test")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void gsonConditionNor() {
|
||||
assertFalse(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"nor\": [true, false]}", Condition.class).evaluate("test")));
|
||||
assertFalse(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"nor\": [true, true]}", Condition.class).evaluate("test")));
|
||||
assertTrue(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"nor\": [false, false]}", Condition.class).evaluate("test")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void gsonConditionAnd() {
|
||||
assertFalse(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"and\": [true, false]}", Condition.class).evaluate("test")));
|
||||
assertTrue(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"and\": [true, true]}", Condition.class).evaluate("test")));
|
||||
assertFalse(assertDoesNotThrow(() -> Respackopts.GSON.fromJson("{\"and\": [false, false]}", Condition.class).evaluate("test")));
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
package io.gitlab.jfronny.respackopts;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import io.gitlab.jfronny.respackopts.data.ConfigFile;
|
||||
import io.gitlab.jfronny.respackopts.data.entry.*;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.ConfigSyncMode;
|
||||
import io.gitlab.jfronny.respackopts.data.enums.NumericEntryType;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -10,14 +11,12 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Set;
|
||||
|
||||
import static io.gitlab.jfronny.respackopts.Respackopts.*;
|
||||
import static io.gitlab.jfronny.respackopts.RpoModInfo.*;
|
||||
import static io.gitlab.jfronny.respackopts.Respackopts.CONFIG_BRANCH;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class RespackoptsTest {
|
||||
class ConfigTreeTest {
|
||||
private static final String testEntryName = "test";
|
||||
private static final String testEntry1Name = "test1";
|
||||
|
||||
|
@ -65,7 +64,7 @@ class RespackoptsTest {
|
|||
void syncSimple() {
|
||||
ConfigBranch test = new ConfigBranch();
|
||||
test.add(testEntry1Name, new ConfigBooleanEntry(false));
|
||||
CONFIG_BRANCH.get(testEntryName).sync(test, SyncMode.RESPACK_LOAD);
|
||||
CONFIG_BRANCH.get(testEntryName).sync(test, ConfigSyncMode.RESPACK_LOAD);
|
||||
save();
|
||||
load(testEntryName);
|
||||
assertFalse((Boolean) CONFIG_BRANCH.get(testEntryName).get(testEntry1Name).getValue());
|
||||
|
@ -78,9 +77,9 @@ class RespackoptsTest {
|
|||
be.setValue(true);
|
||||
assertFalse((Boolean) CONFIG_BRANCH.get(testEntryName).get(testEntry1Name).getValue());
|
||||
LOGGER.info("E");
|
||||
CONFIG_BRANCH.get(testEntryName).sync(test, SyncMode.RESPACK_LOAD);
|
||||
CONFIG_BRANCH.get(testEntryName).sync(test, ConfigSyncMode.RESPACK_LOAD);
|
||||
assertFalse((Boolean) CONFIG_BRANCH.get(testEntryName).get(testEntry1Name).getValue());
|
||||
CONFIG_BRANCH.get(testEntryName).sync(test, SyncMode.CONF_LOAD);
|
||||
CONFIG_BRANCH.get(testEntryName).sync(test, ConfigSyncMode.CONF_LOAD);
|
||||
save();
|
||||
load(testEntryName);
|
||||
assertTrue((Boolean) CONFIG_BRANCH.get(testEntryName).get(testEntry1Name).getValue());
|
||||
|
@ -91,32 +90,11 @@ class RespackoptsTest {
|
|||
ConfigBranch cb = new ConfigBranch();
|
||||
ConfigBranch cbNew = new ConfigBranch();
|
||||
cb.add(testEntryName, new ConfigBooleanEntry(false));
|
||||
cbNew.add(testEntryName, new ConfigNumericEntry());
|
||||
cbNew.add(testEntryName, new ConfigNumericEntry(NumericEntryType.Slider));
|
||||
LOGGER.info("Expecting warning message");
|
||||
cbNew.sync(cb, SyncMode.RESPACK_LOAD);
|
||||
cbNew.sync(cb, ConfigSyncMode.RESPACK_LOAD);
|
||||
LOGGER.info("Expected warning end");
|
||||
cbNew.add(testEntryName, new ConfigBooleanEntry(true));
|
||||
cbNew.sync(cb, SyncMode.RESPACK_LOAD);
|
||||
}
|
||||
|
||||
@Test
|
||||
void gsonSetOrder() {
|
||||
String[] expected = new String[] {"one", "two", "three", "zero", "76"};
|
||||
String gson = "[\"one\", \"two\", \"three\", \"zero\", \"76\"]";
|
||||
Set<String> parsed = GSON.fromJson(gson, new TypeToken<Set<String>>(){}.getType());
|
||||
int i = 0;
|
||||
for (String s : parsed) {
|
||||
assertEquals(s, expected[i++]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void gsonSingleEntrySet() {
|
||||
String gson = "\"someText\"";
|
||||
Set<String> parsed = GSON.fromJson(gson, new TypeToken<Set<String>>(){}.getType());
|
||||
assertEquals(parsed.size(), 1);
|
||||
for (String s : parsed) {
|
||||
assertEquals(s, "someText");
|
||||
}
|
||||
cbNew.sync(cb, ConfigSyncMode.RESPACK_LOAD);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue