From 391adfef1a0f709d9476267161275561b82746ff Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Wed, 5 Apr 2023 18:03:25 -0700 Subject: [PATCH] Instance Refactor II --- .../java/com/jozufozu/flywheel/Flywheel.java | 8 +- .../flywheel/api/backend/Backend.java | 3 +- .../flywheel/api/backend/BackendManager.java | 7 - .../jozufozu/flywheel/api/backend/Engine.java | 25 ++- .../api/backend/RenderDispatcher.java | 27 --- .../api/instance/DynamicInstance.java | 11 ++ .../flywheel/api/instance/EffectInstance.java | 6 + .../flywheel/api/instance/EntityInstance.java | 2 +- .../flywheel/api/instance/Instance.java | 12 -- .../BlockEntityInstancingController.java | 2 +- .../EntityInstancingController.java | 2 +- .../instance/controller/InstanceContext.java | 1 - .../InstancingControllerRegistry.java | 2 +- .../flywheel/api/instance/effect/Effect.java | 6 +- .../api/instancer/InstancerProvider.java | 2 +- .../api/vertex/VertexListProvider.java | 18 -- .../vertex/VertexListProviderRegistry.java | 17 ++ .../flywheel/backend/BackendUtil.java | 21 +- .../com/jozufozu/flywheel/backend/Loader.java | 6 +- .../flywheel/backend/compile/Compilation.java | 5 +- .../engine/batching/BatchedMeshPool.java | 4 +- .../engine/batching/BatchingEngine.java | 17 +- .../engine/batching/DrawBufferSet.java | 3 +- .../engine/indirect/IndirectEngine.java | 61 ++---- .../engine/instancing/InstancingEngine.java | 64 ++---- .../backend/instancing/InstanceWorld.java | 151 -------------- .../instancing/InstancedRenderDispatcher.java | 133 ------------- .../manager/EffectInstanceManager.java | 111 ----------- .../flywheel/config/BackendArgument.java | 8 +- .../jozufozu/flywheel/config/FlwCommands.java | 46 ++--- .../flywheel/handler/EntityWorldHandler.java | 27 ++- .../flywheel/handler/ForgeEvents.java | 6 +- .../flywheel/impl/BackendManagerImpl.java | 22 +-- .../InstancingControllerRegistryImpl.java | 3 +- .../impl/VertexListProviderRegistryImpl.java | 26 +++ .../impl/instancing/InstanceWorld.java | 135 +++++++++++++ .../instancing/InstancedRenderDispatcher.java | 184 ++++++++++++++++++ .../InstancingControllerHelper.java | 77 ++++++++ .../manager/BlockEntityInstanceManager.java | 19 +- .../manager/EffectInstanceManager.java | 39 ++++ .../manager/EntityInstanceManager.java | 14 +- .../instancing/manager/InstanceManager.java | 133 +++++-------- .../ratelimit/BandedPrimeLimiter.java | 2 +- .../ratelimit/DistanceUpdateLimiter.java | 2 +- .../instancing/ratelimit/NonLimiter.java | 2 +- .../instancing/storage/AbstractStorage.java | 6 +- .../instancing/storage/One2ManyStorage.java | 86 ++++++++ .../instancing/storage/One2OneStorage.java | 23 +-- .../instancing/storage/Storage.java | 11 +- .../flywheel/lib/backend/Backends.java | 8 +- .../flywheel/lib/backend/SimpleBackend.java | 20 +- .../instance/AbstractBlockEntityInstance.java | 44 ++--- .../lib/instance/AbstractEntityInstance.java | 24 ++- .../lib/instance/AbstractInstance.java | 42 ++-- .../instance/InstancingControllerHelper.java | 85 -------- .../flywheel/lib/model/ModelUtil.java | 4 +- .../flywheel/lib/struct/ColoredLitPart.java | 1 - .../instancer => lib/struct}/FlatLit.java | 12 +- .../lib/uniform/FlwShaderUniforms.java | 10 +- .../flywheel/mixin/ClientLevelMixin.java | 6 +- .../ChunkRebuildHooksMixin.java | 6 +- .../instancemanage/InstanceAddMixin.java | 12 +- .../instancemanage/InstanceRemoveMixin.java | 8 +- .../instancemanage/InstanceUpdateMixin.java | 6 +- .../jozufozu/flywheel/util/WorldAttached.java | 12 +- .../flywheel/vanilla/BellInstance.java | 15 +- .../flywheel/vanilla/ChestInstance.java | 31 ++- .../flywheel/vanilla/MinecartInstance.java | 12 +- .../flywheel/vanilla/ShulkerBoxInstance.java | 20 +- .../vanilla/effect/ExampleEffect.java | 16 +- 70 files changed, 972 insertions(+), 1020 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/api/backend/RenderDispatcher.java create mode 100644 src/main/java/com/jozufozu/flywheel/api/instance/EffectInstance.java create mode 100644 src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProviderRegistry.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/manager/EffectInstanceManager.java rename src/main/java/com/jozufozu/flywheel/impl/{instance => }/InstancingControllerRegistryImpl.java (96%) create mode 100644 src/main/java/com/jozufozu/flywheel/impl/VertexListProviderRegistryImpl.java create mode 100644 src/main/java/com/jozufozu/flywheel/impl/instancing/InstanceWorld.java create mode 100644 src/main/java/com/jozufozu/flywheel/impl/instancing/InstancedRenderDispatcher.java create mode 100644 src/main/java/com/jozufozu/flywheel/impl/instancing/InstancingControllerHelper.java rename src/main/java/com/jozufozu/flywheel/{backend => impl}/instancing/manager/BlockEntityInstanceManager.java (76%) create mode 100644 src/main/java/com/jozufozu/flywheel/impl/instancing/manager/EffectInstanceManager.java rename src/main/java/com/jozufozu/flywheel/{backend => impl}/instancing/manager/EntityInstanceManager.java (69%) rename src/main/java/com/jozufozu/flywheel/{backend => impl}/instancing/manager/InstanceManager.java (59%) rename src/main/java/com/jozufozu/flywheel/{backend => impl}/instancing/ratelimit/BandedPrimeLimiter.java (91%) rename src/main/java/com/jozufozu/flywheel/{backend => impl}/instancing/ratelimit/DistanceUpdateLimiter.java (88%) rename src/main/java/com/jozufozu/flywheel/{backend => impl}/instancing/ratelimit/NonLimiter.java (75%) rename src/main/java/com/jozufozu/flywheel/{backend => impl}/instancing/storage/AbstractStorage.java (85%) create mode 100644 src/main/java/com/jozufozu/flywheel/impl/instancing/storage/One2ManyStorage.java rename src/main/java/com/jozufozu/flywheel/{backend => impl}/instancing/storage/One2OneStorage.java (87%) rename src/main/java/com/jozufozu/flywheel/{backend => impl}/instancing/storage/Storage.java (60%) delete mode 100644 src/main/java/com/jozufozu/flywheel/lib/instance/InstancingControllerHelper.java rename src/main/java/com/jozufozu/flywheel/{api/instancer => lib/struct}/FlatLit.java (75%) diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index b555f6ca2..d1d7a51f7 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -3,17 +3,17 @@ package com.jozufozu.flywheel; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.slf4j.Logger; -import com.jozufozu.flywheel.api.backend.BackendManager; import com.jozufozu.flywheel.backend.Loader; import com.jozufozu.flywheel.backend.engine.batching.DrawBuffer; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.config.BackendArgument; import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.handler.EntityWorldHandler; import com.jozufozu.flywheel.handler.ForgeEvents; +import com.jozufozu.flywheel.impl.BackendManagerImpl; import com.jozufozu.flywheel.impl.IdRegistryImpl; import com.jozufozu.flywheel.impl.RegistryImpl; +import com.jozufozu.flywheel.impl.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.lib.backend.Backends; import com.jozufozu.flywheel.lib.context.Contexts; import com.jozufozu.flywheel.lib.format.Formats; @@ -115,7 +115,7 @@ public class Flywheel { VanillaInstances.init(); - CrashReportCallables.registerCrashCallable("Flywheel Backend", BackendManager::getBackendNameForCrashReport); + CrashReportCallables.registerCrashCallable("Flywheel Backend", BackendManagerImpl::getBackendNameForCrashReport); // https://github.com/Jozufozu/Flywheel/issues/69 // Weird issue with accessor loading. @@ -129,7 +129,7 @@ public class Flywheel { RegistryImpl.freezeAll(); IdRegistryImpl.freezeAll(); - ArgumentTypes.register(rl("backend").toString(), BackendArgument.class, new EmptyArgumentSerializer<>(BackendArgument::getInstance)); + ArgumentTypes.register(rl("backend").toString(), BackendArgument.class, new EmptyArgumentSerializer<>(() -> BackendArgument.INSTANCE)); } public static ArtifactVersion getVersion() { diff --git a/src/main/java/com/jozufozu/flywheel/api/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/api/backend/Backend.java index 0546c3b4f..3a7cfb6bd 100644 --- a/src/main/java/com/jozufozu/flywheel/api/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/api/backend/Backend.java @@ -7,6 +7,7 @@ import com.jozufozu.flywheel.api.registry.IdRegistry; import com.jozufozu.flywheel.impl.IdRegistryImpl; import net.minecraft.network.chat.Component; +import net.minecraft.world.level.LevelAccessor; public interface Backend { static IdRegistry REGISTRY = IdRegistryImpl.create(); @@ -19,7 +20,7 @@ public interface Backend { /** * Create a new engine instance. */ - Engine createEngine(); + Engine createEngine(LevelAccessor level); /** * Get a fallback backend in case this backend is not supported. diff --git a/src/main/java/com/jozufozu/flywheel/api/backend/BackendManager.java b/src/main/java/com/jozufozu/flywheel/api/backend/BackendManager.java index 71c58fa10..5819bea8e 100644 --- a/src/main/java/com/jozufozu/flywheel/api/backend/BackendManager.java +++ b/src/main/java/com/jozufozu/flywheel/api/backend/BackendManager.java @@ -13,13 +13,6 @@ public final class BackendManager { return BackendManagerImpl.getBackend(); } - /** - * Get a string describing the current backend. - */ - public static String getBackendNameForCrashReport() { - return BackendManagerImpl.getBackendNameForCrashReport(); - } - public static boolean isOn() { return BackendManagerImpl.isOn(); } diff --git a/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java b/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java index b77b19e6d..09765ca87 100644 --- a/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java +++ b/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java @@ -2,11 +2,30 @@ package com.jozufozu.flywheel.api.backend; import java.util.List; +import com.jozufozu.flywheel.api.event.RenderContext; +import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instancer.InstancerProvider; -import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager; +import com.jozufozu.flywheel.api.task.TaskExecutor; -public interface Engine extends RenderDispatcher, InstancerProvider { - void attachManagers(InstanceManager... listener); +import net.minecraft.client.Camera; +import net.minecraft.core.Vec3i; + +public interface Engine extends InstancerProvider { + void beginFrame(TaskExecutor executor, RenderContext context); + + void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage); + + /** + * Maintain the render origin to be within a certain distance from the camera in all directions, + * preventing floating point precision issues at high coordinates. + * + * @return {@code true} if the render origin changed, {@code false} otherwise. + */ + boolean updateRenderOrigin(Camera camera); + + Vec3i renderOrigin(); void addDebugInfo(List info); + + void delete(); } diff --git a/src/main/java/com/jozufozu/flywheel/api/backend/RenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/api/backend/RenderDispatcher.java deleted file mode 100644 index 72a8e1560..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/backend/RenderDispatcher.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.jozufozu.flywheel.api.backend; - -import com.jozufozu.flywheel.api.event.RenderContext; -import com.jozufozu.flywheel.api.event.RenderStage; -import com.jozufozu.flywheel.api.task.TaskExecutor; - -import net.minecraft.client.Camera; -import net.minecraft.core.Vec3i; - -public interface RenderDispatcher { - - void beginFrame(TaskExecutor executor, RenderContext context); - - void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage); - - /** - * Maintain the integer origin coordinate to be within a certain distance from the camera in all directions, - * preventing floating point precision issues at high coordinates. - * - * @return {@code true} if the origin coordinate was changed, {@code false} otherwise. - */ - boolean maintainOriginCoordinate(Camera camera); - - Vec3i renderOrigin(); - - void delete(); -} diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java b/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java index 6f49b4f1b..36c8088b8 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.api.instance; +import org.joml.FrustumIntersection; + import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.Instancer; @@ -34,4 +36,13 @@ public interface DynamicInstance extends Instance { default boolean decreaseFramerateWithDistance() { return true; } + + /** + * Check this instance against a frustum.

+ * An implementor may choose to return a constant to skip the frustum check. + * + * @param frustum A frustum intersection tester for the current frame. + * @return {@code true} if this instance should be considered for updates. + */ + boolean isVisible(FrustumIntersection frustum); } diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/EffectInstance.java b/src/main/java/com/jozufozu/flywheel/api/instance/EffectInstance.java new file mode 100644 index 000000000..8289e8938 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/instance/EffectInstance.java @@ -0,0 +1,6 @@ +package com.jozufozu.flywheel.api.instance; + +import com.jozufozu.flywheel.api.instance.effect.Effect; + +public interface EffectInstance extends Instance { +} diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/EntityInstance.java b/src/main/java/com/jozufozu/flywheel/api/instance/EntityInstance.java index 668ffa749..277e25ff2 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/EntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/EntityInstance.java @@ -2,5 +2,5 @@ package com.jozufozu.flywheel.api.instance; import net.minecraft.world.entity.Entity; -public interface EntityInstance extends Instance { +public interface EntityInstance extends Instance { } diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java b/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java index 4e19c9d8e..eb0f5b241 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.api.instance; -import org.joml.FrustumIntersection; - /** * A general interface providing information about any type of thing that could use Flywheel's instanced rendering. */ @@ -33,15 +31,6 @@ public interface Instance { */ boolean shouldReset(); - /** - * Check this instance against a frustum.

- * An implementor may choose to return a constant to skip the frustum check. - * - * @param frustum A frustum intersection tester for the current frame. - * @return {@code true} if this instance should be considered for updates. - */ - boolean checkFrustum(FrustumIntersection frustum); - /** * Calculate the distance squared between this instance and the given world position. * @@ -56,5 +45,4 @@ public interface Instance { * Free any acquired resources. */ void delete(); - } diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/controller/BlockEntityInstancingController.java b/src/main/java/com/jozufozu/flywheel/api/instance/controller/BlockEntityInstancingController.java index c4d32613e..2eae34f2e 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/controller/BlockEntityInstancingController.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/controller/BlockEntityInstancingController.java @@ -10,7 +10,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; */ public interface BlockEntityInstancingController { /** - * Given a block entity and an instancer manager, constructs an instance for the block entity. + * Given a block entity and context, constructs an instance for the block entity. * * @param ctx Context for creating an Instance. * @param blockEntity The block entity to construct an instance for. diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/controller/EntityInstancingController.java b/src/main/java/com/jozufozu/flywheel/api/instance/controller/EntityInstancingController.java index 20eb3e149..c04cb485d 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/controller/EntityInstancingController.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/controller/EntityInstancingController.java @@ -10,7 +10,7 @@ import net.minecraft.world.entity.Entity; */ public interface EntityInstancingController { /** - * Given an entity and an instancer manager, constructs an instance for the entity. + * Given an entity and context, constructs an instance for the entity. * * @param ctx Context for creating an Instance. * @param entity The entity to construct an instance for. diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/controller/InstanceContext.java b/src/main/java/com/jozufozu/flywheel/api/instance/controller/InstanceContext.java index b8bd8ff88..c60772c9a 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/controller/InstanceContext.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/controller/InstanceContext.java @@ -12,5 +12,4 @@ import net.minecraft.core.Vec3i; * All models render as if this position is (0, 0, 0). */ public record InstanceContext(InstancerProvider instancerProvider, Vec3i renderOrigin) { - } diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/controller/InstancingControllerRegistry.java b/src/main/java/com/jozufozu/flywheel/api/instance/controller/InstancingControllerRegistry.java index c51759d92..30b8d0614 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/controller/InstancingControllerRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/controller/InstancingControllerRegistry.java @@ -2,7 +2,7 @@ package com.jozufozu.flywheel.api.instance.controller; import org.jetbrains.annotations.Nullable; -import com.jozufozu.flywheel.impl.instance.InstancingControllerRegistryImpl; +import com.jozufozu.flywheel.impl.InstancingControllerRegistryImpl; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/effect/Effect.java b/src/main/java/com/jozufozu/flywheel/api/instance/effect/Effect.java index 16cb49e3c..546bcac05 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/effect/Effect.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/effect/Effect.java @@ -2,9 +2,11 @@ package com.jozufozu.flywheel.api.instance.effect; import java.util.Collection; -import com.jozufozu.flywheel.api.instance.Instance; +import com.jozufozu.flywheel.api.instance.EffectInstance; import com.jozufozu.flywheel.api.instance.controller.InstanceContext; +// TODO: add level getter? +// TODO: return single instance instead of many? public interface Effect { - Collection createInstances(InstanceContext ctx); + Collection> createInstances(InstanceContext ctx); } diff --git a/src/main/java/com/jozufozu/flywheel/api/instancer/InstancerProvider.java b/src/main/java/com/jozufozu/flywheel/api/instancer/InstancerProvider.java index f9317ebbf..74338c8fb 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instancer/InstancerProvider.java +++ b/src/main/java/com/jozufozu/flywheel/api/instancer/InstancerProvider.java @@ -10,5 +10,5 @@ public interface InstancerProvider { * * @return An instancer for the given struct type, model, and render stage. */ - Instancer getInstancer(StructType type, Model model, RenderStage stage); + Instancer instancer(StructType type, Model model, RenderStage stage); } diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProvider.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProvider.java index 8a8428ab7..a200e03ad 100644 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProvider.java +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProvider.java @@ -1,23 +1,5 @@ package com.jozufozu.flywheel.api.vertex; -import com.jozufozu.flywheel.extension.VertexFormatExtension; -import com.jozufozu.flywheel.impl.vertex.InferredVertexListProviderImpl; -import com.mojang.blaze3d.vertex.VertexFormat; - public interface VertexListProvider { ReusableVertexList createVertexList(); - - static VertexListProvider get(VertexFormat format) { - VertexFormatExtension extension = (VertexFormatExtension) format; - VertexListProvider provider = extension.flywheel$getVertexListProvider(); - if (provider == null) { - provider = new InferredVertexListProviderImpl(format); - extension.flywheel$setVertexListProvider(provider); - } - return provider; - } - - static void set(VertexFormat format, VertexListProvider provider) { - ((VertexFormatExtension) format).flywheel$setVertexListProvider(provider); - } } diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProviderRegistry.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProviderRegistry.java new file mode 100644 index 000000000..7307a5bf0 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProviderRegistry.java @@ -0,0 +1,17 @@ +package com.jozufozu.flywheel.api.vertex; + +import com.jozufozu.flywheel.impl.VertexListProviderRegistryImpl; +import com.mojang.blaze3d.vertex.VertexFormat; + +public final class VertexListProviderRegistry { + public static VertexListProvider getProvider(VertexFormat format) { + return VertexListProviderRegistryImpl.getProvider(format); + } + + public static void setProvider(VertexFormat format, VertexListProvider provider) { + VertexListProviderRegistryImpl.setProvider(format, provider); + } + + private VertexListProviderRegistry() { + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/BackendUtil.java b/src/main/java/com/jozufozu/flywheel/backend/BackendUtil.java index 6105c98db..15fc3e3e6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/BackendUtil.java +++ b/src/main/java/com/jozufozu/flywheel/backend/BackendUtil.java @@ -8,12 +8,9 @@ import com.jozufozu.flywheel.api.backend.BackendManager; import com.jozufozu.flywheel.backend.task.ParallelTaskExecutor; import net.minecraft.client.Minecraft; -import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; public class BackendUtil { - public static final boolean DUMP_SHADER_SOURCE = System.getProperty("flw.dumpShaderSource") != null; - private static ParallelTaskExecutor executor; /** @@ -30,7 +27,7 @@ public class BackendUtil { } @Contract("null -> false") - public static boolean canUseInstancing(@Nullable Level level) { + public static boolean canUseInstancing(@Nullable LevelAccessor level) { return BackendManager.isOn() && isFlywheelLevel(level); } @@ -38,11 +35,17 @@ public class BackendUtil { * Used to avoid calling Flywheel functions on (fake) levels that don't specifically support it. */ public static boolean isFlywheelLevel(@Nullable LevelAccessor level) { - if (level == null) return false; + if (level == null) { + return false; + } - if (!level.isClientSide()) return false; + if (!level.isClientSide()) { + return false; + } - if (level instanceof FlywheelLevel && ((FlywheelLevel) level).supportsFlywheel()) return true; + if (level instanceof FlywheelLevel flywheelLevel && flywheelLevel.supportsFlywheel()) { + return true; + } return level == Minecraft.getInstance().level; } @@ -50,8 +53,4 @@ public class BackendUtil { public static boolean isGameActive() { return !(Minecraft.getInstance().level == null || Minecraft.getInstance().player == null); } - - public static void reloadWorldRenderers() { - Minecraft.getInstance().levelRenderer.allChanged(); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 3d3650bf7..69f72dbbe 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -2,9 +2,9 @@ package com.jozufozu.flywheel.backend; import com.jozufozu.flywheel.api.backend.BackendManager; import com.jozufozu.flywheel.backend.compile.FlwCompiler; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.glsl.ShaderSources; import com.jozufozu.flywheel.glsl.error.ErrorReporter; +import com.jozufozu.flywheel.impl.instancing.InstancedRenderDispatcher; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; @@ -39,8 +39,8 @@ public class Loader implements ResourceManagerReloadListener { FlwCompiler.INSTANCE = new FlwCompiler(sources); ClientLevel level = Minecraft.getInstance().level; - if (BackendUtil.canUseInstancing(level)) { - InstancedRenderDispatcher.resetInstanceLevel(level); + if (level != null) { + InstancedRenderDispatcher.resetInstanceWorld(level); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/Compilation.java b/src/main/java/com/jozufozu/flywheel/backend/compile/Compilation.java index 52ae6c39d..281541c1e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/Compilation.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/Compilation.java @@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull; import org.lwjgl.opengl.GL20; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.backend.BackendUtil; import com.jozufozu.flywheel.gl.GLSLVersion; import com.jozufozu.flywheel.gl.shader.GlShader; import com.jozufozu.flywheel.gl.shader.ShaderType; @@ -29,6 +28,8 @@ import net.minecraft.resources.ResourceLocation; * and interprets/pretty prints any errors that occur. */ public class Compilation { + public static final boolean DUMP_SHADER_SOURCE = System.getProperty("flw.dumpShaderSource") != null; + private final List files = new ArrayList<>(); private final List componentNames = new ArrayList<>(); private final StringBuilder generatedSource; @@ -131,7 +132,7 @@ public class Compilation { } private static void dumpSource(String source, String fileName) { - if (!BackendUtil.DUMP_SHADER_SOURCE) { + if (!DUMP_SHADER_SOURCE) { return; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchedMeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchedMeshPool.java index 777e1473c..5bddbf1af 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchedMeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchedMeshPool.java @@ -11,7 +11,7 @@ import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.vertex.ReusableVertexList; -import com.jozufozu.flywheel.api.vertex.VertexListProvider; +import com.jozufozu.flywheel.api.vertex.VertexListProviderRegistry; import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.mojang.blaze3d.vertex.VertexFormat; @@ -35,7 +35,7 @@ public class BatchedMeshPool { */ public BatchedMeshPool(VertexFormat vertexFormat) { this.vertexFormat = vertexFormat; - vertexList = VertexListProvider.get(vertexFormat).createVertexList(); + vertexList = VertexListProviderRegistry.getProvider(vertexFormat).createVertexList(); growthMargin = vertexFormat.getVertexSize() * 32; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchingEngine.java index 2c1b06a22..bf55fbde6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchingEngine.java @@ -10,7 +10,6 @@ import com.jozufozu.flywheel.api.instancer.Instancer; import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.task.TaskExecutor; -import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager; import com.jozufozu.flywheel.util.FlwUtil; import com.mojang.blaze3d.vertex.PoseStack; @@ -21,11 +20,11 @@ import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; public class BatchingEngine implements Engine { - protected final BatchingTransformManager transformManager = new BatchingTransformManager(); - protected final BatchingDrawTracker drawTracker = new BatchingDrawTracker(); + private final BatchingTransformManager transformManager = new BatchingTransformManager(); + private final BatchingDrawTracker drawTracker = new BatchingDrawTracker(); @Override - public Instancer getInstancer(StructType type, Model model, RenderStage stage) { + public Instancer instancer(StructType type, Model model, RenderStage stage) { return transformManager.getInstancer(type, model, stage); } @@ -42,7 +41,7 @@ public class BatchingEngine implements Engine { submitTasks(executor, stack.last(), context.level()); } - public void submitTasks(TaskExecutor executor, PoseStack.Pose matrices, ClientLevel level) { + private void submitTasks(TaskExecutor executor, PoseStack.Pose matrices, ClientLevel level) { for (var transformSetEntry : transformManager.getTransformSetsView().entrySet()) { var stage = transformSetEntry.getKey(); var transformSet = transformSetEntry.getValue(); @@ -79,16 +78,10 @@ public class BatchingEngine implements Engine { } @Override - public boolean maintainOriginCoordinate(Camera camera) { - // do nothing + public boolean updateRenderOrigin(Camera camera) { return false; } - @Override - public void attachManagers(InstanceManager... listener) { - // noop - } - @Override public Vec3i renderOrigin() { return BlockPos.ZERO; diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/DrawBufferSet.java b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/DrawBufferSet.java index 2d9b1630f..c4c15093f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/DrawBufferSet.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/DrawBufferSet.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.ApiStatus; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.vertex.VertexListProvider; +import com.jozufozu.flywheel.api.vertex.VertexListProviderRegistry; import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.client.renderer.RenderType; @@ -24,7 +25,7 @@ public class DrawBufferSet { this.renderType = renderType; format = renderType.format(); stride = format.getVertexSize(); - provider = VertexListProvider.get(format); + provider = VertexListProviderRegistry.getProvider(format); } public DrawBuffer getBuffer(RenderStage stage) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java index 1fbd843fc..207766137 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java @@ -1,13 +1,10 @@ package com.jozufozu.flywheel.backend.engine.indirect; -import java.util.Collections; import java.util.List; -import java.util.Set; import org.lwjgl.opengl.GL32; import com.jozufozu.flywheel.api.backend.Engine; -import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instancer.InstancedPart; @@ -15,40 +12,29 @@ import com.jozufozu.flywheel.api.instancer.Instancer; import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.task.TaskExecutor; -import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager; import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.GlTextureUnit; -import com.jozufozu.flywheel.util.FlwUtil; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.core.Vec3i; -import net.minecraft.util.Mth; import net.minecraft.world.phys.Vec3; public class IndirectEngine implements Engine { + private final int sqrMaxOriginDistance; - protected final IndirectDrawManager drawManager = new IndirectDrawManager(); + private final IndirectDrawManager drawManager = new IndirectDrawManager(); - /** - * The set of instance managers that are attached to this engine. - */ - private final Set> instanceManagers = FlwUtil.createWeakHashSet(); + private BlockPos renderOrigin = BlockPos.ZERO; - protected final Context context; - protected final int sqrMaxOriginDistance; - - protected BlockPos originCoordinate = BlockPos.ZERO; - - public IndirectEngine(Context context, int sqrMaxOriginDistance) { - this.context = context; - this.sqrMaxOriginDistance = sqrMaxOriginDistance; + public IndirectEngine(int maxOriginDistance) { + this.sqrMaxOriginDistance = maxOriginDistance * maxOriginDistance; } @Override - public Instancer getInstancer(StructType type, Model model, RenderStage stage) { + public Instancer instancer(StructType type, Model model, RenderStage stage) { return drawManager.getInstancer(type, model, stage); } @@ -70,7 +56,7 @@ public class IndirectEngine implements Engine { } } - protected void setup() { + private void setup() { GlTextureUnit.T2.makeActive(); Minecraft.getInstance().gameRenderer.lightTexture().turnOnLightLayer(); @@ -82,36 +68,25 @@ public class IndirectEngine implements Engine { } @Override - public boolean maintainOriginCoordinate(Camera camera) { + public boolean updateRenderOrigin(Camera camera) { Vec3 cameraPos = camera.getPosition(); + double dx = renderOrigin.getX() - cameraPos.x; + double dy = renderOrigin.getY() - cameraPos.y; + double dz = renderOrigin.getZ() - cameraPos.z; + double distanceSqr = dx * dx + dy * dy + dz * dz; - double distanceSqr = Vec3.atLowerCornerOf(originCoordinate) - .subtract(cameraPos) - .lengthSqr(); - - if (distanceSqr > sqrMaxOriginDistance) { - shiftListeners(Mth.floor(cameraPos.x), Mth.floor(cameraPos.y), Mth.floor(cameraPos.z)); - return true; + if (distanceSqr <= sqrMaxOriginDistance) { + return false; } - return false; - } - - private void shiftListeners(int cX, int cY, int cZ) { - originCoordinate = new BlockPos(cX, cY, cZ); + renderOrigin = new BlockPos(cameraPos); drawManager.clearInstancers(); - - instanceManagers.forEach(InstanceManager::onOriginShift); - } - - @Override - public void attachManagers(InstanceManager... listener) { - Collections.addAll(instanceManagers, listener); + return true; } @Override public Vec3i renderOrigin() { - return originCoordinate; + return renderOrigin; } @Override @@ -122,6 +97,6 @@ public class IndirectEngine implements Engine { @Override public void addDebugInfo(List info) { info.add("GL46 Indirect"); - info.add("Origin: " + originCoordinate.getX() + ", " + originCoordinate.getY() + ", " + originCoordinate.getZ()); + info.add("Origin: " + renderOrigin.getX() + ", " + renderOrigin.getY() + ", " + renderOrigin.getZ()); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java index 197349828..639d3e771 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java @@ -1,8 +1,6 @@ package com.jozufozu.flywheel.backend.engine.instancing; -import java.util.Collections; import java.util.List; -import java.util.Set; import org.lwjgl.opengl.GL32; @@ -17,42 +15,33 @@ import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.backend.compile.FlwCompiler; import com.jozufozu.flywheel.backend.engine.UniformBuffer; -import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager; import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.GlTextureUnit; import com.jozufozu.flywheel.lib.material.MaterialIndices; import com.jozufozu.flywheel.lib.pipeline.Pipelines; -import com.jozufozu.flywheel.util.FlwUtil; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.core.Vec3i; -import net.minecraft.util.Mth; import net.minecraft.world.phys.Vec3; public class InstancingEngine implements Engine { + private final Context context; + private final int sqrMaxOriginDistance; - protected final InstancingDrawManager drawManager = new InstancingDrawManager(); + private final InstancingDrawManager drawManager = new InstancingDrawManager(); - /** - * The set of instance managers that are attached to this engine. - */ - private final Set> instanceManagers = FlwUtil.createWeakHashSet(); + private BlockPos renderOrigin = BlockPos.ZERO; - protected final Context context; - protected final int sqrMaxOriginDistance; - - protected BlockPos originCoordinate = BlockPos.ZERO; - - public InstancingEngine(Context context, int sqrMaxOriginDistance) { + public InstancingEngine(Context context, int maxOriginDistance) { this.context = context; - this.sqrMaxOriginDistance = sqrMaxOriginDistance; + this.sqrMaxOriginDistance = maxOriginDistance * maxOriginDistance; } @Override - public Instancer getInstancer(StructType type, Model model, RenderStage stage) { + public Instancer instancer(StructType type, Model model, RenderStage stage) { return drawManager.getInstancer(type, model, stage); } @@ -78,7 +67,7 @@ public class InstancingEngine implements Engine { } } - protected void setup() { + private void setup() { GlTextureUnit.T2.makeActive(); Minecraft.getInstance().gameRenderer.lightTexture().turnOnLightLayer(); @@ -89,7 +78,7 @@ public class InstancingEngine implements Engine { RenderSystem.enableCull(); } - protected void render(InstancingDrawManager.DrawSet drawSet) { + private void render(InstancingDrawManager.DrawSet drawSet) { for (var entry : drawSet) { var shader = entry.getKey(); var drawCalls = entry.getValue(); @@ -112,7 +101,7 @@ public class InstancingEngine implements Engine { } } - protected void setup(ShaderState desc) { + private void setup(ShaderState desc) { var vertexType = desc.vertex(); var structType = desc.instance(); var material = desc.material(); @@ -127,36 +116,25 @@ public class InstancingEngine implements Engine { } @Override - public boolean maintainOriginCoordinate(Camera camera) { + public boolean updateRenderOrigin(Camera camera) { Vec3 cameraPos = camera.getPosition(); + double dx = renderOrigin.getX() - cameraPos.x; + double dy = renderOrigin.getY() - cameraPos.y; + double dz = renderOrigin.getZ() - cameraPos.z; + double distanceSqr = dx * dx + dy * dy + dz * dz; - double distanceSqr = Vec3.atLowerCornerOf(originCoordinate) - .subtract(cameraPos) - .lengthSqr(); - - if (distanceSqr > sqrMaxOriginDistance) { - shiftListeners(Mth.floor(cameraPos.x), Mth.floor(cameraPos.y), Mth.floor(cameraPos.z)); - return true; + if (distanceSqr <= sqrMaxOriginDistance) { + return false; } - return false; - } - - private void shiftListeners(int cX, int cY, int cZ) { - originCoordinate = new BlockPos(cX, cY, cZ); + renderOrigin = new BlockPos(cameraPos); drawManager.clearInstancers(); - - instanceManagers.forEach(InstanceManager::onOriginShift); - } - - @Override - public void attachManagers(InstanceManager... listener) { - Collections.addAll(instanceManagers, listener); + return true; } @Override public Vec3i renderOrigin() { - return originCoordinate; + return renderOrigin; } @Override @@ -167,6 +145,6 @@ 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("Origin: " + renderOrigin.getX() + ", " + renderOrigin.getY() + ", " + renderOrigin.getZ()); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java deleted file mode 100644 index add8a8e18..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing; - -import com.jozufozu.flywheel.api.backend.BackendManager; -import com.jozufozu.flywheel.api.backend.Engine; -import com.jozufozu.flywheel.api.event.BeginFrameEvent; -import com.jozufozu.flywheel.api.event.RenderContext; -import com.jozufozu.flywheel.api.event.RenderStage; -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.api.instance.TickableInstance; -import com.jozufozu.flywheel.api.instance.effect.Effect; -import com.jozufozu.flywheel.backend.BackendUtil; -import com.jozufozu.flywheel.backend.instancing.manager.BlockEntityInstanceManager; -import com.jozufozu.flywheel.backend.instancing.manager.EffectInstanceManager; -import com.jozufozu.flywheel.backend.instancing.manager.EntityInstanceManager; -import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager; -import com.jozufozu.flywheel.backend.task.ParallelTaskExecutor; -import com.jozufozu.flywheel.extension.ClientLevelExtension; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.entity.BlockEntity; - -/** - * A manager class for a single world where instancing is supported. - *

- * The instancer manager is shared between the different instance managers. - *

- */ -public class InstanceWorld implements AutoCloseable { - protected final Engine engine; - protected final InstanceManager entities; - protected final InstanceManager blockEntities; - - public final ParallelTaskExecutor taskExecutor; - private final InstanceManager effects; - - public static InstanceWorld create(LevelAccessor level) { - var engine = BackendManager.getBackend() - .createEngine(); - - var entities = new EntityInstanceManager(engine); - var blockEntities = new BlockEntityInstanceManager(engine); - var effects = new EffectInstanceManager(engine); - - engine.attachManagers(entities, blockEntities, effects); - - return new InstanceWorld(engine, entities, blockEntities, effects); - } - - public InstanceWorld(Engine engine, InstanceManager entities, InstanceManager blockEntities, - InstanceManager effects) { - this.engine = engine; - this.entities = entities; - this.blockEntities = blockEntities; - this.effects = effects; - this.taskExecutor = BackendUtil.getTaskExecutor(); - } - - public InstanceManager getEntities() { - return entities; - } - - public InstanceManager getEffects() { - return effects; - } - - public InstanceManager getBlockEntities() { - return blockEntities; - } - - /** - * Free all acquired resources and invalidate this instance world. - */ - public void delete() { - engine.delete(); - entities.delete(); - blockEntities.delete(); - } - - /** - * Get ready to render a frame. - *

- * Check and shift the origin coordinate. - *
- * Call {@link DynamicInstance#beginFrame()} on all instances in this world. - *

- */ - public void beginFrame(BeginFrameEvent event) { - RenderContext context = event.getContext(); - boolean shifted = engine.maintainOriginCoordinate(context.camera()); - - taskExecutor.syncPoint(); - - if (!shifted) { - blockEntities.beginFrame(taskExecutor, context); - entities.beginFrame(taskExecutor, context); - effects.beginFrame(taskExecutor, context); - } - - engine.beginFrame(taskExecutor, context); - } - - /** - * Tick the renderers after the game has ticked: - *

- * Call {@link TickableInstance#tick()} on all instances in this world. - *

- */ - public void tick() { - Minecraft mc = Minecraft.getInstance(); - - if (mc.isPaused()) return; - - Entity renderViewEntity = mc.cameraEntity != null ? mc.cameraEntity : mc.player; - - if (renderViewEntity == null) return; - - double x = renderViewEntity.getX(); - double y = renderViewEntity.getY(); - double z = renderViewEntity.getZ(); - - blockEntities.tick(taskExecutor, x, y, z); - entities.tick(taskExecutor, x, y, z); - effects.tick(taskExecutor, x, y, z); - } - - /** - * Draw all instances for the given stage. - */ - public void renderStage(RenderContext context, RenderStage stage) { - taskExecutor.syncPoint(); - engine.renderStage(taskExecutor, context, stage); - } - - /** - * Instantiate all the necessary instances to render the given world. - */ - public void loadEntities(ClientLevel level) { - // Block entities are loaded while chunks are baked. - // Entities are loaded with the level, so when chunks are reloaded they need to be re-added. - ClientLevelExtension.getAllLoadedEntities(level) - .forEach(entities::add); - } - - @Override - public void close() { - delete(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java deleted file mode 100644 index ecea90a82..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ /dev/null @@ -1,133 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing; - -import java.util.List; - -import com.jozufozu.flywheel.api.backend.BackendManager; -import com.jozufozu.flywheel.api.event.BeginFrameEvent; -import com.jozufozu.flywheel.api.event.ReloadRenderersEvent; -import com.jozufozu.flywheel.api.event.RenderStageEvent; -import com.jozufozu.flywheel.api.instance.Instance; -import com.jozufozu.flywheel.api.instance.effect.Effect; -import com.jozufozu.flywheel.backend.BackendUtil; -import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager; -import com.jozufozu.flywheel.config.FlwCommands; -import com.jozufozu.flywheel.config.FlwConfig; -import com.jozufozu.flywheel.util.AnimationTickHolder; -import com.jozufozu.flywheel.util.WorldAttached; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.core.Vec3i; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.event.TickEvent; - -public class InstancedRenderDispatcher { - - private static final WorldAttached instanceWorlds = new WorldAttached<>(InstanceWorld::create); - - /** - * Call this when you want to manually run {@link Instance#update()}. - * @param blockEntity The block entity whose instance you want to update. - */ - public static void enqueueUpdate(BlockEntity blockEntity) { - if (BackendManager.isOn() && blockEntity.hasLevel() && blockEntity.getLevel() instanceof ClientLevel) { - instanceWorlds.get(blockEntity.getLevel()) - .getBlockEntities() - .queueUpdate(blockEntity); - } - } - - /** - * Call this when you want to manually run {@link Instance#update()}. - * @param entity The entity whose instance you want to update. - */ - public static void enqueueUpdate(Entity entity) { - if (BackendManager.isOn()) { - instanceWorlds.get(entity.level) - .getEntities() - .queueUpdate(entity); - } - } - - public static InstanceManager getBlockEntities(LevelAccessor world) { - return getInstanceWorld(world).getBlockEntities(); - } - - public static InstanceManager getEntities(LevelAccessor world) { - return getInstanceWorld(world).getEntities(); - } - - public static InstanceManager getEffects(LevelAccessor world) { - return getInstanceWorld(world).getEffects(); - } - - /** - * Get or create the {@link InstanceWorld} for the given world. - * @throws NullPointerException if the backend is off - */ - public static InstanceWorld getInstanceWorld(LevelAccessor world) { - if (BackendManager.isOn()) { - return instanceWorlds.get(world); - } else { - throw new NullPointerException("Backend is off, cannot retrieve instance world."); - } - } - - public static void tick(TickEvent.ClientTickEvent event) { - if (!BackendUtil.isGameActive() || event.phase == TickEvent.Phase.START) { - return; - } - Minecraft mc = Minecraft.getInstance(); - ClientLevel level = mc.level; - AnimationTickHolder.tick(); - - if (BackendManager.isOn()) { - instanceWorlds.get(level) - .tick(); - } - } - - public static void onBeginFrame(BeginFrameEvent event) { - if (BackendUtil.isGameActive() && BackendManager.isOn()) { - instanceWorlds.get(event.getContext().level()) - .beginFrame(event); - } - } - - public static void onRenderStage(RenderStageEvent event) { - ClientLevel level = event.getContext().level(); - if (!BackendUtil.canUseInstancing(level)) return; - - instanceWorlds.get(level).renderStage(event.getContext(), event.getStage()); - } - - public static void onReloadRenderers(ReloadRenderersEvent event) { - ClientLevel level = event.getLevel(); - if (BackendManager.isOn() && level != null) { - resetInstanceLevel(level); - } - } - - public static void resetInstanceLevel(ClientLevel level) { - instanceWorlds.replace(level, InstanceWorld::delete) - .loadEntities(level); - } - - public static void getDebugString(List debug) { - if (BackendManager.isOn()) { - InstanceWorld instanceWorld = instanceWorlds.get(Minecraft.getInstance().level); - - debug.add("Update limiting: " + FlwCommands.boolToText(FlwConfig.get().limitUpdates()).getString()); - debug.add("B: " + instanceWorld.blockEntities.getInstanceCount() + ", E: " + instanceWorld.entities.getInstanceCount()); - instanceWorld.engine.addDebugInfo(debug); - } else { - debug.add("Disabled"); - } - } - - public static Vec3i getOriginCoordinate(ClientLevel level) { - return instanceWorlds.get(level).engine.renderOrigin(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/manager/EffectInstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/manager/EffectInstanceManager.java deleted file mode 100644 index 52447562c..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/manager/EffectInstanceManager.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.manager; - -import java.util.ArrayList; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.jozufozu.flywheel.api.backend.Engine; -import com.jozufozu.flywheel.api.instance.Instance; -import com.jozufozu.flywheel.api.instance.controller.InstanceContext; -import com.jozufozu.flywheel.api.instance.effect.Effect; -import com.jozufozu.flywheel.backend.instancing.storage.AbstractStorage; -import com.jozufozu.flywheel.backend.instancing.storage.Storage; - -public class EffectInstanceManager extends InstanceManager { - private final EffectStorage storage; - - public EffectInstanceManager(Engine engine) { - storage = new EffectStorage<>(engine); - } - - @Override - protected Storage getStorage() { - return storage; - } - - @Override - protected boolean canCreateInstance(Effect obj) { - return true; - } - - private static class EffectStorage extends AbstractStorage { - private final Multimap instances; - - public EffectStorage(Engine engine) { - super(engine); - this.instances = HashMultimap.create(); - } - - @Override - public Iterable getAllInstances() { - return instances.values(); - } - - @Override - public int getInstanceCount() { - return instances.size(); - } - - @Override - public void add(T obj) { - var instances = this.instances.get(obj); - - if (instances.isEmpty()) { - create(obj); - } - } - - @Override - public void remove(T obj) { - var instances = this.instances.removeAll(obj); - - if (instances.isEmpty()) { - return; - } - - this.tickableInstances.removeAll(instances); - this.dynamicInstances.removeAll(instances); - for (Instance instance : instances) { - instance.delete(); - } - } - - @Override - public void update(T obj) { - var instances = this.instances.get(obj); - - if (instances.isEmpty()) { - return; - } - - instances.forEach(Instance::update); - } - - @Override - public void recreateAll() { - tickableInstances.clear(); - dynamicInstances.clear(); - instances.values().forEach(Instance::delete); - - var backup = new ArrayList<>(instances.keySet()); - instances.clear(); - backup.forEach(this::create); - } - - @Override - public void invalidate() { - instances.values().forEach(Instance::delete); - instances.clear(); - tickableInstances.clear(); - dynamicInstances.clear(); - } - - private void create(T obj) { - var instances = obj.createInstances(new InstanceContext(engine, engine.renderOrigin())); - - this.instances.putAll(obj, instances); - - instances.forEach(this::setup); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/config/BackendArgument.java b/src/main/java/com/jozufozu/flywheel/config/BackendArgument.java index 86b0a99d9..64e2bd23d 100644 --- a/src/main/java/com/jozufozu/flywheel/config/BackendArgument.java +++ b/src/main/java/com/jozufozu/flywheel/config/BackendArgument.java @@ -17,9 +17,7 @@ import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; -public enum BackendArgument implements ArgumentType { - INSTANCE; - +public class BackendArgument implements ArgumentType { private static final List STRING_IDS = Backend.REGISTRY.getAllIds().stream().map(ResourceLocation::toString).toList(); private static final Dynamic2CommandExceptionType INVALID = new Dynamic2CommandExceptionType((found, constants) -> { @@ -27,9 +25,7 @@ public enum BackendArgument implements ArgumentType { return new TranslatableComponent("commands.forge.arguments.enum.invalid", constants, found); }); - public static BackendArgument getInstance() { - return INSTANCE; - } + public static final BackendArgument INSTANCE = new BackendArgument(); @Override public Backend parse(StringReader reader) throws CommandSyntaxException { diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java index 6b6cf650c..b642e7d5d 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java @@ -3,10 +3,8 @@ package com.jozufozu.flywheel.config; import java.util.function.BiConsumer; import com.jozufozu.flywheel.api.backend.Backend; -import com.jozufozu.flywheel.backend.BackendUtil; import com.jozufozu.flywheel.lib.uniform.FlwShaderUniforms; import com.mojang.brigadier.Command; -import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; @@ -30,9 +28,9 @@ public class FlwCommands { public static void registerClientCommands(RegisterClientCommandsEvent event) { FlwConfig config = FlwConfig.get(); - ConfigCommandBuilder commandBuilder = new ConfigCommandBuilder("flywheel"); + LiteralArgumentBuilder command = Commands.literal("flywheel"); - commandBuilder.addValue(config.client.backend, "backend", (builder, value) -> + addValue(command, config.client.backend, "backend", (builder, value) -> builder .executes(context -> { LocalPlayer player = Minecraft.getInstance().player; @@ -68,12 +66,12 @@ public class FlwCommands { Component message = backend.engineMessage(); player.displayClientMessage(message, false); - BackendUtil.reloadWorldRenderers(); + Minecraft.getInstance().levelRenderer.allChanged(); } return Command.SINGLE_SUCCESS; }))); - commandBuilder.addValue(config.client.limitUpdates, "limitUpdates", (builder, value) -> booleanValueCommand(builder, value, + addValue(command, config.client.limitUpdates, "limitUpdates", (builder, value) -> booleanValueCommand(builder, value, (source, bool) -> { LocalPlayer player = Minecraft.getInstance().player; if (player == null) return; @@ -88,12 +86,12 @@ public class FlwCommands { Component text = boolToText(bool).append(new TextComponent(" update limiting.").withStyle(ChatFormatting.WHITE)); player.displayClientMessage(text, false); - BackendUtil.reloadWorldRenderers(); + Minecraft.getInstance().levelRenderer.allChanged(); } )); // TODO - commandBuilder.command.then(Commands.literal("debugNormals")) + command.then(Commands.literal("debugNormals")) .executes(context -> { LocalPlayer player = Minecraft.getInstance().player; if (player == null) return 0; @@ -103,7 +101,7 @@ public class FlwCommands { return Command.SINGLE_SUCCESS; }); - commandBuilder.command.then(Commands.literal("debugCrumbling") + command.then(Commands.literal("debugCrumbling") .then(Commands.argument("pos", BlockPosArgument.blockPos()) .then(Commands.argument("stage", IntegerArgumentType.integer(0, 9)) .executes(context -> { @@ -122,7 +120,7 @@ public class FlwCommands { return Command.SINGLE_SUCCESS; })))); - commandBuilder.command.then(Commands.literal("debugFrustum") + command.then(Commands.literal("debugFrustum") .then(Commands.literal("pause") .executes(context -> { FlwShaderUniforms.FRUSTUM_PAUSED = true; @@ -139,10 +137,16 @@ public class FlwCommands { return 1; }))); - commandBuilder.build(event.getDispatcher()); + event.getDispatcher().register(command); } - public static void booleanValueCommand(LiteralArgumentBuilder builder, ConfigValue value, BiConsumer displayAction, BiConsumer setAction) { + private static > void addValue(LiteralArgumentBuilder command, T value, String subcommand, BiConsumer, T> consumer) { + LiteralArgumentBuilder builder = Commands.literal(subcommand); + consumer.accept(builder, value); + command.then(builder); + } + + private static void booleanValueCommand(LiteralArgumentBuilder builder, ConfigValue value, BiConsumer displayAction, BiConsumer setAction) { builder .executes(context -> { displayAction.accept(context.getSource(), value.get()); @@ -165,22 +169,4 @@ public class FlwCommands { public static MutableComponent boolToText(boolean b) { return b ? new TextComponent("enabled").withStyle(ChatFormatting.DARK_GREEN) : new TextComponent("disabled").withStyle(ChatFormatting.RED); } - - 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/handler/EntityWorldHandler.java b/src/main/java/com/jozufozu/flywheel/handler/EntityWorldHandler.java index d0889e5ca..fd4895fda 100644 --- a/src/main/java/com/jozufozu/flywheel/handler/EntityWorldHandler.java +++ b/src/main/java/com/jozufozu/flywheel/handler/EntityWorldHandler.java @@ -1,19 +1,34 @@ package com.jozufozu.flywheel.handler; -import com.jozufozu.flywheel.api.backend.BackendManager; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.backend.BackendUtil; +import com.jozufozu.flywheel.impl.instancing.InstancedRenderDispatcher; +import net.minecraft.world.level.Level; import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.event.entity.EntityLeaveWorldEvent; public class EntityWorldHandler { public static void onEntityJoinWorld(EntityJoinWorldEvent event) { - if (event.getWorld().isClientSide && BackendManager.isOn()) InstancedRenderDispatcher.getEntities(event.getWorld()) - .queueAdd(event.getEntity()); + Level level = event.getWorld(); + if (!level.isClientSide) { + return; + } + + if (BackendUtil.canUseInstancing(level)) { + InstancedRenderDispatcher.getEntities(level) + .queueAdd(event.getEntity()); + } } public static void onEntityLeaveWorld(EntityLeaveWorldEvent event) { - if (event.getWorld().isClientSide && BackendManager.isOn()) InstancedRenderDispatcher.getEntities(event.getWorld()) - .remove(event.getEntity()); + Level level = event.getWorld(); + if (!level.isClientSide) { + return; + } + + if (BackendUtil.canUseInstancing(level)) { + InstancedRenderDispatcher.getEntities(level) + .remove(event.getEntity()); + } } } diff --git a/src/main/java/com/jozufozu/flywheel/handler/ForgeEvents.java b/src/main/java/com/jozufozu/flywheel/handler/ForgeEvents.java index 6d8ca0e17..61e78fdc1 100644 --- a/src/main/java/com/jozufozu/flywheel/handler/ForgeEvents.java +++ b/src/main/java/com/jozufozu/flywheel/handler/ForgeEvents.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.BackendUtil; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.impl.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.lib.light.LightUpdater; import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker; import com.jozufozu.flywheel.util.StringUtil; @@ -16,14 +16,13 @@ import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.world.WorldEvent; public class ForgeEvents { - public static void addToDebugScreen(RenderGameOverlayEvent.Text event) { if (Minecraft.getInstance().options.renderDebug) { ArrayList debug = event.getRight(); debug.add(""); debug.add("Flywheel: " + Flywheel.getVersion()); - InstancedRenderDispatcher.getDebugString(debug); + InstancedRenderDispatcher.addDebugInfo(debug); debug.add("Memory Usage: CPU: " + StringUtil.formatBytes(FlwMemoryTracker.getCPUMemory()) + ", GPU: " + StringUtil.formatBytes(FlwMemoryTracker.getGPUMemory())); } @@ -39,5 +38,4 @@ public class ForgeEvents { .tick(); } } - } diff --git a/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java b/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java index 6c6367443..c7a573b22 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java +++ b/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java @@ -18,17 +18,6 @@ public final class BackendManagerImpl { return backend; } - public static String getBackendNameForCrashReport() { - if (backend == null) { - return "Uninitialized"; - } - var backendId = Backend.REGISTRY.getId(backend); - if (backendId == null) { - return "Unregistered"; - } - return backendId.toString(); - } - public static boolean isOn() { return backend != null && backend != Backends.OFF; } @@ -58,6 +47,17 @@ public final class BackendManagerImpl { return Backends.INDIRECT; } + public static String getBackendNameForCrashReport() { + if (backend == null) { + return "Uninitialized"; + } + var backendId = Backend.REGISTRY.getId(backend); + if (backendId == null) { + return "Unregistered"; + } + return backendId.toString(); + } + private BackendManagerImpl() { } } diff --git a/src/main/java/com/jozufozu/flywheel/impl/instance/InstancingControllerRegistryImpl.java b/src/main/java/com/jozufozu/flywheel/impl/InstancingControllerRegistryImpl.java similarity index 96% rename from src/main/java/com/jozufozu/flywheel/impl/instance/InstancingControllerRegistryImpl.java rename to src/main/java/com/jozufozu/flywheel/impl/InstancingControllerRegistryImpl.java index 0febe856f..522bdfde9 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/instance/InstancingControllerRegistryImpl.java +++ b/src/main/java/com/jozufozu/flywheel/impl/InstancingControllerRegistryImpl.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.impl.instance; +package com.jozufozu.flywheel.impl; import org.jetbrains.annotations.Nullable; @@ -12,6 +12,7 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; +//TODO: Add freezing @SuppressWarnings("unchecked") public final class InstancingControllerRegistryImpl { @Nullable diff --git a/src/main/java/com/jozufozu/flywheel/impl/VertexListProviderRegistryImpl.java b/src/main/java/com/jozufozu/flywheel/impl/VertexListProviderRegistryImpl.java new file mode 100644 index 000000000..ea4422c8e --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/VertexListProviderRegistryImpl.java @@ -0,0 +1,26 @@ +package com.jozufozu.flywheel.impl; + +import com.jozufozu.flywheel.api.vertex.VertexListProvider; +import com.jozufozu.flywheel.extension.VertexFormatExtension; +import com.jozufozu.flywheel.impl.vertex.InferredVertexListProviderImpl; +import com.mojang.blaze3d.vertex.VertexFormat; + +// TODO: Add freezing +public final class VertexListProviderRegistryImpl { + public static VertexListProvider getProvider(VertexFormat format) { + VertexFormatExtension extension = (VertexFormatExtension) format; + VertexListProvider provider = extension.flywheel$getVertexListProvider(); + if (provider == null) { + provider = new InferredVertexListProviderImpl(format); + extension.flywheel$setVertexListProvider(provider); + } + return provider; + } + + public static void setProvider(VertexFormat format, VertexListProvider provider) { + ((VertexFormatExtension) format).flywheel$setVertexListProvider(provider); + } + + private VertexListProviderRegistryImpl() { + } +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/InstanceWorld.java new file mode 100644 index 000000000..635fff41d --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/InstanceWorld.java @@ -0,0 +1,135 @@ +package com.jozufozu.flywheel.impl.instancing; + +import java.util.List; + +import org.joml.FrustumIntersection; + +import com.jozufozu.flywheel.api.backend.BackendManager; +import com.jozufozu.flywheel.api.backend.Engine; +import com.jozufozu.flywheel.api.event.RenderContext; +import com.jozufozu.flywheel.api.event.RenderStage; +import com.jozufozu.flywheel.api.instance.DynamicInstance; +import com.jozufozu.flywheel.api.instance.TickableInstance; +import com.jozufozu.flywheel.api.instance.effect.Effect; +import com.jozufozu.flywheel.api.task.TaskExecutor; +import com.jozufozu.flywheel.backend.BackendUtil; +import com.jozufozu.flywheel.config.FlwCommands; +import com.jozufozu.flywheel.config.FlwConfig; +import com.jozufozu.flywheel.impl.instancing.manager.BlockEntityInstanceManager; +import com.jozufozu.flywheel.impl.instancing.manager.EffectInstanceManager; +import com.jozufozu.flywheel.impl.instancing.manager.EntityInstanceManager; +import com.jozufozu.flywheel.impl.instancing.manager.InstanceManager; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; + +/** + * A manager class for a single world where instancing is supported. + */ +public class InstanceWorld { + private final Engine engine; + private final TaskExecutor taskExecutor; + + private final InstanceManager blockEntities; + private final InstanceManager entities; + private final InstanceManager effects; + + public InstanceWorld(LevelAccessor level) { + engine = BackendManager.getBackend().createEngine(level); + taskExecutor = BackendUtil.getTaskExecutor(); + + blockEntities = new BlockEntityInstanceManager(engine); + entities = new EntityInstanceManager(engine); + effects = new EffectInstanceManager(engine); + } + + public Engine getEngine() { + return engine; + } + + public InstanceManager getBlockEntities() { + return blockEntities; + } + + public InstanceManager getEntities() { + return entities; + } + + public InstanceManager getEffects() { + return effects; + } + + /** + * Tick the instances after the game has ticked: + *

+ * Call {@link TickableInstance#tick()} on all instances in this world. + *

+ */ + public void tick(double cameraX, double cameraY, double cameraZ) { + blockEntities.tick(taskExecutor, cameraX, cameraY, cameraZ); + entities.tick(taskExecutor, cameraX, cameraY, cameraZ); + effects.tick(taskExecutor, cameraX, cameraY, cameraZ); + } + + /** + * Get ready to render a frame. + *

+ * Check and update the render origin. + *
+ * Call {@link DynamicInstance#beginFrame()} on all instances in this world. + *

+ */ + public void beginFrame(RenderContext context) { + boolean originChanged = engine.updateRenderOrigin(context.camera()); + + if (originChanged) { + blockEntities.recreateAll(); + entities.recreateAll(); + effects.recreateAll(); + } + + taskExecutor.syncPoint(); + + if (!originChanged) { + var cameraPos = context.camera() + .getPosition(); + double cameraX = cameraPos.x; + double cameraY = cameraPos.y; + double cameraZ = cameraPos.z; + FrustumIntersection culler = context.culler(); + + blockEntities.beginFrame(taskExecutor, cameraX, cameraY, cameraZ, culler); + entities.beginFrame(taskExecutor, cameraX, cameraY, cameraZ, culler); + effects.beginFrame(taskExecutor, cameraX, cameraY, cameraZ, culler); + } + + engine.beginFrame(taskExecutor, context); + } + + /** + * Draw all instances for the given stage. + */ + public void renderStage(RenderContext context, RenderStage stage) { + taskExecutor.syncPoint(); + engine.renderStage(taskExecutor, context, stage); + } + + public void addDebugInfo(List info) { + info.add("B: " + blockEntities.getInstanceCount() + + ", E: " + entities.getInstanceCount() + + ", F: " + effects.getInstanceCount()); + info.add("Update limiting: " + FlwCommands.boolToText(FlwConfig.get().limitUpdates()).getString()); + engine.addDebugInfo(info); + } + + /** + * Free all acquired resources and invalidate this instance world. + */ + public void delete() { + blockEntities.invalidate(); + entities.invalidate(); + effects.invalidate(); + engine.delete(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/InstancedRenderDispatcher.java new file mode 100644 index 000000000..b44513e12 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/InstancedRenderDispatcher.java @@ -0,0 +1,184 @@ +package com.jozufozu.flywheel.impl.instancing; + +import java.util.List; + +import com.jozufozu.flywheel.api.event.BeginFrameEvent; +import com.jozufozu.flywheel.api.event.ReloadRenderersEvent; +import com.jozufozu.flywheel.api.event.RenderStageEvent; +import com.jozufozu.flywheel.api.instance.Instance; +import com.jozufozu.flywheel.api.instance.effect.Effect; +import com.jozufozu.flywheel.backend.BackendUtil; +import com.jozufozu.flywheel.extension.ClientLevelExtension; +import com.jozufozu.flywheel.impl.instancing.manager.InstanceManager; +import com.jozufozu.flywheel.util.AnimationTickHolder; +import com.jozufozu.flywheel.util.WorldAttached; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.Vec3i; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.event.TickEvent; + +public class InstancedRenderDispatcher { + private static final WorldAttached INSTANCE_WORLDS = new WorldAttached<>(InstanceWorld::new); + + /** + * Call this when you want to run {@link Instance#update()}. + * @param blockEntity The block entity whose instance you want to update. + */ + public static void queueUpdate(BlockEntity blockEntity) { + if (!(blockEntity.getLevel() instanceof ClientLevel level)) { + return; + } + + if (!BackendUtil.canUseInstancing(level)) { + return; + } + + INSTANCE_WORLDS.get(level) + .getBlockEntities() + .queueUpdate(blockEntity); + } + + /** + * Call this when you want to run {@link Instance#update()}. + * @param entity The entity whose instance you want to update. + */ + public static void queueUpdate(Entity entity) { + Level level = entity.level; + if (!BackendUtil.canUseInstancing(level)) { + return; + } + + INSTANCE_WORLDS.get(level) + .getEntities() + .queueUpdate(entity); + } + + /** + * Call this when you want to run {@link Instance#update()}. + * @param effect The effect whose instance you want to update. + */ + public static void queueUpdate(LevelAccessor level, Effect effect) { + if (!BackendUtil.canUseInstancing(level)) { + return; + } + + INSTANCE_WORLDS.get(level) + .getEffects() + .queueUpdate(effect); + } + + /** + * Get or create the {@link InstanceWorld} for the given world. + * @throws IllegalStateException if the backend is off + */ + private static InstanceWorld getInstanceWorld(LevelAccessor level) { + if (!BackendUtil.canUseInstancing(level)) { + throw new IllegalStateException("Cannot retrieve instance world when backend is off!"); + } + return INSTANCE_WORLDS.get(level); + } + + public static InstanceManager getBlockEntities(LevelAccessor level) { + return getInstanceWorld(level).getBlockEntities(); + } + + public static InstanceManager getEntities(LevelAccessor level) { + return getInstanceWorld(level).getEntities(); + } + + public static InstanceManager getEffects(LevelAccessor level) { + return getInstanceWorld(level).getEffects(); + } + + public static Vec3i getRenderOrigin(LevelAccessor level) { + return getInstanceWorld(level).getEngine().renderOrigin(); + } + + public static void tick(TickEvent.ClientTickEvent event) { + if (!BackendUtil.isGameActive() || event.phase == TickEvent.Phase.START) { + return; + } + + AnimationTickHolder.tick(); + + Minecraft mc = Minecraft.getInstance(); + if (mc.isPaused()) { + return; + } + + Entity cameraEntity = mc.getCameraEntity() == null ? mc.player : mc.getCameraEntity(); + if (cameraEntity == null) { + return; + } + + Level level = cameraEntity.level; + if (!BackendUtil.canUseInstancing(level)) { + return; + } + + double cameraX = cameraEntity.getX(); + double cameraY = cameraEntity.getEyeY(); + double cameraZ = cameraEntity.getZ(); + + INSTANCE_WORLDS.get(level).tick(cameraX, cameraY, cameraZ); + } + + public static void onBeginFrame(BeginFrameEvent event) { + if (!BackendUtil.isGameActive()) { + return; + } + + ClientLevel level = event.getContext().level(); + if (!BackendUtil.canUseInstancing(level)) { + return; + } + + INSTANCE_WORLDS.get(level).beginFrame(event.getContext()); + } + + public static void onRenderStage(RenderStageEvent event) { + ClientLevel level = event.getContext().level(); + if (!BackendUtil.canUseInstancing(level)) { + return; + } + + INSTANCE_WORLDS.get(level).renderStage(event.getContext(), event.getStage()); + } + + public static void onReloadRenderers(ReloadRenderersEvent event) { + ClientLevel level = event.getLevel(); + if (level == null) { + return; + } + + resetInstanceWorld(level); + } + + public static void resetInstanceWorld(ClientLevel level) { + INSTANCE_WORLDS.remove(level, InstanceWorld::delete); + + if (!BackendUtil.canUseInstancing(level)) { + return; + } + + InstanceWorld world = INSTANCE_WORLDS.get(level); + // Block entities are loaded while chunks are baked. + // Entities are loaded with the level, so when chunks are reloaded they need to be re-added. + ClientLevelExtension.getAllLoadedEntities(level) + .forEach(world.getEntities()::add); + } + + public static void addDebugInfo(List info) { + ClientLevel level = Minecraft.getInstance().level; + if (BackendUtil.canUseInstancing(level)) { + INSTANCE_WORLDS.get(level).addDebugInfo(info); + } else { + info.add("Disabled"); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/instancing/InstancingControllerHelper.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/InstancingControllerHelper.java new file mode 100644 index 000000000..b95b90763 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/InstancingControllerHelper.java @@ -0,0 +1,77 @@ +package com.jozufozu.flywheel.impl.instancing; + +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.api.instance.controller.BlockEntityInstancingController; +import com.jozufozu.flywheel.api.instance.controller.EntityInstancingController; +import com.jozufozu.flywheel.api.instance.controller.InstancingControllerRegistry; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; + +public final class InstancingControllerHelper { + @SuppressWarnings("unchecked") + @Nullable + public static BlockEntityInstancingController getController(T blockEntity) { + return InstancingControllerRegistry.getController((BlockEntityType) blockEntity.getType()); + } + + @SuppressWarnings("unchecked") + @Nullable + public static EntityInstancingController getController(T entity) { + return InstancingControllerRegistry.getController((EntityType) entity.getType()); + } + + /** + * Checks if the given block entity can be instanced. + * @param type The block entity to check. + * @param The block entity. + * @return {@code true} if the block entity can be instanced. + */ + public static boolean canInstance(T blockEntity) { + return getController(blockEntity) != null; + } + + /** + * Checks if the given entity can be instanced. + * @param type The entity to check. + * @param The entity. + * @return {@code true} if the entity can be instanced. + */ + public static boolean canInstance(T entity) { + return getController(entity) != null; + } + + /** + * Checks if the given block entity is instanced and should not be rendered normally. + * @param blockEntity The block entity to check. + * @param The type of the block entity. + * @return {@code true} if the block entity is instanced and should not be rendered normally. + */ + public static boolean shouldSkipRender(T blockEntity) { + BlockEntityInstancingController controller = getController(blockEntity); + if (controller == null) { + return false; + } + return controller.shouldSkipRender(blockEntity); + } + + /** + * Checks if the given entity is instanced and should not be rendered normally. + * @param entity The entity to check. + * @param The type of the entity. + * @return {@code true} if the entity is instanced and should not be rendered normally. + */ + public static boolean shouldSkipRender(T entity) { + EntityInstancingController controller = getController(entity); + if (controller == null) { + return false; + } + return controller.shouldSkipRender(entity); + } + + private InstancingControllerHelper() { + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/manager/BlockEntityInstanceManager.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/manager/BlockEntityInstanceManager.java similarity index 76% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/manager/BlockEntityInstanceManager.java rename to src/main/java/com/jozufozu/flywheel/impl/instancing/manager/BlockEntityInstanceManager.java index 7a31ed9fa..254fd4358 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/manager/BlockEntityInstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/manager/BlockEntityInstanceManager.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.instancing.manager; +package com.jozufozu.flywheel.impl.instancing.manager; import java.util.List; @@ -8,11 +8,10 @@ import com.jozufozu.flywheel.api.backend.Engine; import com.jozufozu.flywheel.api.instance.BlockEntityInstance; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.controller.InstanceContext; -import com.jozufozu.flywheel.api.instance.controller.InstancingControllerRegistry; import com.jozufozu.flywheel.backend.BackendUtil; -import com.jozufozu.flywheel.backend.instancing.storage.One2OneStorage; -import com.jozufozu.flywheel.backend.instancing.storage.Storage; -import com.jozufozu.flywheel.lib.instance.InstancingControllerHelper; +import com.jozufozu.flywheel.impl.instancing.InstancingControllerHelper; +import com.jozufozu.flywheel.impl.instancing.storage.One2OneStorage; +import com.jozufozu.flywheel.impl.instancing.storage.Storage; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -46,7 +45,7 @@ public class BlockEntityInstanceManager extends InstanceManager { return false; } - if (!InstancingControllerHelper.canInstance(blockEntity.getType())) { + if (!InstancingControllerHelper.canInstance(blockEntity)) { return false; } @@ -81,17 +80,17 @@ public class BlockEntityInstanceManager extends InstanceManager { @Override @Nullable protected Instance createRaw(BlockEntity obj) { - var controller = InstancingControllerRegistry.getController(InstancingControllerHelper.getType(obj)); + var controller = InstancingControllerHelper.getController(obj); if (controller == null) { return null; } - var out = controller.createInstance(new InstanceContext(engine, engine.renderOrigin()), obj); + var instance = controller.createInstance(new InstanceContext(engine, engine.renderOrigin()), obj); BlockPos blockPos = obj.getBlockPos(); - posLookup.put(blockPos.asLong(), out); + posLookup.put(blockPos.asLong(), instance); - return out; + return instance; } @Override diff --git a/src/main/java/com/jozufozu/flywheel/impl/instancing/manager/EffectInstanceManager.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/manager/EffectInstanceManager.java new file mode 100644 index 000000000..185e4edaa --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/manager/EffectInstanceManager.java @@ -0,0 +1,39 @@ +package com.jozufozu.flywheel.impl.instancing.manager; + +import java.util.Collection; + +import com.jozufozu.flywheel.api.backend.Engine; +import com.jozufozu.flywheel.api.instance.Instance; +import com.jozufozu.flywheel.api.instance.controller.InstanceContext; +import com.jozufozu.flywheel.api.instance.effect.Effect; +import com.jozufozu.flywheel.impl.instancing.storage.One2ManyStorage; +import com.jozufozu.flywheel.impl.instancing.storage.Storage; + +public class EffectInstanceManager extends InstanceManager { + private final EffectStorage storage; + + public EffectInstanceManager(Engine engine) { + storage = new EffectStorage(engine); + } + + @Override + protected Storage getStorage() { + return storage; + } + + @Override + protected boolean canCreateInstance(Effect obj) { + return true; + } + + private static class EffectStorage extends One2ManyStorage { + public EffectStorage(Engine engine) { + super(engine); + } + + @Override + protected Collection createRaw(Effect obj) { + return obj.createInstances(new InstanceContext(engine, engine.renderOrigin())); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/manager/EntityInstanceManager.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/manager/EntityInstanceManager.java similarity index 69% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/manager/EntityInstanceManager.java rename to src/main/java/com/jozufozu/flywheel/impl/instancing/manager/EntityInstanceManager.java index 9b3ba443f..326527acd 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/manager/EntityInstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/manager/EntityInstanceManager.java @@ -1,15 +1,14 @@ -package com.jozufozu.flywheel.backend.instancing.manager; +package com.jozufozu.flywheel.impl.instancing.manager; import org.jetbrains.annotations.Nullable; import com.jozufozu.flywheel.api.backend.Engine; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.controller.InstanceContext; -import com.jozufozu.flywheel.api.instance.controller.InstancingControllerRegistry; import com.jozufozu.flywheel.backend.BackendUtil; -import com.jozufozu.flywheel.backend.instancing.storage.One2OneStorage; -import com.jozufozu.flywheel.backend.instancing.storage.Storage; -import com.jozufozu.flywheel.lib.instance.InstancingControllerHelper; +import com.jozufozu.flywheel.impl.instancing.InstancingControllerHelper; +import com.jozufozu.flywheel.impl.instancing.storage.One2OneStorage; +import com.jozufozu.flywheel.impl.instancing.storage.Storage; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; @@ -32,7 +31,7 @@ public class EntityInstanceManager extends InstanceManager { return false; } - if (!InstancingControllerHelper.canInstance(entity.getType())) { + if (!InstancingControllerHelper.canInstance(entity)) { return false; } @@ -49,10 +48,11 @@ public class EntityInstanceManager extends InstanceManager { @Override @Nullable protected Instance createRaw(Entity obj) { - var controller = InstancingControllerRegistry.getController(InstancingControllerHelper.getType(obj)); + var controller = InstancingControllerHelper.getController(obj); if (controller == null) { return null; } + return controller.createInstance(new InstanceContext(engine, engine.renderOrigin()), obj); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/manager/InstanceManager.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/manager/InstanceManager.java similarity index 59% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/manager/InstanceManager.java rename to src/main/java/com/jozufozu/flywheel/impl/instancing/manager/InstanceManager.java index 464710716..f164dfe43 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/manager/InstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/manager/InstanceManager.java @@ -1,7 +1,5 @@ -package com.jozufozu.flywheel.backend.instancing.manager; +package com.jozufozu.flywheel.impl.instancing.manager; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -9,28 +7,26 @@ import java.util.function.Consumer; import org.joml.FrustumIntersection; -import com.jozufozu.flywheel.api.backend.BackendManager; -import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.task.TaskExecutor; -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.backend.instancing.storage.Storage; import com.jozufozu.flywheel.config.FlwConfig; +import com.jozufozu.flywheel.impl.instancing.ratelimit.BandedPrimeLimiter; +import com.jozufozu.flywheel.impl.instancing.ratelimit.DistanceUpdateLimiter; +import com.jozufozu.flywheel.impl.instancing.ratelimit.NonLimiter; +import com.jozufozu.flywheel.impl.instancing.storage.Storage; public abstract class InstanceManager { private final Set queuedAdditions = new HashSet<>(64); private final Set queuedUpdates = new HashSet<>(64); - protected DistanceUpdateLimiter frameLimiter; protected DistanceUpdateLimiter tickLimiter; + protected DistanceUpdateLimiter frameLimiter; public InstanceManager() { - frameLimiter = createUpdateLimiter(); tickLimiter = createUpdateLimiter(); + frameLimiter = createUpdateLimiter(); } protected abstract Storage getStorage(); @@ -60,22 +56,18 @@ public abstract class InstanceManager { * @return The object count. */ public int getInstanceCount() { - return getStorage().getInstanceCount(); + return getStorage().getAllInstances().size(); } public void add(T obj) { - if (!BackendManager.isOn()) return; - - if (canCreateInstance(obj)) { - getStorage().add(obj); - } - } - - public void queueAdd(T obj) { - if (!BackendManager.isOn()) { + if (!canCreateInstance(obj)) { return; } + getStorage().add(obj); + } + + public void queueAdd(T obj) { if (!canCreateInstance(obj)) { return; } @@ -85,38 +77,26 @@ public abstract class InstanceManager { } } - public void queueAddAll(Collection objects) { - if (!BackendManager.isOn() || objects.isEmpty()) { - return; - } - - synchronized (queuedAdditions) { - queuedAdditions.addAll(objects); - } - } - /** * Update the instance associated with an object. * *

- * By default this is the only hook an IInstance has to change its internal state. This is the lowest frequency - * update hook IInstance gets. For more frequent updates, see {@link TickableInstance} and + * By default this is the only hook an {@link Instance} has to change its internal state. This is the lowest frequency + * update hook {@link Instance} gets. For more frequent updates, see {@link TickableInstance} and * {@link DynamicInstance}. *

* * @param obj the object to update. */ public void update(T obj) { - if (!BackendManager.isOn()) return; - - if (canCreateInstance(obj)) { - getStorage().update(obj); + if (!canCreateInstance(obj)) { + return; } + + getStorage().update(obj); } public void queueUpdate(T obj) { - if (!BackendManager.isOn()) return; - if (!canCreateInstance(obj)) { return; } @@ -127,12 +107,10 @@ public abstract class InstanceManager { } public void remove(T obj) { - if (!BackendManager.isOn()) return; - getStorage().remove(obj); } - public void onOriginShift() { + public void recreateAll() { getStorage().recreateAll(); } @@ -140,21 +118,15 @@ public abstract class InstanceManager { getStorage().invalidate(); } - public void delete() { - for (Instance instance : getStorage().getAllInstances()) { - instance.delete(); - } - } - protected void processQueuedAdditions() { if (queuedAdditions.isEmpty()) { return; } - ArrayList queued; + List queued; synchronized (queuedAdditions) { - queued = new ArrayList<>(queuedAdditions); + queued = List.copyOf(queuedAdditions); queuedAdditions.clear(); } @@ -164,14 +136,18 @@ public abstract class InstanceManager { } protected void processQueuedUpdates() { - ArrayList queued; + if (queuedUpdates.isEmpty()) { + return; + } + + List queued; synchronized (queuedUpdates) { - queued = new ArrayList<>(queuedUpdates); + queued = List.copyOf(queuedUpdates); queuedUpdates.clear(); } - if (queued.size() > 0) { + if (!queued.isEmpty()) { queued.forEach(getStorage()::update); } } @@ -187,40 +163,34 @@ public abstract class InstanceManager { */ public void tick(TaskExecutor executor, double cameraX, double cameraY, double cameraZ) { tickLimiter.tick(); + processQueuedAdditions(); processQueuedUpdates(); - var instances = getStorage().getInstancesForTicking(); + var instances = getStorage().getTickableInstances(); distributeWork(executor, instances, instance -> tickInstance(instance, cameraX, cameraY, cameraZ)); } - protected void tickInstance(TickableInstance instance, double cX, double cY, double cZ) { - if (!instance.decreaseTickRateWithDistance()) { + protected void tickInstance(TickableInstance instance, double cameraX, double cameraY, double cameraZ) { + if (!instance.decreaseTickRateWithDistance() || tickLimiter.shouldUpdate(instance.distanceSquared(cameraX, cameraY, cameraZ))) { instance.tick(); - return; } - - var dsq = instance.distanceSquared(cX, cY, cZ); - - if (!tickLimiter.shouldUpdate(dsq)) { - return; - } - - instance.tick(); } - public void beginFrame(TaskExecutor executor, RenderContext context) { + public void beginFrame(TaskExecutor executor, double cameraX, double cameraY, double cameraZ, FrustumIntersection frustum) { frameLimiter.tick(); processQueuedAdditions(); + processQueuedUpdates(); - var cameraPos = context.camera() - .getPosition(); - double cX = cameraPos.x; - double cY = cameraPos.y; - double cZ = cameraPos.z; - FrustumIntersection culler = context.culler(); + var instances = getStorage().getDynamicInstances(); + distributeWork(executor, instances, instance -> updateInstance(instance, cameraX, cameraY, cameraZ, frustum)); + } - var instances = getStorage().getInstancesForUpdate(); - distributeWork(executor, instances, instance -> updateInstance(instance, culler, cX, cY, cZ)); + protected void updateInstance(DynamicInstance instance, double cameraX, double cameraY, double cameraZ, FrustumIntersection frustum) { + if (!instance.decreaseFramerateWithDistance() || frameLimiter.shouldUpdate(instance.distanceSquared(cameraX, cameraY, cameraZ))) { + if (instance.isVisible(frustum)) { + instance.beginFrame(); + } + } } private static void distributeWork(TaskExecutor executor, List instances, Consumer action) { @@ -239,19 +209,4 @@ public abstract class InstanceManager { } } } - - protected void updateInstance(DynamicInstance instance, FrustumIntersection frustum, double cX, double cY, double cZ) { - if (!instance.decreaseFramerateWithDistance()) { - instance.beginFrame(); - return; - } - - if (!frameLimiter.shouldUpdate(instance.distanceSquared(cX, cY, cZ))) { - return; - } - - if (instance.checkFrustum(frustum)) { - instance.beginFrame(); - } - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/BandedPrimeLimiter.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/ratelimit/BandedPrimeLimiter.java similarity index 91% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/BandedPrimeLimiter.java rename to src/main/java/com/jozufozu/flywheel/impl/instancing/ratelimit/BandedPrimeLimiter.java index cade56aa9..3b58e4e09 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/BandedPrimeLimiter.java +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/ratelimit/BandedPrimeLimiter.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.instancing.ratelimit; +package com.jozufozu.flywheel.impl.instancing.ratelimit; import net.minecraft.util.Mth; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/DistanceUpdateLimiter.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/ratelimit/DistanceUpdateLimiter.java similarity index 88% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/DistanceUpdateLimiter.java rename to src/main/java/com/jozufozu/flywheel/impl/instancing/ratelimit/DistanceUpdateLimiter.java index 35ae6857c..127e2ce6a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/DistanceUpdateLimiter.java +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/ratelimit/DistanceUpdateLimiter.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.instancing.ratelimit; +package com.jozufozu.flywheel.impl.instancing.ratelimit; /** * Interface for rate-limiting updates based on an object's distance from the camera. diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/NonLimiter.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/ratelimit/NonLimiter.java similarity index 75% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/NonLimiter.java rename to src/main/java/com/jozufozu/flywheel/impl/instancing/ratelimit/NonLimiter.java index 53edba57d..807005e73 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/ratelimit/NonLimiter.java +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/ratelimit/NonLimiter.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.instancing.ratelimit; +package com.jozufozu.flywheel.impl.instancing.ratelimit; public class NonLimiter implements DistanceUpdateLimiter { @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/storage/AbstractStorage.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/storage/AbstractStorage.java similarity index 85% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/storage/AbstractStorage.java rename to src/main/java/com/jozufozu/flywheel/impl/instancing/storage/AbstractStorage.java index be0ab9e82..ce811413a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/storage/AbstractStorage.java +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/storage/AbstractStorage.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.instancing.storage; +package com.jozufozu.flywheel.impl.instancing.storage; import java.util.ArrayList; import java.util.List; @@ -18,12 +18,12 @@ public abstract class AbstractStorage implements Storage { } @Override - public List getInstancesForTicking() { + public List getTickableInstances() { return tickableInstances; } @Override - public List getInstancesForUpdate() { + public List getDynamicInstances() { return dynamicInstances; } diff --git a/src/main/java/com/jozufozu/flywheel/impl/instancing/storage/One2ManyStorage.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/storage/One2ManyStorage.java new file mode 100644 index 000000000..e75838054 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/storage/One2ManyStorage.java @@ -0,0 +1,86 @@ +package com.jozufozu.flywheel.impl.instancing.storage; + +import java.util.Collection; +import java.util.List; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.jozufozu.flywheel.api.backend.Engine; +import com.jozufozu.flywheel.api.instance.Instance; + +public abstract class One2ManyStorage extends AbstractStorage { + private final Multimap allInstances = HashMultimap.create(); + + public One2ManyStorage(Engine engine) { + super(engine); + } + + @Override + public Collection getAllInstances() { + return allInstances.values(); + } + + @Override + public void add(T obj) { + Collection instances = allInstances.get(obj); + + if (instances.isEmpty()) { + create(obj); + } + } + + @Override + public void remove(T obj) { + Collection instances = allInstances.removeAll(obj); + + if (instances.isEmpty()) { + return; + } + + tickableInstances.removeAll(instances); + dynamicInstances.removeAll(instances); + instances.forEach(Instance::delete); + } + + @Override + public void update(T obj) { + Collection instances = allInstances.get(obj); + + if (instances.isEmpty()) { + return; + } + + // TODO: shouldReset cannot be checked here because all instances are created at once + instances.forEach(Instance::update); + } + + @Override + public void recreateAll() { + tickableInstances.clear(); + dynamicInstances.clear(); + allInstances.values().forEach(Instance::delete); + + List objects = List.copyOf(allInstances.keySet()); + allInstances.clear(); + objects.forEach(this::create); + } + + @Override + public void invalidate() { + tickableInstances.clear(); + dynamicInstances.clear(); + allInstances.values().forEach(Instance::delete); + allInstances.clear(); + } + + private void create(T obj) { + Collection instances = createRaw(obj); + + if (!instances.isEmpty()) { + instances.forEach(this::setup); + allInstances.putAll(obj, instances); + } + } + + protected abstract Collection createRaw(T obj); +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/storage/One2OneStorage.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/storage/One2OneStorage.java similarity index 87% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/storage/One2OneStorage.java rename to src/main/java/com/jozufozu/flywheel/impl/instancing/storage/One2OneStorage.java index af9f239d1..f806ef557 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/storage/One2OneStorage.java +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/storage/One2OneStorage.java @@ -1,5 +1,6 @@ -package com.jozufozu.flywheel.backend.instancing.storage; +package com.jozufozu.flywheel.impl.instancing.storage; +import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -9,23 +10,17 @@ import com.jozufozu.flywheel.api.backend.Engine; import com.jozufozu.flywheel.api.instance.Instance; public abstract class One2OneStorage extends AbstractStorage { - private final Map instances; + private final Map instances = new HashMap<>(); public One2OneStorage(Engine engine) { super(engine); - this.instances = new HashMap<>(); } @Override - public Iterable getAllInstances() { + public Collection getAllInstances() { return instances.values(); } - @Override - public int getInstanceCount() { - return instances.size(); - } - @Override public void add(T obj) { Instance instance = instances.get(obj); @@ -43,9 +38,9 @@ public abstract class One2OneStorage extends AbstractStorage { return; } - instance.delete(); - dynamicInstances.remove(instance); tickableInstances.remove(instance); + dynamicInstances.remove(instance); + instance.delete(); } @Override @@ -69,8 +64,8 @@ public abstract class One2OneStorage extends AbstractStorage { @Override public void recreateAll() { - dynamicInstances.clear(); tickableInstances.clear(); + dynamicInstances.clear(); instances.replaceAll((obj, instance) -> { instance.delete(); @@ -86,10 +81,10 @@ public abstract class One2OneStorage extends AbstractStorage { @Override public void invalidate() { - instances.values().forEach(Instance::delete); - instances.clear(); tickableInstances.clear(); dynamicInstances.clear(); + instances.values().forEach(Instance::delete); + instances.clear(); } private void create(T obj) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/storage/Storage.java b/src/main/java/com/jozufozu/flywheel/impl/instancing/storage/Storage.java similarity index 60% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/storage/Storage.java rename to src/main/java/com/jozufozu/flywheel/impl/instancing/storage/Storage.java index a182f3d11..9052cb59b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/storage/Storage.java +++ b/src/main/java/com/jozufozu/flywheel/impl/instancing/storage/Storage.java @@ -1,5 +1,6 @@ -package com.jozufozu.flywheel.backend.instancing.storage; +package com.jozufozu.flywheel.impl.instancing.storage; +import java.util.Collection; import java.util.List; import com.jozufozu.flywheel.api.instance.DynamicInstance; @@ -7,13 +8,11 @@ import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.TickableInstance; public interface Storage { - Iterable getAllInstances(); + Collection getAllInstances(); - int getInstanceCount(); + List getTickableInstances(); - List getInstancesForTicking(); - - List getInstancesForUpdate(); + List getDynamicInstances(); void add(T obj); diff --git a/src/main/java/com/jozufozu/flywheel/lib/backend/Backends.java b/src/main/java/com/jozufozu/flywheel/lib/backend/Backends.java index f51afdab9..4535ab1fe 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/backend/Backends.java +++ b/src/main/java/com/jozufozu/flywheel/lib/backend/Backends.java @@ -16,7 +16,7 @@ import net.minecraft.network.chat.TextComponent; public class Backends { public static final Backend OFF = SimpleBackend.builder() .engineMessage(new TextComponent("Disabled Flywheel").withStyle(ChatFormatting.RED)) - .engineSupplier(() -> { + .engineFactory(level -> { throw new IllegalStateException("Cannot create engine when backend is off."); }) .fallback(() -> Backends.OFF) @@ -28,7 +28,7 @@ public class Backends { */ public static final Backend BATCHING = SimpleBackend.builder() .engineMessage(new TextComponent("Using Batching Engine").withStyle(ChatFormatting.GREEN)) - .engineSupplier(BatchingEngine::new) + .engineFactory(level -> new BatchingEngine()) .fallback(() -> Backends.OFF) .supported(() -> !ShadersModHandler.isShaderPackInUse()) .register(Flywheel.rl("batching")); @@ -38,7 +38,7 @@ public class Backends { */ public static final Backend INSTANCING = SimpleBackend.builder() .engineMessage(new TextComponent("Using Instancing Engine").withStyle(ChatFormatting.GREEN)) - .engineSupplier(() -> new InstancingEngine(Contexts.WORLD, 100 * 100)) + .engineFactory(level -> new InstancingEngine(Contexts.WORLD, 100)) .fallback(() -> Backends.BATCHING) .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .instancedArraysSupported()) @@ -50,7 +50,7 @@ public class Backends { */ public static final Backend INDIRECT = SimpleBackend.builder() .engineMessage(new TextComponent("Using Indirect Engine").withStyle(ChatFormatting.GREEN)) - .engineSupplier(() -> new IndirectEngine(Contexts.WORLD, 100 * 100)) + .engineFactory(level -> new IndirectEngine(100)) .fallback(() -> Backends.INSTANCING) .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .supportsIndirect()) diff --git a/src/main/java/com/jozufozu/flywheel/lib/backend/SimpleBackend.java b/src/main/java/com/jozufozu/flywheel/lib/backend/SimpleBackend.java index 32d135b4d..07aff3df7 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/backend/SimpleBackend.java +++ b/src/main/java/com/jozufozu/flywheel/lib/backend/SimpleBackend.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.lib.backend; import java.util.function.BooleanSupplier; +import java.util.function.Function; import java.util.function.Supplier; import org.jetbrains.annotations.Nullable; @@ -11,17 +12,18 @@ import com.jozufozu.flywheel.api.pipeline.Pipeline; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.LevelAccessor; public class SimpleBackend implements Backend { private final Component engineMessage; - private final Supplier engineSupplier; + private final Function engineFactory; private final Supplier fallback; private final BooleanSupplier isSupported; private final Pipeline pipelineShader; - public SimpleBackend(Component engineMessage, Supplier engineSupplier, Supplier fallback, BooleanSupplier isSupported, @Nullable Pipeline pipelineShader) { + public SimpleBackend(Component engineMessage, Function engineFactory, Supplier fallback, BooleanSupplier isSupported, @Nullable Pipeline pipelineShader) { this.engineMessage = engineMessage; - this.engineSupplier = engineSupplier; + this.engineFactory = engineFactory; this.fallback = fallback; this.isSupported = isSupported; this.pipelineShader = pipelineShader; @@ -37,8 +39,8 @@ public class SimpleBackend implements Backend { } @Override - public Engine createEngine() { - return engineSupplier.get(); + public Engine createEngine(LevelAccessor level) { + return engineFactory.apply(level); } @Override @@ -63,7 +65,7 @@ public class SimpleBackend implements Backend { public static class Builder { private Component engineMessage; - private Supplier engineSupplier; + private Function engineFactory; private Supplier fallback; private BooleanSupplier isSupported; private Pipeline pipelineShader; @@ -73,8 +75,8 @@ public class SimpleBackend implements Backend { return this; } - public Builder engineSupplier(Supplier engineSupplier) { - this.engineSupplier = engineSupplier; + public Builder engineFactory(Function engineFactory) { + this.engineFactory = engineFactory; return this; } @@ -94,7 +96,7 @@ public class SimpleBackend implements Backend { } public Backend register(ResourceLocation id) { - return Backend.REGISTRY.registerAndGet(id, new SimpleBackend(engineMessage, engineSupplier, fallback, isSupported, pipelineShader)); + return Backend.REGISTRY.registerAndGet(id, new SimpleBackend(engineMessage, engineFactory, fallback, isSupported, pipelineShader)); } } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractBlockEntityInstance.java b/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractBlockEntityInstance.java index 15378291c..73491dbcd 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractBlockEntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractBlockEntityInstance.java @@ -1,16 +1,12 @@ package com.jozufozu.flywheel.lib.instance; -import java.util.ArrayList; -import java.util.List; - import org.joml.FrustumIntersection; import com.jozufozu.flywheel.api.instance.BlockEntityInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instance.controller.InstanceContext; -import com.jozufozu.flywheel.api.instancer.InstancedPart; -import com.jozufozu.flywheel.backend.instancing.manager.BlockEntityInstanceManager; +import com.jozufozu.flywheel.impl.instancing.manager.BlockEntityInstanceManager; import com.jozufozu.flywheel.lib.box.ImmutableBox; import com.jozufozu.flywheel.lib.box.MutableBox; @@ -30,13 +26,12 @@ import net.minecraft.world.level.block.state.BlockState; * * See the interfaces' documentation for more information about each one. * - *
Implementing one or more of these will give a {@link AbstractBlockEntityInstance} access + *
Implementing one or more of these will give an {@link AbstractBlockEntityInstance} access * to more interesting and regular points within a tick or a frame. * * @param The type of {@link BlockEntity} your class is an instance of. */ public abstract class AbstractBlockEntityInstance extends AbstractInstance implements BlockEntityInstance { - protected final T blockEntity; protected final BlockPos pos; protected final BlockPos instancePos; @@ -50,17 +45,6 @@ public abstract class AbstractBlockEntityInstance extends this.instancePos = pos.subtract(renderOrigin); } - @Override - public List getCrumblingParts() { - var out = new ArrayList(); - addCrumblingParts(out); - return out; - } - - public void addCrumblingParts(List data) { - - } - /** * Just before {@link #update()} would be called, {@code shouldReset()} is checked. * If this function returns {@code true}, then this instance will be {@link #delete removed}, @@ -69,10 +53,21 @@ public abstract class AbstractBlockEntityInstance extends * * @return {@code true} if this instance should be discarded and refreshed. */ + @Override public boolean shouldReset() { return blockEntity.getBlockState() != blockState; } + @Override + public double distanceSquared(double x, double y, double z) { + return pos.distToCenterSqr(x, y, z); + } + + @Override + public ImmutableBox getVolume() { + return MutableBox.from(pos); + } + /** * In order to accommodate for floating point precision errors at high coordinates, * {@link BlockEntityInstanceManager}s are allowed to arbitrarily adjust the origin, and @@ -85,18 +80,7 @@ public abstract class AbstractBlockEntityInstance extends return pos.subtract(renderOrigin); } - @Override - public ImmutableBox getVolume() { - return MutableBox.from(pos); - } - - @Override - public boolean checkFrustum(FrustumIntersection frustum) { + public boolean isVisible(FrustumIntersection frustum) { return frustum.testAab(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1); } - - @Override - public double distanceSquared(double x, double y, double z) { - return pos.distToCenterSqr(x, y, z); - } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractEntityInstance.java b/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractEntityInstance.java index 7d2658abd..f2ab16121 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractEntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractEntityInstance.java @@ -6,19 +6,19 @@ import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.EntityInstance; import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instance.controller.InstanceContext; -import com.jozufozu.flywheel.backend.instancing.manager.BlockEntityInstanceManager; +import com.jozufozu.flywheel.impl.instancing.manager.BlockEntityInstanceManager; +import com.jozufozu.flywheel.lib.box.ImmutableBox; import com.jozufozu.flywheel.lib.box.MutableBox; import com.jozufozu.flywheel.lib.light.TickingLightListener; import com.mojang.math.Vector3f; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; /** - * The layer between a {@link BlockEntity} and the Flywheel backend. + * The layer between an {@link Entity} and the Flywheel backend. * * *

There are a few additional features that overriding classes can opt in to: *
    @@ -27,13 +27,12 @@ import net.minecraft.world.phys.Vec3; *
* See the interfaces' documentation for more information about each one. * - *
Implementing one or more of these will give a {@link AbstractEntityInstance} access + *
Implementing one or more of these will give an {@link AbstractEntityInstance} access * to more interesting and regular points within a tick or a frame. * * @param The type of {@link Entity} your class is an instance of. */ public abstract class AbstractEntityInstance extends AbstractInstance implements EntityInstance, TickingLightListener { - protected final E entity; protected final MutableBox bounds; @@ -44,7 +43,12 @@ public abstract class AbstractEntityInstance extends AbstractI } @Override - public MutableBox getVolume() { + public double distanceSquared(double x, double y, double z) { + return entity.distanceToSqr(x, y, z); + } + + @Override + public ImmutableBox getVolume() { return bounds; } @@ -87,14 +91,8 @@ public abstract class AbstractEntityInstance extends AbstractI return new Vector3f((float) (Mth.lerp(partialTicks, entity.xOld, pos.x) - renderOrigin.getX()), (float) (Mth.lerp(partialTicks, entity.yOld, pos.y) - renderOrigin.getY()), (float) (Mth.lerp(partialTicks, entity.zOld, pos.z) - renderOrigin.getZ())); } - @Override - public boolean checkFrustum(FrustumIntersection frustum) { + public boolean isVisible(FrustumIntersection frustum) { AABB aabb = entity.getBoundingBox(); return frustum.testAab((float) aabb.minX, (float) aabb.minY, (float) aabb.minZ, (float) aabb.maxX, (float) aabb.maxY, (float) aabb.maxZ); } - - @Override - public double distanceSquared(double x, double y, double z) { - return entity.distanceToSqr(x, y, z); - } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractInstance.java b/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractInstance.java index 6e01449c4..bc9ed00a9 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractInstance.java +++ b/src/main/java/com/jozufozu/flywheel/lib/instance/AbstractInstance.java @@ -1,14 +1,13 @@ package com.jozufozu.flywheel.lib.instance; -import java.util.Arrays; import java.util.stream.Stream; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.controller.InstanceContext; -import com.jozufozu.flywheel.api.instancer.FlatLit; import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.lib.light.LightListener; import com.jozufozu.flywheel.lib.light.LightUpdater; +import com.jozufozu.flywheel.lib.struct.FlatLit; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; @@ -17,23 +16,22 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.LightLayer; public abstract class AbstractInstance implements Instance, LightListener { - public final Level level; - public final Vec3i renderOrigin; + protected final InstancerProvider instancerProvider; + protected final Vec3i renderOrigin; + protected final Level level; - protected final InstancerProvider instancerManager; protected boolean deleted = false; public AbstractInstance(InstanceContext ctx, Level level) { - this.instancerManager = ctx.instancerProvider(); + this.instancerProvider = ctx.instancerProvider(); this.renderOrigin = ctx.renderOrigin(); this.level = level; } @Override public void init() { + LightUpdater.get(level).addListener(this); updateLight(); - LightUpdater.get(level) - .addListener(this); } @Override @@ -65,31 +63,31 @@ public abstract class AbstractInstance implements Instance, LightListener { deleted = true; } - @Override - public boolean isInvalid() { - return deleted; - } - @Override public void onLightUpdate(LightLayer type, SectionPos pos) { updateLight(); } - protected void relight(BlockPos pos, FlatLit... models) { - relight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos), models); + @Override + public boolean isInvalid() { + return deleted; } - protected > void relight(BlockPos pos, Stream models) { - relight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos), models); + protected void relight(BlockPos pos, FlatLit... parts) { + relight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos), parts); } - protected void relight(int block, int sky, FlatLit... models) { - relight(block, sky, Arrays.stream(models)); + protected void relight(int block, int sky, FlatLit... parts) { + for (FlatLit part : parts) { + part.setLight(block, sky); + } } - protected > void relight(int block, int sky, Stream models) { - models.forEach(model -> model.setBlockLight(block) - .setSkyLight(sky)); + protected > void relight(BlockPos pos, Stream parts) { + relight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos), parts); } + protected > void relight(int block, int sky, Stream parts) { + parts.forEach(model -> model.setLight(block, sky)); + } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/instance/InstancingControllerHelper.java b/src/main/java/com/jozufozu/flywheel/lib/instance/InstancingControllerHelper.java deleted file mode 100644 index 733918ad1..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/instance/InstancingControllerHelper.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.jozufozu.flywheel.lib.instance; - -import com.jozufozu.flywheel.api.instance.controller.BlockEntityInstancingController; -import com.jozufozu.flywheel.api.instance.controller.EntityInstancingController; -import com.jozufozu.flywheel.api.instance.controller.InstancingControllerRegistry; - -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; - -public final class InstancingControllerHelper { - /** - * Checks if the given block entity type can be instanced. - * @param type The block entity type to check. - * @param The type of the block entity. - * @return {@code true} if the block entity type can be instanced. - */ - public static boolean canInstance(BlockEntityType type) { - return InstancingControllerRegistry.getController(type) != null; - } - - /** - * Checks if the given entity type can be instanced. - * @param type The entity type to check. - * @param The type of the entity. - * @return {@code true} if the entity type can be instanced. - */ - public static boolean canInstance(EntityType type) { - return InstancingControllerRegistry.getController(type) != null; - } - - /** - * Checks if the given block entity is instanced and should not be rendered normally. - * @param blockEntity The block entity to check. - * @param The type of the block entity. - * @return {@code true} if the block entity is instanced and should not be rendered normally. - */ - public static boolean shouldSkipRender(T blockEntity) { - BlockEntityInstancingController controller = InstancingControllerRegistry.getController(getType(blockEntity)); - if (controller == null) { - return false; - } - return controller.shouldSkipRender(blockEntity); - } - - /** - * Checks if the given entity is instanced and should not be rendered normally. - * @param entity The entity to check. - * @param The type of the entity. - * @return {@code true} if the entity is instanced and should not be rendered normally. - */ - public static boolean shouldSkipRender(T entity) { - EntityInstancingController controller = InstancingControllerRegistry.getController(getType(entity)); - if (controller == null) { - return false; - } - return controller.shouldSkipRender(entity); - } - - /** - * Gets the type of the given block entity. - * @param blockEntity The block entity to get the type of. - * @param The type of the block entity. - * @return The {@link BlockEntityType} associated with the given block entity. - */ - @SuppressWarnings("unchecked") - public static BlockEntityType getType(T blockEntity) { - return (BlockEntityType) blockEntity.getType(); - } - - /** - * Gets the type of the given entity. - * @param entity The entity to get the type of. - * @param The type of the entity. - * @return The {@link EntityType} associated with the given entity. - */ - @SuppressWarnings("unchecked") - public static EntityType getType(T entity) { - return (EntityType) entity.getType(); - } - - private InstancingControllerHelper() { - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java b/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java index 5c900b275..654d5ef9f 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java @@ -13,7 +13,7 @@ import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.vertex.ReusableVertexList; import com.jozufozu.flywheel.api.vertex.VertexList; -import com.jozufozu.flywheel.api.vertex.VertexListProvider; +import com.jozufozu.flywheel.api.vertex.VertexListProviderRegistry; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.lib.format.Formats; import com.jozufozu.flywheel.lib.material.Materials; @@ -62,7 +62,7 @@ public class ModelUtil { long srcPtr = MemoryUtil.memAddress(src); long dstPtr = dst.ptr(); - ReusableVertexList srcList = VertexListProvider.get(srcFormat).createVertexList(); + ReusableVertexList srcList = VertexListProviderRegistry.getProvider(srcFormat).createVertexList(); ReusableVertexList dstList = dstVertexType.createVertexList(); srcList.ptr(srcPtr); dstList.ptr(dstPtr); diff --git a/src/main/java/com/jozufozu/flywheel/lib/struct/ColoredLitPart.java b/src/main/java/com/jozufozu/flywheel/lib/struct/ColoredLitPart.java index c384760b2..1b952ee9f 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/struct/ColoredLitPart.java +++ b/src/main/java/com/jozufozu/flywheel/lib/struct/ColoredLitPart.java @@ -1,6 +1,5 @@ package com.jozufozu.flywheel.lib.struct; -import com.jozufozu.flywheel.api.instancer.FlatLit; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.struct.StructType; diff --git a/src/main/java/com/jozufozu/flywheel/api/instancer/FlatLit.java b/src/main/java/com/jozufozu/flywheel/lib/struct/FlatLit.java similarity index 75% rename from src/main/java/com/jozufozu/flywheel/api/instancer/FlatLit.java rename to src/main/java/com/jozufozu/flywheel/lib/struct/FlatLit.java index 188933eac..cad1b8b85 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instancer/FlatLit.java +++ b/src/main/java/com/jozufozu/flywheel/lib/struct/FlatLit.java @@ -1,4 +1,6 @@ -package com.jozufozu.flywheel.api.instancer; +package com.jozufozu.flywheel.lib.struct; + +import com.jozufozu.flywheel.api.instancer.InstancedPart; import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockAndTintGetter; @@ -27,9 +29,13 @@ public interface FlatLit> { */ D setSkyLight(int skyLight); + default D setLight(int blockLight, int skyLight) { + return setBlockLight(blockLight) + .setSkyLight(skyLight); + } + default D updateLight(BlockAndTintGetter level, BlockPos pos) { - return setBlockLight(level.getBrightness(LightLayer.BLOCK, pos)) - .setSkyLight(level.getBrightness(LightLayer.SKY, pos)); + return setLight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos)); } int getPackedLight(); diff --git a/src/main/java/com/jozufozu/flywheel/lib/uniform/FlwShaderUniforms.java b/src/main/java/com/jozufozu/flywheel/lib/uniform/FlwShaderUniforms.java index 7010671ce..a967fadfb 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/uniform/FlwShaderUniforms.java +++ b/src/main/java/com/jozufozu/flywheel/lib/uniform/FlwShaderUniforms.java @@ -8,7 +8,7 @@ import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.event.BeginFrameEvent; import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.uniform.ShaderUniforms; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.impl.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.util.FlwUtil; import com.jozufozu.flywheel.util.MatrixUtil; import com.mojang.blaze3d.systems.RenderSystem; @@ -73,13 +73,13 @@ public class FlwShaderUniforms implements ShaderUniforms { } RenderContext context = event.getContext(); - Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level()); + Vec3i renderOrigin = InstancedRenderDispatcher.getRenderOrigin(context.level()); Vec3 camera = context.camera() .getPosition(); - var camX = (float) (camera.x - originCoordinate.getX()); - var camY = (float) (camera.y - originCoordinate.getY()); - var camZ = (float) (camera.z - originCoordinate.getZ()); + var camX = (float) (camera.x - renderOrigin.getX()); + var camY = (float) (camera.y - renderOrigin.getY()); + var camZ = (float) (camera.z - renderOrigin.getZ()); // don't want to mutate viewProjection var vp = context.viewProjection() diff --git a/src/main/java/com/jozufozu/flywheel/mixin/ClientLevelMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/ClientLevelMixin.java index ddfa8c0c3..0740b96f0 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/ClientLevelMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/ClientLevelMixin.java @@ -9,9 +9,9 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.google.common.collect.Lists; -import com.jozufozu.flywheel.api.backend.BackendManager; +import com.jozufozu.flywheel.backend.BackendUtil; import com.jozufozu.flywheel.extension.ClientLevelExtension; -import com.jozufozu.flywheel.lib.instance.InstancingControllerHelper; +import com.jozufozu.flywheel.impl.instancing.InstancingControllerHelper; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.world.entity.Entity; @@ -29,7 +29,7 @@ public abstract class ClientLevelMixin implements ClientLevelExtension { @Inject(method = "entitiesForRendering", at = @At("RETURN"), cancellable = true) private void flywheel$filterEntities(CallbackInfoReturnable> cir) { - if (BackendManager.isOn()) { + if (BackendUtil.canUseInstancing((ClientLevel) (Object) this)) { Iterable entities = cir.getReturnValue(); ArrayList filtered = Lists.newArrayList(entities); diff --git a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/ChunkRebuildHooksMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/ChunkRebuildHooksMixin.java index c81db100b..48c90075b 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/ChunkRebuildHooksMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/ChunkRebuildHooksMixin.java @@ -8,8 +8,8 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.jozufozu.flywheel.backend.BackendUtil; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.jozufozu.flywheel.lib.instance.InstancingControllerHelper; +import com.jozufozu.flywheel.impl.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.impl.instancing.InstancingControllerHelper; import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; import net.minecraft.world.level.block.entity.BlockEntity; @@ -19,7 +19,7 @@ public class ChunkRebuildHooksMixin { @Inject(method = "handleBlockEntity", at = @At("HEAD"), cancellable = true) private void flywheel$addAndFilterBEs(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set set, E be, CallbackInfo ci) { if (BackendUtil.canUseInstancing(be.getLevel())) { - if (InstancingControllerHelper.canInstance(be.getType())) + if (InstancingControllerHelper.canInstance(be)) InstancedRenderDispatcher.getBlockEntities(be.getLevel()).queueAdd(be); if (InstancingControllerHelper.shouldSkipRender(be)) diff --git a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceAddMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceAddMixin.java index 4c6ab5798..dcbcd7203 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceAddMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceAddMixin.java @@ -7,8 +7,8 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.jozufozu.flywheel.api.backend.BackendManager; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.backend.BackendUtil; +import com.jozufozu.flywheel.impl.instancing.InstancedRenderDispatcher; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; @@ -22,10 +22,10 @@ public class InstanceAddMixin { @Inject(method = "setBlockEntity", at = @At(value = "INVOKE_ASSIGN", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")) - private void flywheel$onBlockEntityAdded(BlockEntity be, CallbackInfo ci) { - if (level.isClientSide && BackendManager.isOn()) { - InstancedRenderDispatcher.getBlockEntities(this.level) - .add(be); + private void flywheel$onBlockEntityAdded(BlockEntity blockEntity, CallbackInfo ci) { + if (level.isClientSide && BackendUtil.canUseInstancing(level)) { + InstancedRenderDispatcher.getBlockEntities(level) + .add(blockEntity); } } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceRemoveMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceRemoveMixin.java index 4c504a462..4b4bce61b 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceRemoveMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceRemoveMixin.java @@ -7,8 +7,8 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.jozufozu.flywheel.api.backend.BackendManager; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.backend.BackendUtil; +import com.jozufozu.flywheel.impl.instancing.InstancedRenderDispatcher; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.world.level.Level; @@ -22,8 +22,8 @@ public class InstanceRemoveMixin { @Inject(at = @At("TAIL"), method = "setRemoved") private void flywheel$removeInstance(CallbackInfo ci) { - if (level instanceof ClientLevel && BackendManager.isOn()) { - InstancedRenderDispatcher.getBlockEntities(this.level) + if (level instanceof ClientLevel && BackendUtil.canUseInstancing(level)) { + InstancedRenderDispatcher.getBlockEntities(level) .remove((BlockEntity) (Object) this); } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceUpdateMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceUpdateMixin.java index 5674ae7dd..17b11ceab 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceUpdateMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/instancemanage/InstanceUpdateMixin.java @@ -6,8 +6,8 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.jozufozu.flywheel.api.backend.BackendManager; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.backend.BackendUtil; +import com.jozufozu.flywheel.impl.instancing.InstancedRenderDispatcher; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.LevelRenderer; @@ -25,7 +25,7 @@ public class InstanceUpdateMixin { */ @Inject(at = @At("TAIL"), method = "setBlockDirty(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)V") private void flywheel$checkUpdate(BlockPos pos, BlockState lastState, BlockState newState, CallbackInfo ci) { - if (!BackendManager.isOn()) { + if (!BackendUtil.canUseInstancing(level)) { return; } BlockEntity blockEntity = level.getBlockEntity(pos); diff --git a/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java b/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java index 93b79a310..244dff288 100644 --- a/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java +++ b/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java @@ -78,14 +78,18 @@ public class WorldAttached { */ @NotNull public T replace(LevelAccessor world, Consumer finalizer) { - T remove = attached.remove(world); - - if (remove != null) - finalizer.accept(remove); + remove(world, finalizer); return get(world); } + public void remove(LevelAccessor world, Consumer finalizer) { + T removed = attached.remove(world); + + if (removed != null) + finalizer.accept(removed); + } + /** * Deletes all entries after calling a function on them. * diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java index 9764b77a8..949cc71b4 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java @@ -1,6 +1,5 @@ package com.jozufozu.flywheel.vanilla; -import java.util.Collections; import java.util.List; import org.jetbrains.annotations.NotNull; @@ -24,18 +23,22 @@ import net.minecraft.util.Mth; import net.minecraft.world.level.block.entity.BellBlockEntity; public class BellInstance extends AbstractBlockEntityInstance implements DynamicInstance { - private static final SimpleLazyModel MODEL = new SimpleLazyModel(BellInstance::createBellModel, Materials.BELL); - private final OrientedPart bell; + private OrientedPart bell; private float lastRingTime = Float.NaN; public BellInstance(InstanceContext ctx, BellBlockEntity blockEntity) { super(ctx, blockEntity); + } + @Override + public void init() { bell = createBellInstance().setPivot(0.5f, 0.75f, 0.5f) .setPosition(getInstancePosition()); + + super.init(); } @Override @@ -65,8 +68,8 @@ public class BellInstance extends AbstractBlockEntityInstance i } @Override - public void addCrumblingParts(List data) { - Collections.addAll(data, bell); + public List getCrumblingParts() { + return List.of(bell); } @Override @@ -75,7 +78,7 @@ public class BellInstance extends AbstractBlockEntityInstance i } private OrientedPart createBellInstance() { - return instancerManager.getInstancer(StructTypes.ORIENTED, MODEL, RenderStage.AFTER_BLOCK_ENTITIES) + return instancerProvider.instancer(StructTypes.ORIENTED, MODEL, RenderStage.AFTER_BLOCK_ENTITIES) .createInstance(); } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java index 857954130..83fc3ad6c 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java @@ -1,12 +1,9 @@ package com.jozufozu.flywheel.vanilla; import java.util.Calendar; -import java.util.Collections; import java.util.List; import java.util.function.BiFunction; -import org.jetbrains.annotations.NotNull; - import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.controller.InstanceContext; @@ -36,24 +33,25 @@ import net.minecraft.world.level.block.entity.LidBlockEntity; import net.minecraft.world.level.block.state.properties.ChestType; public class ChestInstance extends AbstractBlockEntityInstance implements DynamicInstance { - private static final BiFunction LID = Util.memoize((type, mat) -> new SimpleLazyModel(() -> createLidModel(type, mat), Materials.CHEST)); private static final BiFunction BASE = Util.memoize((type, mat) -> new SimpleLazyModel(() -> createBaseModel(type, mat), Materials.CHEST)); - private final OrientedPart body; - private final TransformedPart lid; + private OrientedPart body; + private TransformedPart lid; - private final Float2FloatFunction lidProgress; - private final TextureAtlasSprite sprite; - @NotNull - private final ChestType chestType; - private final Quaternion baseRotation; + private Float2FloatFunction lidProgress; + private TextureAtlasSprite sprite; + private ChestType chestType; + private Quaternion baseRotation; private float lastProgress = Float.NaN; public ChestInstance(InstanceContext ctx, T blockEntity) { super(ctx, blockEntity); + } + @Override + public void init() { Block block = blockState.getBlock(); chestType = blockState.hasProperty(ChestBlock.TYPE) ? blockState.getValue(ChestBlock.TYPE) : ChestType.SINGLE; @@ -64,7 +62,6 @@ public class ChestInstance extends Abstr lid = lidInstance(); if (block instanceof AbstractChestBlock chestBlock) { - float horizontalAngle = blockState.getValue(ChestBlock.FACING).toYRot(); baseRotation = Vector3f.YP.rotationDegrees(-horizontalAngle); @@ -78,6 +75,8 @@ public class ChestInstance extends Abstr baseRotation = Quaternion.ONE; lidProgress = $ -> 0f; } + + super.init(); } @Override @@ -112,8 +111,8 @@ public class ChestInstance extends Abstr } @Override - public void addCrumblingParts(List data) { - Collections.addAll(data, body, lid); + public List getCrumblingParts() { + return List.of(body, lid); } @Override @@ -123,12 +122,12 @@ public class ChestInstance extends Abstr } private OrientedPart baseInstance() { - return instancerManager.getInstancer(StructTypes.ORIENTED, BASE.apply(chestType, sprite), RenderStage.AFTER_BLOCK_ENTITIES) + return instancerProvider.instancer(StructTypes.ORIENTED, BASE.apply(chestType, sprite), RenderStage.AFTER_BLOCK_ENTITIES) .createInstance(); } private TransformedPart lidInstance() { - return instancerManager.getInstancer(StructTypes.TRANSFORMED, LID.apply(chestType, sprite), RenderStage.AFTER_BLOCK_ENTITIES) + return instancerProvider.instancer(StructTypes.TRANSFORMED, LID.apply(chestType, sprite), RenderStage.AFTER_BLOCK_ENTITIES) .createInstance(); } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java index b042fcfe5..d4b3bd9da 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java @@ -26,22 +26,26 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; public class MinecartInstance extends AbstractEntityInstance implements DynamicInstance, TickableInstance { - private static final SimpleLazyModel MODEL = new SimpleLazyModel(MinecartInstance::getBodyModel, Materials.MINECART); private final PoseStack stack = new PoseStack(); - private final TransformedPart body; + private TransformedPart body; private TransformedPart contents; private BlockState blockState; private boolean active; public MinecartInstance(InstanceContext ctx, T entity) { super(ctx, entity); + } + @Override + public void init() { body = getBody(); blockState = entity.getDisplayBlockState(); contents = getContents(); + + super.init(); } @Override @@ -167,12 +171,12 @@ public class MinecartInstance extends AbstractEntity return null; } - return instancerManager.getInstancer(StructTypes.TRANSFORMED, Models.block(blockState), RenderStage.AFTER_ENTITIES) + return instancerProvider.instancer(StructTypes.TRANSFORMED, Models.block(blockState), RenderStage.AFTER_ENTITIES) .createInstance(); } private TransformedPart getBody() { - return instancerManager.getInstancer(StructTypes.TRANSFORMED, MODEL, RenderStage.AFTER_ENTITIES) + return instancerProvider.instancer(StructTypes.TRANSFORMED, MODEL, RenderStage.AFTER_ENTITIES) .createInstance(); } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java index 2aefef791..4b32d9c8e 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java @@ -1,6 +1,5 @@ package com.jozufozu.flywheel.vanilla; -import java.util.Collections; import java.util.List; import java.util.function.Function; @@ -33,17 +32,20 @@ public class ShulkerBoxInstance extends AbstractBlockEntityInstance BASE = Util.memoize(it -> new SimpleLazyModel(() -> makeBaseModel(it), Materials.SHULKER)); private static final Function LID = Util.memoize(it -> new SimpleLazyModel(() -> makeLidModel(it), Materials.SHULKER)); - private final TextureAtlasSprite texture; + private TextureAtlasSprite texture; - private final TransformedPart base; - private final TransformedPart lid; + private TransformedPart base; + private TransformedPart lid; private final PoseStack stack = new PoseStack(); private float lastProgress = Float.NaN; public ShulkerBoxInstance(InstanceContext ctx, ShulkerBoxBlockEntity blockEntity) { super(ctx, blockEntity); + } + @Override + public void init() { DyeColor color = blockEntity.getColor(); if (color == null) { texture = Sheets.DEFAULT_SHULKER_TEXTURE_LOCATION.sprite(); @@ -67,6 +69,8 @@ public class ShulkerBoxInstance extends AbstractBlockEntityInstance data) { - Collections.addAll(data, base, lid); + public List getCrumblingParts() { + return List.of(base, lid); } @Override @@ -107,12 +111,12 @@ public class ShulkerBoxInstance extends AbstractBlockEntityInstance createInstances(InstanceContext ctx) { + public Collection> createInstances(InstanceContext ctx) { effects.clear(); boids.clear(); for (int i = 0; i < INSTANCE_COUNT; i++) { @@ -238,10 +238,10 @@ public class ExampleEffect implements Effect { } } - public class BoidInstance extends AbstractInstance implements DynamicInstance, TickableInstance { + public class BoidInstance extends AbstractInstance implements EffectInstance, DynamicInstance, TickableInstance { private final Boid self; - TransformedPart instance; + private TransformedPart instance; public BoidInstance(InstanceContext ctx, Level level, Boid self) { super(ctx, level); @@ -250,11 +250,13 @@ public class ExampleEffect implements Effect { @Override public void init() { - instance = instancerManager.getInstancer(StructTypes.TRANSFORMED, Models.block(Blocks.SHROOMLIGHT.defaultBlockState()), RenderStage.AFTER_PARTICLES) + instance = instancerProvider.instancer(StructTypes.TRANSFORMED, Models.block(Blocks.SHROOMLIGHT.defaultBlockState()), RenderStage.AFTER_PARTICLES) .createInstance(); instance.setBlockLight(15) .setSkyLight(15); + + super.init(); } @Override @@ -297,7 +299,7 @@ public class ExampleEffect implements Effect { } @Override - public boolean checkFrustum(FrustumIntersection frustum) { + public boolean isVisible(FrustumIntersection frustum) { return true; }