From dbede41ebaf4a8349201ec55c1978ce9f6f39b64 Mon Sep 17 00:00:00 2001 From: grimmauld Date: Mon, 19 Apr 2021 09:58:11 +0200 Subject: [PATCH] Finally, a properly working state (reflection maths is still of by a bit) --- .../simibubi/create/content/optics/Beam.java | 74 +++++++++++++ .../create/content/optics/BeamSegment.java | 31 +++--- .../create/content/optics/ILightHandler.java | 52 +++++++-- .../mirror/BeaconSegmentListWrapper.java | 5 - .../content/optics/mirror/MirrorRenderer.java | 12 +- .../optics/mirror/MirrorTileEntity.java | 103 +++++++++++++++--- 6 files changed, 216 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/optics/Beam.java delete mode 100644 src/main/java/com/simibubi/create/content/optics/mirror/BeaconSegmentListWrapper.java diff --git a/src/main/java/com/simibubi/create/content/optics/Beam.java b/src/main/java/com/simibubi/create/content/optics/Beam.java new file mode 100644 index 000000000..22aae0e9a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/optics/Beam.java @@ -0,0 +1,74 @@ +package com.simibubi.create.content.optics; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import javax.annotation.Nullable; + +import com.mojang.blaze3d.matrix.MatrixStack; + +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.util.math.vector.Vector3d; + +public class Beam extends ArrayList { + public final Set subBeams; + private final Set> lightEventListeners; + private final Vector3d direction; + private boolean removed = false; + + public Beam(Vector3d direction) { + super(); + this.direction = direction; + lightEventListeners = new HashSet<>(); + subBeams = new HashSet<>(); + } + + public void onRemoved() { + lightEventListeners.forEach(handler -> handler.onBeamRemoved(this)); + subBeams.forEach(Beam::onRemoved); + subBeams.clear(); + removed = true; + clear(); + } + + public void onCreated() { + lightEventListeners.stream() + .flatMap(handler -> handler.constructSubBeams(this)) + .forEach(subBeams::add); + } + + public void registerSubBeam(Beam beam) { + subBeams.add(beam); + } + + public void render(MatrixStack ms, IRenderTypeBuffer buffer, float partialTicks) { + if (removed) + throw new IllegalStateException("tried to render removed beam"); + forEach(beamSegment -> beamSegment.renderSegment(ms, buffer, partialTicks)); + } + + public void addListener(@Nullable ILightHandler tile) { + if (tile != null) + lightEventListeners.add(tile); + } + + public Vector3d getDirection() { + return direction; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + Beam that = (Beam) o; + return removed == that.removed && subBeams.equals(that.subBeams) && lightEventListeners.equals(that.lightEventListeners) && Objects.equals(direction, that.direction); + } + + public void removeSubBeam(Beam out) { + if (subBeams.remove(out)) + out.onRemoved(); + } +} diff --git a/src/main/java/com/simibubi/create/content/optics/BeamSegment.java b/src/main/java/com/simibubi/create/content/optics/BeamSegment.java index 2c95bf5c5..117b046e2 100644 --- a/src/main/java/com/simibubi/create/content/optics/BeamSegment.java +++ b/src/main/java/com/simibubi/create/content/optics/BeamSegment.java @@ -32,7 +32,7 @@ public class BeamSegment { private final Vector3d direction; private final Vector3d start; private final LazyValue normalized; - private final LazyValue totalSectionLength; + private final LazyValue totalSectionLength; private final ILightHandler handler; @Nullable private Quaternion beaconBeamModifier; @@ -46,27 +46,27 @@ public class BeamSegment { this.length = 1; this.normalized = new LazyValue<>(direction::normalize); beaconBeamModifier = null; - totalSectionLength = new LazyValue<>(() -> getDirection().scale(getLength()) + totalSectionLength = new LazyValue<>(() -> (float) getDirection().scale(getLength()) .length()); } @OnlyIn(Dist.CLIENT) - private static void renderBeam(MatrixStack ms, IVertexBuilder builder, float[] colors, float alpha, double segemntLength, double length, float p_228840_9_, float p_228840_10_, float p_228840_11_, float p_228840_12_, float p_228840_13_, float p_228840_14_, float p_228840_15_, float p_228840_18_, float p_228840_19_) { + private static void renderBeam(MatrixStack ms, IVertexBuilder builder, float[] colors, float alpha, float segmentLength, float p_228840_9_, float p_228840_10_, float p_228840_11_, float p_228840_12_, float p_228840_13_, float p_228840_14_, float p_228840_15_, float p_228840_18_, float p_228840_19_) { MatrixStack.Entry matrixstack$entry = ms.peek(); Matrix4f model = matrixstack$entry.getModel(); Matrix3f normal = matrixstack$entry.getNormal(); - putVertices(model, normal, builder, colors, alpha, segemntLength, length, (float) 0.0, p_228840_9_, p_228840_10_, p_228840_11_, p_228840_18_, p_228840_19_); - putVertices(model, normal, builder, colors, alpha, segemntLength, length, p_228840_14_, p_228840_15_, p_228840_12_, p_228840_13_, p_228840_18_, p_228840_19_); - putVertices(model, normal, builder, colors, alpha, segemntLength, length, p_228840_10_, p_228840_11_, p_228840_14_, p_228840_15_, p_228840_18_, p_228840_19_); - putVertices(model, normal, builder, colors, alpha, segemntLength, length, p_228840_12_, p_228840_13_, (float) 0.0, p_228840_9_, p_228840_18_, p_228840_19_); + putVertices(model, normal, builder, colors, alpha, segmentLength, 0F, p_228840_9_, p_228840_10_, p_228840_11_, p_228840_18_, p_228840_19_); + putVertices(model, normal, builder, colors, alpha, segmentLength, p_228840_14_, p_228840_15_, p_228840_12_, p_228840_13_, p_228840_18_, p_228840_19_); + putVertices(model, normal, builder, colors, alpha, segmentLength, p_228840_10_, p_228840_11_, p_228840_14_, p_228840_15_, p_228840_18_, p_228840_19_); + putVertices(model, normal, builder, colors, alpha, segmentLength, p_228840_12_, p_228840_13_, 0F, p_228840_9_, p_228840_18_, p_228840_19_); } @OnlyIn(Dist.CLIENT) - private static void putVertices(Matrix4f model, Matrix3f normal, IVertexBuilder builder, float[] colors, float alpha, double segemntLength, double length, float p_228839_9_, float p_228839_10_, float p_228839_11_, float p_228839_12_, float p_228839_15_, float p_228839_16_) { - putVertex(model, normal, builder, colors, alpha, (float) length, p_228839_9_, p_228839_10_, (float) 1.0, p_228839_15_); - putVertex(model, normal, builder, colors, alpha, (float) segemntLength, p_228839_9_, p_228839_10_, (float) 1.0, p_228839_16_); - putVertex(model, normal, builder, colors, alpha, (float) segemntLength, p_228839_11_, p_228839_12_, (float) 0.0, p_228839_16_); - putVertex(model, normal, builder, colors, alpha, (float) length, p_228839_11_, p_228839_12_, (float) 0.0, p_228839_15_); + private static void putVertices(Matrix4f model, Matrix3f normal, IVertexBuilder builder, float[] colors, float alpha, float segmentLength, float p_228839_9_, float p_228839_10_, float p_228839_11_, float p_228839_12_, float p_228839_15_, float p_228839_16_) { + putVertex(model, normal, builder, colors, alpha, segmentLength, p_228839_9_, p_228839_10_, 1F, p_228839_15_); + putVertex(model, normal, builder, colors, alpha, 0F, p_228839_9_, p_228839_10_, 1F, p_228839_16_); + putVertex(model, normal, builder, colors, alpha, 0F, p_228839_11_, p_228839_12_, 0F, p_228839_16_); + putVertex(model, normal, builder, colors, alpha, segmentLength, p_228839_11_, p_228839_12_, 0F, p_228839_15_); } @OnlyIn(Dist.CLIENT) @@ -140,9 +140,8 @@ public class BeamSegment { } @OnlyIn(Dist.CLIENT) - public void renderSegment(MatrixStack ms, IRenderTypeBuffer buffer, float partialTicks, double segmentOffset) { + public void renderSegment(MatrixStack ms, IRenderTypeBuffer buffer, float partialTicks) { float adjustedGameTime = (float) Math.floorMod(getWorldTick(), 40L) + partialTicks; - double totalLength = totalSectionLength.getValue() + segmentOffset; float textureOffset1 = MathHelper.fractionalPart(-adjustedGameTime * 0.2F - (float) MathHelper.floor(-adjustedGameTime * 0.1F)) - 1; float textureOffset2 = (float) this.getLength() * 2.5f + textureOffset1; @@ -157,11 +156,11 @@ public class BeamSegment { .multiply(Vector3f.POSITIVE_Y, adjustedGameTime * 2.25F - 45.0F); renderBeam(stacker.unwrap(), buffer.getBuffer(RenderType.getBeaconBeam(TEXTURE_BEACON_BEAM, false)), this.colors, 1F, - segmentOffset, totalLength, 0.2F, .2F, 0F, -.2f, + totalSectionLength.getValue(), 0.2F, .2F, 0F, -.2f, 0f, 0f, -.2f, textureOffset2, textureOffset1); stacker.pop(); renderBeam(stacker.unwrap(), buffer.getBuffer(RenderType.getBeaconBeam(TEXTURE_BEACON_BEAM, true)), this.colors, 0.125F, - segmentOffset, totalLength, -.25f, .25f, -.25f, -.25f, + totalSectionLength.getValue(), -.25f, .25f, -.25f, -.25f, .25f, .25f, .25f, textureOffset2, textureOffset1); stacker.pop() .pop(); diff --git a/src/main/java/com/simibubi/create/content/optics/ILightHandler.java b/src/main/java/com/simibubi/create/content/optics/ILightHandler.java index 60926dbca..ea0328ba3 100644 --- a/src/main/java/com/simibubi/create/content/optics/ILightHandler.java +++ b/src/main/java/com/simibubi/create/content/optics/ILightHandler.java @@ -1,11 +1,13 @@ package com.simibubi.create.content.optics; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; +import java.util.Collections; +import java.util.Iterator; +import java.util.stream.Stream; import javax.annotation.Nullable; +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.utility.BeaconHelper; import com.simibubi.create.foundation.utility.VecHelper; @@ -18,29 +20,41 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; -public interface ILightHandler> { - default List constructOutBeam(Vector3d beamDirection) { - ArrayList beam = new ArrayList<>(); +public interface ILightHandler> { + @Nullable + default Beam constructOutBeam(Vector3d beamDirection) { + return constructOutBeam(beamDirection, getTile().getPos()); + } + + @Nullable + default Beam constructOutBeam(Vector3d beamDirection, BlockPos testBlockPos) { + float[] segmentColor = getSegmentStartColor(); World world = getTile().getWorld(); if (world == null) - return beam; + return null; Vector3d direction = VecHelper.step(beamDirection); - Vector3d testPos = VecHelper.getCenterOf(getTile().getPos()); + Beam beam = new Beam(direction); + Vector3d testPos = VecHelper.getCenterOf(testBlockPos); BeamSegment segment = new BeamSegment(this, segmentColor, testPos, direction); beam.add(segment); for (int i = 0; i < 128; i++) { testPos = testPos.add(direction); // check next block - BlockPos testBlockPos = new BlockPos(testPos.x, testPos.y, testPos.z); + testBlockPos = new BlockPos(testPos.x, testPos.y, testPos.z); BlockState testState = world.getBlockState(testBlockPos); float[] newColor = BeaconHelper.getBeaconColorAt(testState.getBlock()); + + TileEntity te = testState.hasTileEntity() ? world.getTileEntity(testBlockPos) : null; + ILightHandler lightHandler = te instanceof ILightHandler ? (ILightHandler) te : null; + if (lightHandler != this) + beam.addListener(lightHandler); + if (newColor == null) { - TileEntity te = testState.hasTileEntity() ? world.getTileEntity(testBlockPos) : null; - if (testState.getOpacity(world, testBlockPos) >= 15 && testState.getBlock() != Blocks.BEDROCK || te instanceof ILightHandler) { - if (te instanceof ILightHandler) { - ((ILightHandler) te).setColor(segmentColor); + if (testState.getOpacity(world, testBlockPos) >= 15 && testState.getBlock() != Blocks.BEDROCK || (lightHandler != null && !lightHandler.canLightPass())) { + if (lightHandler != null) { + lightHandler.setColor(segmentColor); } break; } @@ -69,4 +83,18 @@ public interface ILightHandler> { return null; } + default void onBeamRemoved(Beam beam) { + } + + default Stream constructSubBeams(Beam beam) { + return Stream.empty(); + } + + default Iterator getRenderBeams() { + return Collections.emptyIterator(); + } + + default boolean canLightPass() { + return false; + } } diff --git a/src/main/java/com/simibubi/create/content/optics/mirror/BeaconSegmentListWrapper.java b/src/main/java/com/simibubi/create/content/optics/mirror/BeaconSegmentListWrapper.java deleted file mode 100644 index 077708019..000000000 --- a/src/main/java/com/simibubi/create/content/optics/mirror/BeaconSegmentListWrapper.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.simibubi.create.content.optics.mirror; - -public class BeaconSegmentListWrapper { - -} diff --git a/src/main/java/com/simibubi/create/content/optics/mirror/MirrorRenderer.java b/src/main/java/com/simibubi/create/content/optics/mirror/MirrorRenderer.java index 37793d8d2..66b340c05 100644 --- a/src/main/java/com/simibubi/create/content/optics/mirror/MirrorRenderer.java +++ b/src/main/java/com/simibubi/create/content/optics/mirror/MirrorRenderer.java @@ -6,7 +6,6 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; -import com.simibubi.create.content.optics.BeamSegment; import com.simibubi.create.foundation.render.SuperByteBuffer; import com.simibubi.create.foundation.utility.AngleHelper; @@ -30,15 +29,8 @@ public class MirrorRenderer extends KineticTileEntityRenderer { MirrorTileEntity mirrorTe = (MirrorTileEntity) te; renderMirror(mirrorTe, partialTicks, ms, buffer, light); - renderOutBeam(mirrorTe.beam, partialTicks, ms, buffer); - } - - private void renderOutBeam(Iterable beam, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer) { - double totalLength = 0; - for (BeamSegment beamSegment : beam) { - beamSegment.renderSegment(ms, buffer, partialTicks, totalLength); - totalLength += beamSegment.getTotalSectionLength(); - } + ((MirrorTileEntity) te).getRenderBeams() + .forEachRemaining(beam -> beam.render(ms, buffer, partialTicks)); } private void renderMirror(MirrorTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, int light) { diff --git a/src/main/java/com/simibubi/create/content/optics/mirror/MirrorTileEntity.java b/src/main/java/com/simibubi/create/content/optics/mirror/MirrorTileEntity.java index 2d4e368f9..5e9786da6 100644 --- a/src/main/java/com/simibubi/create/content/optics/mirror/MirrorTileEntity.java +++ b/src/main/java/com/simibubi/create/content/optics/mirror/MirrorTileEntity.java @@ -1,7 +1,17 @@ package com.simibubi.create.content.optics.mirror; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.stream.Stream; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.google.common.collect.Iterators; import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.optics.BeamSegment; +import com.simibubi.create.content.optics.Beam; import com.simibubi.create.content.optics.ILightHandler; import com.simibubi.create.foundation.collision.Matrix3d; import com.simibubi.create.foundation.utility.AngleHelper; @@ -22,24 +32,20 @@ import net.minecraft.util.math.vector.Vector3d; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import javax.annotation.Nonnull; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - public class MirrorTileEntity extends KineticTileEntity implements ILightHandler { - public final List beam; protected float angle; protected float clientAngleDiff; + Map beams; private float prevAngle; - private Optional beacon; + @Nullable + private BeaconTileEntity beacon; + private Beam beaconBeam = null; private float[] initialColor = DyeColor.WHITE.getColorComponentValues(); public MirrorTileEntity(TileEntityType typeIn) { super(typeIn); - beacon = Optional.empty(); - beam = new ArrayList<>(); + beacon = null; + beams = new HashMap<>(); setLazyTickRate(20); } @@ -86,14 +92,40 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler float newAngle = angle + angularSpeed; angle = newAngle % 360; - if (angle != prevAngle) - updateBeams(); + if (angle != prevAngle) { + updateReflections(); + } + + if (beacon != null && beacon.isRemoved()) + updateBeaconState(); } - private void updateBeams() { - beacon = BeaconHelper.getBeaconTE(pos, world); - beam.clear(); - beam.addAll(constructOutBeam(getReflectionAngle(VecHelper.UP))); + private void updateBeaconState() { + BeaconTileEntity beaconBefore = beacon; + beacon = BeaconHelper.getBeaconTE(pos, world) + .orElse(null); + + if (beaconBefore == beacon) + return; + + if (beaconBefore != null) { + beaconBeam.onRemoved(); + beaconBeam = null; + updateReflections(); + } + + if (beacon != null) { + beaconBeam = constructOutBeam(VecHelper.UP, beacon.getPos()); + if (beaconBeam != null) { + beaconBeam.addListener(this); + beaconBeam.onCreated(); + } + } + } + + private void updateReflections() { + new HashMap<>(beams).forEach(Beam::removeSubBeam); + beams.replaceAll((b, v) -> reflectBeam(b)); } private Vector3d getReflectionAngle(Vector3d inputAngle) { @@ -107,7 +139,8 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler @Override public void lazyTick() { super.lazyTick(); - updateBeams(); + updateBeaconState(); + updateReflections(); } @Override @@ -158,4 +191,38 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler public double getMaxRenderDistanceSquared() { return 256.0D; } + + @Override + public Iterator getRenderBeams() { + Iterator beaconIter = beaconBeam == null ? Collections.emptyIterator() : Collections.singleton(beaconBeam) + .iterator(); + return Iterators.concat(beams.values() + .iterator(), beaconIter); + } + + @Override + public void onBeamRemoved(Beam beam) { + beams.remove(beam); + } + + + @Override + public Stream constructSubBeams(Beam beam) { + Beam reflected = reflectBeam(beam); + if (reflected != null) { + beams.put(beam, reflected); + return Stream.of(reflected); + } + return Stream.empty(); + } + + + private Beam reflectBeam(Beam beam) { + Beam reflected = constructOutBeam(getReflectionAngle(beam.getDirection())); + if (reflected != null) { + beam.registerSubBeam(reflected); + reflected.onCreated(); + } + return reflected; + } }