From b403ca3d2b35efad4cf467e127cde470a53331c2 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Tue, 1 Feb 2022 12:46:47 -0800 Subject: [PATCH 1/3] Pepper's catches - GlCompat now a singleton, doesn't need to be re-created - Fix crash with F3 open and backend off - Clear program spec map before loading - Merge FlywheelClient and Flywheel classes --- .../java/com/jozufozu/flywheel/Flywheel.java | 45 +++++++++++++++++-- .../com/jozufozu/flywheel/FlywheelClient.java | 45 ------------------- .../jozufozu/flywheel/backend/Backend.java | 10 ++--- .../com/jozufozu/flywheel/backend/Loader.java | 22 ++++----- .../flywheel/backend/gl/buffer/GlBuffer.java | 5 ++- .../backend/gl/buffer/PersistentGlBuffer.java | 4 +- .../backend/gl/versioned/GlCompat.java | 11 ++++- .../backend/instancing/InstanceWorld.java | 9 ---- .../instancing/InstancedRenderDispatcher.java | 14 +++++- .../instancing/instancing/GPUInstancer.java | 4 +- .../instancing/InstancedMaterialGroup.java | 5 ++- .../jozufozu/flywheel/config/FlwCommands.java | 2 +- 12 files changed, 86 insertions(+), 90 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/FlywheelClient.java diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index 95effd761..cecf6fae8 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -4,15 +4,26 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.maven.artifact.versioning.ArtifactVersion; +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.OptifineHandler; import com.jozufozu.flywheel.config.EngineArgument; import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; +import com.jozufozu.flywheel.core.Contexts; +import com.jozufozu.flywheel.core.PartialModel; +import com.jozufozu.flywheel.core.StitchedSprite; +import com.jozufozu.flywheel.core.compile.ProgramCompiler; +import com.jozufozu.flywheel.event.ReloadRenderersEvent; +import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor; +import com.jozufozu.flywheel.vanilla.VanillaInstances; import net.minecraft.commands.synchronization.ArgumentTypes; import net.minecraft.commands.synchronization.EmptyArgumentSerializer; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.CrashReportCallables; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod; @@ -39,18 +50,44 @@ public class Flywheel { .getModEventBus() .addListener(this::setup); - MinecraftForge.EVENT_BUS.addListener(FlwCommands::onServerStarting); - FlwConfig.init(); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> FlywheelClient::clientInit); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> Flywheel::clientInit); } public static ResourceLocation rl(String path) { return new ResourceLocation(ID, path); } - private void setup(final FMLCommonSetupEvent event) { + public static void clientInit() { + CrashReportCallables.registerCrashCallable("Flywheel Backend", Backend::getBackendDescriptor); + + OptifineHandler.init(); + Backend.init(); + IEventBus modEventBus = FMLJavaModLoadingContext.get() + .getModEventBus(); + + modEventBus.addListener(Contexts::flwInit); + modEventBus.addListener(PartialModel::onModelRegistry); + modEventBus.addListener(PartialModel::onModelBake); + modEventBus.addListener(StitchedSprite::onTextureStitchPre); + modEventBus.addListener(StitchedSprite::onTextureStitchPost); + + MinecraftForge.EVENT_BUS.addListener(FlwCommands::registerClientCommands); + + MinecraftForge.EVENT_BUS.addListener(ProgramCompiler::invalidateAll); + + VanillaInstances.init(); + + // https://github.com/Jozufozu/Flywheel/issues/69 + // Weird issue with accessor loading. + // Only thing I've seen that's close to a fix is to force the class to load before trying to use it. + // From the SpongePowered discord: + // https://discord.com/channels/142425412096491520/626802111455297538/675007581168599041 + LOGGER.info("Successfully loaded {}", PausedPartialTickAccessor.class.getName()); + } + + private void setup(final FMLCommonSetupEvent event) { ArgumentTypes.register(rl("engine").toString(), EngineArgument.class, new EmptyArgumentSerializer<>(EngineArgument::getInstance)); } } diff --git a/src/main/java/com/jozufozu/flywheel/FlywheelClient.java b/src/main/java/com/jozufozu/flywheel/FlywheelClient.java deleted file mode 100644 index 4b74ab5ce..000000000 --- a/src/main/java/com/jozufozu/flywheel/FlywheelClient.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.jozufozu.flywheel; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.OptifineHandler; -import com.jozufozu.flywheel.core.Contexts; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.core.StitchedSprite; -import com.jozufozu.flywheel.core.compile.ProgramCompiler; -import com.jozufozu.flywheel.event.ReloadRenderersEvent; -import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor; -import com.jozufozu.flywheel.vanilla.VanillaInstances; - -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.fml.CrashReportCallables; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; - -public class FlywheelClient { - - public static void clientInit() { - CrashReportCallables.registerCrashCallable("Flywheel Backend", Backend::getBackendDescriptor); - - OptifineHandler.init(); - Backend.init(); - IEventBus modEventBus = FMLJavaModLoadingContext.get() - .getModEventBus(); - - modEventBus.addListener(Contexts::flwInit); - modEventBus.addListener(PartialModel::onModelRegistry); - modEventBus.addListener(PartialModel::onModelBake); - modEventBus.addListener(StitchedSprite::onTextureStitchPre); - modEventBus.addListener(StitchedSprite::onTextureStitchPost); - - MinecraftForge.EVENT_BUS.addListener(ProgramCompiler::invalidateAll); - - VanillaInstances.init(); - - // https://github.com/Jozufozu/Flywheel/issues/69 - // Weird issue with accessor loading. - // Only thing I've seen that's close to a fix is to force the class to load before trying to use it. - // From the SpongePowered discord: - // https://discord.com/channels/142425412096491520/626802111455297538/675007581168599041 - Flywheel.LOGGER.info("Successfully loaded {}", PausedPartialTickAccessor.class.getName()); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index 6988f3239..c6c58f13b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -21,8 +21,6 @@ public class Backend { private static FlwEngine engine; - public static GlCompat compat; - private static final Loader loader = new Loader(); public static FlwEngine getEngine() { @@ -45,9 +43,7 @@ public class Backend { public static void refresh() { OptifineHandler.refresh(); - compat = new GlCompat(); - - engine = chooseEngine(compat); + engine = chooseEngine(); } public static boolean isOn() { @@ -79,7 +75,7 @@ public class Backend { RenderWork.enqueue(Minecraft.getInstance().levelRenderer::allChanged); } - private static FlwEngine chooseEngine(GlCompat compat) { + private static FlwEngine chooseEngine() { FlwEngine preferredChoice = FlwConfig.get() .getEngine(); @@ -87,7 +83,7 @@ public class Backend { boolean canUseEngine = switch (preferredChoice) { case OFF -> true; case BATCHING -> !usingShaders; - case INSTANCING -> !usingShaders && compat.instancedArraysSupported(); + case INSTANCING -> !usingShaders && GlCompat.getInstance().instancedArraysSupported(); }; return canUseEngine ? preferredChoice : FlwEngine.OFF; diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 9f0f9b43c..7d08882d7 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -42,7 +42,7 @@ public class Loader implements ResourceManagerReloadListener { public static final String PROGRAM_DIR = "flywheel/programs/"; private static final Gson GSON = new GsonBuilder().create(); - private final Map programSpecRegistry = new HashMap<>(); + private final Map programs = new HashMap<>(); private boolean firstLoad = true; @@ -59,7 +59,7 @@ public class Loader implements ResourceManagerReloadListener { @Nullable public ProgramSpec get(ResourceLocation name) { - return programSpecRegistry.get(name); + return programs.get(name); } @Override @@ -91,6 +91,8 @@ public class Loader implements ResourceManagerReloadListener { } private void loadProgramSpecs(ResourceManager manager) { + programs.clear(); + Collection programSpecs = manager.listResources(PROGRAM_DIR, s -> s.endsWith(".json")); for (ResourceLocation location : programSpecs) { @@ -109,21 +111,15 @@ public class Loader implements ResourceManagerReloadListener { spec.setName(specName); - register(spec); + if (programs.containsKey(specName)) { + throw new IllegalStateException("Program spec '" + specName + "' already registered."); + } + programs.put(specName, spec); + } catch (Exception e) { Backend.LOGGER.error(e); } } } - /** - * Register a shader program. - */ - private void register(ProgramSpec spec) { - ResourceLocation name = spec.name; - if (programSpecRegistry.containsKey(name)) { - throw new IllegalStateException("Program spec '" + name + "' already registered."); - } - programSpecRegistry.put(name, spec); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java index 346db8814..55d8d7037 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java @@ -4,8 +4,8 @@ import java.nio.ByteBuffer; import org.lwjgl.opengl.GL20; -import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlObject; +import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; public abstract class GlBuffer extends GlObject { @@ -21,7 +21,8 @@ public abstract class GlBuffer extends GlObject { * @return A buffer that will be persistent if the driver supports it. */ public static GlBuffer requestPersistent(GlBufferType type) { - if (Backend.compat.bufferStorageSupported()) { + if (GlCompat.getInstance() + .bufferStorageSupported()) { return new PersistentGlBuffer(type); } else { return new MappedGlBuffer(type); diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java index 6c4b474cd..ff81679c2 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java @@ -8,10 +8,10 @@ import java.nio.ByteBuffer; import org.lwjgl.opengl.GL30; -import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlFence; import com.jozufozu.flywheel.backend.gl.error.GlError; import com.jozufozu.flywheel.backend.gl.error.GlException; +import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; public class PersistentGlBuffer extends GlBuffer implements Mappable { @@ -46,7 +46,7 @@ public class PersistentGlBuffer extends GlBuffer implements Mappable { fence.clear(); - Backend.compat.bufferStorage.bufferStorage(type, size, flags); + GlCompat.getInstance().bufferStorage.bufferStorage(type, size, flags); ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, 0, size, flags); diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java index 0d550124f..0aaffe754 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java @@ -20,11 +20,20 @@ import net.minecraft.Util; */ public class GlCompat { + private static GlCompat instance; + + public static GlCompat getInstance() { + if (instance == null) { + instance = new GlCompat(); + } + return instance; + } + public final InstancedArrays instancedArrays; public final BufferStorage bufferStorage; public final boolean amd; - public GlCompat() { + private GlCompat() { GLCapabilities caps = GL.createCapabilities(); instancedArrays = getLatest(InstancedArrays.class, caps); bufferStorage = getLatest(BufferStorage.class, caps); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java index 9595069eb..02ec9ceac 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -1,8 +1,5 @@ package com.jozufozu.flywheel.backend.instancing; -import java.util.List; - -import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.backend.Backend; @@ -137,10 +134,4 @@ public class InstanceWorld { .forEach(entityInstanceManager::add); } - public void getDebugString(List debug) { - debug.add(""); - debug.add("Flywheel: " + Flywheel.VERSION); - debug.add("B: " + blockEntityInstanceManager.getObjectCount() + ", E: " + entityInstanceManager.getObjectCount()); - engine.addDebugInfo(debug); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java index f434a4871..e1a4eb904 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing; import java.util.List; +import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent; @@ -116,7 +117,16 @@ public class InstancedRenderDispatcher { } public static void getDebugString(List debug) { - instanceWorlds.get(Minecraft.getInstance().level) - .getDebugString(debug); + debug.add(""); + debug.add("Flywheel: " + Flywheel.VERSION); + + if (Backend.isOn()) { + InstanceWorld instanceWorld = instanceWorlds.get(Minecraft.getInstance().level); + + debug.add("B: " + instanceWorld.blockEntityInstanceManager.getObjectCount() + ", E: " + instanceWorld.entityInstanceManager.getObjectCount()); + instanceWorld.engine.addDebugInfo(debug); + } else { + debug.add("Disabled"); + } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java index ffac02ae3..3f0ff7c87 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java @@ -6,11 +6,11 @@ import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.struct.Instanced; import com.jozufozu.flywheel.api.struct.StructWriter; -import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlVertexArray; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; +import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; import com.jozufozu.flywheel.backend.instancing.AbstractInstancer; import com.jozufozu.flywheel.backend.model.BufferedModel; import com.jozufozu.flywheel.backend.model.ModelAllocator; @@ -198,7 +198,7 @@ public class GPUInstancer extends AbstractInstancer { vao.bindAttributes(attributeBaseIndex, instanceFormat); for (int i = 0; i < instanceFormat.getAttributeCount(); i++) { - Backend.compat.instancedArrays.vertexAttribDivisor(attributeBaseIndex + i, 1); + GlCompat.getInstance().instancedArrays.vertexAttribDivisor(attributeBaseIndex + i, 1); } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java index 6c640f716..73ea3e1c5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java @@ -7,8 +7,8 @@ import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.MaterialGroup; import com.jozufozu.flywheel.api.struct.Instanced; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.RenderLayer; +import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; import com.jozufozu.flywheel.backend.model.FallbackAllocator; import com.jozufozu.flywheel.backend.model.ModelAllocator; import com.jozufozu.flywheel.backend.model.ModelPool; @@ -40,7 +40,8 @@ public class InstancedMaterialGroup

implements MaterialG public InstancedMaterialGroup(InstancingEngine

owner, RenderType type) { this.owner = owner; this.type = type; - if (Backend.compat.onAMDWindows()) { + if (GlCompat.getInstance() + .onAMDWindows()) { this.allocator = FallbackAllocator.INSTANCE; } else { this.allocator = new ModelPool(Formats.POS_TEX_NORMAL, 2048); diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java index 5562d535a..5d945cc26 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java @@ -9,7 +9,7 @@ import net.minecraft.commands.Commands; import net.minecraftforge.client.event.RegisterClientCommandsEvent; public class FlwCommands { - public static void onServerStarting(RegisterClientCommandsEvent event) { + public static void registerClientCommands(RegisterClientCommandsEvent event) { CommandDispatcher dispatcher = event.getDispatcher(); dispatcher.register(Commands.literal("flywheel") From 9219fef20a9a35611d75a26041715d00e6ea7f54 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Tue, 1 Feb 2022 13:54:38 -0800 Subject: [PATCH 2/3] Toggleable update limiting - Extract update limiting behavior to interface - Move original impl to BandedPrimeLimiter - Add dummy NonLimiter impl - Add command/config to toggle update limiting - Refactor InstanceManager to be more consistent between frame updates and tick updates - Bump version - 0.6.1 --- gradle.properties | 2 +- .../backend/instancing/InstanceManager.java | 67 ++++++++++--------- .../instancing/InstancedRenderDispatcher.java | 3 + .../instancing/InstancingEngine.java | 2 +- .../ratelimit/BandedPrimeLimiter.java | 28 ++++++++ .../ratelimit/DistanceUpdateLimiter.java | 20 ++++++ .../instancing/ratelimit/NonLimiter.java | 13 ++++ .../flywheel/config/BooleanConfig.java | 35 +++++++--- .../flywheel/config/BooleanConfigCommand.java | 6 +- .../jozufozu/flywheel/config/FlwCommands.java | 11 ++- .../jozufozu/flywheel/config/FlwConfig.java | 20 ++++++ .../crumbling/CrumblingInstanceManager.java | 7 +- .../jozufozu/flywheel/event/ForgeEvents.java | 2 +- 13 files changed, 162 insertions(+), 54 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/BandedPrimeLimiter.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/DistanceUpdateLimiter.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/NonLimiter.java diff --git a/gradle.properties b/gradle.properties index 0476c1c99..ef7e50b34 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs = -Xmx3G org.gradle.daemon = false # mod version info -mod_version = 0.6.0 +mod_version = 0.6.1 mc_update_version = 1.18 minecraft_version = 1.18.1 forge_version = 39.0.59 diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java index 38936f656..871572127 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java @@ -14,13 +14,14 @@ import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; +import com.jozufozu.flywheel.backend.instancing.ratelimit.DistanceUpdateLimiter; +import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.light.LightUpdater; import com.mojang.math.Vector3f; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.client.Camera; import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; public abstract class InstanceManager implements InstancingEngine.OriginShiftListener { @@ -33,8 +34,8 @@ public abstract class InstanceManager implements InstancingEngine.OriginShift protected final Object2ObjectOpenHashMap tickableInstances; protected final Object2ObjectOpenHashMap dynamicInstances; - protected int frame; - protected int tick; + protected DistanceUpdateLimiter frame; + protected DistanceUpdateLimiter tick; public InstanceManager(MaterialManager materialManager) { this.materialManager = materialManager; @@ -44,6 +45,10 @@ public abstract class InstanceManager implements InstancingEngine.OriginShift this.dynamicInstances = new Object2ObjectOpenHashMap<>(); this.tickableInstances = new Object2ObjectOpenHashMap<>(); + + FlwConfig config = FlwConfig.get(); + frame = config.createUpdateLimiter(); + tick = config.createUpdateLimiter(); } /** @@ -86,7 +91,7 @@ public abstract class InstanceManager implements InstancingEngine.OriginShift *

*/ public void tick(TaskEngine taskEngine, double cameraX, double cameraY, double cameraZ) { - tick++; + tick.tick(); processQueuedUpdates(); // integer camera pos as a micro-optimization @@ -112,7 +117,7 @@ public abstract class InstanceManager implements InstancingEngine.OriginShift } } - private void tickInstance(int cX, int cY, int cZ, TickableInstance instance) { + protected void tickInstance(int cX, int cY, int cZ, TickableInstance instance) { if (!instance.decreaseTickRateWithDistance()) { instance.tick(); return; @@ -124,11 +129,11 @@ public abstract class InstanceManager implements InstancingEngine.OriginShift int dY = pos.getY() - cY; int dZ = pos.getZ() - cZ; - if ((tick % getUpdateDivisor(dX, dY, dZ)) == 0) instance.tick(); + if (tick.shouldUpdate(dX, dY, dZ)) instance.tick(); } public void beginFrame(TaskEngine taskEngine, Camera info) { - frame++; + frame.tick(); processQueuedAdditions(); Vector3f look = info.getLookVector(); @@ -151,8 +156,7 @@ public abstract class InstanceManager implements InstancingEngine.OriginShift List sub = instances.subList(start, end); taskEngine.submit(() -> { for (DynamicInstance dyn : sub) { - if (!dyn.decreaseFramerateWithDistance() || shouldFrameUpdate(dyn.getWorldPosition(), lookX, lookY, lookZ, cX, cY, cZ)) - dyn.beginFrame(); + updateInstance(dyn, lookX, lookY, lookZ, cX, cY, cZ); } }); @@ -160,6 +164,28 @@ public abstract class InstanceManager implements InstancingEngine.OriginShift } } + protected void updateInstance(DynamicInstance dyn, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) { + if (!dyn.decreaseFramerateWithDistance()) { + dyn.beginFrame(); + return; + } + + BlockPos worldPos = dyn.getWorldPosition(); + int dX = worldPos.getX() - cX; + int dY = worldPos.getY() - cY; + int dZ = worldPos.getZ() - cZ; + + // is it more than 2 blocks behind the camera? + int dist = 2; + float dot = (dX + lookX * dist) * lookX + (dY + lookY * dist) * lookY + (dZ + lookZ * dist) * lookZ; + if (dot < 0) { + return; + } + + if (frame.shouldUpdate(dX, dY, dZ)) + dyn.beginFrame(); + } + public void add(T obj) { if (!Backend.isOn()) return; @@ -268,29 +294,6 @@ public abstract class InstanceManager implements InstancingEngine.OriginShift } } - protected boolean shouldFrameUpdate(BlockPos worldPos, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) { - int dX = worldPos.getX() - cX; - int dY = worldPos.getY() - cY; - int dZ = worldPos.getZ() - cZ; - - // is it more than 2 blocks behind the camera? - int dist = 2; - float dot = (dX + lookX * dist) * lookX + (dY + lookY * dist) * lookY + (dZ + lookZ * dist) * lookZ; - if (dot < 0) return false; - - return (frame % getUpdateDivisor(dX, dY, dZ)) == 0; - } - - // 1 followed by the prime numbers - private static final int[] divisorSequence = new int[] { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 }; - protected int getUpdateDivisor(int dX, int dY, int dZ) { - int dSq = dX * dX + dY * dY + dZ * dZ; - - int i = (dSq / 2048); - - return divisorSequence[Mth.clamp(i, 0, divisorSequence.length - 1)]; - } - protected void addInternal(T obj) { if (!Backend.isOn()) return; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java index e1a4eb904..ebf6a8e56 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -4,6 +4,8 @@ import java.util.List; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.config.BooleanConfig; +import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.event.RenderLayerEvent; @@ -123,6 +125,7 @@ public class InstancedRenderDispatcher { if (Backend.isOn()) { InstanceWorld instanceWorld = instanceWorlds.get(Minecraft.getInstance().level); + debug.add("Update limiting: " + BooleanConfig.boolToText(FlwConfig.get().limitUpdates()).getString()); debug.add("B: " + instanceWorld.blockEntityInstanceManager.getObjectCount() + ", E: " + instanceWorld.entityInstanceManager.getObjectCount()); instanceWorld.engine.addDebugInfo(debug); } else { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index 42cca0e13..e3efc8a71 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -154,9 +154,9 @@ public class InstancingEngine

implements Engine { @Override public void addDebugInfo(List info) { info.add("GL33 Instanced Arrays"); - info.add("Origin: " + originCoordinate.getX() + ", " + originCoordinate.getY() + ", " + originCoordinate.getZ()); info.add("Instances: " + getGroupsToRender(null).mapToInt(InstancedMaterialGroup::getInstanceCount).sum()); info.add("Vertices: " + getGroupsToRender(null).mapToInt(InstancedMaterialGroup::getVertexCount).sum()); + info.add("Origin: " + originCoordinate.getX() + ", " + originCoordinate.getY() + ", " + originCoordinate.getZ()); } @FunctionalInterface diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/BandedPrimeLimiter.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/BandedPrimeLimiter.java new file mode 100644 index 000000000..278f5ff1e --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/BandedPrimeLimiter.java @@ -0,0 +1,28 @@ +package com.jozufozu.flywheel.backend.instancing.ratelimit; + +import net.minecraft.util.Mth; + +public class BandedPrimeLimiter implements DistanceUpdateLimiter { + // 1 followed by the prime numbers + private static final int[] divisorSequence = new int[] { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 }; + + private int tickCount = 0; + + @Override + public void tick() { + tickCount++; + } + + @Override + public boolean shouldUpdate(int dX, int dY, int dZ) { + return (tickCount % getUpdateDivisor(dX, dY, dZ)) == 0; + } + + protected int getUpdateDivisor(int dX, int dY, int dZ) { + int dSq = dX * dX + dY * dY + dZ * dZ; + + int i = (dSq / 2048); + + return divisorSequence[Mth.clamp(i, 0, divisorSequence.length - 1)]; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/DistanceUpdateLimiter.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/DistanceUpdateLimiter.java new file mode 100644 index 000000000..7fb3ceff6 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/DistanceUpdateLimiter.java @@ -0,0 +1,20 @@ +package com.jozufozu.flywheel.backend.instancing.ratelimit; + +/** + * Interface for rate-limiting updates based on an object's distance from the camera. + */ +public interface DistanceUpdateLimiter { + /** + * Call this before every update. + */ + void tick(); + + /** + * Check to see if an object at the given position relative to the camera should be updated. + * @param dX The X distance from the camera. + * @param dY The Y distance from the camera. + * @param dZ The Z distance from the camera. + * @return {@code true} if the object should be updated, {@code false} otherwise. + */ + boolean shouldUpdate(int dX, int dY, int dZ); +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/NonLimiter.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/NonLimiter.java new file mode 100644 index 000000000..ea5afb230 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/NonLimiter.java @@ -0,0 +1,13 @@ +package com.jozufozu.flywheel.backend.instancing.ratelimit; + +public class NonLimiter implements DistanceUpdateLimiter { + @Override + public void tick() { + // noop + } + + @Override + public boolean shouldUpdate(int dX, int dY, int dZ) { + return true; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java b/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java index 4014fe5bd..2cdf578b6 100644 --- a/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java +++ b/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java @@ -1,7 +1,8 @@ package com.jozufozu.flywheel.config; import java.util.function.Consumer; -import java.util.function.Supplier; + +import com.jozufozu.flywheel.backend.Backend; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; @@ -9,20 +10,36 @@ import net.minecraft.client.player.LocalPlayer; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.TextComponent; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; public enum BooleanConfig { - NORMAL_OVERLAY(() -> BooleanConfig::normalOverlay), - ; + NORMAL_OVERLAY(BooleanConfig::normalOverlay), + LIMIT_UPDATES(BooleanConfig::limitUpdates); - final Supplier> receiver; + final Consumer receiver; - BooleanConfig(Supplier> receiver) { + BooleanConfig(Consumer receiver) { this.receiver = receiver; } - @OnlyIn(Dist.CLIENT) + private static void limitUpdates(BooleanDirective booleanDirective) { + LocalPlayer player = Minecraft.getInstance().player; + if (player == null || booleanDirective == null) return; + + if (booleanDirective == BooleanDirective.DISPLAY) { + Component text = new TextComponent("Update limiting is currently: ").append(boolToText(FlwConfig.get().limitUpdates())); + player.displayClientMessage(text, false); + return; + } + + FlwConfig.get().client.limitUpdates.set(booleanDirective.get()); + + Component text = boolToText(FlwConfig.get().limitUpdates()).append(new TextComponent(" update limiting.").withStyle(ChatFormatting.WHITE)); + + player.displayClientMessage(text, false); + + Backend.reloadWorldRenderers(); + } + private static void normalOverlay(BooleanDirective state) { LocalPlayer player = Minecraft.getInstance().player; if (player == null || state == null) return; @@ -40,7 +57,7 @@ public enum BooleanConfig { player.displayClientMessage(text, false); } - private static MutableComponent boolToText(boolean b) { + public static MutableComponent boolToText(boolean b) { return b ? new TextComponent("enabled").withStyle(ChatFormatting.DARK_GREEN) : new TextComponent("disabled").withStyle(ChatFormatting.RED); } } diff --git a/src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java b/src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java index 9c690af30..d3be59e10 100644 --- a/src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java +++ b/src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java @@ -20,17 +20,17 @@ public class BooleanConfigCommand { public ArgumentBuilder register() { return Commands.literal(name) .executes(context -> { - value.receiver.get().accept(BooleanDirective.DISPLAY); + value.receiver.accept(BooleanDirective.DISPLAY); return Command.SINGLE_SUCCESS; }) .then(Commands.literal("on") .executes(context -> { - value.receiver.get().accept(BooleanDirective.TRUE); + value.receiver.accept(BooleanDirective.TRUE); return Command.SINGLE_SUCCESS; })) .then(Commands.literal("off") .executes(context -> { - value.receiver.get().accept(BooleanDirective.FALSE); + value.receiver.accept(BooleanDirective.FALSE); return Command.SINGLE_SUCCESS; })); } diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java index 5d945cc26..018e8efce 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java @@ -13,15 +13,20 @@ public class FlwCommands { CommandDispatcher dispatcher = event.getDispatcher(); dispatcher.register(Commands.literal("flywheel") - .then(debugCommand()) - .then(backendCommand()) + .then(debugNormalsCommand()) + .then(backendCommand()) + .then(limitUpdatesCommand()) ); } - private static ArgumentBuilder debugCommand() { + private static ArgumentBuilder debugNormalsCommand() { return new BooleanConfigCommand("debugNormals", BooleanConfig.NORMAL_OVERLAY).register(); } + private static ArgumentBuilder limitUpdatesCommand() { + return new BooleanConfigCommand("limitUpdates", BooleanConfig.LIMIT_UPDATES).register(); + } + private static ArgumentBuilder backendCommand() { return Commands.literal("backend") .executes(context -> { diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java index a7457e70d..468252db0 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java @@ -2,6 +2,10 @@ package com.jozufozu.flywheel.config; import org.apache.commons.lang3.tuple.Pair; +import com.jozufozu.flywheel.backend.instancing.ratelimit.BandedPrimeLimiter; +import com.jozufozu.flywheel.backend.instancing.ratelimit.DistanceUpdateLimiter; +import com.jozufozu.flywheel.backend.instancing.ratelimit.NonLimiter; + import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec.BooleanValue; import net.minecraftforge.fml.ModLoadingContext; @@ -34,12 +38,25 @@ public class FlwConfig { return client.debugNormals.get(); } + public boolean limitUpdates() { + return client.limitUpdates.get(); + } + + public DistanceUpdateLimiter createUpdateLimiter() { + if (limitUpdates()) { + return new BandedPrimeLimiter(); + } else { + return new NonLimiter(); + } + } + public static void init() { } public static class ClientConfig { public final ForgeConfigSpec.EnumValue engine; public final BooleanValue debugNormals; + public final BooleanValue limitUpdates; public ClientConfig(ForgeConfigSpec.Builder builder) { @@ -48,6 +65,9 @@ public class FlwConfig { debugNormals = builder.comment("Enable or disable a debug overlay that colors pixels by their normal") .define("debugNormals", false); + + limitUpdates = builder.comment("Enable or disable instance update limiting with distance.") + .define("limitUpdates", true); } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingInstanceManager.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingInstanceManager.java index edfcd2c0c..3d8abed17 100644 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingInstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingInstanceManager.java @@ -1,10 +1,9 @@ package com.jozufozu.flywheel.core.crumbling; import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager; -import net.minecraft.core.BlockPos; - public class CrumblingInstanceManager extends BlockEntityInstanceManager { public CrumblingInstanceManager(MaterialManager materialManager) { @@ -12,7 +11,7 @@ public class CrumblingInstanceManager extends BlockEntityInstanceManager { } @Override - protected boolean shouldFrameUpdate(BlockPos worldPos, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) { - return true; + protected void updateInstance(DynamicInstance dyn, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) { + dyn.beginFrame(); } } diff --git a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java index 64aec0c2a..056966700 100644 --- a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java +++ b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java @@ -21,7 +21,7 @@ public class ForgeEvents { if (Minecraft.getInstance().options.renderDebug) { - InstancedRenderDispatcher.getDebugString(event.getLeft()); + InstancedRenderDispatcher.getDebugString(event.getRight()); } } From 1d0e0eb6bc295522a331449fc69fd45bf05716e6 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Tue, 1 Feb 2022 20:44:53 -0800 Subject: [PATCH 3/3] Compress config command code - Remove BooleanConfig, BooleanConfigCommand, and BooleanDirective - Make Flywheel.VERSION private so it cannot be changed - Move createUpdateLimiter from FlwConfig to InstanceManager --- .../java/com/jozufozu/flywheel/Flywheel.java | 25 +-- .../backend/instancing/InstanceManager.java | 15 +- .../instancing/InstancedRenderDispatcher.java | 7 +- .../flywheel/config/BooleanConfig.java | 63 ------- .../flywheel/config/BooleanConfigCommand.java | 37 ----- .../flywheel/config/BooleanDirective.java | 22 --- .../jozufozu/flywheel/config/FlwCommands.java | 154 +++++++++++++++--- .../jozufozu/flywheel/config/FlwConfig.java | 16 +- .../jozufozu/flywheel/config/FlwEngine.java | 64 +------- .../core/compile/ProgramCompiler.java | 1 + 10 files changed, 166 insertions(+), 238 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java delete mode 100644 src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java delete mode 100644 src/main/java/com/jozufozu/flywheel/config/BooleanDirective.java diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index cecf6fae8..653aecf7d 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -36,30 +36,26 @@ public class Flywheel { public static final String ID = "flywheel"; public static final Logger LOGGER = LogManager.getLogger(Flywheel.class); - public static ArtifactVersion VERSION; + private static ArtifactVersion version; public Flywheel() { IModFileInfo modFileById = ModList.get() .getModFileById(ID); - VERSION = modFileById.getMods() + version = modFileById.getMods() .get(0) .getVersion(); FMLJavaModLoadingContext.get() .getModEventBus() - .addListener(this::setup); + .addListener(Flywheel::setup); FlwConfig.init(); DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> Flywheel::clientInit); } - public static ResourceLocation rl(String path) { - return new ResourceLocation(ID, path); - } - - public static void clientInit() { + private static void clientInit() { CrashReportCallables.registerCrashCallable("Flywheel Backend", Backend::getBackendDescriptor); OptifineHandler.init(); @@ -74,7 +70,6 @@ public class Flywheel { modEventBus.addListener(StitchedSprite::onTextureStitchPost); MinecraftForge.EVENT_BUS.addListener(FlwCommands::registerClientCommands); - MinecraftForge.EVENT_BUS.addListener(ProgramCompiler::invalidateAll); VanillaInstances.init(); @@ -84,10 +79,18 @@ public class Flywheel { // Only thing I've seen that's close to a fix is to force the class to load before trying to use it. // From the SpongePowered discord: // https://discord.com/channels/142425412096491520/626802111455297538/675007581168599041 - LOGGER.info("Successfully loaded {}", PausedPartialTickAccessor.class.getName()); + LOGGER.debug("Successfully loaded {}", PausedPartialTickAccessor.class.getName()); } - private void setup(final FMLCommonSetupEvent event) { + private static void setup(final FMLCommonSetupEvent event) { ArgumentTypes.register(rl("engine").toString(), EngineArgument.class, new EmptyArgumentSerializer<>(EngineArgument::getInstance)); } + + public static ArtifactVersion getVersion() { + return version; + } + + public static ResourceLocation rl(String path) { + return new ResourceLocation(ID, path); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java index 871572127..7f741cd8c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java @@ -14,7 +14,9 @@ import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; +import com.jozufozu.flywheel.backend.instancing.ratelimit.BandedPrimeLimiter; import com.jozufozu.flywheel.backend.instancing.ratelimit.DistanceUpdateLimiter; +import com.jozufozu.flywheel.backend.instancing.ratelimit.NonLimiter; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.light.LightUpdater; import com.mojang.math.Vector3f; @@ -46,9 +48,16 @@ public abstract class InstanceManager implements InstancingEngine.OriginShift this.dynamicInstances = new Object2ObjectOpenHashMap<>(); this.tickableInstances = new Object2ObjectOpenHashMap<>(); - FlwConfig config = FlwConfig.get(); - frame = config.createUpdateLimiter(); - tick = config.createUpdateLimiter(); + frame = createUpdateLimiter(); + tick = createUpdateLimiter(); + } + + protected DistanceUpdateLimiter createUpdateLimiter() { + if (FlwConfig.get().limitUpdates()) { + return new BandedPrimeLimiter(); + } else { + return new NonLimiter(); + } } /** diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java index ebf6a8e56..ca423380b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -4,7 +4,7 @@ import java.util.List; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.config.BooleanConfig; +import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent; @@ -73,7 +73,6 @@ public class InstancedRenderDispatcher { @SubscribeEvent public static void tick(TickEvent.ClientTickEvent event) { - if (!Backend.isGameActive() || event.phase == TickEvent.Phase.START) { return; } @@ -120,12 +119,12 @@ public class InstancedRenderDispatcher { public static void getDebugString(List debug) { debug.add(""); - debug.add("Flywheel: " + Flywheel.VERSION); + debug.add("Flywheel: " + Flywheel.getVersion()); if (Backend.isOn()) { InstanceWorld instanceWorld = instanceWorlds.get(Minecraft.getInstance().level); - debug.add("Update limiting: " + BooleanConfig.boolToText(FlwConfig.get().limitUpdates()).getString()); + debug.add("Update limiting: " + FlwCommands.boolToText(FlwConfig.get().limitUpdates()).getString()); debug.add("B: " + instanceWorld.blockEntityInstanceManager.getObjectCount() + ", E: " + instanceWorld.entityInstanceManager.getObjectCount()); instanceWorld.engine.addDebugInfo(debug); } else { diff --git a/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java b/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java deleted file mode 100644 index 2cdf578b6..000000000 --- a/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.jozufozu.flywheel.config; - -import java.util.function.Consumer; - -import com.jozufozu.flywheel.backend.Backend; - -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.TextComponent; - -public enum BooleanConfig { - NORMAL_OVERLAY(BooleanConfig::normalOverlay), - LIMIT_UPDATES(BooleanConfig::limitUpdates); - - final Consumer receiver; - - BooleanConfig(Consumer receiver) { - this.receiver = receiver; - } - - private static void limitUpdates(BooleanDirective booleanDirective) { - LocalPlayer player = Minecraft.getInstance().player; - if (player == null || booleanDirective == null) return; - - if (booleanDirective == BooleanDirective.DISPLAY) { - Component text = new TextComponent("Update limiting is currently: ").append(boolToText(FlwConfig.get().limitUpdates())); - player.displayClientMessage(text, false); - return; - } - - FlwConfig.get().client.limitUpdates.set(booleanDirective.get()); - - Component text = boolToText(FlwConfig.get().limitUpdates()).append(new TextComponent(" update limiting.").withStyle(ChatFormatting.WHITE)); - - player.displayClientMessage(text, false); - - Backend.reloadWorldRenderers(); - } - - private static void normalOverlay(BooleanDirective state) { - LocalPlayer player = Minecraft.getInstance().player; - if (player == null || state == null) return; - - if (state == BooleanDirective.DISPLAY) { - Component text = new TextComponent("Normal debug mode is currently: ").append(boolToText(FlwConfig.get().debugNormals())); - player.displayClientMessage(text, false); - return; - } - - FlwConfig.get().client.debugNormals.set(state.get()); - - Component text = boolToText(FlwConfig.get().debugNormals()).append(new TextComponent(" normal debug mode").withStyle(ChatFormatting.WHITE)); - - player.displayClientMessage(text, false); - } - - public static MutableComponent boolToText(boolean b) { - return b ? new TextComponent("enabled").withStyle(ChatFormatting.DARK_GREEN) : new TextComponent("disabled").withStyle(ChatFormatting.RED); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java b/src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java deleted file mode 100644 index d3be59e10..000000000 --- a/src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.jozufozu.flywheel.config; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.builder.ArgumentBuilder; - -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; - -public class BooleanConfigCommand { - - private final String name; - - private final BooleanConfig value; - - public BooleanConfigCommand(String name, BooleanConfig value) { - this.name = name; - this.value = value; - } - - public ArgumentBuilder register() { - return Commands.literal(name) - .executes(context -> { - value.receiver.accept(BooleanDirective.DISPLAY); - return Command.SINGLE_SUCCESS; - }) - .then(Commands.literal("on") - .executes(context -> { - value.receiver.accept(BooleanDirective.TRUE); - return Command.SINGLE_SUCCESS; - })) - .then(Commands.literal("off") - .executes(context -> { - value.receiver.accept(BooleanDirective.FALSE); - return Command.SINGLE_SUCCESS; - })); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/config/BooleanDirective.java b/src/main/java/com/jozufozu/flywheel/config/BooleanDirective.java deleted file mode 100644 index 1d6892478..000000000 --- a/src/main/java/com/jozufozu/flywheel/config/BooleanDirective.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.jozufozu.flywheel.config; - -public enum BooleanDirective { - TRUE(true), - FALSE(false), - /** - * Don't change anything, just display what the value currently is. - */ - DISPLAY(true), - ; - - private final boolean b; - - BooleanDirective(boolean b) { - this.b = b; - } - - public boolean get() { - if (this == DISPLAY) throw new IllegalStateException("DISPLAY directive has no value"); - return b; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java index 018e8efce..ccd9e262d 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java @@ -1,46 +1,152 @@ package com.jozufozu.flywheel.config; +import java.util.function.BiConsumer; + +import org.jetbrains.annotations.NotNull; + +import com.jozufozu.flywheel.backend.Backend; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.TextComponent; import net.minecraftforge.client.event.RegisterClientCommandsEvent; +import net.minecraftforge.common.ForgeConfigSpec.ConfigValue; +import net.minecraftforge.fml.ModList; public class FlwCommands { public static void registerClientCommands(RegisterClientCommandsEvent event) { - CommandDispatcher dispatcher = event.getDispatcher(); + FlwConfig config = FlwConfig.get(); - dispatcher.register(Commands.literal("flywheel") - .then(debugNormalsCommand()) - .then(backendCommand()) - .then(limitUpdatesCommand()) - ); - } + ConfigCommandBuilder commandBuilder = new ConfigCommandBuilder("flywheel"); - private static ArgumentBuilder debugNormalsCommand() { - return new BooleanConfigCommand("debugNormals", BooleanConfig.NORMAL_OVERLAY).register(); - } - - private static ArgumentBuilder limitUpdatesCommand() { - return new BooleanConfigCommand("limitUpdates", BooleanConfig.LIMIT_UPDATES).register(); - } - - private static ArgumentBuilder backendCommand() { - return Commands.literal("backend") + commandBuilder.addValue(config.client.engine, "backend", (builder, value) -> + builder .executes(context -> { - FlwEngine.handle(null); - + LocalPlayer player = Minecraft.getInstance().player; + if (player != null) { + player.displayClientMessage(getEngineMessage(value.get()), false); + } return Command.SINGLE_SUCCESS; }) .then(Commands.argument("type", EngineArgument.INSTANCE) - .executes(context -> { + .executes(context -> { + LocalPlayer player = Minecraft.getInstance().player; + if (player != null) { FlwEngine type = context.getArgument("type", FlwEngine.class); + value.set(type); - FlwEngine.handle(type); + Component message = getEngineMessage(type); + player.displayClientMessage(message, false); - return Command.SINGLE_SUCCESS; - })); + Backend.reloadWorldRenderers(); + } + return Command.SINGLE_SUCCESS; + }))); + + commandBuilder.addValue(config.client.debugNormals, "debugNormals", (builder, value) -> booleanValueCommand(builder, config, value, + (source, bool) -> { + LocalPlayer player = Minecraft.getInstance().player; + if (player == null) return; + + Component text = new TextComponent("Normal debug mode is currently: ").append(boolToText(bool)); + player.displayClientMessage(text, false); + }, + (source, bool) -> { + LocalPlayer player = Minecraft.getInstance().player; + if (player == null) return; + + Component text = boolToText(bool).append(new TextComponent(" normal debug mode").withStyle(ChatFormatting.WHITE)); + player.displayClientMessage(text, false); + } + )); + + commandBuilder.addValue(config.client.limitUpdates, "limitUpdates", (builder, value) -> booleanValueCommand(builder, config, value, + (source, bool) -> { + LocalPlayer player = Minecraft.getInstance().player; + if (player == null) return; + + Component text = new TextComponent("Update limiting is currently: ").append(boolToText(bool)); + player.displayClientMessage(text, false); + }, + (source, bool) -> { + LocalPlayer player = Minecraft.getInstance().player; + if (player == null) return; + + Component text = boolToText(bool).append(new TextComponent(" update limiting.").withStyle(ChatFormatting.WHITE)); + player.displayClientMessage(text, false); + + Backend.reloadWorldRenderers(); + } + )); + + commandBuilder.build(event.getDispatcher()); + } + + public static void booleanValueCommand(LiteralArgumentBuilder builder, FlwConfig config, ConfigValue value, BiConsumer displayAction, BiConsumer setAction) { + builder + .executes(context -> { + displayAction.accept(context.getSource(), value.get()); + return Command.SINGLE_SUCCESS; + }) + .then(Commands.literal("on") + .executes(context -> { + value.set(true); + setAction.accept(context.getSource(), value.get()); + return Command.SINGLE_SUCCESS; + })) + .then(Commands.literal("off") + .executes(context -> { + value.set(false); + setAction.accept(context.getSource(), value.get()); + return Command.SINGLE_SUCCESS; + })); + } + + public static MutableComponent boolToText(boolean b) { + return b ? new TextComponent("enabled").withStyle(ChatFormatting.DARK_GREEN) : new TextComponent("disabled").withStyle(ChatFormatting.RED); + } + + public static Component getEngineMessage(@NotNull FlwEngine type) { + return switch (type) { + case OFF -> new TextComponent("Disabled Flywheel").withStyle(ChatFormatting.RED); + case INSTANCING -> new TextComponent("Using Instancing Engine").withStyle(ChatFormatting.GREEN); + case BATCHING -> { + MutableComponent msg = new TextComponent("Using Batching Engine").withStyle(ChatFormatting.GREEN); + + if (ModList.get() + .isLoaded("create")) { + // FIXME: batching engine contraption lighting issues + msg.append(new TextComponent("\nWARNING: May cause issues with Create Contraptions").withStyle(ChatFormatting.RED)); + } + + yield msg; + } + }; + } + + public static class ConfigCommandBuilder { + protected LiteralArgumentBuilder command; + + public ConfigCommandBuilder(String baseLiteral) { + command = Commands.literal(baseLiteral); + } + + public > void addValue(T value, String subcommand, BiConsumer, T> consumer) { + LiteralArgumentBuilder builder = Commands.literal(subcommand); + consumer.accept(builder, value); + command.then(builder); + } + + public void build(CommandDispatcher dispatcher) { + dispatcher.register(command); + } } } diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java index 468252db0..95be3cc46 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java @@ -2,12 +2,9 @@ package com.jozufozu.flywheel.config; import org.apache.commons.lang3.tuple.Pair; -import com.jozufozu.flywheel.backend.instancing.ratelimit.BandedPrimeLimiter; -import com.jozufozu.flywheel.backend.instancing.ratelimit.DistanceUpdateLimiter; -import com.jozufozu.flywheel.backend.instancing.ratelimit.NonLimiter; - import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec.BooleanValue; +import net.minecraftforge.common.ForgeConfigSpec.EnumValue; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.config.ModConfig; @@ -42,24 +39,15 @@ public class FlwConfig { return client.limitUpdates.get(); } - public DistanceUpdateLimiter createUpdateLimiter() { - if (limitUpdates()) { - return new BandedPrimeLimiter(); - } else { - return new NonLimiter(); - } - } - public static void init() { } public static class ClientConfig { - public final ForgeConfigSpec.EnumValue engine; + public final EnumValue engine; public final BooleanValue debugNormals; public final BooleanValue limitUpdates; public ClientConfig(ForgeConfigSpec.Builder builder) { - engine = builder.comment("Enable or disable the entire engine") .defineEnum("backend", FlwEngine.INSTANCING); diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwEngine.java b/src/main/java/com/jozufozu/flywheel/config/FlwEngine.java index f0a977224..f5665e1f4 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwEngine.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwEngine.java @@ -6,19 +6,6 @@ import java.util.Map; import javax.annotation.Nullable; -import org.jetbrains.annotations.NotNull; - -import com.jozufozu.flywheel.backend.Backend; - -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.TextComponent; -import net.minecraftforge.fml.ModList; - public enum FlwEngine { OFF("off", "Off"), BATCHING("batching", "Parallel Batching"), @@ -42,57 +29,14 @@ public enum FlwEngine { this.properName = properName; } + public String getShortName() { + return shortName; + } + public String getProperName() { return properName; } - public void encode(FriendlyByteBuf buffer) { - buffer.writeByte(this.ordinal()); - } - - public static void handle(@Nullable FlwEngine type) { - LocalPlayer player = Minecraft.getInstance().player; - if (player == null) return; - - if (type != null) { - FlwConfig.get().client.engine.set(type); - - Component message = getMessage(type); - - player.displayClientMessage(message, false); - Backend.reloadWorldRenderers(); - } else { - player.displayClientMessage(getMessage(FlwConfig.get().getEngine()), false); - } - } - - private static Component getMessage(@NotNull FlwEngine type) { - return switch (type) { - case OFF -> new TextComponent("Disabled Flywheel").withStyle(ChatFormatting.RED); - case INSTANCING -> new TextComponent("Using Instancing Engine").withStyle(ChatFormatting.GREEN); - case BATCHING -> { - MutableComponent msg = new TextComponent("Using Batching Engine").withStyle(ChatFormatting.GREEN); - - if (ModList.get() - .isLoaded("create")) { - // FIXME: batching engine contraption lighting issues - msg.append(new TextComponent("\nWARNING: May cause issues with Create Contraptions").withStyle(ChatFormatting.RED)); - } - - yield msg; - } - }; - } - - @Nullable - public static FlwEngine decode(FriendlyByteBuf buffer) { - byte b = buffer.readByte(); - - if (b == -1) return null; - - return values()[b]; - } - @Nullable public static FlwEngine byName(String name) { return lookup.get(name); diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java index 4931c63fd..43d0d7193 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java @@ -54,6 +54,7 @@ public class ProgramCompiler

extends Memoizer