Contraptions and engines

- Sort of get the batching engine working for contraptions but this feels wrong
 - TaskEngine gets passed in methods
 - Better naming for TaskEngines
 - Do BufferSource ourselves
 - Change BufferBuilderMixin to allow for injection into BufferBuilder objects
This commit is contained in:
Jozufozu 2021-12-23 14:41:10 -08:00
parent 3cb84a5db5
commit 0a4311b51e
16 changed files with 143 additions and 84 deletions

View file

@ -7,9 +7,9 @@ import net.minecraft.client.renderer.RenderType;
public class ContraptionGroup<P extends ContraptionProgram> extends InstancedMaterialGroup<P> { public class ContraptionGroup<P extends ContraptionProgram> extends InstancedMaterialGroup<P> {
private final RenderedContraption contraption; private final FlwContraption contraption;
public ContraptionGroup(RenderedContraption contraption, InstancingEngine<P> owner, RenderType type) { public ContraptionGroup(FlwContraption contraption, InstancingEngine<P> owner, RenderType type) {
super(owner, type); super(owner, type);
this.contraption = contraption; this.contraption = contraption;
@ -20,7 +20,7 @@ public class ContraptionGroup<P extends ContraptionProgram> extends InstancedMat
contraption.setup(program); contraption.setup(program);
} }
public static <P extends ContraptionProgram> InstancingEngine.GroupFactory<P> forContraption(RenderedContraption c) { public static <P extends ContraptionProgram> InstancingEngine.GroupFactory<P> forContraption(FlwContraption c) {
return (materialManager, type) -> new ContraptionGroup<>(c, materialManager, type); return (materialManager, type) -> new ContraptionGroup<>(c, materialManager, type);
} }
} }

View file

@ -1,6 +1,5 @@
package com.simibubi.create.content.contraptions.components.structureMovement.render; package com.simibubi.create.content.contraptions.components.structureMovement.render;
import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -8,11 +7,12 @@ import javax.annotation.Nullable;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.backend.instancing.ImmediateExecutor; import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager; import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager;
import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.AllMovementBehaviours;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld;
import net.minecraft.client.Camera; import net.minecraft.client.Camera;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -22,11 +22,11 @@ public class ContraptionInstanceManager extends TileInstanceManager {
protected ArrayList<ActorInstance> actors = new ArrayList<>(); protected ArrayList<ActorInstance> actors = new ArrayList<>();
private final WeakReference<RenderedContraption> contraption; private final PlacementSimulationWorld renderWorld;
ContraptionInstanceManager(RenderedContraption contraption, MaterialManager materialManager) { ContraptionInstanceManager(MaterialManager materialManager, PlacementSimulationWorld contraption) {
super(ImmediateExecutor.INSTANCE, materialManager); super(materialManager);
this.contraption = new WeakReference<>(contraption); this.renderWorld = contraption;
} }
public void tick() { public void tick() {
@ -34,8 +34,8 @@ public class ContraptionInstanceManager extends TileInstanceManager {
} }
@Override @Override
public void beginFrame(Camera info) { public void beginFrame(TaskEngine taskEngine, Camera info) {
super.beginFrame(info); super.beginFrame(taskEngine, info);
actors.forEach(ActorInstance::beginFrame); actors.forEach(ActorInstance::beginFrame);
} }
@ -53,7 +53,7 @@ public class ContraptionInstanceManager extends TileInstanceManager {
MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state); MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state);
if (movementBehaviour != null && movementBehaviour.hasSpecialInstancedRendering()) { if (movementBehaviour != null && movementBehaviour.hasSpecialInstancedRendering()) {
ActorInstance instance = movementBehaviour.createInstance(materialManager, getContraption().renderWorld, context); ActorInstance instance = movementBehaviour.createInstance(materialManager, renderWorld, context);
actors.add(instance); actors.add(instance);
@ -62,9 +62,5 @@ public class ContraptionInstanceManager extends TileInstanceManager {
return null; return null;
} }
public RenderedContraption getContraption() {
return contraption.get();
}
} }

View file

@ -43,7 +43,7 @@ import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(Dist.CLIENT) @Mod.EventBusSubscriber(Dist.CLIENT)
public class ContraptionRenderDispatcher { public class ContraptionRenderDispatcher {
private static WorldAttached<ContraptionRenderManager<?>> WORLDS = new WorldAttached<>(SBBContraptionManager::new); private static WorldAttached<ContraptionRenderingWorld<?>> WORLDS = new WorldAttached<>(SBBContraptionManager::new);
/** /**
* Reset a contraption's renderer. * Reset a contraption's renderer.
@ -113,8 +113,7 @@ public class ContraptionRenderDispatcher {
// Skip individual lighting updates to prevent lag with large contraptions // Skip individual lighting updates to prevent lag with large contraptions
renderWorld.setBlock(info.pos, info.state, Block.UPDATE_SUPPRESS_LIGHT); renderWorld.setBlock(info.pos, info.state, Block.UPDATE_SUPPRESS_LIGHT);
renderWorld.updateLightSources(); renderWorld.runLightingEngine();
renderWorld.lighter.runUpdates(Integer.MAX_VALUE, false, false);
return renderWorld; return renderWorld;
} }
@ -176,7 +175,7 @@ public class ContraptionRenderDispatcher {
} }
public static void reset() { public static void reset() {
WORLDS.empty(ContraptionRenderManager::delete); WORLDS.empty(ContraptionRenderingWorld::delete);
if (Backend.isOn()) { if (Backend.isOn()) {
WORLDS = new WorldAttached<>(FlwContraptionManager::new); WORLDS = new WorldAttached<>(FlwContraptionManager::new);

View file

@ -1,5 +1,6 @@
package com.simibubi.create.content.contraptions.components.structureMovement.render; package com.simibubi.create.content.contraptions.components.structureMovement.render;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;

View file

@ -17,7 +17,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
public abstract class ContraptionRenderManager<C extends ContraptionRenderInfo> { public abstract class ContraptionRenderingWorld<C extends ContraptionRenderInfo> {
protected final Level world; protected final Level world;
private int removalTimer; private int removalTimer;
@ -25,7 +25,7 @@ public abstract class ContraptionRenderManager<C extends ContraptionRenderInfo>
protected final Int2ObjectMap<C> renderInfos = new Int2ObjectOpenHashMap<>(); protected final Int2ObjectMap<C> renderInfos = new Int2ObjectOpenHashMap<>();
protected final List<C> visible = new ObjectArrayList<>(); protected final List<C> visible = new ObjectArrayList<>();
public ContraptionRenderManager(LevelAccessor world) { public ContraptionRenderingWorld(LevelAccessor world) {
this.world = (Level) world; this.world = (Level) world;
} }

View file

@ -7,13 +7,18 @@ import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry; import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.instancing.batching.BatchingEngine;
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
import com.jozufozu.flywheel.backend.model.ArrayModelRenderer; import com.jozufozu.flywheel.backend.model.ArrayModelRenderer;
import com.jozufozu.flywheel.backend.model.ModelRenderer; import com.jozufozu.flywheel.backend.model.ModelRenderer;
import com.jozufozu.flywheel.core.model.Model; import com.jozufozu.flywheel.core.model.Model;
import com.jozufozu.flywheel.core.model.WorldModel; import com.jozufozu.flywheel.core.model.WorldModel;
import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
@ -30,29 +35,23 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public class RenderedContraption extends ContraptionRenderInfo { public class FlwContraption extends ContraptionRenderInfo {
private final ContraptionLighter<?> lighter; private final ContraptionLighter<?> lighter;
public final InstancingEngine<ContraptionProgram> engine;
public final ContraptionInstanceManager kinetics;
private final Map<RenderType, ModelRenderer> renderLayers = new HashMap<>(); private final Map<RenderType, ModelRenderer> renderLayers = new HashMap<>();
private final Matrix4f modelViewPartial = new Matrix4f(); private final Matrix4f modelViewPartial = new Matrix4f();
private final ContraptionInstanceWorld instanceWorld;
private boolean modelViewPartialReady; private boolean modelViewPartialReady;
// floats because we're uploading this to the gpu // floats because we upload this to the gpu
private AABB lightBox; private AABB lightBox;
public RenderedContraption(Contraption contraption, PlacementSimulationWorld renderWorld) { public FlwContraption(Contraption contraption, PlacementSimulationWorld renderWorld) {
super(contraption, renderWorld); super(contraption, renderWorld);
this.lighter = contraption.makeLighter(); this.lighter = contraption.makeLighter();
this.engine = InstancingEngine.builder(CreateContexts.CWORLD)
.setGroupFactory(ContraptionGroup.forContraption(this)) instanceWorld = new ContraptionInstanceWorld(this);
.setIgnoreOriginCoordinate(true)
.build();
this.kinetics = new ContraptionInstanceManager(this, engine);
this.engine.addListener(this.kinetics);
buildLayers(); buildLayers();
if (Backend.isOn()) { if (Backend.isOn()) {
@ -65,7 +64,7 @@ public class RenderedContraption extends ContraptionRenderInfo {
return lighter; return lighter;
} }
public void doRenderLayer(RenderType layer, ContraptionProgram shader) { public void renderStructureLayer(RenderType layer, ContraptionProgram shader) {
ModelRenderer structure = renderLayers.get(layer); ModelRenderer structure = renderLayers.get(layer);
if (structure != null) { if (structure != null) {
setup(shader); setup(shader);
@ -73,6 +72,21 @@ public class RenderedContraption extends ContraptionRenderInfo {
} }
} }
public void renderInstanceLayer(RenderLayerEvent event) {
event.stack.pushPose();
float partialTicks = AnimationTickHolder.getPartialTicks();
AbstractContraptionEntity entity = contraption.entity;
double x = Mth.lerp(partialTicks, entity.xOld, entity.getX());
double y = Mth.lerp(partialTicks, entity.yOld, entity.getY());
double z = Mth.lerp(partialTicks, entity.zOld, entity.getZ());
event.stack.translate(x - event.camX, y - event.camY, z - event.camZ);
ContraptionMatrices.transform(event.stack, getMatrices().getModel());
instanceWorld.engine.render(SerialTaskEngine.INSTANCE, event);
event.stack.popPose();
}
public void beginFrame(BeginFrameEvent event) { public void beginFrame(BeginFrameEvent event) {
super.beginFrame(event); super.beginFrame(event);
@ -81,7 +95,7 @@ public class RenderedContraption extends ContraptionRenderInfo {
if (!isVisible()) return; if (!isVisible()) return;
kinetics.beginFrame(event.getInfo()); instanceWorld.tileInstanceManager.beginFrame(SerialTaskEngine.INSTANCE, event.getInfo());
Vec3 cameraPos = event.getCameraPos(); Vec3 cameraPos = event.getCameraPos();
@ -113,8 +127,7 @@ public class RenderedContraption extends ContraptionRenderInfo {
lighter.delete(); lighter.delete();
engine.delete(); instanceWorld.delete();
kinetics.invalidate();
} }
private void buildLayers() { private void buildLayers() {
@ -141,7 +154,7 @@ public class RenderedContraption extends ContraptionRenderInfo {
.canInstance(te.getType())) { .canInstance(te.getType())) {
Level world = te.getLevel(); Level world = te.getLevel();
te.setLevel(renderWorld); te.setLevel(renderWorld);
kinetics.add(te); instanceWorld.tileInstanceManager.add(te);
te.setLevel(world); te.setLevel(world);
} }
} }
@ -149,7 +162,7 @@ public class RenderedContraption extends ContraptionRenderInfo {
} }
private void buildActors() { private void buildActors() {
contraption.getActors().forEach(kinetics::createActor); contraption.getActors().forEach(instanceWorld.tileInstanceManager::createActor);
} }
public static void setupModelViewPartial(Matrix4f matrix, Matrix4f modelMatrix, AbstractContraptionEntity entity, double camX, double camY, double camZ, float pt) { public static void setupModelViewPartial(Matrix4f matrix, Matrix4f modelMatrix, AbstractContraptionEntity entity, double camX, double camY, double camZ, float pt) {
@ -160,4 +173,38 @@ public class RenderedContraption extends ContraptionRenderInfo {
matrix.multiply(modelMatrix); matrix.multiply(modelMatrix);
} }
public void tick() {
instanceWorld.tileInstanceManager.tick();
}
public static class ContraptionInstanceWorld {
private final Engine engine;
private final ContraptionInstanceManager tileInstanceManager;
public ContraptionInstanceWorld(FlwContraption parent) {
switch (Backend.getInstance().getEngine()) {
case INSTANCING -> {
InstancingEngine<ContraptionProgram> engine = InstancingEngine.builder(CreateContexts.CWORLD)
.setGroupFactory(ContraptionGroup.forContraption(parent))
.setIgnoreOriginCoordinate(true)
.build();
tileInstanceManager = new ContraptionInstanceManager(engine, parent.renderWorld);
engine.addListener(tileInstanceManager);
this.engine = engine;
}
case BATCHING -> {
engine = new BatchingEngine();
tileInstanceManager = new ContraptionInstanceManager(engine, parent.renderWorld);
}
default -> throw new IllegalArgumentException("Unknown engine type");
}
}
public void delete() {
engine.delete();
tileInstanceManager.invalidate();
}
}
} }

View file

@ -17,7 +17,7 @@ import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationW
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
public class FlwContraptionManager extends ContraptionRenderManager<RenderedContraption> { public class FlwContraptionManager extends ContraptionRenderingWorld<FlwContraption> {
public FlwContraptionManager(LevelAccessor world) { public FlwContraptionManager(LevelAccessor world) {
super(world); super(world);
@ -27,8 +27,8 @@ public class FlwContraptionManager extends ContraptionRenderManager<RenderedCont
public void tick() { public void tick() {
super.tick(); super.tick();
for (RenderedContraption contraption : visible) { for (FlwContraption contraption : visible) {
contraption.kinetics.tick(); contraption.tick();
} }
} }
@ -52,8 +52,8 @@ public class FlwContraptionManager extends ContraptionRenderManager<RenderedCont
structureShader.uploadViewProjection(event.viewProjection); structureShader.uploadViewProjection(event.viewProjection);
structureShader.uploadCameraPos(event.camX, event.camY, event.camZ); structureShader.uploadCameraPos(event.camX, event.camY, event.camZ);
for (RenderedContraption renderedContraption : visible) { for (FlwContraption flwContraption : visible) {
renderedContraption.doRenderLayer(layer, structureShader); flwContraption.renderStructureLayer(layer, structureShader);
} }
GlVertexArray.unbind(); GlVertexArray.unbind();
@ -61,8 +61,9 @@ public class FlwContraptionManager extends ContraptionRenderManager<RenderedCont
if (Backend.isOn()) { if (Backend.isOn()) {
RenderLayer renderLayer = event.getLayer(); RenderLayer renderLayer = event.getLayer();
if (renderLayer != null) { if (renderLayer != null) {
for (RenderedContraption renderer : visible) {
renderer.engine.render(event); for (FlwContraption renderer : visible) {
renderer.renderInstanceLayer(event);
} }
} }
} }
@ -76,9 +77,9 @@ public class FlwContraptionManager extends ContraptionRenderManager<RenderedCont
} }
@Override @Override
protected RenderedContraption create(Contraption c) { protected FlwContraption create(Contraption c) {
PlacementSimulationWorld renderWorld = ContraptionRenderDispatcher.setupRenderWorld(world, c); PlacementSimulationWorld renderWorld = ContraptionRenderDispatcher.setupRenderWorld(world, c);
return new RenderedContraption(c, renderWorld); return new FlwContraption(c, renderWorld);
} }
@Override @Override

View file

@ -11,7 +11,7 @@ import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationW
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
public class SBBContraptionManager extends ContraptionRenderManager<ContraptionRenderInfo> { public class SBBContraptionManager extends ContraptionRenderingWorld<ContraptionRenderInfo> {
public static final SuperByteBufferCache.Compartment<Pair<Contraption, RenderType>> CONTRAPTION = new SuperByteBufferCache.Compartment<>(); public static final SuperByteBufferCache.Compartment<Pair<Contraption, RenderType>> CONTRAPTION = new SuperByteBufferCache.Compartment<>();
public SBBContraptionManager(LevelAccessor world) { public SBBContraptionManager(LevelAccessor world) {

View file

@ -76,7 +76,7 @@ public class TreeFertilizerItem extends Item {
return super.useOn(context); return super.useOn(context);
} }
private class TreesDreamWorld extends PlacementSimulationServerWorld { private static class TreesDreamWorld extends PlacementSimulationServerWorld {
private final BlockPos saplingPos; private final BlockPos saplingPos;
private final BlockState soil; private final BlockState soil;

View file

@ -45,7 +45,7 @@ public class SchematicWorld extends WrappedWorld implements ServerLevelAccessor
protected List<BlockEntity> renderedTileEntities; protected List<BlockEntity> renderedTileEntities;
protected List<Entity> entities; protected List<Entity> entities;
protected BoundingBox bounds; protected BoundingBox bounds;
public BlockPos anchor; public BlockPos anchor;
public boolean renderMode; public boolean renderMode;
@ -149,12 +149,12 @@ public class SchematicWorld extends WrappedWorld implements ServerLevelAccessor
public int getBrightness(LightLayer p_226658_1_, BlockPos p_226658_2_) { public int getBrightness(LightLayer p_226658_1_, BlockPos p_226658_2_) {
return 10; return 10;
} }
@Override @Override
public LevelTickAccess<Block> getBlockTicks() { public LevelTickAccess<Block> getBlockTicks() {
return BlackholeTickAccess.emptyLevelList(); return BlackholeTickAccess.emptyLevelList();
} }
@Override @Override
public LevelTickAccess<Fluid> getFluidTicks() { public LevelTickAccess<Fluid> getFluidTicks() {
return BlackholeTickAccess.emptyLevelList(); return BlackholeTickAccess.emptyLevelList();
@ -170,7 +170,7 @@ public class SchematicWorld extends WrappedWorld implements ServerLevelAccessor
Predicate<? super T> arg2) { Predicate<? super T> arg2) {
return Collections.emptyList(); return Collections.emptyList();
} }
@Override @Override
public List<? extends Player> players() { public List<? extends Player> players() {
return Collections.emptyList(); return Collections.emptyList();

View file

@ -1,5 +1,7 @@
package com.simibubi.create.foundation.utility.worldWrappers; package com.simibubi.create.foundation.utility.worldWrappers;
import javax.annotation.Nullable;
import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
@ -10,7 +12,7 @@ public class DummyStatusListener implements ChunkProgressListener {
public void updateSpawnPos(ChunkPos pCenter) {} public void updateSpawnPos(ChunkPos pCenter) {}
@Override @Override
public void onStatusChange(ChunkPos pChunkPosition, ChunkStatus pNewStatus) {} public void onStatusChange(ChunkPos pChunkPosition, @Nullable ChunkStatus pNewStatus) {}
@Override @Override
public void start() {} public void start() {}

View file

@ -7,6 +7,8 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import javax.annotation.Nullable;
import com.jozufozu.flywheel.api.FlywheelWorld; import com.jozufozu.flywheel.api.FlywheelWorld;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -19,33 +21,31 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
public class PlacementSimulationWorld extends WrappedWorld implements FlywheelWorld { public class PlacementSimulationWorld extends WrappedWorld implements FlywheelWorld {
public Map<BlockPos, BlockState> blocksAdded; public Map<BlockPos, BlockState> blocksAdded = new HashMap<>();
public Map<BlockPos, BlockEntity> tesAdded; public Map<BlockPos, BlockEntity> tesAdded = new HashMap<>();
public Set<SectionPos> spannedSections; public Set<SectionPos> spannedSections = new HashSet<>();
public LevelLightEngine lighter; public LevelLightEngine lighter;
public WrappedChunkProvider chunkProvider; public final WrappedChunkProvider chunkSource;
private final BlockPos.MutableBlockPos scratch = new BlockPos.MutableBlockPos(); private final BlockPos.MutableBlockPos scratch = new BlockPos.MutableBlockPos();
public PlacementSimulationWorld(Level wrapped) { public PlacementSimulationWorld(Level wrapped) {
this(wrapped, new WrappedChunkProvider()); this(wrapped, new WrappedChunkProvider());
} }
public PlacementSimulationWorld(Level wrapped, WrappedChunkProvider chunkProvider) { public PlacementSimulationWorld(Level wrapped, WrappedChunkProvider chunkSource) {
super(wrapped, chunkProvider); super(wrapped, chunkSource);
this.chunkProvider = chunkProvider.setPlacementWorld(this); // You can't leak this before the super ctor is called.
spannedSections = new HashSet<>(); // You can't create inner classes before super ctor is called.
lighter = new LevelLightEngine(chunkProvider, true, false); // blockLight, skyLight chunkSource.setPlacementWorld(this);
blocksAdded = new HashMap<>(); this.chunkSource = chunkSource;
tesAdded = new HashMap<>(); lighter = new LevelLightEngine(chunkSource, true, false);
} }
@Override /**
public LevelLightEngine getLightEngine() { * Run this after you're done using setBlock().
return lighter; */
} public void runLightingEngine() {
public void updateLightSources() {
for (Map.Entry<BlockPos, BlockState> entry : blocksAdded.entrySet()) { for (Map.Entry<BlockPos, BlockState> entry : blocksAdded.entrySet()) {
BlockPos pos = entry.getKey(); BlockPos pos = entry.getKey();
BlockState state = entry.getValue(); BlockState state = entry.getValue();
@ -54,6 +54,13 @@ public class PlacementSimulationWorld extends WrappedWorld implements FlywheelWo
lighter.onBlockEmissionIncrease(pos, light); lighter.onBlockEmissionIncrease(pos, light);
} }
} }
lighter.runUpdates(Integer.MAX_VALUE, false, false);
}
@Override
public LevelLightEngine getLightEngine() {
return lighter;
} }
public void setTileEntities(Collection<BlockEntity> tileEntities) { public void setTileEntities(Collection<BlockEntity> tileEntities) {
@ -87,6 +94,7 @@ public class PlacementSimulationWorld extends WrappedWorld implements FlywheelWo
} }
@Override @Override
@Nullable
public BlockEntity getBlockEntity(BlockPos pos) { public BlockEntity getBlockEntity(BlockPos pos) {
return tesAdded.get(pos); return tesAdded.get(pos);
} }

