Assimilate Backend Config

- Merge flywheel-backend config into an object within the base flywheel
  config
- On forge, push a path in the toml
- On fabric, serialize a nested json object
- Still expose the BackendConfig via FlwBackendXplat, but have the impl
  set a static field in the xplat impl
- Revert debug shulker box changes in previous commit
This commit is contained in:
Jozufozu 2024-08-10 12:54:15 -07:00
parent 744c40a56a
commit 76a4b35ce6
12 changed files with 112 additions and 185 deletions

View file

@ -8,9 +8,6 @@ public interface BackendConfig {
/**
* How smooth/accurate our flw_light impl is.
*
* <p>This makes more sense here as a backend-specific config because it's tightly coupled to
* our backend's implementation. 3rd party backend may have different approaches and configurations.
*
* @return The current light smoothness setting.
*/
LightSmoothness lightSmoothness();

View file

@ -8,12 +8,10 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import dev.engine_room.flywheel.api.instance.Instance;
import dev.engine_room.flywheel.api.visual.ShaderLightVisual;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.lib.instance.InstanceTypes;
import dev.engine_room.flywheel.lib.instance.TransformedInstance;
import dev.engine_room.flywheel.lib.material.CutoutShaders;
import dev.engine_room.flywheel.lib.material.LightShaders;
import dev.engine_room.flywheel.lib.material.SimpleMaterial;
import dev.engine_room.flywheel.lib.model.ModelCache;
import dev.engine_room.flywheel.lib.model.SingleMeshModel;
@ -21,20 +19,17 @@ import dev.engine_room.flywheel.lib.model.part.ModelPartConverter;
import dev.engine_room.flywheel.lib.transform.TransformStack;
import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual;
import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual;
import it.unimi.dsi.fastutil.longs.LongArraySet;
import net.minecraft.client.model.geom.ModelLayers;
import net.minecraft.client.renderer.Sheets;
import net.minecraft.client.resources.model.Material;
import net.minecraft.core.Direction;
import net.minecraft.core.SectionPos;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.block.ShulkerBoxBlock;
import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockEntity> implements SimpleDynamicVisual, ShaderLightVisual {
public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockEntity> implements SimpleDynamicVisual {
private static final dev.engine_room.flywheel.api.material.Material MATERIAL = SimpleMaterial.builder()
.cutout(CutoutShaders.ONE_TENTH)
.light(LightShaders.SMOOTH)
.texture(Sheets.SHULKER_SHEET)
.mipmap(false)
.backfaceCulling(false)
@ -72,7 +67,6 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
.translate(getVisualPosition())
.translate(0.5f)
.scale(0.9995f)
.scale(11f)
.rotate(rotation)
.scale(1, -1, -1)
.translateY(-1);
@ -126,26 +120,9 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
stack.popPose();
}
@Override
public void setSectionCollector(SectionCollector sectionCollector) {
var center = SectionPos.asLong(pos);
var out = new LongArraySet();
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -1; z <= 1; z++) {
out.add(SectionPos.offset(center, x, y, z));
}
}
}
sectionCollector.sections(out);
}
@Override
public void updateLight(float partialTick) {
// relight(base, lid);
relight(base, lid);
}
@Override

View file

