Fix a bunch of stuff, mirroring colors now works correctly

This commit is contained in:
grimmauld 2021-04-19 18:27:53 +02:00
parent 5d54ed4682
commit 2b3fb358ad
4 changed files with 81 additions and 72 deletions

View file

@ -8,44 +8,33 @@ import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.item.DyeColor;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3d;
public class Beam extends ArrayList<BeamSegment> { public class Beam extends ArrayList<BeamSegment> {
public final Set<Beam> subBeams;
private final Set<ILightHandler<?>> lightEventListeners; private final Set<ILightHandler<?>> lightEventListeners;
private final Vector3d direction; 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(); super();
this.parent = parent;
this.direction = direction; this.direction = direction;
lightEventListeners = new HashSet<>(); 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() { public void onCreated() {
lightEventListeners.stream() lightEventListeners.stream()
.flatMap(handler -> handler.constructSubBeams(this)) .flatMap(handler -> handler.constructSubBeams(this))
.forEach(subBeams::add); .forEach(Beam::onCreated);
}
public void registerSubBeam(Beam beam) {
subBeams.add(beam);
} }
public void render(MatrixStack ms, IRenderTypeBuffer buffer, float partialTicks) { 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)); forEach(beamSegment -> beamSegment.renderSegment(ms, buffer, partialTicks));
} }
@ -64,11 +53,28 @@ public class Beam extends ArrayList<BeamSegment> {
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
Beam that = (Beam) o; 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) { public boolean isRemoved() {
if (subBeams.remove(out)) return isEmpty() || get(0).getHandler()
out.onRemoved(); .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;
} }
} }

View file

