Instance Refactor I

This commit is contained in:
PepperCode1 2023-04-04 12:36:54 -07:00
parent 4ac0adf703
commit b65cb7eb7f
72 changed files with 625 additions and 535 deletions

View File

@ -59,7 +59,6 @@ body:
label: Mod Version label: Mod Version
description: The version of the mod you were using when the bug occured description: The version of the mod you were using when the bug occured
options: options:
- "0.7.0"
- "0.6.8.a" - "0.6.8.a"
- "0.6.8" - "0.6.8"
- "0.6.7" - "0.6.7"

View File

@ -2,7 +2,7 @@ org.gradle.jvmargs = -Xmx3G
org.gradle.daemon = false org.gradle.daemon = false
# mod version info # mod version info
mod_version = 0.7.0 mod_version = 1.0.0-alpha
artifact_minecraft_version = 1.18.2 artifact_minecraft_version = 1.18.2
minecraft_version = 1.18.2 minecraft_version = 1.18.2

View File

@ -17,7 +17,7 @@ import com.jozufozu.flywheel.impl.RegistryImpl;
import com.jozufozu.flywheel.lib.backend.Backends; import com.jozufozu.flywheel.lib.backend.Backends;
import com.jozufozu.flywheel.lib.context.Contexts; import com.jozufozu.flywheel.lib.context.Contexts;
import com.jozufozu.flywheel.lib.format.Formats; import com.jozufozu.flywheel.lib.format.Formats;
import com.jozufozu.flywheel.lib.material.MaterialIndicies; import com.jozufozu.flywheel.lib.material.MaterialIndices;
import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.material.Materials;
import com.jozufozu.flywheel.lib.model.Models; import com.jozufozu.flywheel.lib.model.Models;
import com.jozufozu.flywheel.lib.model.PartialModel; import com.jozufozu.flywheel.lib.model.PartialModel;
@ -111,7 +111,7 @@ public class Flywheel {
Contexts.init(); Contexts.init();
Pipelines.init(); Pipelines.init();
MaterialIndicies.init(); MaterialIndices.init();
VanillaInstances.init(); VanillaInstances.init();
@ -126,10 +126,10 @@ public class Flywheel {
} }
private static void setup(final FMLCommonSetupEvent event) { private static void setup(final FMLCommonSetupEvent event) {
ArgumentTypes.register(rl("backend").toString(), BackendArgument.class, new EmptyArgumentSerializer<>(BackendArgument::getInstance));
RegistryImpl.freezeAll(); RegistryImpl.freezeAll();
IdRegistryImpl.freezeAll(); IdRegistryImpl.freezeAll();
ArgumentTypes.register(rl("backend").toString(), BackendArgument.class, new EmptyArgumentSerializer<>(BackendArgument::getInstance));
} }
public static ArtifactVersion getVersion() { public static ArtifactVersion getVersion() {

View File

@ -3,7 +3,7 @@ package com.jozufozu.flywheel.api.backend;
import java.util.List; import java.util.List;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager;
public interface Engine extends RenderDispatcher, InstancerProvider { public interface Engine extends RenderDispatcher, InstancerProvider {
void attachManagers(InstanceManager<?>... listener); void attachManagers(InstanceManager<?>... listener);

View File

@ -0,0 +1,11 @@
package com.jozufozu.flywheel.api.instance;
import java.util.List;
import com.jozufozu.flywheel.api.instancer.InstancedPart;
import net.minecraft.world.level.block.entity.BlockEntity;
public interface BlockEntityInstance<T extends BlockEntity> extends Instance {
List<InstancedPart> getCrumblingParts();
}

View File

@ -2,11 +2,10 @@ package com.jozufozu.flywheel.api.instance;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.instancer.Instancer; import com.jozufozu.flywheel.api.instancer.Instancer;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
/** /**
* An interface giving {@link BlockEntityInstance}s a hook to have a function called at * An interface giving {@link Instance}s a hook to have a function called at
* the start of a frame. By implementing {@link DynamicInstance}, a {@link BlockEntityInstance} * the start of a frame. By implementing {@link DynamicInstance}, an {@link Instance}
* can animate its models in ways that could not be easily achieved by shader attribute * can animate its models in ways that could not be easily achieved by shader attribute
* parameterization. * parameterization.
* *

View File

@ -0,0 +1,6 @@
package com.jozufozu.flywheel.api.instance;
import net.minecraft.world.entity.Entity;
public interface EntityInstance<E extends Entity> extends Instance {
}

View File

@ -4,9 +4,38 @@ import org.joml.FrustumIntersection;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
/**
* A general interface providing information about any type of thing that could use Flywheel's instanced rendering.
*/
public interface Instance { public interface Instance {
BlockPos getWorldPosition(); BlockPos getWorldPosition();
/**
* Initialize parts here.
*/
void init();
/**
* Update instance data here. Good for when data doesn't change very often and when animations are GPU based.
*
* <br><br> If your animations are complex or more CPU driven, see {@link DynamicInstance} or {@link TickableInstance}.
*/
void update();
/**
* When an instance is reset, the instance is deleted and re-created.
*
* <p>
* Just before {@link #update()} would be called, {@code shouldReset()} is checked.
* If this function returns {@code true}, then this instance will be {@link #delete deleted},
* and another instance will be constructed to replace it. This allows for more sane resource
* acquisition compared to trying to update everything within the lifetime of an instance.
* </p>
*
* @return {@code true} if this instance should be discarded and refreshed.
*/
boolean shouldReset();
/** /**
* Check this instance against a frustum.<p> * Check this instance against a frustum.<p>
* An implementor may choose to return a constant to skip the frustum check. * An implementor may choose to return a constant to skip the frustum check.
@ -15,5 +44,12 @@ public interface Instance {
*/ */
boolean checkFrustum(FrustumIntersection frustum); boolean checkFrustum(FrustumIntersection frustum);
boolean isRemoved(); /**
* Free any acquired resources.
*/
void delete();
// TODO
@Deprecated
void removeNow();
} }

View File

@ -2,11 +2,10 @@ package com.jozufozu.flywheel.api.instance;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.instancer.Instancer; import com.jozufozu.flywheel.api.instancer.Instancer;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
/** /**
* An interface giving {@link BlockEntityInstance}s a hook to have a function called at * An interface giving {@link Instance}s a hook to have a function called at
* the end of every tick. By implementing {@link TickableInstance}, a {@link BlockEntityInstance} * the end of every tick. By implementing {@link TickableInstance}, an {@link Instance}
* can update frequently, but not every frame. * can update frequently, but not every frame.
* <br> There are a few cases in which this should be considered over {@link DynamicInstance}: * <br> There are a few cases in which this should be considered over {@link DynamicInstance}:
* <ul> * <ul>

View File

@ -1,7 +1,7 @@
package com.jozufozu.flywheel.api.instance.blockentity; package com.jozufozu.flywheel.api.instance.controller;
import com.jozufozu.flywheel.api.instance.BlockEntityInstance;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;

View File

@ -1,7 +1,7 @@
package com.jozufozu.flywheel.api.instance.entity; package com.jozufozu.flywheel.api.instance.controller;
import com.jozufozu.flywheel.api.instance.EntityInstance;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;

View File

@ -0,0 +1,60 @@
package com.jozufozu.flywheel.api.instance.controller;
import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.impl.instance.InstancingControllerRegistryImpl;
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;
/**
* A utility class for registering and retrieving {@code InstancingController}s.
*/
public final class InstancingControllerRegistry {
/**
* Gets the instancing controller for the given block entity type, if one exists.
* @param type The block entity type to get the instancing controller for.
* @param <T> The type of the block entity.
* @return The instancing controller for the given block entity type, or {@code null} if none exists.
*/
@Nullable
public static <T extends BlockEntity> BlockEntityInstancingController<? super T> getController(BlockEntityType<T> type) {
return InstancingControllerRegistryImpl.getController(type);
}
/**
* Gets the instancing controller for the given entity type, if one exists.
* @param type The entity type to get the instancing controller for.
* @param <T> The type of the entity.
* @return The instancing controller for the given entity type, or {@code null} if none exists.
*/
@Nullable
public static <T extends Entity> EntityInstancingController<? super T> getController(EntityType<T> type) {
return InstancingControllerRegistryImpl.getController(type);
}
/**
* Sets the instancing controller for the given block entity type.
* @param type The block entity type to set the instancing controller for.
* @param instancingController The instancing controller to set.
* @param <T> The type of the block entity.
*/
public static <T extends BlockEntity> void setController(BlockEntityType<T> type, BlockEntityInstancingController<? super T> instancingController) {
InstancingControllerRegistryImpl.setController(type, instancingController);
}
/**
* Sets the instancing controller for the given entity type.
* @param type The entity type to set the instancing controller for.
* @param instancingController The instancing controller to set.
* @param <T> The type of the entity.
*/
public static <T extends Entity> void setController(EntityType<T> type, EntityInstancingController<? super T> instancingController) {
InstancingControllerRegistryImpl.setController(type, instancingController);
}
private InstancingControllerRegistry() {
}
}

View File

@ -0,0 +1,10 @@
package com.jozufozu.flywheel.api.instance.effect;
import java.util.Collection;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instancer.InstancerProvider;
public interface Effect {
Collection<Instance> createInstances(InstancerProvider instancerManager);
}

View File

@ -14,6 +14,6 @@ public interface InstancerProvider {
*/ */
<D extends InstancedPart> Instancer<D> getInstancer(StructType<D> type, Model model, RenderStage stage); <D extends InstancedPart> Instancer<D> getInstancer(StructType<D> type, Model model, RenderStage stage);
// TODO: this method does not belong in the interface // TODO: this method does not belong in this interface
Vec3i getOriginCoordinate(); Vec3i getOriginCoordinate();
} }

View File

@ -21,6 +21,10 @@ public interface IdRegistry<T> extends Iterable<T> {
@Nullable @Nullable
ResourceLocation getId(T object); ResourceLocation getId(T object);
T getOrThrow(ResourceLocation id);
ResourceLocation getIdOrThrow(T object);
@Unmodifiable @Unmodifiable
Set<ResourceLocation> getAllIds(); Set<ResourceLocation> getAllIds();

View File

@ -9,7 +9,7 @@ import com.jozufozu.flywheel.api.struct.StructType;
public class CullingContextSet { public class CullingContextSet {
static CullingContextSet create() { static CullingContextSet create() {
var builder = new CullingContextSet(); var builder = new CullingContextSet();
for (StructType<?> structType : StructType.REGISTRY.getAll()) { for (StructType<?> structType : StructType.REGISTRY) {
builder.add(structType); builder.add(structType);
} }
return builder; return builder;

View File

@ -26,7 +26,7 @@ import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
import com.jozufozu.flywheel.glsl.generate.FnSignature; import com.jozufozu.flywheel.glsl.generate.FnSignature;
import com.jozufozu.flywheel.glsl.generate.GlslExpr; import com.jozufozu.flywheel.glsl.generate.GlslExpr;
import com.jozufozu.flywheel.lib.material.MaterialIndicies; import com.jozufozu.flywheel.lib.material.MaterialIndices;
import com.jozufozu.flywheel.lib.pipeline.Pipelines; import com.jozufozu.flywheel.lib.pipeline.Pipelines;
import com.jozufozu.flywheel.util.StringUtil; import com.jozufozu.flywheel.util.StringUtil;
@ -55,12 +55,12 @@ public class FlwCompiler {
this.sources = sources; this.sources = sources;
this.vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter")) this.vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
.materialSources(MaterialIndicies.getAllVertexShaders()) .materialSources(MaterialIndices.getAllVertexShaders())
.adapt(FnSignature.ofVoid("flw_materialVertex")) .adapt(FnSignature.ofVoid("flw_materialVertex"))
.switchOn(GlslExpr.variable("flw_materialVertexID")) .switchOn(GlslExpr.variable("flw_materialVertexID"))
.build(sources); .build(sources);
this.fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter")) this.fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
.materialSources(MaterialIndicies.getAllFragmentShaders()) .materialSources(MaterialIndices.getAllFragmentShaders())
.adapt(FnSignature.ofVoid("flw_materialFragment")) .adapt(FnSignature.ofVoid("flw_materialFragment"))
.adapt(FnSignature.create() .adapt(FnSignature.create()
.returnType("bool") .returnType("bool")

View File

@ -24,8 +24,8 @@ public class PipelineContextSet {
static PipelineContextSet create() { static PipelineContextSet create() {
var builder = new PipelineContextSet(); var builder = new PipelineContextSet();
for (Pipeline pipelineShader : availablePipelineShaders()) { for (Pipeline pipelineShader : availablePipelineShaders()) {
for (StructType<?> structType : StructType.REGISTRY.getAll()) { for (StructType<?> structType : StructType.REGISTRY) {
for (VertexType vertexType : VertexType.REGISTRY.getAll()) { for (VertexType vertexType : VertexType.REGISTRY) {
builder.add(vertexType, structType, Contexts.WORLD, pipelineShader); builder.add(vertexType, structType, Contexts.WORLD, pipelineShader);
} }
} }

View File

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.backend.instancing; package com.jozufozu.flywheel.backend.engine;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet; import java.util.BitSet;

View File

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.backend.instancing; package com.jozufozu.flywheel.backend.engine;
import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;

View File

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.backend.uniform; package com.jozufozu.flywheel.backend.engine;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;

View File

@ -10,7 +10,7 @@ import com.jozufozu.flywheel.api.instancer.Instancer;
import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager;
import com.jozufozu.flywheel.util.FlwUtil; import com.jozufozu.flywheel.util.FlwUtil;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;

View File

@ -20,7 +20,7 @@ import com.jozufozu.flywheel.api.instancer.Instancer;
import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.instancing.InstancerKey; import com.jozufozu.flywheel.backend.engine.InstancerKey;
import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;

View File

@ -2,7 +2,7 @@ package com.jozufozu.flywheel.backend.engine.batching;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer; import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
public class CPUInstancer<D extends InstancedPart> extends AbstractInstancer<D> { public class CPUInstancer<D extends InstancedPart> extends AbstractInstancer<D> {

View File

@ -16,7 +16,7 @@ import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.compile.FlwCompiler; import com.jozufozu.flywheel.backend.compile.FlwCompiler;
import com.jozufozu.flywheel.backend.uniform.UniformBuffer; import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.lib.context.Contexts; import com.jozufozu.flywheel.lib.context.Contexts;
import com.jozufozu.flywheel.lib.pipeline.Pipelines; import com.jozufozu.flywheel.lib.pipeline.Pipelines;

View File

@ -5,7 +5,7 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.lib.material.MaterialIndicies; import com.jozufozu.flywheel.lib.material.MaterialIndices;
public final class IndirectDraw<T extends InstancedPart> { public final class IndirectDraw<T extends InstancedPart> {
private final IndirectInstancer<T> instancer; private final IndirectInstancer<T> instancer;
@ -25,8 +25,8 @@ public final class IndirectDraw<T extends InstancedPart> {
this.stage = stage; this.stage = stage;
this.mesh = mesh; this.mesh = mesh;
this.vertexMaterialID = MaterialIndicies.getVertexShaderIndex(material.vertexShader()); this.vertexMaterialID = MaterialIndices.getVertexShaderIndex(material);
this.fragmentMaterialID = MaterialIndicies.getFragmentShaderIndex(material.fragmentShader()); this.fragmentMaterialID = MaterialIndices.getFragmentShaderIndex(material);
} }
public void prepare(int baseInstance) { public void prepare(int baseInstance) {

View File

@ -11,7 +11,7 @@ import com.jozufozu.flywheel.api.instancer.Instancer;
import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.instancing.InstancerKey; import com.jozufozu.flywheel.backend.engine.InstancerKey;
import com.jozufozu.flywheel.util.Pair; import com.jozufozu.flywheel.util.Pair;
public class IndirectDrawManager { public class IndirectDrawManager {

View File

@ -13,7 +13,7 @@ import java.util.Map;
import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.lib.material.MaterialIndicies; import com.jozufozu.flywheel.lib.material.MaterialIndices;
import com.jozufozu.flywheel.util.Textures; import com.jozufozu.flywheel.util.Textures;
public class IndirectDrawSet<T extends InstancedPart> { public class IndirectDrawSet<T extends InstancedPart> {
@ -50,7 +50,7 @@ public class IndirectDrawSet<T extends InstancedPart> {
multiDraws.clear(); multiDraws.clear();
// sort by stage, then material // sort by stage, then material
indirectDraws.sort(Comparator.comparing(IndirectDraw<T>::stage) indirectDraws.sort(Comparator.comparing(IndirectDraw<T>::stage)
.thenComparing(draw -> MaterialIndicies.getMaterialIndex(draw.material()))); .thenComparing(draw -> MaterialIndices.getMaterialIndex(draw.material())));
for (int start = 0, i = 0; i < indirectDraws.size(); i++) { for (int start = 0, i = 0; i < indirectDraws.size(); i++) {
var draw = indirectDraws.get(i); var draw = indirectDraws.get(i);

View File

@ -15,7 +15,7 @@ import com.jozufozu.flywheel.api.instancer.Instancer;
import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager;
import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.GlStateTracker;
import com.jozufozu.flywheel.gl.GlTextureUnit; import com.jozufozu.flywheel.gl.GlTextureUnit;
import com.jozufozu.flywheel.util.FlwUtil; import com.jozufozu.flywheel.util.FlwUtil;

View File

@ -5,7 +5,7 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.api.struct.StructWriter;
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer; import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
public class IndirectInstancer<D extends InstancedPart> extends AbstractInstancer<D> { public class IndirectInstancer<D extends InstancedPart> extends AbstractInstancer<D> {

View File

@ -1,8 +0,0 @@
package com.jozufozu.flywheel.backend.engine.indirect;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.vertex.VertexType;
public record ShaderState(Material material, VertexType vertex, StructType<?> instance) {
}

View File

@ -8,7 +8,7 @@ import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.layout.BufferLayout; import com.jozufozu.flywheel.api.layout.BufferLayout;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.api.struct.StructWriter;
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer; import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
import com.jozufozu.flywheel.gl.array.GlVertexArray; import com.jozufozu.flywheel.gl.array.GlVertexArray;
import com.jozufozu.flywheel.gl.buffer.GlBuffer; import com.jozufozu.flywheel.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.gl.buffer.GlBufferType; import com.jozufozu.flywheel.gl.buffer.GlBufferType;

View File

@ -20,7 +20,7 @@ import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.instancing.InstancerKey; import com.jozufozu.flywheel.backend.engine.InstancerKey;
public class InstancingDrawManager { public class InstancingDrawManager {

View File

@ -16,11 +16,11 @@ import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.backend.compile.FlwCompiler; import com.jozufozu.flywheel.backend.compile.FlwCompiler;
import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.backend.uniform.UniformBuffer; import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager;
import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.GlStateTracker;
import com.jozufozu.flywheel.gl.GlTextureUnit; import com.jozufozu.flywheel.gl.GlTextureUnit;
import com.jozufozu.flywheel.lib.material.MaterialIndicies; import com.jozufozu.flywheel.lib.material.MaterialIndices;
import com.jozufozu.flywheel.lib.pipeline.Pipelines; import com.jozufozu.flywheel.lib.pipeline.Pipelines;
import com.jozufozu.flywheel.util.FlwUtil; import com.jozufozu.flywheel.util.FlwUtil;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
@ -121,8 +121,8 @@ public class InstancingEngine implements Engine {
UniformBuffer.syncAndBind(program); UniformBuffer.syncAndBind(program);
var uniformLocation = program.getUniformLocation("_flw_materialID_instancing"); var uniformLocation = program.getUniformLocation("_flw_materialID_instancing");
var vertexID = MaterialIndicies.getVertexShaderIndex(material.vertexShader()); var vertexID = MaterialIndices.getVertexShaderIndex(material);
var fragmentID = MaterialIndicies.getFragmentShaderIndex(material.fragmentShader()); var fragmentID = MaterialIndices.getFragmentShaderIndex(material);
GL32.glUniform2ui(uniformLocation, vertexID, fragmentID); GL32.glUniform2ui(uniformLocation, vertexID, fragmentID);
} }

View File

@ -7,11 +7,12 @@ import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance; 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.BackendUtil;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager; import com.jozufozu.flywheel.backend.instancing.manager.BlockEntityInstanceManager;
import com.jozufozu.flywheel.backend.instancing.effect.Effect; import com.jozufozu.flywheel.backend.instancing.manager.EffectInstanceManager;
import com.jozufozu.flywheel.backend.instancing.effect.EffectInstanceManager; import com.jozufozu.flywheel.backend.instancing.manager.EntityInstanceManager;
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager; import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager;
import com.jozufozu.flywheel.backend.task.ParallelTaskExecutor; import com.jozufozu.flywheel.backend.task.ParallelTaskExecutor;
import com.jozufozu.flywheel.extension.ClientLevelExtension; import com.jozufozu.flywheel.extension.ClientLevelExtension;

View File

@ -6,8 +6,10 @@ import com.jozufozu.flywheel.api.backend.BackendManager;
import com.jozufozu.flywheel.api.event.BeginFrameEvent; import com.jozufozu.flywheel.api.event.BeginFrameEvent;
import com.jozufozu.flywheel.api.event.ReloadRenderersEvent; import com.jozufozu.flywheel.api.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.api.event.RenderStageEvent; 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.BackendUtil;
import com.jozufozu.flywheel.backend.instancing.effect.Effect; import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager;
import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwCommands;
import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.AnimationTickHolder;
@ -26,7 +28,7 @@ public class InstancedRenderDispatcher {
private static final WorldAttached<InstanceWorld> instanceWorlds = new WorldAttached<>(InstanceWorld::create); private static final WorldAttached<InstanceWorld> instanceWorlds = new WorldAttached<>(InstanceWorld::create);
/** /**
* Call this when you want to manually run {@link AbstractInstance#update()}. * Call this when you want to manually run {@link Instance#update()}.
* @param blockEntity The block entity whose instance you want to update. * @param blockEntity The block entity whose instance you want to update.
*/ */
public static void enqueueUpdate(BlockEntity blockEntity) { public static void enqueueUpdate(BlockEntity blockEntity) {
@ -38,7 +40,7 @@ public class InstancedRenderDispatcher {
} }
/** /**
* Call this when you want to manually run {@link AbstractInstance#update()}. * Call this when you want to manually run {@link Instance#update()}.
* @param entity The entity whose instance you want to update. * @param entity The entity whose instance you want to update.
*/ */
public static void enqueueUpdate(Entity entity) { public static void enqueueUpdate(Entity entity) {
@ -118,7 +120,7 @@ public class InstancedRenderDispatcher {
InstanceWorld instanceWorld = instanceWorlds.get(Minecraft.getInstance().level); InstanceWorld instanceWorld = instanceWorlds.get(Minecraft.getInstance().level);
debug.add("Update limiting: " + FlwCommands.boolToText(FlwConfig.get().limitUpdates()).getString()); debug.add("Update limiting: " + FlwCommands.boolToText(FlwConfig.get().limitUpdates()).getString());
debug.add("B: " + instanceWorld.blockEntities.getObjectCount() + ", E: " + instanceWorld.entities.getObjectCount()); debug.add("B: " + instanceWorld.blockEntities.getInstanceCount() + ", E: " + instanceWorld.entities.getInstanceCount());
instanceWorld.engine.addDebugInfo(debug); instanceWorld.engine.addDebugInfo(debug);
} else { } else {
debug.add("Disabled"); debug.add("Disabled");

View File

@ -1,11 +0,0 @@
package com.jozufozu.flywheel.backend.instancing.effect;
import java.util.Collection;
import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
public interface Effect {
Collection<AbstractInstance> createInstances(InstancerProvider instancerManager);
}

View File

@ -1,47 +0,0 @@
package com.jozufozu.flywheel.backend.instancing.entity;
import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.instance.InstancedRenderRegistry;
import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.BackendUtil;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.storage.One2OneStorage;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
public class EntityInstanceManager extends InstanceManager<Entity> {
private final One2OneStorage<Entity> storage;
public EntityInstanceManager(InstancerProvider instancerManager) {
storage = new One2OneStorage<>(instancerManager) {
@Override
protected @Nullable AbstractInstance createRaw(Entity obj) {
return InstancedRenderRegistry.createInstance(this.instancerManager, obj);
}
};
}
@Override
public One2OneStorage<Entity> getStorage() {
return storage;
}
@Override
protected boolean canCreateInstance(Entity entity) {
if (!entity.isAlive()) {
return false;
}
if (!InstancedRenderRegistry.canInstance(entity.getType())) {
return false;
}
Level level = entity.level;
return BackendUtil.isFlywheelLevel(level);
}
}

View File

@ -1,14 +1,16 @@
package com.jozufozu.flywheel.backend.instancing.blockentity; package com.jozufozu.flywheel.backend.instancing.manager;
import java.util.List; import java.util.List;
import com.jozufozu.flywheel.api.instance.InstancedRenderRegistry; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.instance.BlockEntityInstance;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.BackendUtil; import com.jozufozu.flywheel.backend.BackendUtil;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.storage.One2OneStorage; import com.jozufozu.flywheel.backend.instancing.storage.One2OneStorage;
import com.jozufozu.flywheel.backend.instancing.storage.Storage; import com.jozufozu.flywheel.backend.instancing.storage.Storage;
import com.jozufozu.flywheel.lib.instance.InstancingControllerHelper;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
@ -18,7 +20,6 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> { public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
private final BlockEntityStorage storage; private final BlockEntityStorage storage;
public BlockEntityInstanceManager(InstancerProvider instancerManager) { public BlockEntityInstanceManager(InstancerProvider instancerManager) {
@ -26,7 +27,7 @@ public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
} }
@Override @Override
public Storage<BlockEntity> getStorage() { protected Storage<BlockEntity> getStorage() {
return storage; return storage;
} }
@ -43,7 +44,7 @@ public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
return false; return false;
} }
if (!InstancedRenderRegistry.canInstance(blockEntity.getType())) { if (!InstancingControllerHelper.canInstance(blockEntity.getType())) {
return false; return false;
} }
@ -68,18 +69,17 @@ public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
return false; return false;
} }
public static class BlockEntityStorage extends One2OneStorage<BlockEntity> { private static class BlockEntityStorage extends One2OneStorage<BlockEntity> {
private final Long2ObjectMap<BlockEntityInstance<?>> posLookup = new Long2ObjectOpenHashMap<>();
final Long2ObjectMap<BlockEntityInstance<?>> posLookup = new Long2ObjectOpenHashMap<>(); public BlockEntityStorage(InstancerProvider instancerManager) {
super(instancerManager);
public BlockEntityStorage(InstancerProvider manager) {
super(manager);
} }
@Override @Override
protected AbstractInstance createRaw(BlockEntity obj) { @Nullable
var instance = InstancedRenderRegistry.createInstance(instancerManager, obj); protected Instance createRaw(BlockEntity obj) {
BlockEntityInstance<?> instance = InstancingControllerHelper.createInstance(instancerManager, obj);
if (instance != null) { if (instance != null) {
BlockPos blockPos = obj.getBlockPos(); BlockPos blockPos = obj.getBlockPos();

View File

@ -1,18 +1,16 @@
package com.jozufozu.flywheel.backend.instancing.effect; package com.jozufozu.flywheel.backend.instancing.manager;
import java.util.ArrayList; import java.util.ArrayList;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.effect.Effect;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.storage.AbstractStorage; import com.jozufozu.flywheel.backend.instancing.storage.AbstractStorage;
import com.jozufozu.flywheel.backend.instancing.storage.Storage; import com.jozufozu.flywheel.backend.instancing.storage.Storage;
import com.jozufozu.flywheel.lib.light.LightUpdater;
public class EffectInstanceManager extends InstanceManager<Effect> { public class EffectInstanceManager extends InstanceManager<Effect> {
private final EffectStorage<Effect> storage; private final EffectStorage<Effect> storage;
public EffectInstanceManager(InstancerProvider instancerManager) { public EffectInstanceManager(InstancerProvider instancerManager) {
@ -20,7 +18,7 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
} }
@Override @Override
public Storage<Effect> getStorage() { protected Storage<Effect> getStorage() {
return storage; return storage;
} }
@ -29,9 +27,8 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
return true; return true;
} }
public static class EffectStorage<T extends Effect> extends AbstractStorage<T> { private static class EffectStorage<T extends Effect> extends AbstractStorage<T> {
private final Multimap<T, Instance> instances;
private final Multimap<T, AbstractInstance> instances;
public EffectStorage(InstancerProvider manager) { public EffectStorage(InstancerProvider manager) {
super(manager); super(manager);
@ -39,21 +36,13 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
} }
@Override @Override
public int getObjectCount() { public Iterable<Instance> getAllInstances() {
return instances.size();
}
@Override
public Iterable<AbstractInstance> allInstances() {
return instances.values(); return instances.values();
} }
@Override @Override
public void invalidate() { public int getInstanceCount() {
instances.values().forEach(AbstractInstance::removeAndMark); return instances.size();
instances.clear();
tickableInstances.clear();
dynamicInstances.clear();
} }
@Override @Override
@ -75,9 +64,8 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
this.tickableInstances.removeAll(instances); this.tickableInstances.removeAll(instances);
this.dynamicInstances.removeAll(instances); this.dynamicInstances.removeAll(instances);
for (AbstractInstance instance : instances) { for (Instance instance : instances) {
LightUpdater.get(instance.level) instance.removeNow();
.removeListener(instance);
} }
} }
@ -89,20 +77,28 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
return; return;
} }
instances.forEach(AbstractInstance::update); instances.forEach(Instance::update);
} }
@Override @Override
public void recreateAll() { public void recreateAll() {
this.dynamicInstances.clear(); tickableInstances.clear();
this.tickableInstances.clear(); dynamicInstances.clear();
this.instances.values().forEach(AbstractInstance::removeAndMark); instances.values().forEach(Instance::delete);
var backup = new ArrayList<>(this.instances.keySet()); var backup = new ArrayList<>(instances.keySet());
this.instances.clear(); instances.clear();
backup.forEach(this::create); backup.forEach(this::create);
} }
@Override
public void invalidate() {
instances.values().forEach(Instance::delete);
instances.clear();
tickableInstances.clear();
dynamicInstances.clear();
}
private void create(T obj) { private void create(T obj) {
var instances = obj.createInstances(instancerManager); var instances = obj.createInstances(instancerManager);

View File

@ -0,0 +1,53 @@
package com.jozufozu.flywheel.backend.instancing.manager;
import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instancer.InstancerProvider;
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 net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
public class EntityInstanceManager extends InstanceManager<Entity> {
private final EntityStorage storage;
public EntityInstanceManager(InstancerProvider instancerManager) {
storage = new EntityStorage(instancerManager);
}
@Override
protected Storage<Entity> getStorage() {
return storage;
}
@Override
protected boolean canCreateInstance(Entity entity) {
if (!entity.isAlive()) {
return false;
}
if (!InstancingControllerHelper.canInstance(entity.getType())) {
return false;
}
Level level = entity.level;
return BackendUtil.isFlywheelLevel(level);
}
private static class EntityStorage extends One2OneStorage<Entity> {
public EntityStorage(InstancerProvider instancerManager) {
super(instancerManager);
}
@Override
@Nullable
protected Instance createRaw(Entity obj) {
return InstancingControllerHelper.createInstance(instancerManager, obj);
}
}
}

View File

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.backend.instancing; package com.jozufozu.flywheel.backend.instancing.manager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -12,6 +12,7 @@ import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.backend.BackendManager; import com.jozufozu.flywheel.api.backend.BackendManager;
import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.instance.DynamicInstance; 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.instance.TickableInstance;
import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.backend.instancing.ratelimit.BandedPrimeLimiter; import com.jozufozu.flywheel.backend.instancing.ratelimit.BandedPrimeLimiter;
@ -19,33 +20,28 @@ import com.jozufozu.flywheel.backend.instancing.ratelimit.DistanceUpdateLimiter;
import com.jozufozu.flywheel.backend.instancing.ratelimit.NonLimiter; import com.jozufozu.flywheel.backend.instancing.ratelimit.NonLimiter;
import com.jozufozu.flywheel.backend.instancing.storage.Storage; import com.jozufozu.flywheel.backend.instancing.storage.Storage;
import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.lib.light.LightUpdater;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
public abstract class InstanceManager<T> { public abstract class InstanceManager<T> {
private final Set<T> queuedAdditions = new HashSet<>(64);
private final Set<T> queuedUpdates = new HashSet<>(64);
private final Set<T> queuedAdditions; protected DistanceUpdateLimiter frameLimiter;
private final Set<T> queuedUpdates; protected DistanceUpdateLimiter tickLimiter;
protected DistanceUpdateLimiter frame;
protected DistanceUpdateLimiter tick;
public InstanceManager() { public InstanceManager() {
this.queuedUpdates = new HashSet<>(64); frameLimiter = createUpdateLimiter();
this.queuedAdditions = new HashSet<>(64); tickLimiter = createUpdateLimiter();
frame = createUpdateLimiter();
tick = createUpdateLimiter();
} }
public abstract Storage<T> getStorage(); protected abstract Storage<T> getStorage();
/** /**
* Is the given object currently capable of being instanced? * Is the given object currently capable of being instanced?
* *
* <p> * <p>
* This won't be the case for TEs or entities that are outside of loaded chunks. * This won't be the case for block entities or entities that are outside of loaded chunks.
* </p> * </p>
* *
* @return true if the object is currently capable of being instanced. * @return true if the object is currently capable of being instanced.
@ -65,102 +61,8 @@ public abstract class InstanceManager<T> {
* *
* @return The object count. * @return The object count.
*/ */
public int getObjectCount() { public int getInstanceCount() {
return getStorage().getObjectCount(); return getStorage().getInstanceCount();
}
/**
* Ticks the InstanceManager.
*
* <p>
* {@link TickableInstance}s get ticked.
* <br>
* Queued updates are processed.
* </p>
*/
public void tick(TaskExecutor executor, double cameraX, double cameraY, double cameraZ) {
tick.tick();
processQueuedUpdates();
// integer camera pos as a micro-optimization
int cX = (int) cameraX;
int cY = (int) cameraY;
int cZ = (int) cameraZ;
var instances = getStorage().getInstancesForTicking();
distributeWork(executor, instances, instance -> tickInstance(instance, cX, cY, cZ));
}
protected void tickInstance(TickableInstance instance, int cX, int cY, int cZ) {
if (!instance.decreaseTickRateWithDistance()) {
instance.tick();
return;
}
BlockPos pos = instance.getWorldPosition();
int dX = pos.getX() - cX;
int dY = pos.getY() - cY;
int dZ = pos.getZ() - cZ;
if (!tick.shouldUpdate(dX, dY, dZ)) {
return;
}
instance.tick();
}
public void beginFrame(TaskExecutor executor, RenderContext context) {
frame.tick();
processQueuedAdditions();
// integer camera pos
BlockPos cameraIntPos = context.camera().getBlockPosition();
int cX = cameraIntPos.getX();
int cY = cameraIntPos.getY();
int cZ = cameraIntPos.getZ();
FrustumIntersection culler = context.culler();
var instances = getStorage().getInstancesForUpdate();
distributeWork(executor, instances, instance -> updateInstance(instance, culler, cX, cY, cZ));
}
private static <I> void distributeWork(TaskExecutor executor, List<I> instances, Consumer<I> action) {
final int size = instances.size();
final int threadCount = executor.getThreadCount();
if (threadCount == 1) {
executor.execute(() -> instances.forEach(action));
} else {
final int stride = Math.max(size / (threadCount * 2), 1);
for (int start = 0; start < size; start += stride) {
int end = Math.min(start + stride, size);
var sub = instances.subList(start, end);
executor.execute(() -> sub.forEach(action));
}
}
}
protected void updateInstance(DynamicInstance dyn, FrustumIntersection test, int cX, int cY, int cZ) {
if (!dyn.decreaseFramerateWithDistance()) {
dyn.beginFrame();
return;
}
BlockPos worldPos = dyn.getWorldPosition();
int dX = worldPos.getX() - cX;
int dY = worldPos.getY() - cY;
int dZ = worldPos.getZ() - cZ;
if (!frame.shouldUpdate(dX, dY, dZ)) {
return;
}
if (dyn.checkFrustum(test)) {
dyn.beginFrame();
}
} }
public void add(T obj) { public void add(T obj) {
@ -185,15 +87,13 @@ public abstract class InstanceManager<T> {
} }
} }
public void queueUpdate(T obj) { public void queueAddAll(Collection<? extends T> objects) {
if (!BackendManager.isOn()) return; if (!BackendManager.isOn() || objects.isEmpty()) {
if (!canCreateInstance(obj)) {
return; return;
} }
synchronized (queuedUpdates) { synchronized (queuedAdditions) {
queuedUpdates.add(obj); queuedAdditions.addAll(objects);
} }
} }
@ -216,16 +116,38 @@ public abstract class InstanceManager<T> {
} }
} }
public void queueUpdate(T obj) {
if (!BackendManager.isOn()) return;
if (!canCreateInstance(obj)) {
return;
}
synchronized (queuedUpdates) {
queuedUpdates.add(obj);
}
}
public void remove(T obj) { public void remove(T obj) {
if (!BackendManager.isOn()) return; if (!BackendManager.isOn()) return;
getStorage().remove(obj); getStorage().remove(obj);
} }
public void onOriginShift() {
getStorage().recreateAll();
}
public void invalidate() { public void invalidate() {
getStorage().invalidate(); getStorage().invalidate();
} }
public void delete() {
for (Instance instance : getStorage().getAllInstances()) {
instance.removeNow();
}
}
protected void processQueuedAdditions() { protected void processQueuedAdditions() {
if (queuedAdditions.isEmpty()) { if (queuedAdditions.isEmpty()) {
return; return;
@ -256,23 +178,96 @@ public abstract class InstanceManager<T> {
} }
} }
public void onOriginShift() { /**
getStorage().recreateAll(); * Ticks the InstanceManager.
*
* <p>
* {@link TickableInstance}s get ticked.
* <br>
* Queued updates are processed.
* </p>
*/
public void tick(TaskExecutor executor, double cameraX, double cameraY, double cameraZ) {
tickLimiter.tick();
processQueuedUpdates();
// integer camera pos as a micro-optimization
int cX = (int) cameraX;
int cY = (int) cameraY;
int cZ = (int) cameraZ;
var instances = getStorage().getInstancesForTicking();
distributeWork(executor, instances, instance -> tickInstance(instance, cX, cY, cZ));
} }
public void delete() { protected void tickInstance(TickableInstance instance, int cX, int cY, int cZ) {
for (AbstractInstance value : getStorage().allInstances()) { if (!instance.decreaseTickRateWithDistance()) {
LightUpdater.get(value.level).removeListener(value); instance.tick();
}
}
public void queueAddAll(Collection<? extends T> objects) {
if (!BackendManager.isOn() || objects.isEmpty()) {
return; return;
} }
synchronized (queuedAdditions) { BlockPos pos = instance.getWorldPosition();
queuedAdditions.addAll(objects);
int dX = pos.getX() - cX;
int dY = pos.getY() - cY;
int dZ = pos.getZ() - cZ;
if (!tickLimiter.shouldUpdate(dX, dY, dZ)) {
return;
}
instance.tick();
}
public void beginFrame(TaskExecutor executor, RenderContext context) {
frameLimiter.tick();
processQueuedAdditions();
// integer camera pos
BlockPos cameraIntPos = context.camera().getBlockPosition();
int cX = cameraIntPos.getX();
int cY = cameraIntPos.getY();
int cZ = cameraIntPos.getZ();
FrustumIntersection culler = context.culler();
var instances = getStorage().getInstancesForUpdate();
distributeWork(executor, instances, instance -> updateInstance(instance, culler, cX, cY, cZ));
}
private static <I> void distributeWork(TaskExecutor executor, List<I> instances, Consumer<I> action) {
final int size = instances.size();
final int threadCount = executor.getThreadCount();
if (threadCount == 1) {
executor.execute(() -> instances.forEach(action));
} else {
final int stride = Math.max(size / (threadCount * 2), 1);
for (int start = 0; start < size; start += stride) {
int end = Math.min(start + stride, size);
var sub = instances.subList(start, end);
executor.execute(() -> sub.forEach(action));
}
}
}
protected void updateInstance(DynamicInstance instance, FrustumIntersection frustum, int cX, int cY, int cZ) {
if (!instance.decreaseFramerateWithDistance()) {
instance.beginFrame();
return;
}
BlockPos worldPos = instance.getWorldPosition();
int dX = worldPos.getX() - cX;
int dY = worldPos.getY() - cY;
int dZ = worldPos.getZ() - cZ;
if (!frameLimiter.shouldUpdate(dX, dY, dZ)) {
return;
}
if (instance.checkFrustum(frustum)) {
instance.beginFrame();
} }
} }
} }

View File

@ -4,7 +4,7 @@ import net.minecraft.util.Mth;
public class BandedPrimeLimiter implements DistanceUpdateLimiter { public class BandedPrimeLimiter implements DistanceUpdateLimiter {
// 1 followed by the prime numbers // 1 followed by the prime numbers
private static final int[] divisorSequence = new int[] { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 }; private static final int[] DIVISOR_SEQUENCE = new int[] { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 };
private int tickCount = 0; private int tickCount = 0;
@ -23,6 +23,6 @@ public class BandedPrimeLimiter implements DistanceUpdateLimiter {
int i = (dSq / 2048); int i = (dSq / 2048);
return divisorSequence[Mth.clamp(i, 0, divisorSequence.length - 1)]; return DIVISOR_SEQUENCE[Mth.clamp(i, 0, DIVISOR_SEQUENCE.length - 1)];
} }
} }

View File

@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.instancing.ratelimit;
public class NonLimiter implements DistanceUpdateLimiter { public class NonLimiter implements DistanceUpdateLimiter {
@Override @Override
public void tick() { public void tick() {
// noop
} }
@Override @Override

View File

@ -4,21 +4,17 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.jozufozu.flywheel.api.instance.DynamicInstance; 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.instance.TickableInstance;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.lib.light.LightUpdater;
public abstract class AbstractStorage<T> implements Storage<T> { public abstract class AbstractStorage<T> implements Storage<T> {
protected final List<TickableInstance> tickableInstances;
protected final List<DynamicInstance> dynamicInstances;
protected final InstancerProvider instancerManager; protected final InstancerProvider instancerManager;
protected final List<TickableInstance> tickableInstances = new ArrayList<>();
protected final List<DynamicInstance> dynamicInstances = new ArrayList<>();
protected AbstractStorage(InstancerProvider instancerManager) { protected AbstractStorage(InstancerProvider instancerManager) {
this.instancerManager = instancerManager; this.instancerManager = instancerManager;
this.dynamicInstances = new ArrayList<>();
this.tickableInstances = new ArrayList<>();
} }
@Override @Override
@ -31,19 +27,17 @@ public abstract class AbstractStorage<T> implements Storage<T> {
return dynamicInstances; return dynamicInstances;
} }
protected void setup(AbstractInstance renderer) { protected void setup(Instance instance) {
renderer.init(); instance.init();
renderer.updateLight();
LightUpdater.get(renderer.level) if (instance instanceof TickableInstance tickable) {
.addListener(renderer); tickableInstances.add(tickable);
if (renderer instanceof TickableInstance r) { tickable.tick();
tickableInstances.add(r);
r.tick();
} }
if (renderer instanceof DynamicInstance r) { if (instance instanceof DynamicInstance dynamic) {
dynamicInstances.add(r); dynamicInstances.add(dynamic);
r.beginFrame(); dynamic.beginFrame();
} }
} }
} }

View File

@ -5,12 +5,11 @@ import java.util.Map;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.lib.light.LightUpdater;
public abstract class One2OneStorage<T> extends AbstractStorage<T> { public abstract class One2OneStorage<T> extends AbstractStorage<T> {
private final Map<T, AbstractInstance> instances; private final Map<T, Instance> instances;
public One2OneStorage(InstancerProvider instancerManager) { public One2OneStorage(InstancerProvider instancerManager) {
super(instancerManager); super(instancerManager);
@ -18,26 +17,18 @@ public abstract class One2OneStorage<T> extends AbstractStorage<T> {
} }
@Override @Override
public int getObjectCount() { public Iterable<Instance> getAllInstances() {
return instances.size();
}
@Override
public Iterable<AbstractInstance> allInstances() {
return instances.values(); return instances.values();
} }
@Override @Override
public void invalidate() { public int getInstanceCount() {
instances.values().forEach(AbstractInstance::remove); return instances.size();
instances.clear();
dynamicInstances.clear();
tickableInstances.clear();
} }
@Override @Override
public void add(T obj) { public void add(T obj) {
AbstractInstance instance = instances.get(obj); Instance instance = instances.get(obj);
if (instance == null) { if (instance == null) {
create(obj); create(obj);
@ -46,22 +37,21 @@ public abstract class One2OneStorage<T> extends AbstractStorage<T> {
@Override @Override
public void remove(T obj) { public void remove(T obj) {
var instance = instances.remove(obj); Instance instance = instances.remove(obj);
if (instance == null) { if (instance == null) {
return; return;
} }
instance.remove(); instance.delete();
dynamicInstances.remove(instance); dynamicInstances.remove(instance);
tickableInstances.remove(instance); tickableInstances.remove(instance);
LightUpdater.get(instance.level) instance.removeNow();
.removeListener(instance);
} }
@Override @Override
public void update(T obj) { public void update(T obj) {
AbstractInstance instance = instances.get(obj); Instance instance = instances.get(obj);
if (instance == null) { if (instance == null) {
return; return;
@ -83,9 +73,9 @@ public abstract class One2OneStorage<T> extends AbstractStorage<T> {
dynamicInstances.clear(); dynamicInstances.clear();
tickableInstances.clear(); tickableInstances.clear();
instances.replaceAll((obj, instance) -> { instances.replaceAll((obj, instance) -> {
instance.remove(); instance.delete();
AbstractInstance out = createRaw(obj); Instance out = createRaw(obj);
if (out != null) { if (out != null) {
setup(out); setup(out);
@ -95,16 +85,23 @@ public abstract class One2OneStorage<T> extends AbstractStorage<T> {
}); });
} }
@Override
public void invalidate() {
instances.values().forEach(Instance::delete);
instances.clear();
tickableInstances.clear();
dynamicInstances.clear();
}
private void create(T obj) { private void create(T obj) {
AbstractInstance renderer = createRaw(obj); Instance instance = createRaw(obj);
if (renderer != null) { if (instance != null) {
setup(renderer); setup(instance);
instances.put(obj, renderer); instances.put(obj, instance);
} }
} }
@Nullable @Nullable
protected abstract AbstractInstance createRaw(T obj); protected abstract Instance createRaw(T obj);
} }

View File

@ -3,20 +3,18 @@ package com.jozufozu.flywheel.backend.instancing.storage;
import java.util.List; import java.util.List;
import com.jozufozu.flywheel.api.instance.DynamicInstance; 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.instance.TickableInstance;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
public interface Storage<T> { public interface Storage<T> {
int getObjectCount(); Iterable<Instance> getAllInstances();
Iterable<AbstractInstance> allInstances(); int getInstanceCount();
List<TickableInstance> getInstancesForTicking(); List<TickableInstance> getInstancesForTicking();
List<DynamicInstance> getInstancesForUpdate(); List<DynamicInstance> getInstancesForUpdate();
void invalidate();
void add(T obj); void add(T obj);
void remove(T obj); void remove(T obj);
@ -24,4 +22,6 @@ public interface Storage<T> {
void update(T obj); void update(T obj);
void recreateAll(); void recreateAll();
void invalidate();
} }

View File

@ -15,7 +15,6 @@ public class SerialTaskExecutor implements TaskExecutor {
@Override @Override
public void syncPoint() { public void syncPoint() {
// noop
} }
@Override @Override

View File

@ -63,7 +63,7 @@ public class FlwCommands {
LocalPlayer player = Minecraft.getInstance().player; LocalPlayer player = Minecraft.getInstance().player;
if (player != null) { if (player != null) {
Backend backend = context.getArgument("id", Backend.class); Backend backend = context.getArgument("id", Backend.class);
value.set(Backend.REGISTRY.getId(backend).toString()); value.set(Backend.REGISTRY.getIdOrThrow(backend).toString());
Component message = backend.getEngineMessage(); Component message = backend.getEngineMessage();
player.displayClientMessage(message, false); player.displayClientMessage(message, false);

View File

@ -24,10 +24,9 @@ public class FlwConfig {
private final ForgeConfigSpec clientSpec; private final ForgeConfigSpec clientSpec;
public FlwConfig() { public FlwConfig() {
Pair<ClientConfig, ForgeConfigSpec> client = new ForgeConfigSpec.Builder().configure(ClientConfig::new); Pair<ClientConfig, ForgeConfigSpec> clientPair = new ForgeConfigSpec.Builder().configure(ClientConfig::new);
this.client = clientPair.getLeft();
this.client = client.getLeft(); clientSpec = clientPair.getRight();
clientSpec = client.getRight();
} }
public static FlwConfig get() { public static FlwConfig get() {
@ -38,7 +37,7 @@ public class FlwConfig {
Backend backend = parseBackend(client.backend.get()); Backend backend = parseBackend(client.backend.get());
if (backend == null) { if (backend == null) {
backend = BackendManager.getDefaultBackend(); backend = BackendManager.getDefaultBackend();
client.backend.set(Backend.REGISTRY.getId(backend).toString()); client.backend.set(Backend.REGISTRY.getIdOrThrow(backend).toString());
} }
return backend; return backend;
@ -77,7 +76,7 @@ public class FlwConfig {
public ClientConfig(ForgeConfigSpec.Builder builder) { public ClientConfig(ForgeConfigSpec.Builder builder) {
backend = builder.comment("Select the backend to use.") backend = builder.comment("Select the backend to use.")
.define("backend", Backend.REGISTRY.getId(BackendManager.getDefaultBackend()).toString()); .define("backend", Backend.REGISTRY.getIdOrThrow(BackendManager.getDefaultBackend()).toString());
limitUpdates = builder.comment("Enable or disable instance update limiting with distance.") limitUpdates = builder.comment("Enable or disable instance update limiting with distance.")
.define("limitUpdates", true); .define("limitUpdates", true);

View File

@ -2,7 +2,7 @@ package com.jozufozu.flywheel.extension;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.instance.blockentity.BlockEntityInstancingController; import com.jozufozu.flywheel.api.instance.controller.BlockEntityInstancingController;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;

View File

@ -2,7 +2,7 @@ package com.jozufozu.flywheel.extension;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.instance.entity.EntityInstancingController; import com.jozufozu.flywheel.api.instance.controller.EntityInstancingController;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;

View File

@ -39,7 +39,7 @@ public final class BackendManagerImpl {
var actual = preferred.findFallback(); var actual = preferred.findFallback();
if (preferred != actual) { if (preferred != actual) {
LOGGER.warn("Flywheel backend fell back from '{}' to '{}'", Backend.REGISTRY.getId(preferred), Backend.REGISTRY.getId(actual)); LOGGER.warn("Flywheel backend fell back from '{}' to '{}'", Backend.REGISTRY.getIdOrThrow(preferred), Backend.REGISTRY.getIdOrThrow(actual));
} }
return actual; return actual;

View File

@ -72,6 +72,24 @@ public class IdRegistryImpl<T> implements IdRegistry<T> {
return reverseMap.get(object); return reverseMap.get(object);
} }
@Override
public T getOrThrow(ResourceLocation id) {
T object = get(id);
if (object == null) {
throw new IllegalArgumentException("Could not find object for ID '" + id + "'!");
}
return object;
}
@Override
public ResourceLocation getIdOrThrow(T object) {
ResourceLocation id = getId(object);
if (id == null) {
throw new IllegalArgumentException("Could not find ID for object!");
}
return id;
}
@Override @Override
@Unmodifiable @Unmodifiable
public Set<ResourceLocation> getAllIds() { public Set<ResourceLocation> getAllIds() {
@ -107,6 +125,7 @@ public class IdRegistryImpl<T> implements IdRegistry<T> {
for (Runnable runnable : freezeCallbacks) { for (Runnable runnable : freezeCallbacks) {
runnable.run(); runnable.run();
} }
freezeCallbacks.clear();
} }
public static void freezeAll() { public static void freezeAll() {

View File

@ -91,6 +91,7 @@ public class RegistryImpl<T> implements Registry<T> {
for (Runnable runnable : freezeCallbacks) { for (Runnable runnable : freezeCallbacks) {
runnable.run(); runnable.run();
} }
freezeCallbacks.clear();
} }
public static void freezeAll() { public static void freezeAll() {

View File

@ -0,0 +1,37 @@
package com.jozufozu.flywheel.impl.instance;
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.extension.BlockEntityTypeExtension;
import com.jozufozu.flywheel.extension.EntityTypeExtension;
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;
@SuppressWarnings("unchecked")
public final class InstancingControllerRegistryImpl {
@Nullable
public static <T extends BlockEntity> BlockEntityInstancingController<? super T> getController(BlockEntityType<T> type) {
return ((BlockEntityTypeExtension<T>) type).flywheel$getInstancingController();
}
@Nullable
public static <T extends Entity> EntityInstancingController<? super T> getController(EntityType<T> type) {
return ((EntityTypeExtension<T>) type).flywheel$getInstancingController();
}
public static <T extends BlockEntity> void setController(BlockEntityType<T> type, BlockEntityInstancingController<? super T> instancingController) {
((BlockEntityTypeExtension<T>) type).flywheel$setInstancingController(instancingController);
}
public static <T extends Entity> void setController(EntityType<T> type, EntityInstancingController<? super T> instancingController) {
((EntityTypeExtension<T>) type).flywheel$setInstancingController(instancingController);
}
private InstancingControllerRegistryImpl() {
}
}

View File

@ -1,15 +1,16 @@
package com.jozufozu.flywheel.backend.instancing.blockentity; package com.jozufozu.flywheel.lib.instance;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.joml.FrustumIntersection; import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.instance.BlockEntityInstance;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance; import com.jozufozu.flywheel.backend.instancing.manager.BlockEntityInstanceManager;
import com.jozufozu.flywheel.lib.box.ImmutableBox; import com.jozufozu.flywheel.lib.box.ImmutableBox;
import com.jozufozu.flywheel.lib.box.MutableBox; import com.jozufozu.flywheel.lib.box.MutableBox;
@ -29,19 +30,19 @@ import net.minecraft.world.level.block.state.BlockState;
* </ul> * </ul>
* See the interfaces' documentation for more information about each one. * See the interfaces' documentation for more information about each one.
* *
* <br> Implementing one or more of these will give a {@link BlockEntityInstance} access * <br> Implementing one or more of these will give a {@link AbstractBlockEntityInstance} access
* to more interesting and regular points within a tick or a frame. * to more interesting and regular points within a tick or a frame.
* *
* @param <T> The type of {@link BlockEntity} your class is an instance of. * @param <T> The type of {@link BlockEntity} your class is an instance of.
*/ */
public abstract class BlockEntityInstance<T extends BlockEntity> extends AbstractInstance { public abstract class AbstractBlockEntityInstance<T extends BlockEntity> extends AbstractInstance implements BlockEntityInstance<T> {
protected final T blockEntity; protected final T blockEntity;
protected final BlockPos pos; protected final BlockPos pos;
protected final BlockPos instancePos; protected final BlockPos instancePos;
protected final BlockState blockState; protected final BlockState blockState;
public BlockEntityInstance(InstancerProvider instancerManager, T blockEntity) { public AbstractBlockEntityInstance(InstancerProvider instancerManager, T blockEntity) {
super(instancerManager, blockEntity.getLevel()); super(instancerManager, blockEntity.getLevel());
this.blockEntity = blockEntity; this.blockEntity = blockEntity;
this.pos = blockEntity.getBlockPos(); this.pos = blockEntity.getBlockPos();
@ -49,6 +50,7 @@ public abstract class BlockEntityInstance<T extends BlockEntity> extends Abstrac
this.instancePos = pos.subtract(instancerManager.getOriginCoordinate()); this.instancePos = pos.subtract(instancerManager.getOriginCoordinate());
} }
@Override
public List<InstancedPart> getCrumblingParts() { public List<InstancedPart> getCrumblingParts() {
var out = new ArrayList<InstancedPart>(); var out = new ArrayList<InstancedPart>();
addCrumblingParts(out); addCrumblingParts(out);

View File

@ -1,14 +1,13 @@
package com.jozufozu.flywheel.backend.instancing.entity; package com.jozufozu.flywheel.lib.instance;
import org.joml.FrustumIntersection; import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.instance.DynamicInstance; 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.TickableInstance;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance; import com.jozufozu.flywheel.backend.instancing.manager.BlockEntityInstanceManager;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager;
import com.jozufozu.flywheel.lib.box.MutableBox; import com.jozufozu.flywheel.lib.box.MutableBox;
import com.jozufozu.flywheel.lib.light.LightListener;
import com.jozufozu.flywheel.lib.light.TickingLightListener; import com.jozufozu.flywheel.lib.light.TickingLightListener;
import com.mojang.math.Vector3f; import com.mojang.math.Vector3f;
@ -30,17 +29,17 @@ import net.minecraft.world.phys.Vec3;
* </ul> * </ul>
* See the interfaces' documentation for more information about each one. * See the interfaces' documentation for more information about each one.
* *
* <br> Implementing one or more of these will give a {@link EntityInstance} access * <br> Implementing one or more of these will give a {@link AbstractEntityInstance} access
* to more interesting and regular points within a tick or a frame. * to more interesting and regular points within a tick or a frame.
* *
* @param <E> The type of {@link Entity} your class is an instance of. * @param <E> The type of {@link Entity} your class is an instance of.
*/ */
public abstract class EntityInstance<E extends Entity> extends AbstractInstance implements LightListener, TickingLightListener { public abstract class AbstractEntityInstance<E extends Entity> extends AbstractInstance implements EntityInstance<E>, TickingLightListener {
protected final E entity; protected final E entity;
protected final MutableBox bounds; protected final MutableBox bounds;
public EntityInstance(InstancerProvider instancerManager, E entity) { public AbstractEntityInstance(InstancerProvider instancerManager, E entity) {
super(instancerManager, entity.level); super(instancerManager, entity.level);
this.entity = entity; this.entity = entity;
bounds = MutableBox.from(entity.getBoundingBox()); bounds = MutableBox.from(entity.getBoundingBox());

View File

@ -1,66 +1,44 @@
package com.jozufozu.flywheel.backend.instancing; package com.jozufozu.flywheel.lib.instance;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.api.instancer.FlatLit; import com.jozufozu.flywheel.api.instancer.FlatLit;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager;
import com.jozufozu.flywheel.lib.light.LightListener; import com.jozufozu.flywheel.lib.light.LightListener;
import com.jozufozu.flywheel.lib.light.LightUpdater;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos; import net.minecraft.core.SectionPos;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.LightLayer;
/**
* A general interface providing information about any type of thing that could use Flywheel's instanced rendering.
* Right now, that's only {@link BlockEntityInstanceManager}, but there could be an entity equivalent in the future.
*/
public abstract class AbstractInstance implements Instance, LightListener { public abstract class AbstractInstance implements Instance, LightListener {
protected final InstancerProvider instancerManager; protected final InstancerProvider instancerManager;
public final Level level; public final Level level;
protected boolean removed = false; protected boolean deleted = false;
public AbstractInstance(InstancerProvider instancerManager, Level level) { public AbstractInstance(InstancerProvider instancerManager, Level level) {
this.instancerManager = instancerManager; this.instancerManager = instancerManager;
this.level = level; this.level = level;
} }
/** @Override
* Initialize models here.
*/
public void init() { public void init() {
updateLight();
LightUpdater.get(level).addListener(this);
} }
public final void removeAndMark() { @Override
if (removed) {
return;
}
remove();
removed = true;
}
/**
* Free any acquired resources.
*/
public abstract void remove();
/**
* Update instance data here. Good for when data doesn't change very often and when animations are GPU based.
* Don't query lighting data here, that's handled separately in {@link #updateLight()}.
*
* <br><br> If your animations are complex or more CPU driven, see {@link DynamicInstance} or {@link TickableInstance}.
*/
public void update() { public void update() {
} }
@Override
public boolean shouldReset() {
return false;
}
/** /**
* Called after construction and when a light update occurs in the world. * Called after construction and when a light update occurs in the world.
* *
@ -69,30 +47,21 @@ public abstract class AbstractInstance implements Instance, LightListener {
public void updateLight() { public void updateLight() {
} }
/** protected abstract void _delete();
* When an instance is reset, the instance is deleted and re-created.
* @Override
* <p> public final void delete() {
* Just before {@link #update()} would be called, {@code shouldReset()} is checked. if (deleted) {
* If this function returns {@code true}, then this instance will be {@link #remove removed}, return;
* and another instance will be constructed to replace it. This allows for more sane resource }
* acquisition compared to trying to update everything within the lifetime of an instance.
* </p> _delete();
* deleted = true;
* @return {@code true} if this instance should be discarded and refreshed.
*/
public boolean shouldReset() {
return false;
} }
@Override @Override
public boolean isInvalid() { public boolean isInvalid() {
return removed; return deleted;
}
@Override
public boolean isRemoved() {
return removed;
} }
@Override @Override
@ -117,4 +86,8 @@ public abstract class AbstractInstance implements Instance, LightListener {
.setSkyLight(sky)); .setSkyLight(sky));
} }
@Override
public final void removeNow() {
LightUpdater.get(level).removeListener(this);
}
} }

View File

@ -1,25 +1,20 @@
package com.jozufozu.flywheel.api.instance; package com.jozufozu.flywheel.lib.instance;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.instance.blockentity.BlockEntityInstancingController; import com.jozufozu.flywheel.api.instance.BlockEntityInstance;
import com.jozufozu.flywheel.api.instance.entity.EntityInstancingController; import com.jozufozu.flywheel.api.instance.EntityInstance;
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 com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance;
import com.jozufozu.flywheel.extension.BlockEntityTypeExtension;
import com.jozufozu.flywheel.extension.EntityTypeExtension;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
/** public final class InstancingControllerHelper {
* A utility class for registering and retrieving {@code InstancingController}s.
*/
@SuppressWarnings("unchecked")
public class InstancedRenderRegistry {
/** /**
* Checks if the given block entity type can be instanced. * Checks if the given block entity type can be instanced.
* @param type The block entity type to check. * @param type The block entity type to check.
@ -27,7 +22,7 @@ public class InstancedRenderRegistry {
* @return {@code true} if the block entity type can be instanced. * @return {@code true} if the block entity type can be instanced.
*/ */
public static <T extends BlockEntity> boolean canInstance(BlockEntityType<? extends T> type) { public static <T extends BlockEntity> boolean canInstance(BlockEntityType<? extends T> type) {
return getController(type) != null; return InstancingControllerRegistry.getController(type) != null;
} }
/** /**
@ -37,7 +32,7 @@ public class InstancedRenderRegistry {
* @return {@code true} if the entity type can be instanced. * @return {@code true} if the entity type can be instanced.
*/ */
public static <T extends Entity> boolean canInstance(EntityType<? extends T> type) { public static <T extends Entity> boolean canInstance(EntityType<? extends T> type) {
return getController(type) != null; return InstancingControllerRegistry.getController(type) != null;
} }
/** /**
@ -49,7 +44,7 @@ public class InstancedRenderRegistry {
*/ */
@Nullable @Nullable
public static <T extends BlockEntity> BlockEntityInstance<? super T> createInstance(InstancerProvider instancerManager, T blockEntity) { public static <T extends BlockEntity> BlockEntityInstance<? super T> createInstance(InstancerProvider instancerManager, T blockEntity) {
BlockEntityInstancingController<? super T> controller = getController(getType(blockEntity)); BlockEntityInstancingController<? super T> controller = InstancingControllerRegistry.getController(getType(blockEntity));
if (controller == null) { if (controller == null) {
return null; return null;
} }
@ -65,7 +60,7 @@ public class InstancedRenderRegistry {
*/ */
@Nullable @Nullable
public static <T extends Entity> EntityInstance<? super T> createInstance(InstancerProvider instancerManager, T entity) { public static <T extends Entity> EntityInstance<? super T> createInstance(InstancerProvider instancerManager, T entity) {
EntityInstancingController<? super T> controller = getController(getType(entity)); EntityInstancingController<? super T> controller = InstancingControllerRegistry.getController(getType(entity));
if (controller == null) { if (controller == null) {
return null; return null;
} }
@ -79,7 +74,7 @@ public class InstancedRenderRegistry {
* @return {@code true} if the block entity is instanced and should not be rendered normally. * @return {@code true} if the block entity is instanced and should not be rendered normally.
*/ */
public static <T extends BlockEntity> boolean shouldSkipRender(T blockEntity) { public static <T extends BlockEntity> boolean shouldSkipRender(T blockEntity) {
BlockEntityInstancingController<? super T> controller = getController(getType(blockEntity)); BlockEntityInstancingController<? super T> controller = InstancingControllerRegistry.getController(getType(blockEntity));
if (controller == null) { if (controller == null) {
return false; return false;
} }
@ -93,61 +88,20 @@ public class InstancedRenderRegistry {
* @return {@code true} if the entity is instanced and should not be rendered normally. * @return {@code true} if the entity is instanced and should not be rendered normally.
*/ */
public static <T extends Entity> boolean shouldSkipRender(T entity) { public static <T extends Entity> boolean shouldSkipRender(T entity) {
EntityInstancingController<? super T> controller = getController(getType(entity)); EntityInstancingController<? super T> controller = InstancingControllerRegistry.getController(getType(entity));
if (controller == null) { if (controller == null) {
return false; return false;
} }
return controller.shouldSkipRender(entity); return controller.shouldSkipRender(entity);
} }
/**
* Gets the instancing controller for the given block entity type, if one exists.
* @param type The block entity type to get the instancing controller for.
* @param <T> The type of the block entity.
* @return The instancing controller for the given block entity type, or {@code null} if none exists.
*/
@Nullable
public static <T extends BlockEntity> BlockEntityInstancingController<? super T> getController(BlockEntityType<T> type) {
return ((BlockEntityTypeExtension<T>) type).flywheel$getInstancingController();
}
/**
* Gets the instancing controller for the given entity type, if one exists.
* @param type The entity type to get the instancing controller for.
* @param <T> The type of the entity.
* @return The instancing controller for the given entity type, or {@code null} if none exists.
*/
@Nullable
public static <T extends Entity> EntityInstancingController<? super T> getController(EntityType<T> type) {
return ((EntityTypeExtension<T>) type).flywheel$getInstancingController();
}
/**
* Sets the instancing controller for the given block entity type.
* @param type The block entity type to set the instancing controller for.
* @param instancingController The instancing controller to set.
* @param <T> The type of the block entity.
*/
public static <T extends BlockEntity> void setController(BlockEntityType<T> type, BlockEntityInstancingController<? super T> instancingController) {
((BlockEntityTypeExtension<T>) type).flywheel$setInstancingController(instancingController);
}
/**
* Sets the instancing controller for the given entity type.
* @param type The entity type to set the instancing controller for.
* @param instancingController The instancing controller to set.
* @param <T> The type of the entity.
*/
public static <T extends Entity> void setController(EntityType<T> type, EntityInstancingController<? super T> instancingController) {
((EntityTypeExtension<T>) type).flywheel$setInstancingController(instancingController);
}
/** /**
* Gets the type of the given block entity. * Gets the type of the given block entity.
* @param blockEntity The block entity to get the type of. * @param blockEntity The block entity to get the type of.
* @param <T> The type of the block entity. * @param <T> The type of the block entity.
* @return The {@link BlockEntityType} associated with the given block entity. * @return The {@link BlockEntityType} associated with the given block entity.
*/ */
@SuppressWarnings("unchecked")
public static <T extends BlockEntity> BlockEntityType<? super T> getType(T blockEntity) { public static <T extends BlockEntity> BlockEntityType<? super T> getType(T blockEntity) {
return (BlockEntityType<? super T>) blockEntity.getType(); return (BlockEntityType<? super T>) blockEntity.getType();
} }
@ -158,7 +112,11 @@ public class InstancedRenderRegistry {
* @param <T> The type of the entity. * @param <T> The type of the entity.
* @return The {@link EntityType} associated with the given entity. * @return The {@link EntityType} associated with the given entity.
*/ */
@SuppressWarnings("unchecked")
public static <T extends Entity> EntityType<? super T> getType(T entity) { public static <T extends Entity> EntityType<? super T> getType(T entity) {
return (EntityType<? super T>) entity.getType(); return (EntityType<? super T>) entity.getType();
} }
private InstancingControllerHelper() {
}
} }

View File

@ -4,10 +4,10 @@ import java.util.Objects;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Predicate; import java.util.function.Predicate;
import com.jozufozu.flywheel.api.instance.InstancedRenderRegistry; import com.jozufozu.flywheel.api.instance.BlockEntityInstance;
import com.jozufozu.flywheel.api.instance.blockentity.BlockEntityInstancingController; import com.jozufozu.flywheel.api.instance.controller.BlockEntityInstancingController;
import com.jozufozu.flywheel.api.instance.controller.InstancingControllerRegistry;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
@ -93,7 +93,7 @@ public class SimpleBlockEntityInstancingController<T extends BlockEntity> implem
skipRender = be -> false; skipRender = be -> false;
} }
SimpleBlockEntityInstancingController<T> controller = new SimpleBlockEntityInstancingController<>(instanceFactory, skipRender); SimpleBlockEntityInstancingController<T> controller = new SimpleBlockEntityInstancingController<>(instanceFactory, skipRender);
InstancedRenderRegistry.setController(type, controller); InstancingControllerRegistry.setController(type, controller);
return controller; return controller;
} }
} }

View File

@ -4,10 +4,10 @@ import java.util.Objects;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Predicate; import java.util.function.Predicate;
import com.jozufozu.flywheel.api.instance.InstancedRenderRegistry; import com.jozufozu.flywheel.api.instance.EntityInstance;
import com.jozufozu.flywheel.api.instance.entity.EntityInstancingController; import com.jozufozu.flywheel.api.instance.controller.EntityInstancingController;
import com.jozufozu.flywheel.api.instance.controller.InstancingControllerRegistry;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
@ -93,7 +93,7 @@ public class SimpleEntityInstancingController<T extends Entity> implements Entit
skipRender = entity -> false; skipRender = entity -> false;
} }
SimpleEntityInstancingController<T> controller = new SimpleEntityInstancingController<>(instanceFactory, skipRender); SimpleEntityInstancingController<T> controller = new SimpleEntityInstancingController<>(instanceFactory, skipRender);
InstancedRenderRegistry.setController(type, controller); InstancingControllerRegistry.setController(type, controller);
return controller; return controller;
} }
} }

View File

@ -21,10 +21,10 @@ import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
// TODO: add messages to exceptions // TODO: add messages to exceptions
public class MaterialIndicies { public class MaterialIndices {
private static Reference2IntMap<Material> materialIndicies; private static Reference2IntMap<Material> materialIndices;
private static Object2IntMap<ResourceLocation> vertexShaderIndicies; private static Object2IntMap<ResourceLocation> vertexShaderIndices;
private static Object2IntMap<ResourceLocation> fragmentShaderIndicies; private static Object2IntMap<ResourceLocation> fragmentShaderIndices;
private static ObjectList<Material> materialsByIndex; private static ObjectList<Material> materialsByIndex;
private static ObjectList<ResourceLocation> vertexShadersByIndex; private static ObjectList<ResourceLocation> vertexShadersByIndex;
private static ObjectList<ResourceLocation> fragmentShadersByIndex; private static ObjectList<ResourceLocation> fragmentShadersByIndex;
@ -34,21 +34,29 @@ public class MaterialIndicies {
if (!initialized) { if (!initialized) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
return materialIndicies.getInt(material); return materialIndices.getInt(material);
} }
public static int getVertexShaderIndex(ResourceLocation vertexShader) { public static int getVertexShaderIndex(ResourceLocation vertexShader) {
if (!initialized) { if (!initialized) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
return vertexShaderIndicies.getInt(vertexShader); return vertexShaderIndices.getInt(vertexShader);
} }
public static int getFragmentShaderIndex(ResourceLocation fragmentShader) { public static int getFragmentShaderIndex(ResourceLocation fragmentShader) {
if (!initialized) { if (!initialized) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
return fragmentShaderIndicies.getInt(fragmentShader); return fragmentShaderIndices.getInt(fragmentShader);
}
public static int getVertexShaderIndex(Material material) {
return getVertexShaderIndex(material.vertexShader());
}
public static int getFragmentShaderIndex(Material material) {
return getFragmentShaderIndex(material.fragmentShader());
} }
public static Material getMaterial(int index) { public static Material getMaterial(int index) {
@ -99,9 +107,9 @@ public class MaterialIndicies {
private static void initInner() { private static void initInner() {
int amount = Material.REGISTRY.getAll().size(); int amount = Material.REGISTRY.getAll().size();
Reference2IntMap<Material> materialIndicies = new Reference2IntOpenHashMap<>(); Reference2IntMap<Material> materialIndices = new Reference2IntOpenHashMap<>();
Object2IntMap<ResourceLocation> vertexShaderIndicies = new Object2IntOpenHashMap<>(); Object2IntMap<ResourceLocation> vertexShaderIndices = new Object2IntOpenHashMap<>();
Object2IntMap<ResourceLocation> fragmentShaderIndicies = new Object2IntOpenHashMap<>(); Object2IntMap<ResourceLocation> fragmentShaderIndices = new Object2IntOpenHashMap<>();
ObjectList<Material> materialsByIndex = new ObjectArrayList<>(amount); ObjectList<Material> materialsByIndex = new ObjectArrayList<>(amount);
ObjectList<ResourceLocation> vertexShadersByIndex = new ObjectArrayList<>(amount); ObjectList<ResourceLocation> vertexShadersByIndex = new ObjectArrayList<>(amount);
ObjectList<ResourceLocation> fragmentShadersByIndex = new ObjectArrayList<>(amount); ObjectList<ResourceLocation> fragmentShadersByIndex = new ObjectArrayList<>(amount);
@ -113,35 +121,35 @@ public class MaterialIndicies {
int vertexShaderIndex = 0; int vertexShaderIndex = 0;
int fragmentShaderIndex = 0; int fragmentShaderIndex = 0;
for (Material material : Material.REGISTRY) { for (Material material : Material.REGISTRY) {
materialIndicies.put(material, materialIndex); materialIndices.put(material, materialIndex);
materialsByIndex.add(material); materialsByIndex.add(material);
materialIndex++; materialIndex++;
ResourceLocation vertexShader = material.vertexShader(); ResourceLocation vertexShader = material.vertexShader();
if (allVertexShaders.add(vertexShader)) { if (allVertexShaders.add(vertexShader)) {
vertexShaderIndicies.put(vertexShader, vertexShaderIndex); vertexShaderIndices.put(vertexShader, vertexShaderIndex);
vertexShadersByIndex.add(vertexShader); vertexShadersByIndex.add(vertexShader);
vertexShaderIndex++; vertexShaderIndex++;
} }
ResourceLocation fragmentShader = material.fragmentShader(); ResourceLocation fragmentShader = material.fragmentShader();
if (allFragmentShaders.add(fragmentShader)) { if (allFragmentShaders.add(fragmentShader)) {
fragmentShaderIndicies.put(fragmentShader, fragmentShaderIndex); fragmentShaderIndices.put(fragmentShader, fragmentShaderIndex);
fragmentShadersByIndex.add(fragmentShader); fragmentShadersByIndex.add(fragmentShader);
fragmentShaderIndex++; fragmentShaderIndex++;
} }
} }
MaterialIndicies.materialIndicies = Reference2IntMaps.unmodifiable(materialIndicies); MaterialIndices.materialIndices = Reference2IntMaps.unmodifiable(materialIndices);
MaterialIndicies.vertexShaderIndicies = Object2IntMaps.unmodifiable(vertexShaderIndicies); MaterialIndices.vertexShaderIndices = Object2IntMaps.unmodifiable(vertexShaderIndices);
MaterialIndicies.fragmentShaderIndicies = Object2IntMaps.unmodifiable(fragmentShaderIndicies); MaterialIndices.fragmentShaderIndices = Object2IntMaps.unmodifiable(fragmentShaderIndices);
MaterialIndicies.materialsByIndex = ObjectLists.unmodifiable(materialsByIndex); MaterialIndices.materialsByIndex = ObjectLists.unmodifiable(materialsByIndex);
MaterialIndicies.vertexShadersByIndex = ObjectLists.unmodifiable(vertexShadersByIndex); MaterialIndices.vertexShadersByIndex = ObjectLists.unmodifiable(vertexShadersByIndex);
MaterialIndicies.fragmentShadersByIndex = ObjectLists.unmodifiable(fragmentShadersByIndex); MaterialIndices.fragmentShadersByIndex = ObjectLists.unmodifiable(fragmentShadersByIndex);
initialized = true; initialized = true;
} }
@ApiStatus.Internal @ApiStatus.Internal
public static void init() { public static void init() {
Material.REGISTRY.addFreezeCallback(MaterialIndicies::initInner); Material.REGISTRY.addFreezeCallback(MaterialIndices::initInner);
} }
} }

View File

@ -4,7 +4,7 @@ import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import com.jozufozu.flywheel.api.instance.blockentity.BlockEntityInstancingController; import com.jozufozu.flywheel.api.instance.controller.BlockEntityInstancingController;
import com.jozufozu.flywheel.extension.BlockEntityTypeExtension; import com.jozufozu.flywheel.extension.BlockEntityTypeExtension;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;

View File

@ -10,8 +10,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.jozufozu.flywheel.api.backend.BackendManager; import com.jozufozu.flywheel.api.backend.BackendManager;
import com.jozufozu.flywheel.api.instance.InstancedRenderRegistry;
import com.jozufozu.flywheel.extension.ClientLevelExtension; import com.jozufozu.flywheel.extension.ClientLevelExtension;
import com.jozufozu.flywheel.lib.instance.InstancingControllerHelper;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
@ -33,7 +33,7 @@ public abstract class ClientLevelMixin implements ClientLevelExtension {
Iterable<Entity> entities = cir.getReturnValue(); Iterable<Entity> entities = cir.getReturnValue();
ArrayList<Entity> filtered = Lists.newArrayList(entities); ArrayList<Entity> filtered = Lists.newArrayList(entities);
filtered.removeIf(InstancedRenderRegistry::shouldSkipRender); filtered.removeIf(InstancingControllerHelper::shouldSkipRender);
cir.setReturnValue(filtered); cir.setReturnValue(filtered);
} }

View File

@ -4,7 +4,7 @@ import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import com.jozufozu.flywheel.api.instance.entity.EntityInstancingController; import com.jozufozu.flywheel.api.instance.controller.EntityInstancingController;
import com.jozufozu.flywheel.extension.EntityTypeExtension; import com.jozufozu.flywheel.extension.EntityTypeExtension;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;

View File

@ -7,9 +7,9 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.api.instance.InstancedRenderRegistry;
import com.jozufozu.flywheel.backend.BackendUtil; import com.jozufozu.flywheel.backend.BackendUtil;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.lib.instance.InstancingControllerHelper;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -19,10 +19,10 @@ public class ChunkRebuildHooksMixin {
@Inject(method = "handleBlockEntity", at = @At("HEAD"), cancellable = true) @Inject(method = "handleBlockEntity", at = @At("HEAD"), cancellable = true)
private <E extends BlockEntity> void flywheel$addAndFilterBEs(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set<BlockEntity> set, E be, CallbackInfo ci) { private <E extends BlockEntity> void flywheel$addAndFilterBEs(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set<BlockEntity> set, E be, CallbackInfo ci) {
if (BackendUtil.canUseInstancing(be.getLevel())) { if (BackendUtil.canUseInstancing(be.getLevel())) {
if (InstancedRenderRegistry.canInstance(be.getType())) if (InstancingControllerHelper.canInstance(be.getType()))
InstancedRenderDispatcher.getBlockEntities(be.getLevel()).queueAdd(be); InstancedRenderDispatcher.getBlockEntities(be.getLevel()).queueAdd(be);
if (InstancedRenderRegistry.shouldSkipRender(be)) if (InstancingControllerHelper.shouldSkipRender(be))
ci.cancel(); ci.cancel();
} }
} }

View File

@ -9,7 +9,7 @@ import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.lib.instance.AbstractBlockEntityInstance;
import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.material.Materials;
import com.jozufozu.flywheel.lib.model.SimpleLazyModel; import com.jozufozu.flywheel.lib.model.SimpleLazyModel;
import com.jozufozu.flywheel.lib.modelpart.ModelPart; import com.jozufozu.flywheel.lib.modelpart.ModelPart;
@ -23,7 +23,7 @@ import net.minecraft.client.renderer.blockentity.BellRenderer;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.level.block.entity.BellBlockEntity; import net.minecraft.world.level.block.entity.BellBlockEntity;
public class BellInstance extends BlockEntityInstance<BellBlockEntity> implements DynamicInstance { public class BellInstance extends AbstractBlockEntityInstance<BellBlockEntity> implements DynamicInstance {
private static final SimpleLazyModel MODEL = new SimpleLazyModel(BellInstance::createBellModel, Materials.BELL); private static final SimpleLazyModel MODEL = new SimpleLazyModel(BellInstance::createBellModel, Materials.BELL);
@ -68,7 +68,7 @@ public class BellInstance extends BlockEntityInstance<BellBlockEntity> implement
} }
@Override @Override
public void remove() { protected void _delete() {
bell.delete(); bell.delete();
} }

View File

@ -11,7 +11,7 @@ import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.lib.instance.AbstractBlockEntityInstance;
import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.material.Materials;
import com.jozufozu.flywheel.lib.model.SimpleLazyModel; import com.jozufozu.flywheel.lib.model.SimpleLazyModel;
import com.jozufozu.flywheel.lib.modelpart.ModelPart; import com.jozufozu.flywheel.lib.modelpart.ModelPart;
@ -35,7 +35,7 @@ import net.minecraft.world.level.block.entity.ChestBlockEntity;
import net.minecraft.world.level.block.entity.LidBlockEntity; import net.minecraft.world.level.block.entity.LidBlockEntity;
import net.minecraft.world.level.block.state.properties.ChestType; import net.minecraft.world.level.block.state.properties.ChestType;
public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends BlockEntityInstance<T> implements DynamicInstance { public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends AbstractBlockEntityInstance<T> implements DynamicInstance {
private static final BiFunction<ChestType, TextureAtlasSprite, SimpleLazyModel> LID = Util.memoize((type, mat) -> new SimpleLazyModel(() -> createLidModel(type, mat), Materials.CHEST)); private static final BiFunction<ChestType, TextureAtlasSprite, SimpleLazyModel> LID = Util.memoize((type, mat) -> new SimpleLazyModel(() -> createLidModel(type, mat), Materials.CHEST));
private static final BiFunction<ChestType, TextureAtlasSprite, SimpleLazyModel> BASE = Util.memoize((type, mat) -> new SimpleLazyModel(() -> createBaseModel(type, mat), Materials.CHEST)); private static final BiFunction<ChestType, TextureAtlasSprite, SimpleLazyModel> BASE = Util.memoize((type, mat) -> new SimpleLazyModel(() -> createBaseModel(type, mat), Materials.CHEST));
@ -117,7 +117,7 @@ public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends Block
} }
@Override @Override
public void remove() { protected void _delete() {
body.delete(); body.delete();
lid.delete(); lid.delete();
} }

View File

@ -7,7 +7,7 @@ import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance; import com.jozufozu.flywheel.lib.instance.AbstractEntityInstance;
import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.material.Materials;
import com.jozufozu.flywheel.lib.model.Models; import com.jozufozu.flywheel.lib.model.Models;
import com.jozufozu.flywheel.lib.model.SimpleLazyModel; import com.jozufozu.flywheel.lib.model.SimpleLazyModel;
@ -26,7 +26,7 @@ import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance<T> implements DynamicInstance, TickableInstance { public class MinecartInstance<T extends AbstractMinecart> extends AbstractEntityInstance<T> implements DynamicInstance, TickableInstance {
private static final SimpleLazyModel MODEL = new SimpleLazyModel(MinecartInstance::getBodyModel, Materials.MINECART); private static final SimpleLazyModel MODEL = new SimpleLazyModel(MinecartInstance::getBodyModel, Materials.MINECART);
@ -150,7 +150,7 @@ public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance
} }
@Override @Override
public void remove() { protected void _delete() {
body.delete(); body.delete();
if (contents != null) contents.delete(); if (contents != null) contents.delete();
} }

View File

@ -8,7 +8,7 @@ import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.lib.instance.AbstractBlockEntityInstance;
import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.material.Materials;
import com.jozufozu.flywheel.lib.model.SimpleLazyModel; import com.jozufozu.flywheel.lib.model.SimpleLazyModel;
import com.jozufozu.flywheel.lib.modelpart.ModelPart; import com.jozufozu.flywheel.lib.modelpart.ModelPart;
@ -28,7 +28,7 @@ import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.block.ShulkerBoxBlock; import net.minecraft.world.level.block.ShulkerBoxBlock;
import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
public class ShulkerBoxInstance extends BlockEntityInstance<ShulkerBoxBlockEntity> implements DynamicInstance { public class ShulkerBoxInstance extends AbstractBlockEntityInstance<ShulkerBoxBlockEntity> implements DynamicInstance {
private static final Function<TextureAtlasSprite, SimpleLazyModel> BASE = Util.memoize(it -> new SimpleLazyModel(() -> makeBaseModel(it), Materials.SHULKER)); private static final Function<TextureAtlasSprite, SimpleLazyModel> BASE = Util.memoize(it -> new SimpleLazyModel(() -> makeBaseModel(it), Materials.SHULKER));
private static final Function<TextureAtlasSprite, SimpleLazyModel> LID = Util.memoize(it -> new SimpleLazyModel(() -> makeLidModel(it), Materials.SHULKER)); private static final Function<TextureAtlasSprite, SimpleLazyModel> LID = Util.memoize(it -> new SimpleLazyModel(() -> makeLidModel(it), Materials.SHULKER));
@ -95,7 +95,7 @@ public class ShulkerBoxInstance extends BlockEntityInstance<ShulkerBoxBlockEntit
} }
@Override @Override
public void remove() { protected void _delete() {
base.delete(); base.delete();
lid.delete(); lid.delete();
} }

View File

@ -12,12 +12,12 @@ import com.jozufozu.flywheel.api.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.api.instance.effect.Effect;
import com.jozufozu.flywheel.api.instancer.InstancerProvider; import com.jozufozu.flywheel.api.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.backend.instancing.effect.Effect;
import com.jozufozu.flywheel.lib.box.ImmutableBox; import com.jozufozu.flywheel.lib.box.ImmutableBox;
import com.jozufozu.flywheel.lib.box.MutableBox; import com.jozufozu.flywheel.lib.box.MutableBox;
import com.jozufozu.flywheel.lib.instance.AbstractInstance;
import com.jozufozu.flywheel.lib.model.Models; import com.jozufozu.flywheel.lib.model.Models;
import com.jozufozu.flywheel.lib.struct.StructTypes; import com.jozufozu.flywheel.lib.struct.StructTypes;
import com.jozufozu.flywheel.lib.struct.TransformedPart; import com.jozufozu.flywheel.lib.struct.TransformedPart;
@ -109,7 +109,7 @@ public class ExampleEffect implements Effect {
} }
@Override @Override
public Collection<AbstractInstance> createInstances(InstancerProvider instancerManager) { public Collection<com.jozufozu.flywheel.api.instance.Instance> createInstances(InstancerProvider instancerManager) {
effects.clear(); effects.clear();
boids.clear(); boids.clear();
for (int i = 0; i < INSTANCE_COUNT; i++) { for (int i = 0; i < INSTANCE_COUNT; i++) {
@ -262,7 +262,7 @@ public class ExampleEffect implements Effect {
} }
@Override @Override
public void remove() { protected void _delete() {
instance.delete(); instance.delete();
} }