@ -1,106 +0,0 @@
package dev.engine_room.flywheel.backend;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.nio.file.Path;
import java.util.Locale;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
import net.fabricmc.loader.api.FabricLoader;
public class FabricBackendConfig implements BackendConfig {
public static final Path PATH = FabricLoader.getInstance()
.getConfigDir()
.resolve("flywheel-backend.json");
public static final FabricBackendConfig INSTANCE = new FabricBackendConfig(PATH.toFile());
private static final Gson GSON = new GsonBuilder().setPrettyPrinting()
.create();
private final File file;
public LightSmoothness lightSmoothness = LightSmoothness.SMOOTH;
public FabricBackendConfig(File file) {
this.file = file;
}
@Override
public LightSmoothness lightSmoothness() {
return lightSmoothness;
}
public void load() {
if (file.exists()) {
try (FileReader reader = new FileReader(file)) {
fromJson(JsonParser.parseReader(reader));
} catch (Exception e) {
FlwBackend.LOGGER.warn("Could not load config from file '{}'", file.getAbsolutePath(), e);
}
}
// In case we found an error in the config file, immediately save to fix it.
save();
}
public void save() {
try (FileWriter writer = new FileWriter(file)) {
GSON.toJson(toJson(), writer);
} catch (Exception e) {
FlwBackend.LOGGER.warn("Could not save config to file '{}'", file.getAbsolutePath(), e);
}
}
public void fromJson(JsonElement json) {
if (!(json instanceof JsonObject object)) {
FlwBackend.LOGGER.warn("Config JSON must be an object");
lightSmoothness = LightSmoothness.SMOOTH;
return;
}
readLightSmoothness(object);
}
private void readLightSmoothness(JsonObject object) {
var backendJson = object.get("lightSmoothness");
String msg = null;
if (backendJson instanceof JsonPrimitive primitive && primitive.isString()) {
var value = primitive.getAsString();
for (var item : LightSmoothness.values()) {
if (item.name()
.equalsIgnoreCase(value)) {
lightSmoothness = item;
return;
}
}
msg = "Unknown 'lightSmoothness' value: " + value;
} else if (backendJson != null) {
msg = "'lightSmoothness' value must be a string";
}
// Don't log an error if the field is missing.
if (msg != null) {
FlwBackend.LOGGER.warn(msg);
}
lightSmoothness = LightSmoothness.SMOOTH;
}
public JsonObject toJson() {
JsonObject object = new JsonObject();
object.addProperty("lightSmoothness", lightSmoothness.toString()
.toLowerCase(Locale.ROOT));
return object;
}
}

View file

