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
description: The version of the mod you were using when the bug occured
options:
- "0.7.0"
- "0.6.8.a"
- "0.6.8"
- "0.6.7"

View File

@ -2,7 +2,7 @@ org.gradle.jvmargs = -Xmx3G
org.gradle.daemon = false
# mod version info
mod_version = 0.7.0
mod_version = 1.0.0-alpha
artifact_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.context.Contexts;
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.model.Models;
import com.jozufozu.flywheel.lib.model.PartialModel;
@ -111,7 +111,7 @@ public class Flywheel {
Contexts.init();
Pipelines.init();
MaterialIndicies.init();
MaterialIndices.init();
VanillaInstances.init();
@ -126,10 +126,10 @@ public class Flywheel {
}
private static void setup(final FMLCommonSetupEvent event) {
ArgumentTypes.register(rl("backend").toString(), BackendArgument.class, new EmptyArgumentSerializer<>(BackendArgument::getInstance));
RegistryImpl.freezeAll();
IdRegistryImpl.freezeAll();
ArgumentTypes.register(rl("backend").toString(), BackendArgument.class, new EmptyArgumentSerializer<>(BackendArgument::getInstance));
}
public static ArtifactVersion getVersion() {

View File

@ -3,7 +3,7 @@ package com.jozufozu.flywheel.api.backend;
import java.util.List;
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 {
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.Instancer;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
/**
* An interface giving {@link BlockEntityInstance}s a hook to have a function called at
* the start of a frame. By implementing {@link DynamicInstance}, a {@link BlockEntityInstance}
* An interface giving {@link Instance}s a hook to have a function called at
* 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
* 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;
/**
* A general interface providing information about any type of thing that could use Flywheel's instanced rendering.
*/
public interface Instance {
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>
* 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 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.Instancer;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
/**
* An interface giving {@link BlockEntityInstance}s a hook to have a function called at
* the end of every tick. By implementing {@link TickableInstance}, a {@link BlockEntityInstance}
* An interface giving {@link Instance}s a hook to have a function called at
* the end of every tick. By implementing {@link TickableInstance}, an {@link Instance}
* can update frequently, but not every frame.
* <br> There are a few cases in which this should be considered over {@link DynamicInstance}:
* <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.backend.instancing.blockentity.BlockEntityInstance;
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.backend.instancing.entity.EntityInstance;
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);
// TODO: this method does not belong in the interface
// TODO: this method does not belong in this interface
Vec3i getOriginCoordinate();
}

View File

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

View File

@ -9,7 +9,7 @@ import com.jozufozu.flywheel.api.struct.StructType;
public class CullingContextSet {
static CullingContextSet create() {
var builder = new CullingContextSet();
for (StructType<?> structType : StructType.REGISTRY.getAll()) {
for (StructType<?> structType : StructType.REGISTRY) {
builder.add(structType);
}
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.generate.FnSignature;
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.util.StringUtil;
@ -55,12 +55,12 @@ public class FlwCompiler {
this.sources = sources;
this.vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
.materialSources(MaterialIndicies.getAllVertexShaders())
.materialSources(MaterialIndices.getAllVertexShaders())
.adapt(FnSignature.ofVoid("flw_materialVertex"))
.switchOn(GlslExpr.variable("flw_materialVertexID"))
.build(sources);
this.fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
.materialSources(MaterialIndicies.getAllFragmentShaders())
.materialSources(MaterialIndices.getAllFragmentShaders())
.adapt(FnSignature.ofVoid("flw_materialFragment"))
.adapt(FnSignature.create()
.returnType("bool")

View File

@ -24,8 +24,8 @@ public class PipelineContextSet {
static PipelineContextSet create() {
var builder = new PipelineContextSet();
for (Pipeline pipelineShader : availablePipelineShaders()) {
for (StructType<?> structType : StructType.REGISTRY.getAll()) {
for (VertexType vertexType : VertexType.REGISTRY.getAll()) {
for (StructType<?> structType : StructType.REGISTRY) {
for (VertexType vertexType : VertexType.REGISTRY) {
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.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.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.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.struct.StructType;
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.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.Model;
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 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.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> {

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.vertex.VertexType;
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.lib.context.Contexts;
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.instancer.InstancedPart;
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> {
private final IndirectInstancer<T> instancer;
@ -25,8 +25,8 @@ public final class IndirectDraw<T extends InstancedPart> {
this.stage = stage;
this.mesh = mesh;
this.vertexMaterialID = MaterialIndicies.getVertexShaderIndex(material.vertexShader());
this.fragmentMaterialID = MaterialIndicies.getFragmentShaderIndex(material.fragmentShader());
this.vertexMaterialID = MaterialIndices.getVertexShaderIndex(material);
this.fragmentMaterialID = MaterialIndices.getFragmentShaderIndex(material);
}
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.struct.StructType;
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;
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.instancer.InstancedPart;
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;
public class IndirectDrawSet<T extends InstancedPart> {
@ -50,7 +50,7 @@ public class IndirectDrawSet<T extends InstancedPart> {
multiDraws.clear();
// sort by stage, then material
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++) {
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.struct.StructType;
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.GlTextureUnit;
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.struct.StructType;
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> {

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.struct.StructType;
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.buffer.GlBuffer;
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.struct.StructType;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.instancing.InstancerKey;
import com.jozufozu.flywheel.backend.engine.InstancerKey;
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.task.TaskExecutor;
import com.jozufozu.flywheel.backend.compile.FlwCompiler;
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.uniform.UniformBuffer;
import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager;
import com.jozufozu.flywheel.gl.GlStateTracker;
import com.jozufozu.flywheel.gl.GlTextureUnit;
import com.jozufozu.flywheel.lib.material.MaterialIndicies;
import com.jozufozu.flywheel.lib.material.MaterialIndices;
import com.jozufozu.flywheel.lib.pipeline.Pipelines;
import com.jozufozu.flywheel.util.FlwUtil;
import com.mojang.blaze3d.systems.RenderSystem;
@ -121,8 +121,8 @@ public class InstancingEngine implements Engine {
UniformBuffer.syncAndBind(program);
var uniformLocation = program.getUniformLocation("_flw_materialID_instancing");
var vertexID = MaterialIndicies.getVertexShaderIndex(material.vertexShader());
var fragmentID = MaterialIndicies.getFragmentShaderIndex(material.fragmentShader());
var vertexID = MaterialIndices.getVertexShaderIndex(material);
var fragmentID = MaterialIndices.getFragmentShaderIndex(material);
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.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.api.instance.effect.Effect;
import com.jozufozu.flywheel.backend.BackendUtil;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager;
import com.jozufozu.flywheel.backend.instancing.effect.Effect;
import com.jozufozu.flywheel.backend.instancing.effect.EffectInstanceManager;
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager;
import com.jozufozu.flywheel.backend.instancing.manager.BlockEntityInstanceManager;
import com.jozufozu.flywheel.backend.instancing.manager.EffectInstanceManager;
import com.jozufozu.flywheel.backend.instancing.manager.EntityInstanceManager;
import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager;
import com.jozufozu.flywheel.backend.task.ParallelTaskExecutor;
import com.jozufozu.flywheel.extension.ClientLevelExtension;

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.ReloadRenderersEvent;
import com.jozufozu.flywheel.api.event.RenderStageEvent;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.effect.Effect;
import com.jozufozu.flywheel.backend.BackendUtil;
import com.jozufozu.flywheel.backend.instancing.effect.Effect;
import com.jozufozu.flywheel.backend.instancing.manager.InstanceManager;
import com.jozufozu.flywheel.config.FlwCommands;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.util.AnimationTickHolder;
@ -26,7 +28,7 @@ public class InstancedRenderDispatcher {
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.
*/
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.
*/
public static void enqueueUpdate(Entity entity) {
@ -118,7 +120,7 @@ public class InstancedRenderDispatcher {
InstanceWorld instanceWorld = instanceWorlds.get(Minecraft.getInstance().level);
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);
} else {
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 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.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.Storage;
import com.jozufozu.flywheel.lib.instance.InstancingControllerHelper;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
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;
public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
private final BlockEntityStorage storage;
public BlockEntityInstanceManager(InstancerProvider instancerManager) {
@ -26,7 +27,7 @@ public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
}
@Override
public Storage<BlockEntity> getStorage() {
protected Storage<BlockEntity> getStorage() {
return storage;
}
@ -43,7 +44,7 @@ public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
return false;
}
if (!InstancedRenderRegistry.canInstance(blockEntity.getType())) {
if (!InstancingControllerHelper.canInstance(blockEntity.getType())) {
return false;
}
@ -68,18 +69,17 @@ public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
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 manager) {
super(manager);
public BlockEntityStorage(InstancerProvider instancerManager) {
super(instancerManager);
}
@Override
protected AbstractInstance createRaw(BlockEntity obj) {
var instance = InstancedRenderRegistry.createInstance(instancerManager, obj);
@Nullable
protected Instance createRaw(BlockEntity obj) {
BlockEntityInstance<?> instance = InstancingControllerHelper.createInstance(instancerManager, obj);
if (instance != null) {
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 com.google.common.collect.HashMultimap;
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.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.Storage;
import com.jozufozu.flywheel.lib.light.LightUpdater;
public class EffectInstanceManager extends InstanceManager<Effect> {
private final EffectStorage<Effect> storage;
public EffectInstanceManager(InstancerProvider instancerManager) {
@ -20,7 +18,7 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
}
@Override
public Storage<Effect> getStorage() {
protected Storage<Effect> getStorage() {
return storage;
}
@ -29,9 +27,8 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
return true;
}
public static class EffectStorage<T extends Effect> extends AbstractStorage<T> {
private final Multimap<T, AbstractInstance> instances;
private static class EffectStorage<T extends Effect> extends AbstractStorage<T> {
private final Multimap<T, Instance> instances;
public EffectStorage(InstancerProvider manager) {
super(manager);
@ -39,21 +36,13 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
}
@Override
public int getObjectCount() {
return instances.size();
}
@Override
public Iterable<AbstractInstance> allInstances() {
public Iterable<Instance> getAllInstances() {
return instances.values();
}
@Override
public void invalidate() {
instances.values().forEach(AbstractInstance::removeAndMark);
instances.clear();
tickableInstances.clear();
dynamicInstances.clear();
public int getInstanceCount() {
return instances.size();
}
@Override
@ -75,9 +64,8 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
this.tickableInstances.removeAll(instances);
this.dynamicInstances.removeAll(instances);
for (AbstractInstance instance : instances) {
LightUpdater.get(instance.level)
.removeListener(instance);
for (Instance instance : instances) {
instance.removeNow();
}
}
@ -89,20 +77,28 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
return;
}
instances.forEach(AbstractInstance::update);
instances.forEach(Instance::update);
}
@Override
public void recreateAll() {
this.dynamicInstances.clear();
this.tickableInstances.clear();
this.instances.values().forEach(AbstractInstance::removeAndMark);
tickableInstances.clear();
dynamicInstances.clear();
instances.values().forEach(Instance::delete);
var backup = new ArrayList<>(this.instances.keySet());
this.instances.clear();
var backup = new ArrayList<>(instances.keySet());
instances.clear();
backup.forEach(this::create);
}
@Override
public void invalidate() {
instances.values().forEach(Instance::delete);
instances.clear();
tickableInstances.clear();
dynamicInstances.clear();
}
private void create(T obj) {
var instances = obj.createInstances(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.Collection;
@ -12,6 +12,7 @@ import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.backend.BackendManager;
import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.backend.instancing.ratelimit.BandedPrimeLimiter;
@ -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.storage.Storage;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.lib.light.LightUpdater;
import net.minecraft.core.BlockPos;
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;
private final Set<T> queuedUpdates;
protected DistanceUpdateLimiter frame;
protected DistanceUpdateLimiter tick;
protected DistanceUpdateLimiter frameLimiter;
protected DistanceUpdateLimiter tickLimiter;
public InstanceManager() {
this.queuedUpdates = new HashSet<>(64);
this.queuedAdditions = new HashSet<>(64);
frame = createUpdateLimiter();
tick = createUpdateLimiter();
frameLimiter = createUpdateLimiter();
tickLimiter = createUpdateLimiter();
}
public abstract Storage<T> getStorage();
protected abstract Storage<T> getStorage();
/**
* Is the given object currently capable of being instanced?
*
* <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>
*
* @return true if the object is currently capable of being instanced.
@ -65,102 +61,8 @@ public abstract class InstanceManager<T> {
*
* @return The object count.
*/
public int getObjectCount() {
return getStorage().getObjectCount();
}
/**
* 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 int getInstanceCount() {
return getStorage().getInstanceCount();
}
public void add(T obj) {
@ -185,15 +87,13 @@ public abstract class InstanceManager<T> {
}
}
public void queueUpdate(T obj) {
if (!BackendManager.isOn()) return;
if (!canCreateInstance(obj)) {
public void queueAddAll(Collection<? extends T> objects) {
if (!BackendManager.isOn() || objects.isEmpty()) {
return;
}
synchronized (queuedUpdates) {
queuedUpdates.add(obj);
synchronized (queuedAdditions) {
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) {
if (!BackendManager.isOn()) return;
getStorage().remove(obj);
}
public void onOriginShift() {
getStorage().recreateAll();
}
public void invalidate() {
getStorage().invalidate();
}
public void delete() {
for (Instance instance : getStorage().getAllInstances()) {
instance.removeNow();
}
}
protected void processQueuedAdditions() {
if (queuedAdditions.isEmpty()) {
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() {
for (AbstractInstance value : getStorage().allInstances()) {
LightUpdater.get(value.level).removeListener(value);
}
}
public void queueAddAll(Collection<? extends T> objects) {
if (!BackendManager.isOn() || objects.isEmpty()) {
protected void tickInstance(TickableInstance instance, int cX, int cY, int cZ) {
if (!instance.decreaseTickRateWithDistance()) {
instance.tick();
return;
}
synchronized (queuedAdditions) {
queuedAdditions.addAll(objects);
BlockPos pos = instance.getWorldPosition();
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 {
// 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;
@ -23,6 +23,6 @@ public class BandedPrimeLimiter implements DistanceUpdateLimiter {
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 {
@Override
public void tick() {
// noop
}
@Override

View File

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

View File

@ -5,12 +5,11 @@ import java.util.Map;
import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.instance.Instance;
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> {
private final Map<T, AbstractInstance> instances;
private final Map<T, Instance> instances;
public One2OneStorage(InstancerProvider instancerManager) {
super(instancerManager);
@ -18,26 +17,18 @@ public abstract class One2OneStorage<T> extends AbstractStorage<T> {
}
@Override
public int getObjectCount() {
return instances.size();
}
@Override
public Iterable<AbstractInstance> allInstances() {
public Iterable<Instance> getAllInstances() {
return instances.values();
}
@Override
public void invalidate() {
instances.values().forEach(AbstractInstance::remove);
instances.clear();
dynamicInstances.clear();
tickableInstances.clear();
public int getInstanceCount() {
return instances.size();
}
@Override
public void add(T obj) {
AbstractInstance instance = instances.get(obj);
Instance instance = instances.get(obj);
if (instance == null) {
create(obj);
@ -46,22 +37,21 @@ public abstract class One2OneStorage<T> extends AbstractStorage<T> {
@Override
public void remove(T obj) {
var instance = instances.remove(obj);
Instance instance = instances.remove(obj);
if (instance == null) {
return;
}
instance.remove();
instance.delete();
dynamicInstances.remove(instance);
tickableInstances.remove(instance);
LightUpdater.get(instance.level)
.removeListener(instance);
instance.removeNow();
}
@Override
public void update(T obj) {
AbstractInstance instance = instances.get(obj);
Instance instance = instances.get(obj);
if (instance == null) {
return;
@ -83,9 +73,9 @@ public abstract class One2OneStorage<T> extends AbstractStorage<T> {
dynamicInstances.clear();
tickableInstances.clear();
instances.replaceAll((obj, instance) -> {
instance.remove();
instance.delete();
AbstractInstance out = createRaw(obj);
Instance out = createRaw(obj);
if (out != null) {
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) {
AbstractInstance renderer = createRaw(obj);
Instance instance = createRaw(obj);
if (renderer != null) {
setup(renderer);
instances.put(obj, renderer);
if (instance != null) {
setup(instance);
instances.put(obj, instance);
}
}
@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 com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
public interface Storage<T> {
int getObjectCount();
Iterable<Instance> getAllInstances();
Iterable<AbstractInstance> allInstances();
int getInstanceCount();
List<TickableInstance> getInstancesForTicking();
List<DynamicInstance> getInstancesForUpdate();
void invalidate();
void add(T obj);
void remove(T obj);
@ -24,4 +22,6 @@ public interface Storage<T> {
void update(T obj);
void recreateAll();
void invalidate();
}

View File

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

View File

@ -63,7 +63,7 @@ public class FlwCommands {
LocalPlayer player = Minecraft.getInstance().player;
if (player != null) {
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();
player.displayClientMessage(message, false);

View File

@ -24,10 +24,9 @@ public class FlwConfig {
private final ForgeConfigSpec clientSpec;
public FlwConfig() {
Pair<ClientConfig, ForgeConfigSpec> client = new ForgeConfigSpec.Builder().configure(ClientConfig::new);
this.client = client.getLeft();
clientSpec = client.getRight();
Pair<ClientConfig, ForgeConfigSpec> clientPair = new ForgeConfigSpec.Builder().configure(ClientConfig::new);
this.client = clientPair.getLeft();
clientSpec = clientPair.getRight();
}
public static FlwConfig get() {
@ -38,7 +37,7 @@ public class FlwConfig {
Backend backend = parseBackend(client.backend.get());
if (backend == null) {
backend = BackendManager.getDefaultBackend();
client.backend.set(Backend.REGISTRY.getId(backend).toString());
client.backend.set(Backend.REGISTRY.getIdOrThrow(backend).toString());
}
return backend;
@ -77,7 +76,7 @@ public class FlwConfig {
public ClientConfig(ForgeConfigSpec.Builder builder) {
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.")
.define("limitUpdates", true);

View File

@ -2,7 +2,7 @@ package com.jozufozu.flywheel.extension;
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;

View File

@ -2,7 +2,7 @@ package com.jozufozu.flywheel.extension;
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;

View File

@ -39,7 +39,7 @@ public final class BackendManagerImpl {
var actual = preferred.findFallback();
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;

View File

@ -72,6 +72,24 @@ public class IdRegistryImpl<T> implements IdRegistry<T> {
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
@Unmodifiable
public Set<ResourceLocation> getAllIds() {
@ -107,6 +125,7 @@ public class IdRegistryImpl<T> implements IdRegistry<T> {
for (Runnable runnable : freezeCallbacks) {
runnable.run();
}
freezeCallbacks.clear();
}
public static void freezeAll() {

View File

@ -91,6 +91,7 @@ public class RegistryImpl<T> implements Registry<T> {
for (Runnable runnable : freezeCallbacks) {
runnable.run();
}
freezeCallbacks.clear();
}
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.List;
import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.instance.BlockEntityInstance;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.api.instancer.InstancedPart;
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.MutableBox;
@ -29,19 +30,19 @@ import net.minecraft.world.level.block.state.BlockState;
* </ul>
* 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.
*
* @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 BlockPos pos;
protected final BlockPos instancePos;
protected final BlockState blockState;
public BlockEntityInstance(InstancerProvider instancerManager, T blockEntity) {
public AbstractBlockEntityInstance(InstancerProvider instancerManager, T blockEntity) {
super(instancerManager, blockEntity.getLevel());
this.blockEntity = blockEntity;
this.pos = blockEntity.getBlockPos();
@ -49,6 +50,7 @@ public abstract class BlockEntityInstance<T extends BlockEntity> extends Abstrac
this.instancePos = pos.subtract(instancerManager.getOriginCoordinate());
}
@Override
public List<InstancedPart> getCrumblingParts() {
var out = new ArrayList<InstancedPart>();
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 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.instancer.InstancerProvider;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager;
import com.jozufozu.flywheel.backend.instancing.manager.BlockEntityInstanceManager;
import com.jozufozu.flywheel.lib.box.MutableBox;
import com.jozufozu.flywheel.lib.light.LightListener;
import com.jozufozu.flywheel.lib.light.TickingLightListener;
import com.mojang.math.Vector3f;
@ -30,17 +29,17 @@ import net.minecraft.world.phys.Vec3;
* </ul>
* 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.
*
* @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 MutableBox bounds;
public EntityInstance(InstancerProvider instancerManager, E entity) {
public AbstractEntityInstance(InstancerProvider instancerManager, E entity) {
super(instancerManager, entity.level);
this.entity = entity;
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.stream.Stream;
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.instancer.FlatLit;
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.LightUpdater;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.Level;
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 {
protected final InstancerProvider instancerManager;
public final Level level;
protected boolean removed = false;
protected boolean deleted = false;
public AbstractInstance(InstancerProvider instancerManager, Level level) {
this.instancerManager = instancerManager;
this.level = level;
}
/**
* Initialize models here.
*/
@Override
public void init() {
updateLight();
LightUpdater.get(level).addListener(this);
}
public final void removeAndMark() {
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}.
*/
@Override
public void update() {
}
@Override
public boolean shouldReset() {
return false;
}
/**
* 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() {
}
/**
* 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 #remove removed},
* 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.
*/
public boolean shouldReset() {
return false;
protected abstract void _delete();
@Override
public final void delete() {
if (deleted) {
return;
}
_delete();
deleted = true;
}
@Override
public boolean isInvalid() {
return removed;
}
@Override
public boolean isRemoved() {
return removed;
return deleted;
}
@Override
@ -117,4 +86,8 @@ public abstract class AbstractInstance implements Instance, LightListener {
.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 com.jozufozu.flywheel.api.instance.blockentity.BlockEntityInstancingController;
import com.jozufozu.flywheel.api.instance.entity.EntityInstancingController;
import com.jozufozu.flywheel.api.instance.BlockEntityInstance;
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.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.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.
*/
@SuppressWarnings("unchecked")
public class InstancedRenderRegistry {
public final class InstancingControllerHelper {
/**
* Checks if the given block entity type can be instanced.
* @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.
*/
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.
*/
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
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) {
return null;
}
@ -65,7 +60,7 @@ public class InstancedRenderRegistry {
*/
@Nullable
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) {
return null;
}
@ -79,7 +74,7 @@ public class InstancedRenderRegistry {
* @return {@code true} if the block entity is instanced and should not be rendered normally.
*/
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) {
return false;
}
@ -93,61 +88,20 @@ public class InstancedRenderRegistry {
* @return {@code true} if the entity is instanced and should not be rendered normally.
*/
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) {
return false;
}
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.
* @param blockEntity The block entity to get the type of.
* @param <T> The type of the 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) {
return (BlockEntityType<? super T>) blockEntity.getType();
}
@ -158,7 +112,11 @@ public class InstancedRenderRegistry {
* @param <T> The type of the entity.
* @return The {@link EntityType} associated with the given entity.
*/
@SuppressWarnings("unchecked")
public static <T extends Entity> EntityType<? super T> getType(T entity) {
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.Predicate;
import com.jozufozu.flywheel.api.instance.InstancedRenderRegistry;
import com.jozufozu.flywheel.api.instance.blockentity.BlockEntityInstancingController;
import com.jozufozu.flywheel.api.instance.BlockEntityInstance;
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.backend.instancing.blockentity.BlockEntityInstance;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
@ -93,7 +93,7 @@ public class SimpleBlockEntityInstancingController<T extends BlockEntity> implem
skipRender = be -> false;
}
SimpleBlockEntityInstancingController<T> controller = new SimpleBlockEntityInstancingController<>(instanceFactory, skipRender);
InstancedRenderRegistry.setController(type, controller);
InstancingControllerRegistry.setController(type, controller);
return controller;
}
}

View File

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

View File

@ -21,10 +21,10 @@ import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import net.minecraft.resources.ResourceLocation;
// TODO: add messages to exceptions
public class MaterialIndicies {
private static Reference2IntMap<Material> materialIndicies;
private static Object2IntMap<ResourceLocation> vertexShaderIndicies;
private static Object2IntMap<ResourceLocation> fragmentShaderIndicies;
public class MaterialIndices {
private static Reference2IntMap<Material> materialIndices;
private static Object2IntMap<ResourceLocation> vertexShaderIndices;
private static Object2IntMap<ResourceLocation> fragmentShaderIndices;
private static ObjectList<Material> materialsByIndex;
private static ObjectList<ResourceLocation> vertexShadersByIndex;
private static ObjectList<ResourceLocation> fragmentShadersByIndex;
@ -34,21 +34,29 @@ public class MaterialIndicies {
if (!initialized) {
throw new IllegalStateException();
}
return materialIndicies.getInt(material);
return materialIndices.getInt(material);
}
public static int getVertexShaderIndex(ResourceLocation vertexShader) {
if (!initialized) {
throw new IllegalStateException();
}
return vertexShaderIndicies.getInt(vertexShader);
return vertexShaderIndices.getInt(vertexShader);
}
public static int getFragmentShaderIndex(ResourceLocation fragmentShader) {
if (!initialized) {
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) {
@ -99,9 +107,9 @@ public class MaterialIndicies {
private static void initInner() {
int amount = Material.REGISTRY.getAll().size();
Reference2IntMap<Material> materialIndicies = new Reference2IntOpenHashMap<>();
Object2IntMap<ResourceLocation> vertexShaderIndicies = new Object2IntOpenHashMap<>();
Object2IntMap<ResourceLocation> fragmentShaderIndicies = new Object2IntOpenHashMap<>();
Reference2IntMap<Material> materialIndices = new Reference2IntOpenHashMap<>();
Object2IntMap<ResourceLocation> vertexShaderIndices = new Object2IntOpenHashMap<>();
Object2IntMap<ResourceLocation> fragmentShaderIndices = new Object2IntOpenHashMap<>();
ObjectList<Material> materialsByIndex = new ObjectArrayList<>(amount);
ObjectList<ResourceLocation> vertexShadersByIndex = new ObjectArrayList<>(amount);
ObjectList<ResourceLocation> fragmentShadersByIndex = new ObjectArrayList<>(amount);
@ -113,35 +121,35 @@ public class MaterialIndicies {
int vertexShaderIndex = 0;
int fragmentShaderIndex = 0;
for (Material material : Material.REGISTRY) {
materialIndicies.put(material, materialIndex);
materialIndices.put(material, materialIndex);
materialsByIndex.add(material);
materialIndex++;
ResourceLocation vertexShader = material.vertexShader();
if (allVertexShaders.add(vertexShader)) {
vertexShaderIndicies.put(vertexShader, vertexShaderIndex);
vertexShaderIndices.put(vertexShader, vertexShaderIndex);
vertexShadersByIndex.add(vertexShader);
vertexShaderIndex++;
}
ResourceLocation fragmentShader = material.fragmentShader();
if (allFragmentShaders.add(fragmentShader)) {
fragmentShaderIndicies.put(fragmentShader, fragmentShaderIndex);
fragmentShaderIndices.put(fragmentShader, fragmentShaderIndex);
fragmentShadersByIndex.add(fragmentShader);
fragmentShaderIndex++;
}
}
MaterialIndicies.materialIndicies = Reference2IntMaps.unmodifiable(materialIndicies);
MaterialIndicies.vertexShaderIndicies = Object2IntMaps.unmodifiable(vertexShaderIndicies);
MaterialIndicies.fragmentShaderIndicies = Object2IntMaps.unmodifiable(fragmentShaderIndicies);
MaterialIndicies.materialsByIndex = ObjectLists.unmodifiable(materialsByIndex);
MaterialIndicies.vertexShadersByIndex = ObjectLists.unmodifiable(vertexShadersByIndex);
MaterialIndicies.fragmentShadersByIndex = ObjectLists.unmodifiable(fragmentShadersByIndex);
MaterialIndices.materialIndices = Reference2IntMaps.unmodifiable(materialIndices);
MaterialIndices.vertexShaderIndices = Object2IntMaps.unmodifiable(vertexShaderIndices);
MaterialIndices.fragmentShaderIndices = Object2IntMaps.unmodifiable(fragmentShaderIndices);
MaterialIndices.materialsByIndex = ObjectLists.unmodifiable(materialsByIndex);
MaterialIndices.vertexShadersByIndex = ObjectLists.unmodifiable(vertexShadersByIndex);
MaterialIndices.fragmentShadersByIndex = ObjectLists.unmodifiable(fragmentShadersByIndex);
initialized = true;
}
@ApiStatus.Internal
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.Unique;
import com.jozufozu.flywheel.api.instance.blockentity.BlockEntityInstancingController;
import com.jozufozu.flywheel.api.instance.controller.BlockEntityInstancingController;
import com.jozufozu.flywheel.extension.BlockEntityTypeExtension;
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.jozufozu.flywheel.api.backend.BackendManager;
import com.jozufozu.flywheel.api.instance.InstancedRenderRegistry;
import com.jozufozu.flywheel.extension.ClientLevelExtension;
import com.jozufozu.flywheel.lib.instance.InstancingControllerHelper;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.entity.Entity;
@ -33,7 +33,7 @@ public abstract class ClientLevelMixin implements ClientLevelExtension {
Iterable<Entity> entities = cir.getReturnValue();
ArrayList<Entity> filtered = Lists.newArrayList(entities);
filtered.removeIf(InstancedRenderRegistry::shouldSkipRender);
filtered.removeIf(InstancingControllerHelper::shouldSkipRender);
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.Unique;
import com.jozufozu.flywheel.api.instance.entity.EntityInstancingController;
import com.jozufozu.flywheel.api.instance.controller.EntityInstancingController;
import com.jozufozu.flywheel.extension.EntityTypeExtension;
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.callback.CallbackInfo;
import com.jozufozu.flywheel.api.instance.InstancedRenderRegistry;
import com.jozufozu.flywheel.backend.BackendUtil;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.lib.instance.InstancingControllerHelper;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
import net.minecraft.world.level.block.entity.BlockEntity;
@ -19,10 +19,10 @@ public class ChunkRebuildHooksMixin {
@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) {
if (BackendUtil.canUseInstancing(be.getLevel())) {
if (InstancedRenderRegistry.canInstance(be.getType()))
if (InstancingControllerHelper.canInstance(be.getType()))
InstancedRenderDispatcher.getBlockEntities(be.getLevel()).queueAdd(be);
if (InstancedRenderRegistry.shouldSkipRender(be))
if (InstancingControllerHelper.shouldSkipRender(be))
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.instancer.InstancedPart;
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.model.SimpleLazyModel;
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.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);
@ -68,7 +68,7 @@ public class BellInstance extends BlockEntityInstance<BellBlockEntity> implement
}
@Override
public void remove() {
protected void _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.instancer.InstancedPart;
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.model.SimpleLazyModel;
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.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> 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
public void remove() {
protected void _delete() {
body.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.instancer.InstancerProvider;
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.model.Models;
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.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);
@ -150,7 +150,7 @@ public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance
}
@Override
public void remove() {
protected void _delete() {
body.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.instancer.InstancedPart;
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.model.SimpleLazyModel;
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.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> LID = Util.memoize(it -> new SimpleLazyModel(() -> makeLidModel(it), Materials.SHULKER));
@ -95,7 +95,7 @@ public class ShulkerBoxInstance extends BlockEntityInstance<ShulkerBoxBlockEntit
}
@Override
public void remove() {
protected void _delete() {
base.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.instance.DynamicInstance;
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.backend.instancing.AbstractInstance;
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.MutableBox;
import com.jozufozu.flywheel.lib.instance.AbstractInstance;
import com.jozufozu.flywheel.lib.model.Models;
import com.jozufozu.flywheel.lib.struct.StructTypes;
import com.jozufozu.flywheel.lib.struct.TransformedPart;
@ -109,7 +109,7 @@ public class ExampleEffect implements Effect {
}
@Override
public Collection<AbstractInstance> createInstances(InstancerProvider instancerManager) {
public Collection<com.jozufozu.flywheel.api.instance.Instance> createInstances(InstancerProvider instancerManager) {
effects.clear();
boids.clear();
for (int i = 0; i < INSTANCE_COUNT; i++) {
@ -262,7 +262,7 @@ public class ExampleEffect implements Effect {
}
@Override
public void remove() {
protected void _delete() {
instance.delete();
}