mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-02-05 09:54:59 +01:00
Move mirroring to tile entity behavior
This commit is contained in:
parent
8e33eade50
commit
0dd72c236b
8 changed files with 305 additions and 248 deletions
|
@ -1,22 +1,21 @@
|
||||||
package com.simibubi.create.content.optics;
|
package com.simibubi.create.content.optics;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
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.item.DyeColor;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.vector.Vector3d;
|
import net.minecraft.util.math.vector.Vector3d;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class Beam extends ArrayList<BeamSegment> {
|
public class Beam extends ArrayList<BeamSegment> {
|
||||||
private final Set<ILightHandler<?>> lightEventListeners;
|
private final Set<ILightHandler> lightEventListeners;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Beam parent;
|
private final Beam parent;
|
||||||
private boolean removed = false;
|
private boolean removed = false;
|
||||||
|
@ -37,7 +36,7 @@ public class Beam extends ArrayList<BeamSegment> {
|
||||||
forEach(beamSegment -> beamSegment.renderSegment(ms, buffer, partialTicks));
|
forEach(beamSegment -> beamSegment.renderSegment(ms, buffer, partialTicks));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addListener(@Nullable ILightHandler<?> tile) {
|
public void addListener(@Nullable ILightHandler tile) {
|
||||||
if (tile != null)
|
if (tile != null)
|
||||||
lightEventListeners.add(tile);
|
lightEventListeners.add(tile);
|
||||||
}
|
}
|
||||||
|
@ -55,9 +54,8 @@ public class Beam extends ArrayList<BeamSegment> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public TileEntity getHandler() {
|
public ILightHandler getHandler() {
|
||||||
return size() == 0 ? null : get(0).getHandler()
|
return size() == 0 ? null : get(0).getHandler();
|
||||||
.getTile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -71,8 +69,9 @@ public class Beam extends ArrayList<BeamSegment> {
|
||||||
|
|
||||||
public boolean isRemoved() {
|
public boolean isRemoved() {
|
||||||
// || !get(0).getHandler().getOutBeams().contains(this)
|
// || !get(0).getHandler().getOutBeams().contains(this)
|
||||||
TileEntity handler = getHandler();
|
ILightHandler handler = getHandler();
|
||||||
removed = removed || isEmpty() || handler == null || handler.isRemoved() || (parent != null && parent.isRemoved());
|
removed = removed || isEmpty() || handler == null || handler.getTile()
|
||||||
|
.isRemoved() || (parent != null && parent.isRemoved());
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
package com.simibubi.create.content.optics;
|
package com.simibubi.create.content.optics;
|
||||||
|
|
||||||
|
import static com.simibubi.create.foundation.utility.VecHelper.UP;
|
||||||
|
import static net.minecraft.client.renderer.tileentity.BeaconTileEntityRenderer.TEXTURE_BEACON_BEAM;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||||
import com.simibubi.create.foundation.utility.MatrixStacker;
|
import com.simibubi.create.foundation.utility.MatrixStacker;
|
||||||
|
@ -8,33 +14,30 @@ import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.LazyValue;
|
import net.minecraft.util.LazyValue;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.vector.*;
|
import net.minecraft.util.math.vector.Matrix3f;
|
||||||
|
import net.minecraft.util.math.vector.Matrix4f;
|
||||||
|
import net.minecraft.util.math.vector.Quaternion;
|
||||||
|
import net.minecraft.util.math.vector.Vector3d;
|
||||||
|
import net.minecraft.util.math.vector.Vector3f;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static com.simibubi.create.foundation.utility.VecHelper.UP;
|
|
||||||
import static net.minecraft.client.renderer.tileentity.BeaconTileEntityRenderer.TEXTURE_BEACON_BEAM;
|
|
||||||
|
|
||||||
public class BeamSegment {
|
public class BeamSegment {
|
||||||
public final float[] colors;
|
public final float[] colors;
|
||||||
private final Vector3d direction;
|
private final Vector3d direction;
|
||||||
private final Vector3d start;
|
private final Vector3d start;
|
||||||
private final LazyValue<Vector3d> normalized;
|
private final LazyValue<Vector3d> normalized;
|
||||||
private final LazyValue<Float> totalSectionLength;
|
private final LazyValue<Float> totalSectionLength;
|
||||||
private final ILightHandler<? extends TileEntity> handler;
|
private final ILightHandler handler;
|
||||||
@Nullable
|
@Nullable
|
||||||
private Quaternion beaconBeamModifier;
|
private Quaternion beaconBeamModifier;
|
||||||
private int length;
|
private int length;
|
||||||
|
|
||||||
public BeamSegment(ILightHandler<? extends TileEntity> handler, @Nonnull float[] color, Vector3d start, Vector3d direction) {
|
public BeamSegment(ILightHandler handler, @Nonnull float[] color, Vector3d start, Vector3d direction) {
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.colors = color;
|
this.colors = color;
|
||||||
this.direction = direction;
|
this.direction = direction;
|
||||||
|
@ -100,7 +103,7 @@ public class BeamSegment {
|
||||||
return normalized.getValue();
|
return normalized.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ILightHandler<? extends TileEntity> getHandler() {
|
public ILightHandler getHandler() {
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,8 +134,7 @@ public class BeamSegment {
|
||||||
|
|
||||||
public long getWorldTick() {
|
public long getWorldTick() {
|
||||||
World world = getHandler()
|
World world = getHandler()
|
||||||
.getTile()
|
.getHandlerWorld();
|
||||||
.getWorld();
|
|
||||||
if (world == null)
|
if (world == null)
|
||||||
return 0;
|
return 0;
|
||||||
return world.getGameTime();
|
return world.getGameTime();
|
||||||
|
@ -146,8 +148,7 @@ public class BeamSegment {
|
||||||
|
|
||||||
MatrixStacker stacker = MatrixStacker.of(ms)
|
MatrixStacker stacker = MatrixStacker.of(ms)
|
||||||
.push()
|
.push()
|
||||||
.translate(getStart().subtract(VecHelper.getCenterOf(getHandler().getTile()
|
.translate(getStart().subtract(VecHelper.getCenterOf(getHandler().getBlockPos())))
|
||||||
.getPos())))
|
|
||||||
.push()
|
.push()
|
||||||
.translate(VecHelper.CENTER_OF_ORIGIN)
|
.translate(VecHelper.CENTER_OF_ORIGIN)
|
||||||
.multiply(getBeaconBeamModifier())
|
.multiply(getBeaconBeamModifier())
|
||||||
|
|
|
@ -7,7 +7,6 @@ import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
|
||||||
import com.simibubi.create.foundation.utility.BeaconHelper;
|
import com.simibubi.create.foundation.utility.BeaconHelper;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
|
@ -20,14 +19,14 @@ import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.vector.Vector3d;
|
import net.minecraft.util.math.vector.Vector3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public interface ILightHandler<T extends SmartTileEntity & ILightHandler<T>> {
|
public interface ILightHandler {
|
||||||
default Beam constructOutBeam(@Nullable Beam parent, Vector3d beamDirection) {
|
default Beam constructOutBeam(@Nullable Beam parent, Vector3d beamDirection) {
|
||||||
return constructOutBeam(parent, beamDirection, getTile().getPos());
|
return constructOutBeam(parent, beamDirection, getBlockPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
default Beam constructOutBeam(@Nullable Beam parent, Vector3d beamDirection, BlockPos testBlockPos) {
|
default Beam constructOutBeam(@Nullable Beam parent, Vector3d beamDirection, BlockPos testBlockPos) {
|
||||||
Beam beam = new Beam(parent);
|
Beam beam = new Beam(parent);
|
||||||
World world = getTile().getWorld();
|
World world = getHandlerWorld();
|
||||||
if (world == null)
|
if (world == null)
|
||||||
return beam;
|
return beam;
|
||||||
|
|
||||||
|
@ -43,15 +42,15 @@ public interface ILightHandler<T extends SmartTileEntity & ILightHandler<T>> {
|
||||||
testPos = testPos.add(direction); // check next block
|
testPos = testPos.add(direction); // check next block
|
||||||
testBlockPos = new BlockPos(testPos.x, testPos.y, testPos.z);
|
testBlockPos = new BlockPos(testPos.x, testPos.y, testPos.z);
|
||||||
BlockState testState = world.getBlockState(testBlockPos);
|
BlockState testState = world.getBlockState(testBlockPos);
|
||||||
float[] newColor = BeaconHelper.getBeaconColorAt(testState.getBlock());
|
float[] newColor = BeaconHelper.getBeaconColorFor(testState.getBlock());
|
||||||
|
|
||||||
TileEntity te = testState.hasTileEntity() ? world.getTileEntity(testBlockPos) : null;
|
TileEntity te = testState.hasTileEntity() ? world.getTileEntity(testBlockPos) : null;
|
||||||
ILightHandler<?> lightHandler = te instanceof ILightHandler ? (ILightHandler<?>) te : null;
|
ILightHandler lightHandler = te instanceof ILightHandlerProvider ? ((ILightHandlerProvider) te).getHandler() : null;
|
||||||
if (lightHandler != this)
|
if (lightHandler != this)
|
||||||
beam.addListener(lightHandler);
|
beam.addListener(lightHandler);
|
||||||
|
|
||||||
if (newColor == null) {
|
if (newColor == null) {
|
||||||
if (testState.getOpacity(world, testBlockPos) >= 15 && testState.getBlock() != Blocks.BEDROCK || (lightHandler != null && !lightHandler.canLightPass())) {
|
if (testState.getOpacity(world, testBlockPos) >= 15 && testState.getBlock() != Blocks.BEDROCK || (lightHandler != null && lightHandler.absorbsLight())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (!Arrays.equals(segmentColor, newColor)) {
|
} else if (!Arrays.equals(segmentColor, newColor)) {
|
||||||
|
@ -65,7 +64,15 @@ public interface ILightHandler<T extends SmartTileEntity & ILightHandler<T>> {
|
||||||
return beam;
|
return beam;
|
||||||
}
|
}
|
||||||
|
|
||||||
T getTile();
|
default World getHandlerWorld() {
|
||||||
|
return getTile().getWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
default BlockPos getBlockPos() {
|
||||||
|
return getTile().getPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
TileEntity getTile();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
default Direction getBeamRotationAround() {
|
default Direction getBeamRotationAround() {
|
||||||
|
@ -80,9 +87,14 @@ public interface ILightHandler<T extends SmartTileEntity & ILightHandler<T>> {
|
||||||
return Collections.emptyIterator();
|
return Collections.emptyIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean canLightPass() {
|
default boolean absorbsLight() {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
default void updateBeams(){}
|
default void updateBeams() {
|
||||||
|
}
|
||||||
|
|
||||||
|
default float getInterpolatedAngle(float v) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.simibubi.create.content.optics;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ILightHandlerProvider {
|
||||||
|
ILightHandler getHandler();
|
||||||
|
}
|
|
@ -0,0 +1,228 @@
|
||||||
|
package com.simibubi.create.content.optics.mirror;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterators;
|
||||||
|
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.tileEntity.TileEntityBehaviour;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
|
||||||
|
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||||
|
import com.simibubi.create.foundation.utility.BeaconHelper;
|
||||||
|
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
||||||
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.tileentity.BeaconTileEntity;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.util.math.vector.Vector3d;
|
||||||
|
|
||||||
|
public class MirrorBehaviour extends TileEntityBehaviour implements ILightHandler {
|
||||||
|
public static final BehaviourType<MirrorBehaviour> TYPE = new BehaviourType<>();
|
||||||
|
private final MirrorTileEntity mirror;
|
||||||
|
protected float angle;
|
||||||
|
protected float clientAngleDiff;
|
||||||
|
Map<Beam, Beam> beams;
|
||||||
|
private float prevAngle;
|
||||||
|
@Nullable
|
||||||
|
private BeaconTileEntity beacon;
|
||||||
|
private Beam beaconBeam = null;
|
||||||
|
private boolean isUpdating = false;
|
||||||
|
|
||||||
|
|
||||||
|
public MirrorBehaviour(MirrorTileEntity te) {
|
||||||
|
super(te);
|
||||||
|
mirror = te;
|
||||||
|
beacon = null;
|
||||||
|
beams = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(CompoundNBT nbt, boolean clientPacket) {
|
||||||
|
nbt.putFloat("Angle", angle);
|
||||||
|
super.write(nbt, clientPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(CompoundNBT nbt, boolean clientPacket) {
|
||||||
|
angle = nbt.getFloat("Angle");
|
||||||
|
super.read(nbt, clientPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getInterpolatedAngle(float partialTicks) {
|
||||||
|
if (tileEntity.isVirtual())
|
||||||
|
return MathHelper.lerp(partialTicks + .5f, prevAngle, angle);
|
||||||
|
if (mirror.movementMode.get() == RotationMode.ROTATE_LIMITED && Math.abs(angle) == 90)
|
||||||
|
return angle;
|
||||||
|
return MathHelper.lerp(partialTicks, angle, angle + getAngularSpeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAngularSpeed() {
|
||||||
|
float speed = mirror.getSpeed() * 3 / 10f;
|
||||||
|
if (mirror.getSpeed() == 0)
|
||||||
|
speed = 0;
|
||||||
|
if (getHandlerWorld() != null && getHandlerWorld().isRemote) {
|
||||||
|
speed *= ServerSpeedProvider.get();
|
||||||
|
speed += clientAngleDiff / 3f;
|
||||||
|
}
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
|
||||||
|
prevAngle = angle;
|
||||||
|
if (getHandlerWorld() != null && getHandlerWorld().isRemote)
|
||||||
|
clientAngleDiff /= 2;
|
||||||
|
|
||||||
|
float angularSpeed = getAngularSpeed();
|
||||||
|
float newAngle = angle + angularSpeed;
|
||||||
|
angle = newAngle % 360;
|
||||||
|
|
||||||
|
if (mirror.movementMode.get() == RotationMode.ROTATE_LIMITED)
|
||||||
|
angle = MathHelper.clamp(angle, -90, 90);
|
||||||
|
if (mirror.movementMode.get() == RotationMode.ROTATE_45 && angle == prevAngle) // don't snap while still rotating
|
||||||
|
angle = 45F * Math.round(Math.round(angle) / 45F);
|
||||||
|
|
||||||
|
|
||||||
|
if (angle != prevAngle) {
|
||||||
|
updateBeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beacon != null && beacon.isRemoved())
|
||||||
|
updateBeaconState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBeaconState() {
|
||||||
|
BeaconTileEntity beaconBefore = beacon;
|
||||||
|
beacon = BeaconHelper.getBeaconTE(getBlockPos(), getHandlerWorld())
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (beaconBefore != null) {
|
||||||
|
beaconBeam.clear();
|
||||||
|
beaconBeam = null;
|
||||||
|
updateBeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beacon != null) {
|
||||||
|
beaconBeam = constructOutBeam(null, VecHelper.UP, beacon.getPos());
|
||||||
|
if (beaconBeam != null && !beaconBeam.isEmpty()) {
|
||||||
|
beaconBeam.addListener(this);
|
||||||
|
beaconBeam.onCreated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBeams() {
|
||||||
|
if (isUpdating)
|
||||||
|
return;
|
||||||
|
isUpdating = true;
|
||||||
|
|
||||||
|
Map<Beam, Beam> newBeams = new HashMap<>();
|
||||||
|
for (Map.Entry<Beam, Beam> entry : new HashSet<>(beams.entrySet())) {
|
||||||
|
entry.getValue()
|
||||||
|
.onRemoved();
|
||||||
|
if (entry.getKey()
|
||||||
|
.isRemoved())
|
||||||
|
continue;
|
||||||
|
Beam reflected = reflectBeam(entry.getKey());
|
||||||
|
if (reflected != null && !reflected.isEmpty()) {
|
||||||
|
newBeams.put(entry.getKey(), reflected);
|
||||||
|
reflected.onCreated();
|
||||||
|
entry.getKey()
|
||||||
|
.addListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
beams = newBeams;
|
||||||
|
isUpdating = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3d getReflectionAngle(Vector3d inputAngle) {
|
||||||
|
inputAngle = inputAngle.normalize();
|
||||||
|
Direction.Axis axis = mirror.getAxis();
|
||||||
|
Vector3d normal;
|
||||||
|
if (axis.isHorizontal())
|
||||||
|
normal = new Matrix3d().asIdentity()
|
||||||
|
.asAxisRotation(axis, AngleHelper.rad(angle))
|
||||||
|
.transform(VecHelper.UP);
|
||||||
|
else
|
||||||
|
normal = new Matrix3d().asIdentity()
|
||||||
|
.asAxisRotation(axis, AngleHelper.rad(-angle))
|
||||||
|
.transform(VecHelper.SOUTH);
|
||||||
|
|
||||||
|
return inputAngle.subtract(normal.scale(2 * inputAngle.dotProduct(normal)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lazyTick() {
|
||||||
|
super.lazyTick();
|
||||||
|
updateBeaconState();
|
||||||
|
updateBeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileEntity getTile() {
|
||||||
|
return tileEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public Direction getBeamRotationAround() {
|
||||||
|
return Direction.getFacingFromAxisDirection(mirror.getAxis(), Direction.AxisDirection.POSITIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BehaviourType<?> getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Beam> getRenderBeams() {
|
||||||
|
Iterator<Beam> beaconIter = beaconBeam == null ? Collections.emptyIterator() : Collections.singleton(beaconBeam)
|
||||||
|
.iterator();
|
||||||
|
return Iterators.concat(beams.values()
|
||||||
|
.iterator(), beaconIter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<Beam> constructSubBeams(Beam beam) {
|
||||||
|
if (beams.keySet()
|
||||||
|
.stream()
|
||||||
|
.filter(((Predicate<Beam>) Beam::isRemoved).negate())
|
||||||
|
.map(Beam::getDirection)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.anyMatch(b -> b.equals(beam.getDirection())))
|
||||||
|
return Stream.empty();
|
||||||
|
Beam reflected = reflectBeam(beam);
|
||||||
|
if (reflected != null && !reflected.isEmpty()) {
|
||||||
|
beams.put(beam, reflected);
|
||||||
|
beam.addListener(this);
|
||||||
|
return Stream.of(reflected);
|
||||||
|
}
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Beam reflectBeam(Beam beam) {
|
||||||
|
Vector3d inDir = beam.getDirection();
|
||||||
|
if (inDir == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return constructOutBeam(beam, getReflectionAngle(inDir).normalize());
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ public class MirrorRenderer extends KineticTileEntityRenderer {
|
||||||
MirrorTileEntity mirrorTe = (MirrorTileEntity) te;
|
MirrorTileEntity mirrorTe = (MirrorTileEntity) te;
|
||||||
|
|
||||||
renderMirror(mirrorTe, partialTicks, ms, buffer, light);
|
renderMirror(mirrorTe, partialTicks, ms, buffer, light);
|
||||||
((MirrorTileEntity) te).getRenderBeams()
|
((MirrorTileEntity) te).getHandler().getRenderBeams()
|
||||||
.forEachRemaining(beam -> beam.render(ms, buffer, partialTicks));
|
.forEachRemaining(beam -> beam.render(ms, buffer, partialTicks));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,9 +36,9 @@ public class MirrorRenderer extends KineticTileEntityRenderer {
|
||||||
|
|
||||||
final Direction.Axis facing = te.getBlockState()
|
final Direction.Axis facing = te.getBlockState()
|
||||||
.get(BlockStateProperties.AXIS);
|
.get(BlockStateProperties.AXIS);
|
||||||
SuperByteBuffer superBuffer = AllBlockPartials.MIRROR_PLANE.renderOnDirectionalSouth(te.getBlockState(), te.getBeamRotationAround());
|
SuperByteBuffer superBuffer = AllBlockPartials.MIRROR_PLANE.renderOnDirectionalSouth(te.getBlockState(), te.getHandler().getBeamRotationAround());
|
||||||
|
|
||||||
float interpolatedAngle = te.getInterpolatedAngle(partialTicks - 1);
|
float interpolatedAngle = te.getHandler().getInterpolatedAngle(partialTicks - 1);
|
||||||
kineticRotationTransform(superBuffer, te, facing, (float) (interpolatedAngle / 180 * Math.PI), light);
|
kineticRotationTransform(superBuffer, te, facing, (float) (interpolatedAngle / 180 * Math.PI), light);
|
||||||
superBuffer.renderInto(ms, buffer.getBuffer(RenderType.getTranslucent()));
|
superBuffer.renderInto(ms, buffer.getBuffer(RenderType.getTranslucent()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +1,28 @@
|
||||||
package com.simibubi.create.content.optics.mirror;
|
package com.simibubi.create.content.optics.mirror;
|
||||||
|
|
||||||
import com.google.common.collect.Iterators;
|
import java.util.List;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||||
import com.simibubi.create.content.optics.Beam;
|
|
||||||
import com.simibubi.create.content.optics.ILightHandler;
|
import com.simibubi.create.content.optics.ILightHandler;
|
||||||
import com.simibubi.create.foundation.collision.Matrix3d;
|
import com.simibubi.create.content.optics.ILightHandlerProvider;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform;
|
import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform;
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour;
|
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour;
|
||||||
import com.simibubi.create.foundation.utility.*;
|
import com.simibubi.create.foundation.utility.Lang;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
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.TileEntityType;
|
import net.minecraft.tileentity.TileEntityType;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
import net.minecraft.util.math.MathHelper;
|
|
||||||
import net.minecraft.util.math.vector.Vector3d;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
public class MirrorTileEntity extends KineticTileEntity implements ILightHandlerProvider {
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class MirrorTileEntity extends KineticTileEntity implements ILightHandler<MirrorTileEntity> {
|
|
||||||
protected ScrollOptionBehaviour<RotationMode> movementMode;
|
protected ScrollOptionBehaviour<RotationMode> movementMode;
|
||||||
protected float angle;
|
protected MirrorBehaviour mirror;
|
||||||
protected float clientAngleDiff;
|
|
||||||
Map<Beam, Beam> beams;
|
|
||||||
private float prevAngle;
|
|
||||||
@Nullable
|
|
||||||
private BeaconTileEntity beacon;
|
|
||||||
private Beam beaconBeam = null;
|
|
||||||
private boolean isUpdating = false;
|
|
||||||
|
|
||||||
public MirrorTileEntity(TileEntityType<?> typeIn) {
|
public MirrorTileEntity(TileEntityType<?> typeIn) {
|
||||||
super(typeIn);
|
super(typeIn);
|
||||||
beacon = null;
|
|
||||||
beams = new HashMap<>();
|
|
||||||
setLazyTickRate(20);
|
setLazyTickRate(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,133 +33,9 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
|
||||||
this, new CenteredSideValueBoxTransform((state, d) -> getAxis() != d.getAxis()));
|
this, new CenteredSideValueBoxTransform((state, d) -> getAxis() != d.getAxis()));
|
||||||
movementMode.requiresWrench();
|
movementMode.requiresWrench();
|
||||||
behaviours.add(movementMode);
|
behaviours.add(movementMode);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
mirror = new MirrorBehaviour(this);
|
||||||
public void write(CompoundNBT compound, boolean clientPacket) {
|
behaviours.add(mirror);
|
||||||
compound.putFloat("Angle", angle);
|
|
||||||
super.write(compound, clientPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void fromTag(BlockState state, CompoundNBT compound, boolean clientPacket) {
|
|
||||||
super.fromTag(state, compound, clientPacket);
|
|
||||||
|
|
||||||
angle = compound.getFloat("Angle");
|
|
||||||
super.fromTag(state, compound, clientPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getInterpolatedAngle(float partialTicks) {
|
|
||||||
if (isVirtual())
|
|
||||||
return MathHelper.lerp(partialTicks + .5f, prevAngle, angle);
|
|
||||||
if (movementMode.get() == RotationMode.ROTATE_LIMITED && Math.abs(angle) == 90)
|
|
||||||
return angle;
|
|
||||||
return MathHelper.lerp(partialTicks, angle, angle + getAngularSpeed());
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getAngularSpeed() {
|
|
||||||
float speed = getSpeed() * 3 / 10f;
|
|
||||||
if (getSpeed() == 0)
|
|
||||||
speed = 0;
|
|
||||||
if (world != null && world.isRemote) {
|
|
||||||
speed *= ServerSpeedProvider.get();
|
|
||||||
speed += clientAngleDiff / 3f;
|
|
||||||
}
|
|
||||||
return speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tick() {
|
|
||||||
super.tick();
|
|
||||||
|
|
||||||
prevAngle = angle;
|
|
||||||
if (world != null && world.isRemote)
|
|
||||||
clientAngleDiff /= 2;
|
|
||||||
|
|
||||||
float angularSpeed = getAngularSpeed();
|
|
||||||
float newAngle = angle + angularSpeed;
|
|
||||||
angle = newAngle % 360;
|
|
||||||
|
|
||||||
if (movementMode.get() == RotationMode.ROTATE_LIMITED)
|
|
||||||
angle = MathHelper.clamp(angle, -90, 90);
|
|
||||||
if (movementMode.get() == RotationMode.ROTATE_45 && angle == prevAngle) // don't snap while still rotating
|
|
||||||
angle = 45F * Math.round(Math.round(angle) / 45F);
|
|
||||||
|
|
||||||
|
|
||||||
if (angle != prevAngle) {
|
|
||||||
updateBeams();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (beacon != null && beacon.isRemoved())
|
|
||||||
updateBeaconState();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBeaconState() {
|
|
||||||
BeaconTileEntity beaconBefore = beacon;
|
|
||||||
beacon = BeaconHelper.getBeaconTE(pos, world)
|
|
||||||
.orElse(null);
|
|
||||||
|
|
||||||
if (beaconBefore != null) {
|
|
||||||
beaconBeam.clear();
|
|
||||||
beaconBeam = null;
|
|
||||||
updateBeams();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (beacon != null) {
|
|
||||||
beaconBeam = constructOutBeam(null, VecHelper.UP, beacon.getPos());
|
|
||||||
if (beaconBeam != null && !beaconBeam.isEmpty()) {
|
|
||||||
beaconBeam.addListener(this);
|
|
||||||
beaconBeam.onCreated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateBeams() {
|
|
||||||
if (isUpdating)
|
|
||||||
return;
|
|
||||||
isUpdating = true;
|
|
||||||
|
|
||||||
Map<Beam, Beam> newBeams = new HashMap<>();
|
|
||||||
for (Map.Entry<Beam, Beam> entry : new HashSet<>(beams.entrySet())) {
|
|
||||||
entry.getValue()
|
|
||||||
.onRemoved();
|
|
||||||
if (entry.getKey()
|
|
||||||
.isRemoved())
|
|
||||||
continue;
|
|
||||||
Beam reflected = reflectBeam(entry.getKey());
|
|
||||||
if (reflected != null && !reflected.isEmpty()) {
|
|
||||||
newBeams.put(entry.getKey(), reflected);
|
|
||||||
reflected.onCreated();
|
|
||||||
entry.getKey()
|
|
||||||
.addListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
beams = newBeams;
|
|
||||||
isUpdating = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vector3d getReflectionAngle(Vector3d inputAngle) {
|
|
||||||
inputAngle = inputAngle.normalize();
|
|
||||||
Direction.Axis axis = getAxis();
|
|
||||||
Vector3d normal;
|
|
||||||
if (axis.isHorizontal())
|
|
||||||
normal = new Matrix3d().asIdentity()
|
|
||||||
.asAxisRotation(axis, AngleHelper.rad(angle))
|
|
||||||
.transform(VecHelper.UP);
|
|
||||||
else
|
|
||||||
normal = new Matrix3d().asIdentity()
|
|
||||||
.asAxisRotation(axis, AngleHelper.rad(-angle))
|
|
||||||
.transform(VecHelper.SOUTH);
|
|
||||||
|
|
||||||
return inputAngle.subtract(normal.scale(2 * inputAngle.dotProduct(normal)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void lazyTick() {
|
|
||||||
super.lazyTick();
|
|
||||||
updateBeaconState();
|
|
||||||
updateBeams();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -188,17 +43,6 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public MirrorTileEntity getTile() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public Direction getBeamRotationAround() {
|
|
||||||
return Direction.getFacingFromAxisDirection(getAxis(), Direction.AxisDirection.POSITIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AxisAlignedBB getRenderBoundingBox() {
|
public AxisAlignedBB getRenderBoundingBox() {
|
||||||
return INFINITE_EXTENT_AABB;
|
return INFINITE_EXTENT_AABB;
|
||||||
|
@ -210,47 +54,13 @@ public class MirrorTileEntity extends KineticTileEntity implements ILightHandler
|
||||||
return 256.0D;
|
return 256.0D;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Beam> getRenderBeams() {
|
|
||||||
Iterator<Beam> beaconIter = beaconBeam == null ? Collections.emptyIterator() : Collections.singleton(beaconBeam)
|
|
||||||
.iterator();
|
|
||||||
return Iterators.concat(beams.values()
|
|
||||||
.iterator(), beaconIter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Direction.Axis getAxis() {
|
||||||
@Override
|
|
||||||
public Stream<Beam> constructSubBeams(Beam beam) {
|
|
||||||
if (beams.keySet()
|
|
||||||
.stream()
|
|
||||||
.filter(((Predicate<Beam>) Beam::isRemoved).negate())
|
|
||||||
.map(Beam::getDirection)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.anyMatch(b -> b.equals(beam.getDirection())))
|
|
||||||
return Stream.empty();
|
|
||||||
Beam reflected = reflectBeam(beam);
|
|
||||||
if (reflected != null && !reflected.isEmpty()) {
|
|
||||||
beams.put(beam, reflected);
|
|
||||||
beam.addListener(this);
|
|
||||||
return Stream.of(reflected);
|
|
||||||
}
|
|
||||||
return Stream.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Beam reflectBeam(Beam beam) {
|
|
||||||
Vector3d inDir = beam.getDirection();
|
|
||||||
if (inDir == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return constructOutBeam(beam, getReflectionAngle(inDir).normalize());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Direction.Axis getAxis() {
|
|
||||||
return getBlockState().get(BlockStateProperties.AXIS);
|
return getBlockState().get(BlockStateProperties.AXIS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getAngle() {
|
@Override
|
||||||
return angle;
|
public ILightHandler getHandler() {
|
||||||
|
return mirror;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import java.util.Optional;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.simibubi.create.content.optics.ILightHandler;
|
import com.simibubi.create.content.optics.ILightHandlerProvider;
|
||||||
import com.simibubi.create.foundation.block.ITE;
|
import com.simibubi.create.foundation.block.ITE;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
|
@ -56,7 +56,7 @@ public class BeaconHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static float[] getBeaconColorAt(Block block) {
|
public static float[] getBeaconColorFor(Block block) {
|
||||||
if (!(block instanceof IBeaconBeamColorProvider))
|
if (!(block instanceof IBeaconBeamColorProvider))
|
||||||
return null;
|
return null;
|
||||||
return ((IBeaconBeamColorProvider) block).getColor()
|
return ((IBeaconBeamColorProvider) block).getColor()
|
||||||
|
@ -67,7 +67,8 @@ public class BeaconHelper {
|
||||||
try {
|
try {
|
||||||
if (state.getBlock() instanceof ITE) {
|
if (state.getBlock() instanceof ITE) {
|
||||||
TileEntity te = ((ITE<?>) state.getBlock()).getTileEntity(world, pos);
|
TileEntity te = ((ITE<?>) state.getBlock()).getTileEntity(world, pos);
|
||||||
if (te instanceof ILightHandler && !((ILightHandler<?>) te).canLightPass())
|
if (te instanceof ILightHandlerProvider && ((ILightHandlerProvider) te).getHandler()
|
||||||
|
.absorbsLight())
|
||||||
return 15;
|
return 15;
|
||||||
}
|
}
|
||||||
} catch (ITE.TileEntityException ignored) {
|
} catch (ITE.TileEntityException ignored) {
|
||||||
|
|
Loading…
Reference in a new issue