@ -120,16 +120,12 @@ public class BeamSegment {
beaconBeamModifier = Quaternion.IDENTITY; beaconBeamModifier = Quaternion.IDENTITY;
} else { } else {
Vector3f unitVec = axis.getUnitVector(); 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; return beaconBeamModifier;
} }
public double getTotalSectionLength() {
return totalSectionLength.getValue();
}
public long getWorldTick() { public long getWorldTick() {
World world = getHandler() World world = getHandler()
.getTile() .getTile()

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.optics; package com.simibubi.create.content.optics;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -22,19 +23,19 @@ import net.minecraft.world.World;
public interface ILightHandler<T extends SmartTileEntity & ILightHandler<T>> { public interface ILightHandler<T extends SmartTileEntity & ILightHandler<T>> {
@Nullable @Nullable
default Beam constructOutBeam(Vector3d beamDirection) { default Beam constructOutBeam(@Nullable Beam parent, Vector3d beamDirection) {
return constructOutBeam(beamDirection, getTile().getPos()); return constructOutBeam(parent, beamDirection, getTile().getPos());
} }
@Nullable @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(); World world = getTile().getWorld();
if (world == null) if (world == null)
return null; return null;
Vector3d direction = VecHelper.step(beamDirection); Vector3d direction = VecHelper.step(beamDirection);
Beam beam = new Beam(direction); Beam beam = new Beam(parent, direction);
Vector3d testPos = VecHelper.getCenterOf(testBlockPos); Vector3d testPos = VecHelper.getCenterOf(testBlockPos);
BeamSegment segment = new BeamSegment(this, segmentColor, testPos, direction); BeamSegment segment = new BeamSegment(this, segmentColor, testPos, direction);
@ -74,18 +75,11 @@ public interface ILightHandler<T extends SmartTileEntity & ILightHandler<T>> {
default void setColor(float[] segmentColor) { default void setColor(float[] segmentColor) {
} }
default float[] getSegmentStartColor() {
return DyeColor.WHITE.getColorComponentValues();
}
@Nullable @Nullable
default Direction getBeamRotationAround() { default Direction getBeamRotationAround() {
return null; return null;
} }
default void onBeamRemoved(Beam beam) {
}
default Stream<Beam> constructSubBeams(Beam beam) { default Stream<Beam> constructSubBeams(Beam beam) {
return Stream.empty(); return Stream.empty();
} }
@ -97,4 +91,8 @@ public interface ILightHandler<T extends SmartTileEntity & ILightHandler<T>> {
default boolean canLightPass() { default boolean canLightPass() {
return false; return false;
} }
default Collection<Beam> getOutBeams() {
return Collections.emptySet();
}
} }

View file

@ -1,5 +1,6 @@
package com.simibubi.create.content.optics.mirror; package com.simibubi.create.content.optics.mirror;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@ -20,7 +21,6 @@ import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.item.DyeColor;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.BeaconTileEntity; import net.minecraft.tileentity.BeaconTileEntity;
@ -40,7 +40,6 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
@Nullable @Nullable
private BeaconTileEntity beacon; private BeaconTileEntity beacon;
private Beam beaconBeam = null; private Beam beaconBeam = null;
private float[] initialColor = DyeColor.WHITE.getColorComponentValues();
public MirrorTileEntity(TileEntityType<?> typeIn) { public MirrorTileEntity(TileEntityType<?> typeIn) {
super(typeIn); super(typeIn);
@ -93,7 +92,7 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
angle = newAngle % 360; angle = newAngle % 360;
if (angle != prevAngle) { if (angle != prevAngle) {
updateReflections(); updateBeams();
} }
if (beacon != null && beacon.isRemoved()) if (beacon != null && beacon.isRemoved())
@ -105,17 +104,14 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
beacon = BeaconHelper.getBeaconTE(pos, world) beacon = BeaconHelper.getBeaconTE(pos, world)
.orElse(null); .orElse(null);
if (beaconBefore == beacon)
return;
if (beaconBefore != null) { if (beaconBefore != null) {
beaconBeam.onRemoved(); beaconBeam.clear();
beaconBeam = null; beaconBeam = null;
updateReflections(); updateBeams();
} }
if (beacon != null) { if (beacon != null) {
beaconBeam = constructOutBeam(VecHelper.UP, beacon.getPos()); beaconBeam = constructOutBeam(null, VecHelper.UP, beacon.getPos());
if (beaconBeam != null) { if (beaconBeam != null) {
beaconBeam.addListener(this); beaconBeam.addListener(this);
beaconBeam.onCreated(); beaconBeam.onCreated();
@ -123,12 +119,18 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
} }
} }
private void updateReflections() { private void updateBeams() {
new HashMap<>(beams).forEach(Beam::removeSubBeam);
Map<Beam, Beam> newBeams = new HashMap<>(); Map<Beam, Beam> newBeams = new HashMap<>();
for (Beam beam : beams.keySet()) { for (Map.Entry<Beam, Beam> entry : beams.entrySet()) {
newBeams.put(beam, reflectBeam(beam)); if (entry.getKey()
.isRemoved())
continue;
Beam reflected = reflectBeam(entry.getKey());
if (reflected != null) {
newBeams.put(entry.getKey(), reflected);
reflected.onCreated();
}
} }
beams = newBeams; beams = newBeams;
} }
@ -145,7 +147,7 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
public void lazyTick() { public void lazyTick() {
super.lazyTick(); super.lazyTick();
updateBeaconState(); updateBeaconState();
updateReflections(); updateBeams();
} }
@Override @Override
@ -160,12 +162,6 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
@Override @Override
public void setColor(float[] initialColor) { public void setColor(float[] initialColor) {
this.initialColor = initialColor;
}
@Override
public float[] getSegmentStartColor() {
return initialColor;
} }
@Nonnull @Nonnull
@ -205,17 +201,20 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
.iterator(), beaconIter); .iterator(), beaconIter);
} }
@Override
public void onBeamRemoved(Beam beam) {
beams.remove(beam);
}
@Override @Override
public Stream<Beam> constructSubBeams(Beam beam) { public Stream<Beam> 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); Beam reflected = reflectBeam(beam);
if (reflected != null) { if (reflected != null) {
beams.put(beam, reflected); beams.put(beam, reflected);
beam.addListener(this);
return Stream.of(reflected); return Stream.of(reflected);
} }
return Stream.empty(); return Stream.empty();
@ -223,11 +222,21 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
private Beam reflectBeam(Beam beam) { private Beam reflectBeam(Beam beam) {
Beam reflected = constructOutBeam(getReflectionAngle(beam.getDirection())); Vector3d inDir = beam.getDirection()
if (reflected != null) { .normalize();
beam.registerSubBeam(reflected); Vector3d outDir = getReflectionAngle(inDir).normalize();
reflected.onCreated();
} if (inDir.subtract(outDir)
return reflected; .normalize() == Vector3d.ZERO)
return null;
// TE already has input beam at that direction
return constructOutBeam(beam, outDir);
}
@Override
public Collection<Beam> getOutBeams() {
return beams.keySet();
} }
} }