mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-28 22:04:57 +01:00
Suddenly: mod compat
- Config fields default to "default" and can be either disabled or force enabled via the vanillin config file - Alternatively, mods can set custom properties to disable specific visuals - Emit a warning when a visual is disabled due to mod intervention - Emit a warning when a visual is force enabled despite mod intervention
This commit is contained in:
parent
6d2aab7716
commit
94d99af4b0
11 changed files with 413 additions and 133 deletions
|
@ -1,82 +0,0 @@
|
||||||
package dev.engine_room.vanillin;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.visualization.BlockEntityVisualizer;
|
|
||||||
import dev.engine_room.flywheel.api.visualization.EntityVisualizer;
|
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualizerRegistry;
|
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.EntityType;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
|
||||||
|
|
||||||
public class Configurator {
|
|
||||||
public final Map<BlockEntityType<?>, ConfiguredBlockEntity<?>> blockEntities = new HashMap<>();
|
|
||||||
public final Map<EntityType<?>, ConfiguredEntity<?>> entities = new HashMap<>();
|
|
||||||
|
|
||||||
public <T extends BlockEntity> void register(BlockEntityType<T> type, BlockEntityVisualizer<? super T> visualizer, boolean enabledByDefault) {
|
|
||||||
blockEntities.put(type, new ConfiguredBlockEntity<>(type, visualizer, enabledByDefault));
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T extends Entity> void register(EntityType<T> type, EntityVisualizer<? super T> visualizer, boolean enabledByDefault) {
|
|
||||||
entities.put(type, new ConfiguredEntity<>(type, visualizer, enabledByDefault));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ConfiguredBlockEntity<T extends BlockEntity> {
|
|
||||||
public final BlockEntityType<T> type;
|
|
||||||
public final BlockEntityVisualizer<? super T> visualizer;
|
|
||||||
private final boolean enabledByDefault;
|
|
||||||
|
|
||||||
private ConfiguredBlockEntity(BlockEntityType<T> type, BlockEntityVisualizer<? super T> visualizer, boolean enabledByDefault) {
|
|
||||||
this.type = type;
|
|
||||||
this.visualizer = visualizer;
|
|
||||||
this.enabledByDefault = enabledByDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String configKey() {
|
|
||||||
return BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(type).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean enabledByDefault() {
|
|
||||||
return enabledByDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(boolean enabled) {
|
|
||||||
if (enabled) {
|
|
||||||
VisualizerRegistry.setVisualizer(type, visualizer);
|
|
||||||
} else {
|
|
||||||
VisualizerRegistry.setVisualizer(type, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ConfiguredEntity<T extends Entity> {
|
|
||||||
public final EntityType<T> type;
|
|
||||||
public final EntityVisualizer<? super T> visualizer;
|
|
||||||
private final boolean enabledByDefault;
|
|
||||||
|
|
||||||
private ConfiguredEntity(EntityType<T> type, EntityVisualizer<? super T> visualizer, boolean enabledByDefault) {
|
|
||||||
this.type = type;
|
|
||||||
this.visualizer = visualizer;
|
|
||||||
this.enabledByDefault = enabledByDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String configKey() {
|
|
||||||
return BuiltInRegistries.ENTITY_TYPE.getKey(type).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean defaultEnabled() {
|
|
||||||
return enabledByDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(boolean enabled) {
|
|
||||||
if (enabled) {
|
|
||||||
VisualizerRegistry.setVisualizer(type, visualizer);
|
|
||||||
} else {
|
|
||||||
VisualizerRegistry.setVisualizer(type, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +1,9 @@
|
||||||
package dev.engine_room.vanillin;
|
package dev.engine_room.vanillin;
|
||||||
|
|
||||||
import dev.engine_room.vanillin.visuals.BellVisual;
|
import dev.engine_room.vanillin.config.BlockEntityVisualizerBuilder;
|
||||||
import dev.engine_room.vanillin.visuals.ChestVisual;
|
import dev.engine_room.vanillin.config.Configurator;
|
||||||
import dev.engine_room.vanillin.visuals.MinecartVisual;
|
import dev.engine_room.vanillin.config.EntityVisualizerBuilder;
|
||||||
import dev.engine_room.vanillin.visuals.ShulkerBoxVisual;
|
import dev.engine_room.vanillin.visuals.*;
|
||||||
import dev.engine_room.vanillin.visuals.SignVisual;
|
|
||||||
import dev.engine_room.vanillin.visuals.TntMinecartVisual;
|
|
||||||
import net.minecraft.client.model.geom.ModelLayers;
|
import net.minecraft.client.model.geom.ModelLayers;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package dev.engine_room.vanillin;
|
package dev.engine_room.vanillin.config;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
|
@ -0,0 +1,154 @@
|
||||||
|
package dev.engine_room.vanillin.config;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import dev.engine_room.flywheel.api.visualization.BlockEntityVisualizer;
|
||||||
|
import dev.engine_room.flywheel.api.visualization.EntityVisualizer;
|
||||||
|
import dev.engine_room.flywheel.api.visualization.VisualizerRegistry;
|
||||||
|
import dev.engine_room.vanillin.Vanillin;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
|
||||||
|
public class Configurator {
|
||||||
|
public final Map<BlockEntityType<?>, ConfiguredBlockEntity<?>> blockEntities = new HashMap<>();
|
||||||
|
public final Map<EntityType<?>, ConfiguredEntity<?>> entities = new HashMap<>();
|
||||||
|
|
||||||
|
public <T extends BlockEntity> void register(BlockEntityType<T> type, BlockEntityVisualizer<? super T> visualizer, boolean enabledByDefault) {
|
||||||
|
blockEntities.put(type, new ConfiguredBlockEntity<>(type, visualizer, enabledByDefault));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Entity> void register(EntityType<T> type, EntityVisualizer<? super T> visualizer, boolean enabledByDefault) {
|
||||||
|
entities.put(type, new ConfiguredEntity<>(type, visualizer, enabledByDefault));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class ConfiguredVisual {
|
||||||
|
private final boolean enabledByDefault;
|
||||||
|
|
||||||
|
protected ConfiguredVisual(boolean enabledByDefault) {
|
||||||
|
this.enabledByDefault = enabledByDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(VisualConfigValue configValue, @Nullable List<VisualOverride> overrides) {
|
||||||
|
if (configValue == VisualConfigValue.DISABLE) {
|
||||||
|
disable();
|
||||||
|
} else if (configValue == VisualConfigValue.FORCE_ENABLE) {
|
||||||
|
enable();
|
||||||
|
maybeWarnEnabledDespiteOverrides(overrides);
|
||||||
|
} else if (configValue == VisualConfigValue.DEFAULT) {
|
||||||
|
if (disableAndWarnDueToOverrides(overrides)) {
|
||||||
|
disable();
|
||||||
|
} else {
|
||||||
|
if (enabledByDefault) {
|
||||||
|
enable();
|
||||||
|
} else {
|
||||||
|
disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean disableAndWarnDueToOverrides(@Nullable List<VisualOverride> overrides) {
|
||||||
|
if (overrides == null || overrides.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var modIds = disablingModIds(overrides);
|
||||||
|
|
||||||
|
if (modIds.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
Vanillin.CONFIG_LOGGER.warn("Disabling {} visual due to overrides from mods: {}", configKey(), String.join(", ", modIds));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybeWarnEnabledDespiteOverrides(@Nullable List<VisualOverride> overrides) {
|
||||||
|
if (overrides == null || overrides.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var modIds = disablingModIds(overrides);
|
||||||
|
|
||||||
|
if (!modIds.isEmpty()) {
|
||||||
|
Vanillin.CONFIG_LOGGER.warn("Enabling {} visual despite overrides from mods: {}", configKey(), String.join(", ", modIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String configKey();
|
||||||
|
|
||||||
|
protected abstract void enable();
|
||||||
|
|
||||||
|
protected abstract void disable();
|
||||||
|
|
||||||
|
private static List<String> disablingModIds(List<VisualOverride> overrides) {
|
||||||
|
List<String> out = new ArrayList<>();
|
||||||
|
|
||||||
|
for (VisualOverride override : overrides) {
|
||||||
|
if (override.value() == VisualOverrideValue.DISABLE) {
|
||||||
|
out.add(override.modId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConfiguredBlockEntity<T extends BlockEntity> extends ConfiguredVisual {
|
||||||
|
public final BlockEntityType<T> type;
|
||||||
|
public final BlockEntityVisualizer<? super T> visualizer;
|
||||||
|
|
||||||
|
private ConfiguredBlockEntity(BlockEntityType<T> type, BlockEntityVisualizer<? super T> visualizer, boolean enabledByDefault) {
|
||||||
|
super(enabledByDefault);
|
||||||
|
this.type = type;
|
||||||
|
this.visualizer = visualizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String configKey() {
|
||||||
|
return BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(type).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void enable() {
|
||||||
|
VisualizerRegistry.setVisualizer(type, visualizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void disable() {
|
||||||
|
VisualizerRegistry.setVisualizer(type, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConfiguredEntity<T extends Entity> extends ConfiguredVisual {
|
||||||
|
public final EntityType<T> type;
|
||||||
|
public final EntityVisualizer<? super T> visualizer;
|
||||||
|
|
||||||
|
private ConfiguredEntity(EntityType<T> type, EntityVisualizer<? super T> visualizer, boolean enabledByDefault) {
|
||||||
|
super(enabledByDefault);
|
||||||
|
this.type = type;
|
||||||
|
this.visualizer = visualizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String configKey() {
|
||||||
|
return BuiltInRegistries.ENTITY_TYPE.getKey(type).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void enable() {
|
||||||
|
VisualizerRegistry.setVisualizer(type, visualizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void disable() {
|
||||||
|
VisualizerRegistry.setVisualizer(type, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package dev.engine_room.vanillin;
|
package dev.engine_room.vanillin.config;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
|
@ -0,0 +1,15 @@
|
||||||
|
package dev.engine_room.vanillin.config;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public record ModOverrides(Map<String, List<VisualOverride>> blockEntities, Map<String, List<VisualOverride>> entities) {
|
||||||
|
public ModOverrides(List<VisualOverride> blockEntities, List<VisualOverride> entities) {
|
||||||
|
this(sort(blockEntities), sort(entities));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, List<VisualOverride>> sort(List<VisualOverride> list) {
|
||||||
|
return list.stream().collect(Collectors.groupingBy(VisualOverride::name));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package dev.engine_room.vanillin.config;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public enum VisualConfigValue {
|
||||||
|
@SerializedName("default")
|
||||||
|
DEFAULT,
|
||||||
|
@SerializedName("disable")
|
||||||
|
DISABLE,
|
||||||
|
@SerializedName("force_enable")
|
||||||
|
FORCE_ENABLE,
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package dev.engine_room.vanillin.config;
|
||||||
|
|
||||||
|
public record VisualOverride(String name, String modId, VisualOverrideValue value) {
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package dev.engine_room.vanillin.config;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public enum VisualOverrideValue {
|
||||||
|
DEFAULT,
|
||||||
|
DISABLE,
|
||||||
|
;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static VisualOverrideValue parse(String string) {
|
||||||
|
if (string.equals("default")) {
|
||||||
|
return DEFAULT;
|
||||||
|
} else if (string.equals("disable")) {
|
||||||
|
return DISABLE;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,14 +4,24 @@ import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
import dev.engine_room.vanillin.config.Configurator;
|
||||||
|
import dev.engine_room.vanillin.config.ModOverrides;
|
||||||
|
import dev.engine_room.vanillin.config.VisualConfigValue;
|
||||||
|
import dev.engine_room.vanillin.config.VisualOverride;
|
||||||
|
import dev.engine_room.vanillin.config.VisualOverrideValue;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
|
import net.fabricmc.loader.api.metadata.CustomValue;
|
||||||
|
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||||
|
|
||||||
public class FabricVanillinConfig {
|
public class FabricVanillinConfig {
|
||||||
public static final Path PATH = FabricLoader.getInstance()
|
public static final Path PATH = FabricLoader.getInstance()
|
||||||
|
@ -21,10 +31,12 @@ public class FabricVanillinConfig {
|
||||||
public static final FabricVanillinConfig INSTANCE = new FabricVanillinConfig(PATH.toFile());
|
public static final FabricVanillinConfig INSTANCE = new FabricVanillinConfig(PATH.toFile());
|
||||||
|
|
||||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
public static final String VANILLIN_OVERRIDES = "vanillin:overrides";
|
||||||
|
|
||||||
private final File file;
|
private final File file;
|
||||||
|
|
||||||
private Config config;
|
private ModOverrides overrides;
|
||||||
|
private Config config = new Config();
|
||||||
|
|
||||||
public FabricVanillinConfig(File file) {
|
public FabricVanillinConfig(File file) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
@ -36,23 +48,34 @@ public class FabricVanillinConfig {
|
||||||
config = GSON.fromJson(reader, Config.class);
|
config = GSON.fromJson(reader, Config.class);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Vanillin.CONFIG_LOGGER.warn("Could not load config from file '{}'", file.getAbsolutePath(), e);
|
Vanillin.CONFIG_LOGGER.warn("Could not load config from file '{}'", file.getAbsolutePath(), e);
|
||||||
config = new Config();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overrides = modOverrides();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply(Configurator configurator) {
|
public void apply(Configurator configurator) {
|
||||||
for (Configurator.ConfiguredBlockEntity<?> configuredBlockEntity : configurator.blockEntities.values()) {
|
var blockEntities = config.blockEntities;
|
||||||
boolean enabled = config.blockEntities.computeIfAbsent(configuredBlockEntity.configKey(), $ -> configuredBlockEntity.enabledByDefault());
|
var blockEntityOverrides = this.overrides.blockEntities();
|
||||||
configuredBlockEntity.set(enabled);
|
|
||||||
|
for (Configurator.ConfiguredVisual configured : configurator.blockEntities.values()) {
|
||||||
|
apply(configured, blockEntities, blockEntityOverrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Configurator.ConfiguredEntity<?> configured : configurator.entities.values()) {
|
var entities = config.entities;
|
||||||
boolean enabled = config.entities.computeIfAbsent(configured.configKey(), $ -> configured.defaultEnabled());
|
var entityOverrides = this.overrides.entities();
|
||||||
configured.set(enabled);
|
for (Configurator.ConfiguredVisual configured : configurator.entities.values()) {
|
||||||
|
apply(configured, entities, entityOverrides);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void apply(Configurator.ConfiguredVisual configured, Map<String, VisualConfigValue> config, Map<String, List<VisualOverride>> overrides) {
|
||||||
|
var key = configured.configKey();
|
||||||
|
var enabled = config.computeIfAbsent(key, $ -> VisualConfigValue.DEFAULT);
|
||||||
|
|
||||||
|
configured.set(enabled, overrides.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
try (FileWriter writer = new FileWriter(file)) {
|
try (FileWriter writer = new FileWriter(file)) {
|
||||||
GSON.toJson(config, writer);
|
GSON.toJson(config, writer);
|
||||||
|
@ -61,16 +84,75 @@ public class FabricVanillinConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ModOverrides modOverrides() {
|
||||||
|
var blockEntities = new ArrayList<VisualOverride>();
|
||||||
|
var entities = new ArrayList<VisualOverride>();
|
||||||
|
|
||||||
|
for (ModContainer container : FabricLoader.getInstance().getAllMods()) {
|
||||||
|
ModMetadata meta = container.getMetadata();
|
||||||
|
var modid = meta.getId();
|
||||||
|
|
||||||
|
if (meta.containsCustomValue(VANILLIN_OVERRIDES)) {
|
||||||
|
CustomValue overridesValue = meta.getCustomValue(VANILLIN_OVERRIDES);
|
||||||
|
|
||||||
|
if (overridesValue.getType() != CustomValue.CvType.OBJECT) {
|
||||||
|
Vanillin.CONFIG_LOGGER.warn("Mod '{}' attempted to override options with an invalid value, ignoring", modid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var overrides = overridesValue.getAsObject();
|
||||||
|
|
||||||
|
readSection(blockEntities, modid, overrides, "block_entities", "block entity");
|
||||||
|
readSection(entities, modid, overrides, "entities", "entity");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ModOverrides(blockEntities, entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readSection(List<VisualOverride> dst, String modid, CustomValue.CvObject overrides, String sectionName, String singular) {
|
||||||
|
if (!overrides.containsKey(sectionName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var section = overrides.get(sectionName);
|
||||||
|
|
||||||
|
if (section.getType() != CustomValue.CvType.OBJECT) {
|
||||||
|
Vanillin.CONFIG_LOGGER.warn("Mod '{}' attempted to override {} with an invalid value, ignoring", modid, sectionName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<String, CustomValue> entry : section.getAsObject()) {
|
||||||
|
var value = entry.getValue();
|
||||||
|
var key = entry.getKey();
|
||||||
|
if (value.getType() != CustomValue.CvType.STRING) {
|
||||||
|
Vanillin.CONFIG_LOGGER.warn("Mod '{}' attempted to override {} '{}' with an invalid value, ignoring", modid, singular, key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var valueString = value.getAsString();
|
||||||
|
|
||||||
|
var parsed = VisualOverrideValue.parse(valueString);
|
||||||
|
|
||||||
|
if (parsed == null) {
|
||||||
|
Vanillin.CONFIG_LOGGER.warn("Mod '{}' attempted to override {} '{}' with an invalid value '{}', ignoring", modid, singular, key, valueString);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.add(new VisualOverride(key, modid, parsed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class Config {
|
public static class Config {
|
||||||
@SerializedName("block_entities")
|
@SerializedName("block_entities")
|
||||||
public Map<String, Boolean> blockEntities;
|
public Map<String, VisualConfigValue> blockEntities;
|
||||||
public Map<String, Boolean> entities;
|
public Map<String, VisualConfigValue> entities;
|
||||||
|
|
||||||
public Config() {
|
public Config() {
|
||||||
this(new HashMap<>(), new HashMap<>());
|
this(new HashMap<>(), new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Config(Map<String, Boolean> blockEntities, Map<String, Boolean> entities) {
|
public Config(Map<String, VisualConfigValue> blockEntities, Map<String, VisualConfigValue> entities) {
|
||||||
this.blockEntities = blockEntities;
|
this.blockEntities = blockEntities;
|
||||||
this.entities = entities;
|
this.entities = entities;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,62 +1,140 @@
|
||||||
package dev.engine_room.vanillin;
|
package dev.engine_room.vanillin;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.electronwill.nightconfig.core.Config;
|
||||||
|
|
||||||
|
import dev.engine_room.vanillin.config.Configurator;
|
||||||
|
import dev.engine_room.vanillin.config.ModOverrides;
|
||||||
|
import dev.engine_room.vanillin.config.VisualConfigValue;
|
||||||
|
import dev.engine_room.vanillin.config.VisualOverride;
|
||||||
|
import dev.engine_room.vanillin.config.VisualOverrideValue;
|
||||||
import net.minecraftforge.common.ForgeConfigSpec;
|
import net.minecraftforge.common.ForgeConfigSpec;
|
||||||
|
import net.minecraftforge.fml.ModList;
|
||||||
import net.minecraftforge.fml.ModLoadingContext;
|
import net.minecraftforge.fml.ModLoadingContext;
|
||||||
import net.minecraftforge.fml.config.ModConfig;
|
import net.minecraftforge.fml.config.ModConfig;
|
||||||
|
import net.minecraftforge.forgespi.language.IModInfo;
|
||||||
|
|
||||||
public class ForgeVanillinConfig {
|
public class ForgeVanillinConfig {
|
||||||
public static final ForgeVanillinConfig INSTANCE = new ForgeVanillinConfig(VanillaVisuals.CONFIGURATOR);
|
public static final ForgeVanillinConfig INSTANCE = new ForgeVanillinConfig(VanillaVisuals.CONFIGURATOR);
|
||||||
|
|
||||||
public final Map<String, ForgeConfigSpec.BooleanValue> blockEntities = new HashMap<>();
|
|
||||||
public final Map<String, ForgeConfigSpec.BooleanValue> entities = new HashMap<>();
|
|
||||||
|
|
||||||
private final Configurator configurator;
|
private final Configurator configurator;
|
||||||
private final ForgeConfigSpec clientSpec;
|
private final ForgeConfigSpec clientSpec;
|
||||||
|
|
||||||
|
private final ConfigSection blockEntities;
|
||||||
|
private final ConfigSection entities;
|
||||||
|
|
||||||
private ForgeVanillinConfig(Configurator configurator) {
|
private ForgeVanillinConfig(Configurator configurator) {
|
||||||
this.configurator = configurator;
|
this.configurator = configurator;
|
||||||
var builder = new ForgeConfigSpec.Builder();
|
var builder = new ForgeConfigSpec.Builder();
|
||||||
|
|
||||||
builder.push("block_entities");
|
|
||||||
|
|
||||||
// Seems like we need to register all field ahead of time so this constructor must run after VanillaVisuals#init
|
// Seems like we need to register all field ahead of time so this constructor must run after VanillaVisuals#init
|
||||||
for (var configured : configurator.blockEntities.values()) {
|
var blockEntities = setup(builder, configurator.blockEntities.values(), "block_entities");
|
||||||
var name = configured.configKey();
|
var entities = setup(builder, configurator.entities.values(), "entities");
|
||||||
var config = builder.define(name, configured.enabledByDefault());
|
|
||||||
blockEntities.put(name, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.pop();
|
|
||||||
builder.push("entities");
|
|
||||||
|
|
||||||
for (var configured : configurator.entities.values()) {
|
|
||||||
var name = configured.configKey();
|
|
||||||
var config = builder.define(name, configured.defaultEnabled());
|
|
||||||
entities.put(name, config);
|
|
||||||
}
|
|
||||||
clientSpec = builder.build();
|
clientSpec = builder.build();
|
||||||
|
|
||||||
|
var modOverrides = modOverrides();
|
||||||
|
|
||||||
|
this.blockEntities = new ConfigSection(blockEntities, modOverrides.blockEntities());
|
||||||
|
this.entities = new ConfigSection(entities, modOverrides.entities());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply() {
|
public void apply() {
|
||||||
for (var configured : configurator.blockEntities.values()) {
|
blockEntities.apply(configurator.blockEntities.values());
|
||||||
var value = blockEntities.get(configured.configKey());
|
entities.apply(configurator.entities.values());
|
||||||
if (value != null) {
|
|
||||||
configured.set(value.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var configured : configurator.entities.values()) {
|
|
||||||
var value = entities.get(configured.configKey());
|
|
||||||
if (value != null) {
|
|
||||||
configured.set(value.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerSpecs(ModLoadingContext context) {
|
public void registerSpecs(ModLoadingContext context) {
|
||||||
context.registerConfig(ModConfig.Type.CLIENT, clientSpec);
|
context.registerConfig(ModConfig.Type.CLIENT, clientSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ModOverrides modOverrides() {
|
||||||
|
var blockEntities = new ArrayList<VisualOverride>();
|
||||||
|
var entities = new ArrayList<VisualOverride>();
|
||||||
|
|
||||||
|
ModList.get()
|
||||||
|
.forEachModFile(file -> {
|
||||||
|
var info = file.getModFileInfo();
|
||||||
|
for (IModInfo mod : info.getMods()) {
|
||||||
|
var modId = mod.getModId();
|
||||||
|
var modProperties = mod.getModProperties()
|
||||||
|
.get("vanillin:overrides");
|
||||||
|
|
||||||
|
if (modProperties == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's no well-defined API for custom properties like in fabric.
|
||||||
|
// It just returns an object, but internally it's represented with nightconfig.
|
||||||
|
if (modProperties instanceof Config config) {
|
||||||
|
readSection(blockEntities, modId, config, "block_entities", "block entity");
|
||||||
|
readSection(entities, modId, config, "entities", "entity");
|
||||||
|
} else {
|
||||||
|
Vanillin.CONFIG_LOGGER.warn("Mod '{}' attempted to override options with an invalid value, ignoring", modId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new ModOverrides(blockEntities, entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readSection(List<VisualOverride> dst, String modId, Config config, String section, String singular) {
|
||||||
|
if (!config.contains(section)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sectionObject = config.getRaw(section);
|
||||||
|
|
||||||
|
if (sectionObject instanceof Config sectionConfig) {
|
||||||
|
for (var entry : sectionConfig.entrySet()) {
|
||||||
|
var key = entry.getKey();
|
||||||
|
var value = entry.getValue();
|
||||||
|
|
||||||
|
if (value instanceof String valueString) {
|
||||||
|
var parsed = VisualOverrideValue.parse(valueString);
|
||||||
|
|
||||||
|
if (parsed != null) {
|
||||||
|
dst.add(new VisualOverride(key, modId, parsed));
|
||||||
|
} else {
|
||||||
|
Vanillin.CONFIG_LOGGER.warn("Mod '{}' attempted to override {} '{}' with an invalid value '{}', ignoring", modId, singular, key, valueString);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Vanillin.CONFIG_LOGGER.warn("Mod '{}' attempted to override {} '{}' with an invalid value, ignoring", modId, singular, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Vanillin.CONFIG_LOGGER.warn("Mod '{}' attempted to override {} with an invalid value, ignoring", modId, section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, ForgeConfigSpec.EnumValue<VisualConfigValue>> setup(ForgeConfigSpec.Builder builder, Collection<? extends Configurator.ConfiguredVisual> configuredVisuals, String push) {
|
||||||
|
var out = new HashMap<String, ForgeConfigSpec.EnumValue<VisualConfigValue>>();
|
||||||
|
builder.push(push);
|
||||||
|
|
||||||
|
for (var configured : configuredVisuals) {
|
||||||
|
var name = configured.configKey();
|
||||||
|
var config = builder.defineEnum(name, VisualConfigValue.DEFAULT);
|
||||||
|
out.put(name, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.pop();
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private record ConfigSection(Map<String, ForgeConfigSpec.EnumValue<VisualConfigValue>> config, Map<String, List<VisualOverride>> overrides) {
|
||||||
|
void apply(Collection<? extends Configurator.ConfiguredVisual> values) {
|
||||||
|
for (var configured : values) {
|
||||||
|
var key = configured.configKey();
|
||||||
|
var value = config.get(key);
|
||||||
|
if (value != null) {
|
||||||
|
configured.set(value.get(), overrides.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue