From ff0a92847997e03ca273951732c4b7a42c74be4a Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Thu, 18 Apr 2024 19:32:05 -0700 Subject: [PATCH] Everything but models - Trying to get xplat forge working, fabric can wait until the common project compiles - Move backend manager event handling to separate class - Move commands into forge for now - Make FlwConfig an interface and move concrete impl into forge - Remove event parameters from handlers than don't actually use them - Add platform specific blockstate light emission for uniforms - Remove example effect - Add accessor for LevelRenderer#ticks --- .../backend/engine/uniform/FrameUniforms.java | 4 +- .../engine/uniform/PlayerUniforms.java | 4 +- .../backend/engine/uniform/Uniforms.java | 3 +- .../backend/mixin/LevelRendererAccessor.java | 12 + .../jozufozu/flywheel/config/FlwConfig.java | 91 +----- .../flywheel/impl/BackendManagerImpl.java | 25 +- .../flywheel/lib/model/ModelCache.java | 3 +- .../flywheel/lib/model/ModelHolder.java | 3 +- .../flywheel/lib/model/baked/MeshEmitter.java | 11 +- .../flywheel/lib/util/LevelAttached.java | 6 - .../flywheel/platform/ClientPlatform.java | 7 + .../vanilla/effect/ExampleEffect.java | 292 ------------------ .../resources/flywheel.backend.mixins.json | 1 + .../flywheel/platform/ClientPlatformImpl.java | 14 + .../com/jozufozu/flywheel/FlywheelForge.java | 22 +- .../jozufozu/flywheel/config/FlwCommands.java | 2 +- .../flywheel/config/FlwForgeConfig.java | 88 ++++++ .../flywheel/impl/BackendEventHandler.java | 28 ++ .../lib/model/baked/ForgeMeshEmitter.java | 21 ++ .../flywheel/platform/ClientPlatformImpl.java | 14 + 20 files changed, 216 insertions(+), 435 deletions(-) create mode 100644 common/src/main/java/com/jozufozu/flywheel/backend/mixin/LevelRendererAccessor.java delete mode 100644 common/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java rename {common => forge}/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java (99%) create mode 100644 forge/src/main/java/com/jozufozu/flywheel/config/FlwForgeConfig.java create mode 100644 forge/src/main/java/com/jozufozu/flywheel/impl/BackendEventHandler.java create mode 100644 forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeMeshEmitter.java diff --git a/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/FrameUniforms.java b/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/FrameUniforms.java index b9437118d..7bdb80edb 100644 --- a/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/FrameUniforms.java +++ b/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/FrameUniforms.java @@ -6,6 +6,7 @@ import org.joml.Vector3f; import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.visualization.VisualizationManager; +import com.jozufozu.flywheel.backend.mixin.LevelRendererAccessor; import com.jozufozu.flywheel.config.DebugMode; import com.jozufozu.flywheel.lib.math.MatrixMath; @@ -147,8 +148,7 @@ public final class FrameUniforms extends UniformWriter { } private static long writeTime(long ptr, RenderContext context) { - int ticks = context.renderer() - .getTicks(); + int ticks = ((LevelRendererAccessor) context.renderer()).flywheel$ticks(); float partialTick = context.partialTick(); float renderTicks = ticks + partialTick; float renderSeconds = renderTicks / 20f; diff --git a/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/PlayerUniforms.java b/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/PlayerUniforms.java index 1d976226c..02e14a5da 100644 --- a/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/PlayerUniforms.java +++ b/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/PlayerUniforms.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.Nullable; import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.backend.mixin.AbstractClientPlayerAccessor; +import com.jozufozu.flywheel.platform.ClientPlatform; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; @@ -93,7 +94,8 @@ public final class PlayerUniforms extends UniformWriter { Item handItem = player.getItemInHand(hand).getItem(); if (handItem instanceof BlockItem bitem) { Block block = bitem.getBlock(); - int blockLight = block.defaultBlockState().getLightEmission(player.clientLevel, player.blockPosition()); + int blockLight = ClientPlatform.getInstance() + .getLightEmission(block.defaultBlockState(), player.clientLevel, player.blockPosition()); if (heldLight < blockLight) { heldLight = blockLight; } diff --git a/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/Uniforms.java b/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/Uniforms.java index cd11491cc..8fa7e0115 100644 --- a/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/Uniforms.java +++ b/common/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/Uniforms.java @@ -1,6 +1,5 @@ package com.jozufozu.flywheel.backend.engine.uniform; -import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent; import com.jozufozu.flywheel.api.event.RenderContext; public final class Uniforms { @@ -33,7 +32,7 @@ public final class Uniforms { } } - public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) { + public static void onReloadLevelRenderer() { deleteAll(); } } diff --git a/common/src/main/java/com/jozufozu/flywheel/backend/mixin/LevelRendererAccessor.java b/common/src/main/java/com/jozufozu/flywheel/backend/mixin/LevelRendererAccessor.java new file mode 100644 index 000000000..5ddc4a5ba --- /dev/null +++ b/common/src/main/java/com/jozufozu/flywheel/backend/mixin/LevelRendererAccessor.java @@ -0,0 +1,12 @@ +package com.jozufozu.flywheel.backend.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.client.renderer.LevelRenderer; + +@Mixin(LevelRenderer.class) +public interface LevelRendererAccessor { + @Accessor("ticks") + int flywheel$ticks(); +} diff --git a/common/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java b/common/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java index 2fa01e342..4ec3356aa 100644 --- a/common/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java +++ b/common/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java @@ -1,94 +1,17 @@ package com.jozufozu.flywheel.config; -import org.apache.commons.lang3.tuple.Pair; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; - import com.jozufozu.flywheel.api.backend.Backend; -import com.jozufozu.flywheel.api.backend.BackendManager; -import com.mojang.logging.LogUtils; +import com.jozufozu.flywheel.platform.ClientPlatform; -import net.minecraft.ResourceLocationException; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.common.ForgeConfigSpec; -import net.minecraftforge.common.ForgeConfigSpec.BooleanValue; -import net.minecraftforge.common.ForgeConfigSpec.ConfigValue; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.config.ModConfig; - -public class FlwConfig { - private static final Logger LOGGER = LogUtils.getLogger(); - private static final FlwConfig INSTANCE = new FlwConfig(); - - public final ClientConfig client; - private final ForgeConfigSpec clientSpec; - - private FlwConfig() { - Pair clientPair = new ForgeConfigSpec.Builder().configure(ClientConfig::new); - this.client = clientPair.getLeft(); - clientSpec = clientPair.getRight(); - } - - public static FlwConfig get() { +public interface FlwConfig { + FlwConfig INSTANCE = ClientPlatform.getInstance().getConfigInstance(); + static FlwConfig get() { return INSTANCE; } - public Backend getBackend() { - Backend backend = parseBackend(client.backend.get()); - if (backend == null) { - backend = BackendManager.getDefaultBackend(); - client.backend.set(Backend.REGISTRY.getIdOrThrow(backend).toString()); - } + Backend getBackend(); - return backend; - } + boolean limitUpdates(); - @Nullable - private static Backend parseBackend(String idStr) { - ResourceLocation backendId; - try { - backendId = new ResourceLocation(idStr); - } catch (ResourceLocationException e) { - LOGGER.warn("Config contains invalid backend ID '" + idStr + "'!"); - return null; - } - - Backend backend = Backend.REGISTRY.get(backendId); - if (backend == null) { - LOGGER.warn("Config contains non-existent backend with ID '" + backendId + "'!"); - return null; - } - - return backend; - } - - public boolean limitUpdates() { - return client.limitUpdates.get(); - } - - public int workerThreads() { - return client.workerThreads.get(); - } - - public void registerSpecs(ModLoadingContext context) { - context.registerConfig(ModConfig.Type.CLIENT, clientSpec); - } - - public static class ClientConfig { - public final ConfigValue backend; - public final BooleanValue limitUpdates; - public final ForgeConfigSpec.IntValue workerThreads; - - private ClientConfig(ForgeConfigSpec.Builder builder) { - backend = builder.comment("Select the backend to use.") - .define("backend", Backend.REGISTRY.getIdOrThrow(BackendManager.getDefaultBackend()).toString()); - - limitUpdates = builder.comment("Enable or disable instance update limiting with distance.") - .define("limitUpdates", true); - - 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()); - } - } + int workerThreads(); } diff --git a/common/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java b/common/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java index 302959cbf..0f4d10f85 100644 --- a/common/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java +++ b/common/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java @@ -4,8 +4,6 @@ import org.slf4j.Logger; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.backend.Backend; -import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent; -import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent; import com.jozufozu.flywheel.backend.Backends; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl; @@ -14,7 +12,6 @@ import com.mojang.logging.LogUtils; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.fml.CrashReportCallables; public final class BackendManagerImpl { private static final Logger LOGGER = LogUtils.getLogger(); @@ -47,7 +44,7 @@ public final class BackendManagerImpl { return Backends.INDIRECT; } - private static void chooseBackend() { + public static void chooseBackend() { var preferred = FlwConfig.get().getBackend(); var actual = preferred.findFallback(); @@ -67,25 +64,5 @@ public final class BackendManagerImpl { } public static void init() { - CrashReportCallables.registerCrashCallable("Flywheel Backend", BackendManagerImpl::getBackendString); - } - - public static void onEndClientResourceReload(EndClientResourceReloadEvent event) { - if (event.error() - .isPresent()) { - return; - } - - chooseBackend(); - VisualizationManagerImpl.resetAll(); - } - - public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) { - chooseBackend(); - - ClientLevel level = event.level(); - if (level != null) { - VisualizationManagerImpl.reset(level); - } } } diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelCache.java b/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelCache.java index 9f12cfc0b..b514c28ed 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelCache.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelCache.java @@ -8,7 +8,6 @@ import java.util.function.Function; import org.jetbrains.annotations.ApiStatus; -import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent; import com.jozufozu.flywheel.api.model.Model; public class ModelCache { @@ -31,7 +30,7 @@ public class ModelCache { } @ApiStatus.Internal - public static void onEndClientResourceReload(EndClientResourceReloadEvent event) { + public static void onEndClientResourceReload() { for (ModelCache cache : ALL) { cache.clear(); } diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelHolder.java b/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelHolder.java index 84088f6e8..505727da2 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelHolder.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/model/ModelHolder.java @@ -7,7 +7,6 @@ import java.util.function.Supplier; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent; import com.jozufozu.flywheel.api.model.Model; public class ModelHolder { @@ -51,7 +50,7 @@ public class ModelHolder { } @ApiStatus.Internal - public static void onEndClientResourceReload(EndClientResourceReloadEvent event) { + public static void onEndClientResourceReload() { for (ModelHolder holder : ALL) { holder.clear(); } diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MeshEmitter.java b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MeshEmitter.java index 8f00b36a2..caa332875 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MeshEmitter.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/model/baked/MeshEmitter.java @@ -12,7 +12,7 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.model.BakedQuad; class MeshEmitter implements VertexConsumer { - private final BufferBuilder bufferBuilder; + protected final BufferBuilder bufferBuilder; private final RenderType renderType; private boolean lastQuadWasShaded; private boolean seenFirstQuad; @@ -51,7 +51,7 @@ class MeshEmitter implements VertexConsumer { } } - private void observeQuadAndEmitIfNecessary(BakedQuad quad) { + protected void observeQuadAndEmitIfNecessary(BakedQuad quad) { if (seenFirstQuad && lastQuadWasShaded != quad.isShade()) { emit(); begin(); @@ -68,13 +68,6 @@ class MeshEmitter implements VertexConsumer { bufferBuilder.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); } - @Override - public void putBulkData(PoseStack.Pose matrixEntry, BakedQuad quad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) { - observeQuadAndEmitIfNecessary(quad); - - bufferBuilder.putBulkData(matrixEntry, quad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); - } - @Override public VertexConsumer vertex(double x, double y, double z) { throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); diff --git a/common/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java b/common/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java index e19bd7e40..b3175f781 100644 --- a/common/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java +++ b/common/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java @@ -14,7 +14,6 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import net.minecraft.world.level.LevelAccessor; -import net.minecraftforge.event.level.LevelEvent; public final class LevelAttached { private static final ConcurrentLinkedDeque>> ALL = new ConcurrentLinkedDeque<>(); @@ -42,11 +41,6 @@ public final class LevelAttached { this(factory, t -> {}); } - @ApiStatus.Internal - public static void onUnloadLevel(LevelEvent.Unload event) { - invalidateLevel(event.getLevel()); - } - public static void invalidateLevel(LevelAccessor level) { Iterator>> iterator = ALL.iterator(); while (iterator.hasNext()) { diff --git a/common/src/main/java/com/jozufozu/flywheel/platform/ClientPlatform.java b/common/src/main/java/com/jozufozu/flywheel/platform/ClientPlatform.java index d165fe14d..1fc1e41cf 100644 --- a/common/src/main/java/com/jozufozu/flywheel/platform/ClientPlatform.java +++ b/common/src/main/java/com/jozufozu/flywheel/platform/ClientPlatform.java @@ -6,9 +6,12 @@ import org.jetbrains.annotations.Nullable; import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.event.RenderStage; +import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.lib.util.ShadersModHandler; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; public abstract class ClientPlatform { private static final ClientPlatform INSTANCE; @@ -38,4 +41,8 @@ public abstract class ClientPlatform { @Nullable public abstract ShadersModHandler.InternalHandler createIrisOculusHandlerIfPresent(); + + public abstract int getLightEmission(BlockState state, ClientLevel level, BlockPos pos); + + public abstract FlwConfig getConfigInstance(); } diff --git a/common/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java b/common/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java deleted file mode 100644 index fd6712536..000000000 --- a/common/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java +++ /dev/null @@ -1,292 +0,0 @@ -package com.jozufozu.flywheel.vanilla.effect; - -import java.util.ArrayList; -import java.util.List; - -import org.joml.Vector3f; - -import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent; -import com.jozufozu.flywheel.api.task.Plan; -import com.jozufozu.flywheel.api.visual.DynamicVisual; -import com.jozufozu.flywheel.api.visual.Effect; -import com.jozufozu.flywheel.api.visual.EffectVisual; -import com.jozufozu.flywheel.api.visual.TickableVisual; -import com.jozufozu.flywheel.api.visualization.VisualizationContext; -import com.jozufozu.flywheel.api.visualization.VisualizationManager; -import com.jozufozu.flywheel.lib.instance.InstanceTypes; -import com.jozufozu.flywheel.lib.instance.TransformedInstance; -import com.jozufozu.flywheel.lib.model.Models; -import com.jozufozu.flywheel.lib.task.ForEachPlan; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.core.Vec3i; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.event.TickEvent; - -// http://www.kfish.org/boids/pseudocode.html -public class ExampleEffect implements Effect { - private static final List ALL_EFFECTS = new ArrayList<>(); - - private static final int VISUAL_COUNT = 500; - private static final float SPAWN_RADIUS = 8.0f; - private static final float LIMIT_RANGE = 10.0f; - private static final float SPEED_LIMIT = 0.1f; - private static final float RENDER_SCALE = 2 / 16f; - - private static final float SIGHT_RANGE = 5; - - private static final float COHERENCE = 1f / 60f; - private static final float SEPARATION = 0.05f; - private static final float ALIGNMENT = 1 / 20f; - private static final float TENDENCY = 1 / 1000f; - private static final float AVERSION = 1; - - private static final float GNAT_JITTER = 0.05f; - - private final Level level; - private final Vector3f targetPoint; - - public ExampleEffect(Level level, Vector3f targetPoint) { - this.level = level; - this.targetPoint = targetPoint; - } - - public static void tick(TickEvent.ClientTickEvent event) { - if (event.phase != TickEvent.Phase.START || Minecraft.getInstance().isPaused()) { - return; - } - - trySpawnNewEffect(); - } - - public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) { - ALL_EFFECTS.clear(); - } - - private static void trySpawnNewEffect() { - Level level = Minecraft.getInstance().level; - Player player = Minecraft.getInstance().player; - - if (player == null || level == null) { - return; - } - - VisualizationManager manager = VisualizationManager.get(level); - if (manager == null) { - return; - } - - if (!ALL_EFFECTS.isEmpty() && level.random.nextFloat() > 0.005f) { - return; - } - - Vec3 playerPos = player.position(); - - var x = (float) (playerPos.x + Mth.nextFloat(level.random, -20, 20)); - var y = (float) (playerPos.y + Mth.nextFloat(level.random, 0, 5)); - var z = (float) (playerPos.z + Mth.nextFloat(level.random, -20, 20)); - - ExampleEffect effect = new ExampleEffect(level, new Vector3f(x, y, z)); - ALL_EFFECTS.add(effect); - manager.getEffects().queueAdd(effect); - } - - @Override - public EffectVisual visualize(VisualizationContext ctx) { - return new ExampleVisual(ctx); - } - - public class ExampleVisual implements EffectVisual, TickableVisual, DynamicVisual { - private final List effects; - private final List boids; - - public ExampleVisual(VisualizationContext ctx) { - this.effects = new ArrayList<>(VISUAL_COUNT); - this.boids = new ArrayList<>(VISUAL_COUNT); - - for (int i = 0; i < VISUAL_COUNT; i++) { - var x = targetPoint.x + Mth.nextFloat(level.random, -SPAWN_RADIUS, SPAWN_RADIUS); - var y = targetPoint.y + Mth.nextFloat(level.random, -SPAWN_RADIUS, SPAWN_RADIUS); - var z = targetPoint.z + Mth.nextFloat(level.random, -SPAWN_RADIUS, SPAWN_RADIUS); - - Boid boid = new Boid(x, y, z); - boids.add(boid); - effects.add(new BoidVisual(ctx, boid)); - } - } - - @Override - public Plan planTick() { - Plan beginTick = ForEachPlan.of(() -> boids, Boid::beginTick); - return beginTick.then(ForEachPlan.of(() -> effects, boid -> boid.self.tick(boids))); - } - - @Override - public Plan planFrame() { - return ForEachPlan.of(() -> effects, BoidVisual::beginFrame); - } - - @Override - public void init(float partialTick) { - } - - @Override - public void update(float partialTick) { - } - - @Override - public void delete() { - effects.forEach(BoidVisual::_delete); - } - } - - public static class Boid { - final Vector3f lastPosition; - final Vector3f position; - final Vector3f lastVelocity = new Vector3f(0); - final Vector3f velocity = new Vector3f(0); - - final Vector3f scratch = new Vector3f(0); - final Vector3f coherence = new Vector3f(0); - final Vector3f alignment = new Vector3f(0); - - public Boid(float x, float y, float z) { - lastPosition = new Vector3f(x, y, z); - position = new Vector3f(x, y, z); - } - - - private void beginTick() { - lastVelocity.set(velocity); - lastPosition.set(position); - } - - public void tick(List swarm) { - int seen = 0; - coherence.set(0); - alignment.set(0); - for (Boid boid : swarm) { - if (boid == this) { - continue; - } - - float distance = boid.lastPosition.distance(lastPosition); - - if (distance > SIGHT_RANGE) { - continue; - } - seen++; - - coherence(boid); - separation(boid); - alignment(boid); - } - - if (seen > 0) { - coherencePost(seen); - alignmentPost(seen); - } - //tend(ExampleEffect.this.targetPoint); - - avoidPlayer(); - - position.add(capSpeed(velocity)); - } - - private void avoidPlayer() { - var player = Minecraft.getInstance().player.position(); - scratch.set(player.x, player.y, player.z); - - float dsq = lastPosition.distanceSquared(scratch); - if (dsq > SIGHT_RANGE * SIGHT_RANGE) { - return; - } - - lastPosition.sub(scratch, scratch) - .mul(AVERSION / dsq); - - velocity.add(capSpeed(scratch)); - } - - private void coherence(Boid other) { - this.coherence.add(other.lastPosition); - } - - private void separation(Boid other) { - float dsq = lastPosition.distanceSquared(other.lastPosition); - var push = other.lastPosition.sub(lastPosition, this.scratch) - .mul(SEPARATION / dsq); - - this.velocity.sub(push); - } - - private void alignment(Boid boid) { - this.alignment.add(boid.lastVelocity); - } - - private void coherencePost(int seen) { - this.coherence.div(seen) - .sub(lastPosition) - .mul(COHERENCE); - this.velocity.add(capSpeed(this.coherence)); - } - - private void alignmentPost(int seen) { - this.alignment.div(seen) - .sub(lastVelocity) - .mul(ALIGNMENT); - - this.velocity.add(this.alignment); - } - - private void tend(Vector3f target) { - this.scratch.set(target) - .sub(lastPosition) - .mul(TENDENCY); - this.velocity.add(capSpeed(this.scratch)); - } - - private static Vector3f capSpeed(Vector3f vec) { - return vec.normalize(SPEED_LIMIT); - } - } - - public static class BoidVisual { - private final Boid self; - private final Vec3i renderOrigin; - - private final TransformedInstance instance; - - public BoidVisual(VisualizationContext ctx, Boid self) { - renderOrigin = ctx.renderOrigin(); - this.self = self; - - instance = ctx.instancerProvider() - .instancer(InstanceTypes.TRANSFORMED, Models.block(Blocks.SHROOMLIGHT.defaultBlockState())) - .createInstance(); - - instance.light(LightTexture.FULL_BRIGHT); - } - - public void _delete() { - instance.delete(); - } - - public void beginFrame(DynamicVisual.Context context) { - float partialTick = context.partialTick(); - var x = Mth.lerp(partialTick, self.lastPosition.x, self.position.x); - var y = Mth.lerp(partialTick, self.lastPosition.y, self.position.y); - var z = Mth.lerp(partialTick, self.lastPosition.z, self.position.z); - - instance.loadIdentity() - .translateBack(renderOrigin) - .translate(x, y, z) - .scale(RENDER_SCALE); - } - } -} diff --git a/common/src/main/resources/flywheel.backend.mixins.json b/common/src/main/resources/flywheel.backend.mixins.json index 25dbe6fb9..233033999 100644 --- a/common/src/main/resources/flywheel.backend.mixins.json +++ b/common/src/main/resources/flywheel.backend.mixins.json @@ -8,6 +8,7 @@ "AbstractClientPlayerAccessor", "GameRendererAccessor", "GlStateManagerMixin", + "LevelRendererAccessor", "LightTextureAccessor", "OptionsMixin", "OverlayTextureAccessor", diff --git a/fabric/src/main/java/com/jozufozu/flywheel/platform/ClientPlatformImpl.java b/fabric/src/main/java/com/jozufozu/flywheel/platform/ClientPlatformImpl.java index da3be665b..af277f9f9 100644 --- a/fabric/src/main/java/com/jozufozu/flywheel/platform/ClientPlatformImpl.java +++ b/fabric/src/main/java/com/jozufozu/flywheel/platform/ClientPlatformImpl.java @@ -7,11 +7,14 @@ import com.jozufozu.flywheel.api.event.ReloadLevelRendererCallback; import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.event.RenderStageCallback; +import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.lib.util.ShadersModHandler; import net.fabricmc.loader.api.FabricLoader; import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; public class ClientPlatformImpl extends ClientPlatform { @Override @@ -56,4 +59,15 @@ public class ClientPlatformImpl extends ClientPlatform { return null; } } + + @Override + public int getLightEmission(BlockState state, ClientLevel level, BlockPos pos) { + return state.getLightEmission(); + } + + @Override + public FlwConfig getConfigInstance() { + // TODO: fabric config + return null; + } } diff --git a/forge/src/main/java/com/jozufozu/flywheel/FlywheelForge.java b/forge/src/main/java/com/jozufozu/flywheel/FlywheelForge.java index 166e30659..e96eb55f2 100644 --- a/forge/src/main/java/com/jozufozu/flywheel/FlywheelForge.java +++ b/forge/src/main/java/com/jozufozu/flywheel/FlywheelForge.java @@ -5,12 +5,15 @@ import java.util.ArrayList; import org.apache.maven.artifact.versioning.ArtifactVersion; import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent; +import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent; import com.jozufozu.flywheel.api.visualization.VisualizationManager; import com.jozufozu.flywheel.backend.compile.FlwPrograms; import com.jozufozu.flywheel.backend.engine.uniform.Uniforms; import com.jozufozu.flywheel.config.BackendArgument; import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; +import com.jozufozu.flywheel.config.FlwForgeConfig; +import com.jozufozu.flywheel.impl.BackendEventHandler; import com.jozufozu.flywheel.impl.BackendManagerImpl; import com.jozufozu.flywheel.impl.visualization.VisualizationEventHandler; import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker; @@ -29,6 +32,7 @@ import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.level.LevelEvent; import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.CrashReportCallables; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.IExtensionPoint; import net.minecraftforge.fml.ModLoadingContext; @@ -58,7 +62,7 @@ public class FlywheelForge { modEventBus.addListener(FlywheelForge::onCommonSetup); modEventBus.addListener(FlywheelForge::onRegister); - FlwConfig.get().registerSpecs(modLoadingContext); + FlwForgeConfig.INSTANCE.registerSpecs(modLoadingContext); modLoadingContext.registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest( () -> "any", @@ -71,7 +75,7 @@ public class FlywheelForge { private static void clientInit(IEventBus forgeEventBus, IEventBus modEventBus) { forgeEventBus.addListener(FlywheelForge::addDebugInfo); - forgeEventBus.addListener(BackendManagerImpl::onReloadLevelRenderer); + forgeEventBus.addListener(BackendEventHandler::onReloadLevelRenderer); forgeEventBus.addListener(VisualizationEventHandler::onClientTick); forgeEventBus.addListener(VisualizationEventHandler::onBeginFrame); @@ -81,26 +85,24 @@ public class FlywheelForge { forgeEventBus.addListener(FlwCommands::registerClientCommands); - forgeEventBus.addListener(Uniforms::onReloadLevelRenderer); + forgeEventBus.addListener($ -> Uniforms.onReloadLevelRenderer()); - forgeEventBus.addListener((LevelEvent.Unload e) -> LevelAttached.onUnloadLevel(e)); - -// forgeEventBus.addListener(ExampleEffect::tick); -// forgeEventBus.addListener(ExampleEffect::onReload); + forgeEventBus.addListener((LevelEvent.Unload e) -> LevelAttached.invalidateLevel(e.getLevel())); modEventBus.addListener(FlywheelForge::registerClientReloadListeners); modEventBus.addListener(FlywheelForge::onClientSetup); modEventBus.addListener(FlywheelForge::onLoadComplete); - modEventBus.addListener(BackendManagerImpl::onEndClientResourceReload); + modEventBus.addListener(BackendEventHandler::onEndClientResourceReload); - modEventBus.addListener((EndClientResourceReloadEvent e) -> ModelCache.onEndClientResourceReload(e)); - modEventBus.addListener(ModelHolder::onEndClientResourceReload); + modEventBus.addListener($ -> ModelCache.onEndClientResourceReload()); + modEventBus.addListener($ -> ModelHolder.onEndClientResourceReload()); modEventBus.addListener(PartialModel::onModelRegistry); modEventBus.addListener(PartialModel::onModelBake); Flywheel.earlyInit(); + CrashReportCallables.registerCrashCallable("Flywheel Backend", BackendManagerImpl::getBackendString); } private static void registerClientReloadListeners(RegisterClientReloadListenersEvent event) { diff --git a/common/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java b/forge/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java similarity index 99% rename from common/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java rename to forge/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java index d355478fa..3265e495c 100644 --- a/common/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java +++ b/forge/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java @@ -25,7 +25,7 @@ public final class FlwCommands { } public static void registerClientCommands(RegisterClientCommandsEvent event) { - FlwConfig config = FlwConfig.get(); + var config = FlwForgeConfig.INSTANCE; LiteralArgumentBuilder command = Commands.literal("flywheel"); diff --git a/forge/src/main/java/com/jozufozu/flywheel/config/FlwForgeConfig.java b/forge/src/main/java/com/jozufozu/flywheel/config/FlwForgeConfig.java new file mode 100644 index 000000000..a83cf60fd --- /dev/null +++ b/forge/src/main/java/com/jozufozu/flywheel/config/FlwForgeConfig.java @@ -0,0 +1,88 @@ +package com.jozufozu.flywheel.config; + +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; + +import com.jozufozu.flywheel.api.backend.Backend; +import com.jozufozu.flywheel.api.backend.BackendManager; +import com.mojang.logging.LogUtils; + +import net.minecraft.ResourceLocationException; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.config.ModConfig; + +public class FlwForgeConfig implements FlwConfig { + private static final Logger LOGGER = LogUtils.getLogger(); + public static final FlwForgeConfig INSTANCE = new FlwForgeConfig(); + + public final ClientConfig client; + private final ForgeConfigSpec clientSpec; + + private FlwForgeConfig() { + Pair clientPair = new ForgeConfigSpec.Builder().configure(ClientConfig::new); + this.client = clientPair.getLeft(); + clientSpec = clientPair.getRight(); + } + + public Backend getBackend() { + Backend backend = parseBackend(client.backend.get()); + if (backend == null) { + backend = BackendManager.getDefaultBackend(); + client.backend.set(Backend.REGISTRY.getIdOrThrow(backend).toString()); + } + + return backend; + } + + @Nullable + private static Backend parseBackend(String idStr) { + ResourceLocation backendId; + try { + backendId = new ResourceLocation(idStr); + } catch (ResourceLocationException e) { + LOGGER.warn("Config contains invalid backend ID '" + idStr + "'!"); + return null; + } + + Backend backend = Backend.REGISTRY.get(backendId); + if (backend == null) { + LOGGER.warn("Config contains non-existent backend with ID '" + backendId + "'!"); + return null; + } + + return backend; + } + + public boolean limitUpdates() { + return client.limitUpdates.get(); + } + + public int workerThreads() { + return client.workerThreads.get(); + } + + public void registerSpecs(ModLoadingContext context) { + context.registerConfig(ModConfig.Type.CLIENT, clientSpec); + } + + public static class ClientConfig { + public final ForgeConfigSpec.ConfigValue backend; + public final ForgeConfigSpec.BooleanValue limitUpdates; + public final ForgeConfigSpec.IntValue workerThreads; + + private ClientConfig(ForgeConfigSpec.Builder builder) { + backend = builder.comment("Select the backend to use.") + .define("backend", Backend.REGISTRY.getIdOrThrow(BackendManager.getDefaultBackend()).toString()); + + limitUpdates = builder.comment("Enable or disable instance update limiting with distance.") + .define("limitUpdates", true); + + 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()); + } + } +} diff --git a/forge/src/main/java/com/jozufozu/flywheel/impl/BackendEventHandler.java b/forge/src/main/java/com/jozufozu/flywheel/impl/BackendEventHandler.java new file mode 100644 index 000000000..a8254b49d --- /dev/null +++ b/forge/src/main/java/com/jozufozu/flywheel/impl/BackendEventHandler.java @@ -0,0 +1,28 @@ +package com.jozufozu.flywheel.impl; + +import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent; +import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent; +import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl; + +import net.minecraft.client.multiplayer.ClientLevel; + +public class BackendEventHandler { + public static void onEndClientResourceReload(EndClientResourceReloadEvent event) { + if (event.error() + .isPresent()) { + return; + } + + BackendManagerImpl.chooseBackend(); + VisualizationManagerImpl.resetAll(); + } + + public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) { + BackendManagerImpl.chooseBackend(); + + ClientLevel level = event.level(); + if (level != null) { + VisualizationManagerImpl.reset(level); + } + } +} diff --git a/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeMeshEmitter.java b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeMeshEmitter.java new file mode 100644 index 000000000..ffebddce2 --- /dev/null +++ b/forge/src/main/java/com/jozufozu/flywheel/lib/model/baked/ForgeMeshEmitter.java @@ -0,0 +1,21 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.model.BakedQuad; + +class ForgeMeshEmitter extends MeshEmitter { + ForgeMeshEmitter(BufferBuilder bufferBuilder, RenderType renderType) { + super(bufferBuilder, renderType); + } + + // Forge has another putBulkData that we need to override + @Override + public void putBulkData(PoseStack.Pose matrixEntry, BakedQuad quad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) { + observeQuadAndEmitIfNecessary(quad); + + bufferBuilder.putBulkData(matrixEntry, quad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); + } +} diff --git a/forge/src/main/java/com/jozufozu/flywheel/platform/ClientPlatformImpl.java b/forge/src/main/java/com/jozufozu/flywheel/platform/ClientPlatformImpl.java index 1ef702ac0..f82da2fc8 100644 --- a/forge/src/main/java/com/jozufozu/flywheel/platform/ClientPlatformImpl.java +++ b/forge/src/main/java/com/jozufozu/flywheel/platform/ClientPlatformImpl.java @@ -7,10 +7,14 @@ import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent; import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.event.RenderStageEvent; +import com.jozufozu.flywheel.config.FlwConfig; +import com.jozufozu.flywheel.config.FlwForgeConfig; import com.jozufozu.flywheel.lib.util.ShadersModHandler; import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.ModList; @@ -57,4 +61,14 @@ public class ClientPlatformImpl extends ClientPlatform { return null; } } + + @Override + public int getLightEmission(BlockState state, ClientLevel level, BlockPos pos) { + return state.getLightEmission(level, pos); + } + + @Override + public FlwConfig getConfigInstance() { + return FlwForgeConfig.INSTANCE; + } }