diff --git a/src/main/java/com/simibubi/create/content/optics/Beam.java b/src/main/java/com/simibubi/create/content/optics/Beam.java index 22aae0e9a..6d46f963d 100644 --- a/src/main/java/com/simibubi/create/content/optics/Beam.java +++ b/src/main/java/com/simibubi/create/content/optics/Beam.java @@ -8,44 +8,33 @@ import java.util.Set; import javax.annotation.Nullable; import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.item.DyeColor; +import net.minecraft.util.math.BlockPos; 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; + @Nullable + private final Beam parent; - public Beam(Vector3d direction) { + public Beam(@Nullable Beam parent, Vector3d direction) { super(); + this.parent = parent; 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); + .forEach(Beam::onCreated); } 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)); } @@ -64,11 +53,28 @@ public class Beam extends ArrayList { 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); + return lightEventListeners.equals(that.lightEventListeners) && Objects.equals(direction, that.direction); } - public void removeSubBeam(Beam out) { - if (subBeams.remove(out)) - out.onRemoved(); + public boolean isRemoved() { + return isEmpty() || get(0).getHandler() + .getTile() + .isRemoved() || !get(0).getHandler() + .getOutBeams() + .contains(this) || (parent != null && parent.isRemoved()); + } + + public float[] getColorAt(BlockPos testBlockPos) { + float[] out = DyeColor.WHITE.getColorComponentValues(); + for (BeamSegment segment : this) { + if (VecHelper.getCenterOf(testBlockPos) + .subtract(segment.getStart()) + .dotProduct(segment.getNormalized()) > 0) + out = segment.getColors(); + else + break; + } + + return out; } } 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 117b046e2..d74163a8a 100644 --- a/src/main/java/com/simibubi/create/content/optics/BeamSegment.java +++ b/src/main/java/com/simibubi/create/content/optics/BeamSegment.java @@ -120,16 +120,12 @@ public class BeamSegment { beaconBeamModifier = Quaternion.IDENTITY; } else { Vector3f unitVec = axis.getUnitVector(); - beaconBeamModifier = unitVec.getRadialQuaternion((float) (-Math.acos(dotProd) * Math.signum(new Vector3d(unitVec).dotProduct(getNormalized().crossProduct(UP))))); + beaconBeamModifier = unitVec.getRadialQuaternion((float) Math.acos(dotProd) * (new Vector3d(unitVec).dotProduct(getNormalized().crossProduct(UP)) > 0 ? -1 : 1)); } } return beaconBeamModifier; } - public double getTotalSectionLength() { - return totalSectionLength.getValue(); - } - public long getWorldTick() { World world = getHandler() .getTile() 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 ea0328ba3..8c3dbd910 100644 --- a/src/main/java/com/simibubi/create/content/optics/ILightHandler.java +++ b/src/main/java/com/simibubi/create/content/optics/ILightHandler.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.optics; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.stream.Stream; @@ -22,19 +23,19 @@ import net.minecraft.world.World; public interface ILightHandler> { @Nullable - default Beam constructOutBeam(Vector3d beamDirection) { - return constructOutBeam(beamDirection, getTile().getPos()); + default Beam constructOutBeam(@Nullable Beam parent, Vector3d beamDirection) { + return constructOutBeam(parent, beamDirection, getTile().getPos()); } @Nullable - default Beam constructOutBeam(Vector3d beamDirection, BlockPos testBlockPos) { + default Beam constructOutBeam(@Nullable Beam parent, Vector3d beamDirection, BlockPos testBlockPos) { - float[] segmentColor = getSegmentStartColor(); + float[] segmentColor = parent == null ? DyeColor.WHITE.getColorComponentValues() : parent.getColorAt(testBlockPos); World world = getTile().getWorld(); if (world == null) return null; Vector3d direction = VecHelper.step(beamDirection); - Beam beam = new Beam(direction); + Beam beam = new Beam(parent, direction); Vector3d testPos = VecHelper.getCenterOf(testBlockPos); BeamSegment segment = new BeamSegment(this, segmentColor, testPos, direction); @@ -74,18 +75,11 @@ public interface ILightHandler> { default void setColor(float[] segmentColor) { } - default float[] getSegmentStartColor() { - return DyeColor.WHITE.getColorComponentValues(); - } - @Nullable default Direction getBeamRotationAround() { return null; } - default void onBeamRemoved(Beam beam) { - } - default Stream constructSubBeams(Beam beam) { return Stream.empty(); } @@ -97,4 +91,8 @@ public interface ILightHandler> { default boolean canLightPass() { return false; } + + default Collection getOutBeams() { + return Collections.emptySet(); + } } 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 38ceb1623..a184d7ced 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,5 +1,6 @@ package com.simibubi.create.content.optics.mirror; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -20,7 +21,6 @@ import com.simibubi.create.foundation.utility.ServerSpeedProvider; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; -import net.minecraft.item.DyeColor; import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.BeaconTileEntity; @@ -40,7 +40,6 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler @Nullable private BeaconTileEntity beacon; private Beam beaconBeam = null; - private float[] initialColor = DyeColor.WHITE.getColorComponentValues(); public MirrorTileEntity(TileEntityType typeIn) { super(typeIn); @@ -93,7 +92,7 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler angle = newAngle % 360; if (angle != prevAngle) { - updateReflections(); + updateBeams(); } if (beacon != null && beacon.isRemoved()) @@ -105,17 +104,14 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler beacon = BeaconHelper.getBeaconTE(pos, world) .orElse(null); - if (beaconBefore == beacon) - return; - if (beaconBefore != null) { - beaconBeam.onRemoved(); + beaconBeam.clear(); beaconBeam = null; - updateReflections(); + updateBeams(); } if (beacon != null) { - beaconBeam = constructOutBeam(VecHelper.UP, beacon.getPos()); + beaconBeam = constructOutBeam(null, VecHelper.UP, beacon.getPos()); if (beaconBeam != null) { beaconBeam.addListener(this); beaconBeam.onCreated(); @@ -123,12 +119,18 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler } } - private void updateReflections() { - new HashMap<>(beams).forEach(Beam::removeSubBeam); - + private void updateBeams() { Map newBeams = new HashMap<>(); - for (Beam beam : beams.keySet()) { - newBeams.put(beam, reflectBeam(beam)); + for (Map.Entry entry : beams.entrySet()) { + if (entry.getKey() + .isRemoved()) + continue; + + Beam reflected = reflectBeam(entry.getKey()); + if (reflected != null) { + newBeams.put(entry.getKey(), reflected); + reflected.onCreated(); + } } beams = newBeams; } @@ -145,7 +147,7 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler public void lazyTick() { super.lazyTick(); updateBeaconState(); - updateReflections(); + updateBeams(); } @Override @@ -160,12 +162,6 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler @Override public void setColor(float[] initialColor) { - this.initialColor = initialColor; - } - - @Override - public float[] getSegmentStartColor() { - return initialColor; } @Nonnull @@ -205,17 +201,20 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler .iterator(), beaconIter); } - @Override - public void onBeamRemoved(Beam beam) { - beams.remove(beam); - } - @Override public Stream constructSubBeams(Beam beam) { + if (beams.keySet() + .stream() + .map(Beam::getDirection) + .map(Vector3d::normalize) + .anyMatch(beam.getDirection() + .normalize()::equals)) + return Stream.empty(); Beam reflected = reflectBeam(beam); if (reflected != null) { beams.put(beam, reflected); + beam.addListener(this); return Stream.of(reflected); } return Stream.empty(); @@ -223,11 +222,21 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler private Beam reflectBeam(Beam beam) { - Beam reflected = constructOutBeam(getReflectionAngle(beam.getDirection())); - if (reflected != null) { - beam.registerSubBeam(reflected); - reflected.onCreated(); - } - return reflected; + Vector3d inDir = beam.getDirection() + .normalize(); + Vector3d outDir = getReflectionAngle(inDir).normalize(); + + if (inDir.subtract(outDir) + .normalize() == Vector3d.ZERO) + return null; + + // TE already has input beam at that direction + + return constructOutBeam(beam, outDir); + } + + @Override + public Collection getOutBeams() { + return beams.keySet(); } }