diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java index 70a96022a..1fbb1009d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java @@ -217,6 +217,8 @@ public abstract class KineticTileEntity extends SmartTileEntity @Override protected void read(CompoundNBT compound, boolean clientPacket) { boolean overStressedBefore = overStressed; + Long networkBefore = network; + float speedBefore = speed; clearKineticInformation(); // DO NOT READ kinetic information when placed after movement diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java index e22bf6284..f0f2d4cb4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement; import java.util.List; import java.util.Random; +import net.minecraft.world.lighting.WorldLightManager; import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.opengl.GL11; @@ -101,6 +102,15 @@ public class ContraptionRenderer { for (BlockInfo info : c.getBlocks() .values()) renderWorld.setBlockState(info.pos, info.state); + + WorldLightManager lighter = renderWorld.lighter; + + renderWorld.chunkProvider.getLightSources().forEach((pos) -> { + lighter.func_215573_a(pos, renderWorld.getLightValue(pos)); + }); + + lighter.tick(Integer.MAX_VALUE, true, false); + for (BlockInfo info : c.getBlocks() .values()) { BlockState state = info.state; @@ -120,6 +130,7 @@ public class ContraptionRenderer { builder.finishDrawing(); renderWorld.clear(); + renderWorld = null; return builder; } diff --git a/src/main/java/com/simibubi/create/foundation/render/contraption/ContraptionModel.java b/src/main/java/com/simibubi/create/foundation/render/contraption/ContraptionModel.java index 2d778b389..ec89f9df2 100644 --- a/src/main/java/com/simibubi/create/foundation/render/contraption/ContraptionModel.java +++ b/src/main/java/com/simibubi/create/foundation/render/contraption/ContraptionModel.java @@ -4,15 +4,17 @@ import com.simibubi.create.foundation.render.BufferedModel; import com.simibubi.create.foundation.render.instancing.InstancedModel; import com.simibubi.create.foundation.render.instancing.VertexFormat; import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.LightTexture; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL40; import java.nio.ByteBuffer; +import static com.simibubi.create.foundation.render.instancing.VertexAttribute.LIGHT; import static com.simibubi.create.foundation.render.instancing.VertexAttribute.RGBA; public class ContraptionModel extends BufferedModel { - public static final VertexFormat FORMAT = new VertexFormat(InstancedModel.FORMAT, RGBA); + public static final VertexFormat FORMAT = new VertexFormat(InstancedModel.FORMAT, RGBA, LIGHT); public ContraptionModel(BufferBuilder buf) { super(buf); @@ -35,6 +37,14 @@ public class ContraptionModel extends BufferedModel { to.put(getG(template, vertex)); to.put(getB(template, vertex)); to.put(getA(template, vertex)); + + int light = getLight(template, vertex); + + byte sky = (byte) (LightTexture.getSkyLightCoordinates(light) << 4); + byte block = (byte) (LightTexture.getBlockLightCoordinates(light) << 4); + + to.put(block); + to.put(sky); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/render/contraption/RenderedContraption.java b/src/main/java/com/simibubi/create/foundation/render/contraption/RenderedContraption.java index 8fda2a8b9..0d3b6e105 100644 --- a/src/main/java/com/simibubi/create/foundation/render/contraption/RenderedContraption.java +++ b/src/main/java/com/simibubi/create/foundation/render/contraption/RenderedContraption.java @@ -7,10 +7,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.foundation.render.gl.shader.ShaderHelper; -import com.simibubi.create.foundation.render.instancing.IInstanceRendered; -import com.simibubi.create.foundation.render.instancing.InstancedModel; -import com.simibubi.create.foundation.render.instancing.KineticRenderMaterials; -import com.simibubi.create.foundation.render.instancing.RenderMaterial; +import com.simibubi.create.foundation.render.instancing.*; import com.simibubi.create.foundation.render.instancing.actors.StaticRotatingActorData; import com.simibubi.create.foundation.render.light.ContraptionLighter; import net.minecraft.client.renderer.BufferBuilder; diff --git a/src/main/java/com/simibubi/create/foundation/render/gl/shader/Shader.java b/src/main/java/com/simibubi/create/foundation/render/gl/shader/Shader.java index 3ada3d9b3..2190946cd 100644 --- a/src/main/java/com/simibubi/create/foundation/render/gl/shader/Shader.java +++ b/src/main/java/com/simibubi/create/foundation/render/gl/shader/Shader.java @@ -3,7 +3,7 @@ package com.simibubi.create.foundation.render.gl.shader; public enum Shader { ROTATING("shader/rotating.vert", "shader/instanced.frag"), BELT("shader/belt.vert", "shader/instanced.frag"), - CONTRAPTION_STRUCTURE("shader/contraption.vert", "shader/contraption.frag"), + CONTRAPTION_STRUCTURE("shader/contraption_structure.vert", "shader/contraption_structure.frag"), CONTRAPTION_ROTATING("shader/contraption_rotating.vert", "shader/contraption.frag"), CONTRAPTION_BELT("shader/contraption_belt.vert", "shader/contraption.frag"), CONTRAPTION_ACTOR("shader/contraption_actor.vert", "shader/contraption.frag"), diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java index ee209d16f..affececcf 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationWorld.java @@ -2,24 +2,50 @@ package com.simibubi.create.foundation.utility.worldWrappers; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.function.Predicate; +import com.simibubi.create.foundation.render.light.GridAlignedBB; +import com.simibubi.create.foundation.utility.Iterate; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.SectionPos; +import net.minecraft.world.LightType; import net.minecraft.world.World; +import net.minecraft.world.chunk.NibbleArray; +import net.minecraft.world.lighting.WorldLightManager; public class PlacementSimulationWorld extends WrappedWorld { public HashMap blocksAdded; public HashMap tesAdded; + public HashSet spannedChunks; + public WorldLightManager lighter; + public WrappedChunkProvider chunkProvider; + private final BlockPos.Mutable scratch = new BlockPos.Mutable(); + public PlacementSimulationWorld(World wrapped) { - super(wrapped); + this(wrapped, new WrappedChunkProvider()); + } + + public PlacementSimulationWorld(World wrapped, WrappedChunkProvider chunkProvider) { + super(wrapped, chunkProvider); + this.chunkProvider = chunkProvider.setWorld(this); + spannedChunks = new HashSet<>(); + lighter = new WorldLightManager(chunkProvider, true, false); // blockLight, skyLight blocksAdded = new HashMap<>(); tesAdded = new HashMap<>(); } + @Override + public WorldLightManager getLightingProvider() { + return lighter; + } + public void setTileEntities(Collection tileEntities) { tesAdded.clear(); tileEntities.forEach(te -> tesAdded.put(te.getPos(), te)); @@ -31,6 +57,15 @@ public class PlacementSimulationWorld extends WrappedWorld { @Override public boolean setBlockState(BlockPos pos, BlockState newState, int flags) { + + SectionPos sectionPos = SectionPos.from(pos); + + if (spannedChunks.add(sectionPos)) { + lighter.updateSectionStatus(sectionPos, false); + } + + lighter.checkBlock(pos); + blocksAdded.put(pos, newState); return true; } @@ -62,9 +97,11 @@ public class PlacementSimulationWorld extends WrappedWorld { @Override public BlockState getBlockState(BlockPos pos) { - if (blocksAdded.containsKey(pos)) - return blocksAdded.get(pos); - return Blocks.AIR.getDefaultState(); + BlockState state = blocksAdded.get(pos); + if (state != null) + return state; + else + return Blocks.AIR.getDefaultState(); } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedChunkProvider.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedChunkProvider.java new file mode 100644 index 000000000..e34d5cb11 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedChunkProvider.java @@ -0,0 +1,82 @@ +package com.simibubi.create.foundation.utility.worldWrappers; + +import com.simibubi.create.foundation.utility.worldWrappers.chunk.WrappedChunk; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.chunk.AbstractChunkProvider; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.chunk.IChunkLightProvider; +import net.minecraft.world.lighting.WorldLightManager; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BooleanSupplier; +import java.util.stream.Stream; + +public class WrappedChunkProvider extends AbstractChunkProvider { + private PlacementSimulationWorld world; + + public HashMap chunks; + + public WrappedChunkProvider setWorld(PlacementSimulationWorld world) { + this.world = world; + this.chunks = new HashMap<>(); + return this; + } + + public Stream getLightSources() { + return world.blocksAdded + .entrySet() + .stream() + .filter(it -> it.getValue().getLightValue(world, it.getKey()) != 0) + .map(Map.Entry::getKey); + } + + @Nullable + @Override + public IBlockReader getChunkForLight(int x, int z) { + return getChunk(x, z); + } + + @Override + public IBlockReader getWorld() { + return world; + } + + @Nullable + @Override + public IChunk getChunk(int x, int z, ChunkStatus status, boolean p_212849_4_) { + return getChunk(x, z); + } + + public WrappedChunk getChunk(int x, int z) { + long pos = ChunkPos.asLong(x, z); + + WrappedChunk chunk = chunks.get(pos); + + if (chunk == null) { + chunk = new WrappedChunk(world, x, z); + chunks.put(pos, chunk); + } + + return chunk; + } + + @Override + public void tick(BooleanSupplier p_217207_1_) { + + } + + @Override + public String makeString() { + return "WrappedChunkProvider"; + } + + @Override + public WorldLightManager getLightManager() { + return world.getLightingProvider(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java index b198db079..e986bf8bd 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/WrappedWorld.java @@ -19,18 +19,30 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.ITickList; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; +import net.minecraft.world.lighting.WorldLightManager; import net.minecraft.world.storage.MapData; public class WrappedWorld extends World { protected World world; + public WrappedWorld(World world, WrappedChunkProvider provider) { + super(world.getWorldInfo(), world.getDimension().getType(), (w, d) -> provider, + world.getProfiler(), world.isRemote); + this.world = world; + } + public WrappedWorld(World world) { super(world.getWorldInfo(), world.getDimension().getType(), (w, d) -> world.getChunkProvider(), world.getProfiler(), world.isRemote); this.world = world; } + @Override + public WorldLightManager getLightingProvider() { + return super.getLightingProvider(); + } + @Override public World getWorld() { return world; diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/chunk/WrappedChunk.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/chunk/WrappedChunk.java new file mode 100644 index 000000000..521d5319d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/chunk/WrappedChunk.java @@ -0,0 +1,250 @@ +package com.simibubi.create.foundation.utility.worldWrappers.chunk; + +import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; +import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; +import it.unimi.dsi.fastutil.longs.LongSet; +import it.unimi.dsi.fastutil.shorts.ShortList; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.IFluidState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.palette.UpgradeData; +import net.minecraft.world.ITickList; +import net.minecraft.world.biome.BiomeContainer; +import net.minecraft.world.chunk.ChunkSection; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.gen.Heightmap; +import net.minecraft.world.gen.feature.structure.StructureStart; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +public class WrappedChunk implements IChunk { + + private final PlacementSimulationWorld world; + private boolean needsLight; + private final int x; + private final int z; + private final ChunkPos pos; + + public WrappedChunk(PlacementSimulationWorld world, int x, int z) { + this.world = world; + this.needsLight = true; + this.x = x; + this.z = z; + this.pos = new ChunkPos(x, z); + } + + @Override + public Stream getLightSources() { + return world.blocksAdded + .entrySet() + .stream() + .filter(it -> { + BlockPos blockPos = it.getKey(); + boolean chunkContains = blockPos.getX() >> 4 == x && blockPos.getZ() >> 4 == z; + return chunkContains && it.getValue().getLightValue(world, blockPos) != 0; + }) + .map(Map.Entry::getKey); + } + + @Nullable + @Override + public BlockState setBlockState(BlockPos p_177436_1_, BlockState p_177436_2_, boolean p_177436_3_) { + return null; + } + + @Override + public void addTileEntity(BlockPos p_177426_1_, TileEntity p_177426_2_) { + + } + + @Override + public void addEntity(Entity p_76612_1_) { + + } + + @Override + public Set getTileEntitiesPos() { + return null; + } + + @Override + public ChunkSection[] getSections() { + return new ChunkSection[0]; + } + + @Override + public Collection> func_217311_f() { + return null; + } + + @Override + public void setHeightmap(Heightmap.Type p_201607_1_, long[] p_201607_2_) { + + } + + @Override + public Heightmap getHeightmap(Heightmap.Type p_217303_1_) { + return null; + } + + @Override + public int getTopBlockY(Heightmap.Type p_201576_1_, int p_201576_2_, int p_201576_3_) { + return 0; + } + + @Override + public ChunkPos getPos() { + return null; + } + + @Override + public void setLastSaveTime(long p_177432_1_) { + + } + + @Override + public Map getStructureStarts() { + return null; + } + + @Override + public void setStructureStarts(Map p_201612_1_) { + + } + + @Nullable + @Override + public BiomeContainer getBiomeArray() { + return null; + } + + @Override + public void setModified(boolean p_177427_1_) { + + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public ChunkStatus getStatus() { + return null; + } + + @Override + public void removeTileEntity(BlockPos p_177425_1_) { + + } + + @Override + public ShortList[] getPackedPositions() { + return new ShortList[0]; + } + + @Nullable + @Override + public CompoundNBT getDeferredTileEntity(BlockPos p_201579_1_) { + return null; + } + + @Nullable + @Override + public CompoundNBT func_223134_j(BlockPos p_223134_1_) { + return null; + } + + @Override + public ITickList getBlocksToBeTicked() { + return null; + } + + @Override + public ITickList getFluidsToBeTicked() { + return null; + } + + @Override + public UpgradeData getUpgradeData() { + return null; + } + + @Override + public void setInhabitedTime(long p_177415_1_) { + + } + + @Override + public long getInhabitedTime() { + return 0; + } + + @Override + public boolean hasLight() { + return needsLight; + } + + @Override + public void setLight(boolean needsLight) { + this.needsLight = needsLight; + } + + @Nullable + @Override + public TileEntity getTileEntity(BlockPos pos) { + return null; + } + + @Override + public BlockState getBlockState(BlockPos pos) { + return world.getBlockState(pos); + } + + @Override + public IFluidState getFluidState(BlockPos pos) { + return null; + } + + @Nullable + @Override + public StructureStart getStructureStart(String p_201585_1_) { + return null; + } + + @Override + public void putStructureStart(String p_201584_1_, StructureStart p_201584_2_) { + + } + + @Override + public LongSet getStructureReferences(String p_201578_1_) { + return null; + } + + @Override + public void addStructureReference(String p_201583_1_, long p_201583_2_) { + + } + + @Override + public Map getStructureReferences() { + return null; + } + + @Override + public void setStructureReferences(Map p_201606_1_) { + + } +} diff --git a/src/main/resources/assets/create/shader/contraption_structure.frag b/src/main/resources/assets/create/shader/contraption_structure.frag new file mode 100644 index 000000000..b8a07b4dc --- /dev/null +++ b/src/main/resources/assets/create/shader/contraption_structure.frag @@ -0,0 +1,24 @@ +#version 440 core + +in vec2 TexCoords; +in vec4 Color; +in float Diffuse; +in vec3 BoxCoord; +in vec2 ModelLight; + +out vec4 fragColor; + +layout(binding=0) uniform sampler2D BlockAtlas; +layout(binding=2) uniform sampler2D LightMap; +layout(binding=4) uniform sampler3D LightVolume; + +vec4 light() { + vec2 lm = texture(LightVolume, BoxCoord).rg * 0.9375 + 0.03125; + return texture2D(LightMap, max(lm, ModelLight)); +} + +void main() { + vec4 tex = texture2D(BlockAtlas, TexCoords); + + fragColor = vec4(tex.rgb * light().rgb * Diffuse * Color.rgb, tex.a); +} \ No newline at end of file diff --git a/src/main/resources/assets/create/shader/contraption.vert b/src/main/resources/assets/create/shader/contraption_structure.vert similarity index 94% rename from src/main/resources/assets/create/shader/contraption.vert rename to src/main/resources/assets/create/shader/contraption_structure.vert index cffa4e863..9547cf0bd 100644 --- a/src/main/resources/assets/create/shader/contraption.vert +++ b/src/main/resources/assets/create/shader/contraption_structure.vert @@ -5,11 +5,13 @@ layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; layout (location = 2) in vec2 aTexCoords; layout (location = 3) in vec4 aColor; +layout (location = 4) in vec2 modelLight; out float Diffuse; out vec2 TexCoords; out vec4 Color; out vec3 BoxCoord; +out vec2 ModelLight; uniform vec3 lightBoxSize; uniform vec3 lightBoxMin; @@ -48,6 +50,7 @@ void main() { Diffuse = diffuse(norm); Color = aColor / diffuse(aNormal); TexCoords = aTexCoords; + ModelLight = modelLight; gl_Position = projection * view * worldPos; if (debug == 2) {