@ -1,10 +1,15 @@
package dev.engine_room.flywheel.backend;
import org.jetbrains.annotations.UnknownNullability;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.BlockState;
public class FlwBackendXplatImpl implements FlwBackendXplat {
@UnknownNullability
public static BackendConfig CONFIG;
@Override
public int getLightEmission(BlockState state, BlockGetter level, BlockPos pos) {
return state.getLightEmission();
@ -12,6 +17,6 @@ public class FlwBackendXplatImpl implements FlwBackendXplat {
@Override
public BackendConfig getConfig() {
return FabricBackendConfig.INSTANCE;
return CONFIG;
}
}

View file

@ -14,6 +14,10 @@ import com.google.gson.JsonPrimitive;
import dev.engine_room.flywheel.api.backend.Backend;
import dev.engine_room.flywheel.api.backend.BackendManager;
import dev.engine_room.flywheel.backend.BackendConfig;
import dev.engine_room.flywheel.backend.FlwBackend;
import dev.engine_room.flywheel.backend.FlwBackendXplatImpl;
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.ResourceLocationException;
import net.minecraft.resources.ResourceLocation;
@ -35,12 +39,16 @@ public class FabricFlwConfig implements FlwConfig {
private final File file;
public final FabricBackendConfig backendConfig = new FabricBackendConfig();
public Backend backend = BackendManager.defaultBackend();
public boolean limitUpdates = LIMIT_UPDATES_DEFAULT;
public int workerThreads = WORKER_THREADS_DEFAULT;
public FabricFlwConfig(File file) {
this.file = file;
FlwBackendXplatImpl.CONFIG = backendConfig;
}
@Override
@ -90,6 +98,17 @@ public class FabricFlwConfig implements FlwConfig {
readBackend(object);
readLimitUpdates(object);
readWorkerThreads(object);
readFlwBackend(object);
}
private void readFlwBackend(JsonObject object) {
var flwBackendJson = object.get("flw_backend");
if (flwBackendJson instanceof JsonObject flwBackendObject) {
backendConfig.fromJson(flwBackendObject);
} else {
FlwImpl.CONFIG_LOGGER.warn("'flw_backend' value must be an object");
}
}
private void readBackend(JsonObject object) {
@ -158,6 +177,55 @@ public class FabricFlwConfig implements FlwConfig {
object.addProperty("backend", Backend.REGISTRY.getIdOrThrow(backend).toString());
object.addProperty("limitUpdates", limitUpdates);
object.addProperty("workerThreads", workerThreads);
object.add("flw_backend", backendConfig.toJson());
return object;
}
public static class FabricBackendConfig implements BackendConfig {
public static final LightSmoothness LIGHT_SMOOTHNESS_DEFAULT = LightSmoothness.SMOOTH;
public LightSmoothness lightSmoothness = LIGHT_SMOOTHNESS_DEFAULT;
@Override
public LightSmoothness lightSmoothness() {
return lightSmoothness;
}
public void fromJson(JsonObject object) {
readLightSmoothness(object);
}
private void readLightSmoothness(JsonObject object) {
var backendJson = object.get("lightSmoothness");
String msg = null;
if (backendJson instanceof JsonPrimitive primitive && primitive.isString()) {
var value = primitive.getAsString();
for (var item : LightSmoothness.values()) {
if (item.name()
.equalsIgnoreCase(value)) {
lightSmoothness = item;
return;
}
}
msg = "Unknown 'lightSmoothness' value: " + value;
} else if (backendJson != null) {
msg = "'lightSmoothness' value must be a string";
}
// Don't log an error if the field is missing.
if (msg != null) {
FlwBackend.LOGGER.warn(msg);
}
lightSmoothness = LIGHT_SMOOTHNESS_DEFAULT;
}
public JsonObject toJson() {
JsonObject object = new JsonObject();
object.addProperty("lightSmoothness", lightSmoothness.getSerializedName());
return object;
}
}
}

View file

@ -8,7 +8,6 @@ import com.mojang.brigadier.context.CommandContext;
import dev.engine_room.flywheel.api.backend.Backend;
import dev.engine_room.flywheel.api.backend.BackendManager;
import dev.engine_room.flywheel.backend.FabricBackendConfig;
import dev.engine_room.flywheel.backend.LightSmoothnessArgument;
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
import dev.engine_room.flywheel.backend.engine.uniform.DebugMode;
@ -129,12 +128,12 @@ public final class FlwCommands {
command.then(ClientCommandManager.literal("lightSmoothness")
.then(ClientCommandManager.argument("mode", LightSmoothnessArgument.INSTANCE)
.executes(context -> {
var oldValue = FabricBackendConfig.INSTANCE.lightSmoothness;
var oldValue = FabricFlwConfig.INSTANCE.backendConfig.lightSmoothness;
var newValue = context.getArgument("mode", LightSmoothness.class);
if (oldValue != newValue) {
FabricBackendConfig.INSTANCE.lightSmoothness = newValue;
FabricBackendConfig.INSTANCE.save();
FabricFlwConfig.INSTANCE.backendConfig.lightSmoothness = newValue;
FabricFlwConfig.INSTANCE.save();
Minecraft.getInstance()
.reloadResourcePacks();
}

View file

@ -11,7 +11,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import dev.engine_room.flywheel.api.event.EndClientResourceReloadCallback;
import dev.engine_room.flywheel.backend.FabricBackendConfig;
import dev.engine_room.flywheel.impl.FabricFlwConfig;
import dev.engine_room.flywheel.impl.FlwImpl;
import net.minecraft.client.Minecraft;
@ -29,7 +28,6 @@ abstract class MinecraftMixin {
// Load the config after we freeze registries,
// so we can find third party backends.
FabricFlwConfig.INSTANCE.load();
FabricBackendConfig.INSTANCE.load();
}
@Inject(method = "method_24040", at = @At("HEAD"))

View file

@ -1,10 +1,15 @@
package dev.engine_room.flywheel.backend;
import org.jetbrains.annotations.UnknownNullability;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.BlockState;
public class FlwBackendXplatImpl implements FlwBackendXplat {
@UnknownNullability
public static BackendConfig CONFIG;
@Override
public int getLightEmission(BlockState state, BlockGetter level, BlockPos pos) {
return state.getLightEmission(level, pos);
@ -12,6 +17,6 @@ public class FlwBackendXplatImpl implements FlwBackendXplat {
@Override
public BackendConfig getConfig() {
return ForgeBackendConfig.INSTANCE;
return CONFIG;
}
}

View file

@ -1,39 +0,0 @@
package dev.engine_room.flywheel.backend;
import org.apache.commons.lang3.tuple.Pair;
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.config.ModConfig;
public class ForgeBackendConfig implements BackendConfig {
public static final ForgeBackendConfig INSTANCE = new ForgeBackendConfig();
public final ClientConfig client;
private final ForgeConfigSpec clientSpec;
private ForgeBackendConfig() {
Pair<ClientConfig, ForgeConfigSpec> clientPair = new ForgeConfigSpec.Builder().configure(ClientConfig::new);
this.client = clientPair.getLeft();
clientSpec = clientPair.getRight();
}
@Override
public LightSmoothness lightSmoothness() {
return client.lightSmoothness.get();
}
public void registerSpecs(ModLoadingContext context) {
context.registerConfig(ModConfig.Type.CLIENT, clientSpec, "flywheel-backend.toml");
}
public static class ClientConfig {
public final ForgeConfigSpec.EnumValue<LightSmoothness> lightSmoothness;
private ClientConfig(ForgeConfigSpec.Builder builder) {
lightSmoothness = builder.comment("How smooth flywheel's shader-based lighting should be. May have a large performance impact.")
.defineEnum("lightSmoothness", LightSmoothness.SMOOTH);
}
}
}

View file

@ -6,7 +6,6 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import dev.engine_room.flywheel.api.backend.Backend;
import dev.engine_room.flywheel.api.backend.BackendManager;
import dev.engine_room.flywheel.backend.ForgeBackendConfig;
import dev.engine_room.flywheel.backend.LightSmoothnessArgument;
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
import dev.engine_room.flywheel.backend.engine.uniform.DebugMode;
@ -124,7 +123,7 @@ public final class FlwCommands {
return Command.SINGLE_SUCCESS;
})));
var lightSmoothnessValue = ForgeBackendConfig.INSTANCE.client.lightSmoothness;
var lightSmoothnessValue = ForgeFlwConfig.INSTANCE.client.backendConfig.lightSmoothness;
command.then(Commands.literal("lightSmoothness")
.then(Commands.argument("mode", LightSmoothnessArgument.INSTANCE)
.executes(context -> {

View file

@ -6,7 +6,6 @@ import org.jetbrains.annotations.UnknownNullability;
import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.api.event.EndClientResourceReloadEvent;
import dev.engine_room.flywheel.api.event.ReloadLevelRendererEvent;
import dev.engine_room.flywheel.backend.ForgeBackendConfig;
import dev.engine_room.flywheel.backend.LightSmoothnessArgument;
import dev.engine_room.flywheel.backend.compile.FlwProgramsReloader;
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
@ -54,7 +53,6 @@ public final class FlywheelForge {
.getModEventBus();
ForgeFlwConfig.INSTANCE.registerSpecs(modLoadingContext);
ForgeBackendConfig.INSTANCE.registerSpecs(modLoadingContext);
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> FlywheelForge.clientInit(forgeEventBus, modEventBus));
}

View file

@ -5,6 +5,9 @@ import org.jetbrains.annotations.Nullable;
import dev.engine_room.flywheel.api.backend.Backend;
import dev.engine_room.flywheel.api.backend.BackendManager;
import dev.engine_room.flywheel.backend.BackendConfig;
import dev.engine_room.flywheel.backend.FlwBackendXplatImpl;
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
import net.minecraft.ResourceLocationException;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.ForgeConfigSpec;
@ -21,6 +24,8 @@ public class ForgeFlwConfig implements FlwConfig {
Pair<ClientConfig, ForgeConfigSpec> clientPair = new ForgeConfigSpec.Builder().configure(ClientConfig::new);
this.client = clientPair.getLeft();
clientSpec = clientPair.getRight();
FlwBackendXplatImpl.CONFIG = client.backendConfig;
}
@Override
@ -72,6 +77,8 @@ public class ForgeFlwConfig implements FlwConfig {
public final ForgeConfigSpec.BooleanValue limitUpdates;
public final ForgeConfigSpec.IntValue workerThreads;
public final ForgeBackendConfig backendConfig;
private ClientConfig(ForgeConfigSpec.Builder builder) {
backend = builder.comment("Select the backend to use.")
.define("backend", Backend.REGISTRY.getIdOrThrow(BackendManager.defaultBackend()).toString());
@ -82,6 +89,25 @@ public class ForgeFlwConfig implements FlwConfig {
workerThreads = builder.comment("The number of worker threads to use. Set to -1 to let Flywheel decide. Set to 0 to disable parallelism. Requires a game restart to take effect.")
.defineInRange("workerThreads", -1, -1, Runtime.getRuntime()
.availableProcessors());
builder.comment("Config options for flywheel's build-in backends.")
.push("flw_backends");
backendConfig = new ForgeBackendConfig(builder);
}
}
public static class ForgeBackendConfig implements BackendConfig {
public final ForgeConfigSpec.EnumValue<LightSmoothness> lightSmoothness;
public ForgeBackendConfig(ForgeConfigSpec.Builder builder) {
lightSmoothness = builder.comment("How smooth flywheel's shader-based lighting should be. May have a large performance impact.")
.defineEnum("lightSmoothness", LightSmoothness.SMOOTH);
}
@Override
public LightSmoothness lightSmoothness() {
return lightSmoothness.get();
}
}
}