View file

@ -11,8 +11,8 @@ import net.minecraft.world.level.material.FluidState;
public class RayTraceWorld implements BlockGetter { public class RayTraceWorld implements BlockGetter {
private LevelAccessor template; private final LevelAccessor template;
private BiFunction<BlockPos, BlockState, BlockState> stateGetter; private final BiFunction<BlockPos, BlockState, BlockState> stateGetter;
public RayTraceWorld(LevelAccessor template, BiFunction<BlockPos, BlockState, BlockState> stateGetter) { public RayTraceWorld(LevelAccessor template, BiFunction<BlockPos, BlockState, BlockState> stateGetter) {
this.template = template; this.template = template;

View file

@ -29,11 +29,11 @@ public class WrappedChunkProvider extends ChunkSource {
fallbackWorld = world; fallbackWorld = world;
return this; return this;
} }
public WrappedChunkProvider setPlacementWorld(PlacementSimulationWorld world) { // VirtualChunkSource is created before VirtualRenderWorld, so we can't initialize it in the ctor.
public void setPlacementWorld(PlacementSimulationWorld world) {
fallbackWorld = this.world = world; fallbackWorld = this.world = world;
this.chunks = new HashMap<>(); this.chunks = new HashMap<>();
return this;
} }
public Stream<BlockPos> getLightSources() { public Stream<BlockPos> getLightSources() {

View file

@ -32,8 +32,6 @@ import net.minecraft.world.level.storage.WritableLevelData;
import net.minecraft.world.scores.Scoreboard; import net.minecraft.world.scores.Scoreboard;
import net.minecraft.world.ticks.LevelTickAccess; import net.minecraft.world.ticks.LevelTickAccess;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class WrappedWorld extends Level { public class WrappedWorld extends Level {
protected Level world; protected Level world;
@ -67,17 +65,18 @@ public class WrappedWorld extends Level {
} }
@Override @Override
public boolean isStateAtPosition(@Nullable BlockPos p_217375_1_, @Nullable Predicate<BlockState> p_217375_2_) { public boolean isStateAtPosition(BlockPos p_217375_1_, Predicate<BlockState> p_217375_2_) {
return world.isStateAtPosition(p_217375_1_, p_217375_2_); return world.isStateAtPosition(p_217375_1_, p_217375_2_);
} }
@Override @Override
public BlockEntity getBlockEntity(@Nullable BlockPos pos) { @Nullable
public BlockEntity getBlockEntity(BlockPos pos) {
return world.getBlockEntity(pos); return world.getBlockEntity(pos);
} }
@Override @Override
public boolean setBlock(@Nullable BlockPos pos, @Nullable BlockState newState, int flags) { public boolean setBlock(BlockPos pos, BlockState newState, int flags) {
return world.setBlock(pos, newState, flags); return world.setBlock(pos, newState, flags);
} }
@ -95,7 +94,7 @@ public class WrappedWorld extends Level {
public LevelTickAccess<Block> getBlockTicks() { public LevelTickAccess<Block> getBlockTicks() {
return world.getBlockTicks(); return world.getBlockTicks();
} }
@Override @Override
public LevelTickAccess<Fluid> getFluidTicks() { public LevelTickAccess<Fluid> getFluidTicks() {
return world.getFluidTicks(); return world.getFluidTicks();

View file

@ -0,0 +1,6 @@
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
package com.simibubi.create.foundation.utility.worldWrappers;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;