Preparing for The Port

This commit is contained in:
reidbhuntley 2022-01-02 16:00:44 -05:00
parent 6d3c3e0d1f
commit 3b78ad4da5
16 changed files with 70 additions and 581 deletions

View file

@ -1,442 +0,0 @@
package com.simibubi.create.content.contraptions;
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.AXIS;
import java.util.LinkedList;
import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.base.IRotate;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerBlock;
import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel;
import com.simibubi.create.content.contraptions.relays.encased.DirectionalShaftHalvesTileEntity;
import com.simibubi.create.content.contraptions.relays.encased.EncasedBeltBlock;
import com.simibubi.create.content.contraptions.relays.encased.SplitShaftTileEntity;
import com.simibubi.create.content.contraptions.relays.gearbox.GearboxTileEntity;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
public class RotationPropagator {
private static final int MAX_FLICKER_SCORE = 128;
/**
* Determines the change in rotation between two attached kinetic entities. For
* instance, an axis connection returns 1 while a 1-to-1 gear connection
* reverses the rotation and therefore returns -1.
*
* @param from
* @param to
* @return
*/
private static float getRotationSpeedModifier(KineticTileEntity from, KineticTileEntity to) {
final BlockState stateFrom = from.getBlockState();
final BlockState stateTo = to.getBlockState();
Block fromBlock = stateFrom.getBlock();
Block toBlock = stateTo.getBlock();
if (!(fromBlock instanceof IRotate && toBlock instanceof IRotate))
return 0;
final IRotate definitionFrom = (IRotate) fromBlock;
final IRotate definitionTo = (IRotate) toBlock;
final BlockPos diff = to.getBlockPos()
.subtract(from.getBlockPos());
final Direction direction = Direction.getNearest(diff.getX(), diff.getY(), diff.getZ());
final Level world = from.getLevel();
boolean alignedAxes = true;
for (Axis axis : Axis.values())
if (axis != direction.getAxis())
if (axis.choose(diff.getX(), diff.getY(), diff.getZ()) != 0)
alignedAxes = false;
boolean connectedByAxis =
alignedAxes && definitionFrom.hasShaftTowards(world, from.getBlockPos(), stateFrom, direction)
&& definitionTo.hasShaftTowards(world, to.getBlockPos(), stateTo, direction.getOpposite());
boolean connectedByGears = ICogWheel.isSmallCog(stateFrom)
&& ICogWheel.isSmallCog(stateTo);
float custom = from.propagateRotationTo(to, stateFrom, stateTo, diff, connectedByAxis, connectedByGears);
if (custom != 0)
return custom;
// Axis <-> Axis
if (connectedByAxis) {
float axisModifier = getAxisModifier(to, direction.getOpposite());
if (axisModifier != 0)
axisModifier = 1 / axisModifier;
return getAxisModifier(from, direction) * axisModifier;
}
// Attached Encased Belts
if (fromBlock instanceof EncasedBeltBlock && toBlock instanceof EncasedBeltBlock) {
boolean connected = EncasedBeltBlock.areBlocksConnected(stateFrom, stateTo, direction);
return connected ? EncasedBeltBlock.getRotationSpeedModifier(from, to) : 0;
}
// Large Gear <-> Large Gear
if (isLargeToLargeGear(stateFrom, stateTo, diff)) {
Axis sourceAxis = stateFrom.getValue(AXIS);
Axis targetAxis = stateTo.getValue(AXIS);
int sourceAxisDiff = sourceAxis.choose(diff.getX(), diff.getY(), diff.getZ());
int targetAxisDiff = targetAxis.choose(diff.getX(), diff.getY(), diff.getZ());
return sourceAxisDiff > 0 ^ targetAxisDiff > 0 ? -1 : 1;
}
// Gear <-> Large Gear
if (ICogWheel.isLargeCog(stateFrom) && ICogWheel.isSmallCog(stateTo))
if (isLargeToSmallCog(stateFrom, stateTo, definitionTo, diff))
return -2f;
if (ICogWheel.isLargeCog(stateTo) && ICogWheel.isSmallCog(stateFrom))
if (isLargeToSmallCog(stateTo, stateFrom, definitionFrom, diff))
return -.5f;
// Gear <-> Gear
if (connectedByGears) {
if (diff.distManhattan(BlockPos.ZERO) != 1)
return 0;
if (ICogWheel.isLargeCog(stateTo))
return 0;
if (direction.getAxis() == definitionFrom.getRotationAxis(stateFrom))
return 0;
if (definitionFrom.getRotationAxis(stateFrom) == definitionTo.getRotationAxis(stateTo))
return -1;
}
return 0;
}
private static float getConveyedSpeed(KineticTileEntity from, KineticTileEntity to) {
final BlockState stateFrom = from.getBlockState();
final BlockState stateTo = to.getBlockState();
// Rotation Speed Controller <-> Large Gear
if (isLargeCogToSpeedController(stateFrom, stateTo, to.getBlockPos()
.subtract(from.getBlockPos())))
return SpeedControllerTileEntity.getConveyedSpeed(from, to, true);
if (isLargeCogToSpeedController(stateTo, stateFrom, from.getBlockPos()
.subtract(to.getBlockPos())))
return SpeedControllerTileEntity.getConveyedSpeed(to, from, false);
float rotationSpeedModifier = getRotationSpeedModifier(from, to);
return from.getTheoreticalSpeed() * rotationSpeedModifier;
}
private static boolean isLargeToLargeGear(BlockState from, BlockState to, BlockPos diff) {
if (!ICogWheel.isLargeCog(from) || !ICogWheel.isLargeCog(to))
return false;
Axis fromAxis = from.getValue(AXIS);
Axis toAxis = to.getValue(AXIS);
if (fromAxis == toAxis)
return false;
for (Axis axis : Axis.values()) {
int axisDiff = axis.choose(diff.getX(), diff.getY(), diff.getZ());
if (axis == fromAxis || axis == toAxis) {
if (axisDiff == 0)
return false;
} else if (axisDiff != 0)
return false;
}
return true;
}
private static float getAxisModifier(KineticTileEntity te, Direction direction) {
if (!(te.hasSource()||te.isSource()) || !(te instanceof DirectionalShaftHalvesTileEntity))
return 1;
Direction source = ((DirectionalShaftHalvesTileEntity) te).getSourceFacing();
if (te instanceof GearboxTileEntity)
return direction.getAxis() == source.getAxis() ? direction == source ? 1 : -1
: direction.getAxisDirection() == source.getAxisDirection() ? -1 : 1;
if (te instanceof SplitShaftTileEntity)
return ((SplitShaftTileEntity) te).getRotationSpeedModifier(direction);
return 1;
}
private static boolean isLargeToSmallCog(BlockState from, BlockState to, IRotate defTo, BlockPos diff) {
Axis axisFrom = from.getValue(AXIS);
if (axisFrom != defTo.getRotationAxis(to))
return false;
if (axisFrom.choose(diff.getX(), diff.getY(), diff.getZ()) != 0)
return false;
for (Axis axis : Axis.values()) {
if (axis == axisFrom)
continue;
if (Math.abs(axis.choose(diff.getX(), diff.getY(), diff.getZ())) != 1)
return false;
}
return true;
}
private static boolean isLargeCogToSpeedController(BlockState from, BlockState to, BlockPos diff) {
if (!ICogWheel.isLargeCog(from) || !AllBlocks.ROTATION_SPEED_CONTROLLER.has(to))
return false;
if (!diff.equals(BlockPos.ZERO.below()))
return false;
Axis axis = from.getValue(CogWheelBlock.AXIS);
if (axis.isVertical())
return false;
if (to.getValue(SpeedControllerBlock.HORIZONTAL_AXIS) == axis)
return false;
return true;
}
/**
* Insert the added position to the kinetic network.
*
* @param worldIn
* @param pos
*/
public static void handleAdded(Level worldIn, BlockPos pos, KineticTileEntity addedTE) {
// if (worldIn.isClientSide)
// return;
// if (!worldIn.isLoaded(pos))
// return;
// propagateNewSource(addedTE);
}
/**
* Search for sourceless networks attached to the given entity and update them.
*
* @param currentTE
*/
private static void propagateNewSource(KineticTileEntity currentTE) {
BlockPos pos = currentTE.getBlockPos();
Level world = currentTE.getLevel();
for (KineticTileEntity neighbourTE : getConnectedNeighbours(currentTE)) {
float speedOfCurrent = currentTE.getTheoreticalSpeed();
float speedOfNeighbour = neighbourTE.getTheoreticalSpeed();
float newSpeed = getConveyedSpeed(currentTE, neighbourTE);
float oppositeSpeed = getConveyedSpeed(neighbourTE, currentTE);
if (newSpeed == 0 && oppositeSpeed == 0)
continue;
boolean incompatible =
Math.signum(newSpeed) != Math.signum(speedOfNeighbour) && (newSpeed != 0 && speedOfNeighbour != 0);
boolean tooFast = Math.abs(newSpeed) > AllConfigs.SERVER.kinetics.maxRotationSpeed.get();
boolean speedChangedTooOften = currentTE.getFlickerScore() > MAX_FLICKER_SCORE;
if (tooFast || speedChangedTooOften) {
world.destroyBlock(pos, true);
return;
}
// Opposite directions
if (incompatible) {
world.destroyBlock(pos, true);
return;
// Same direction: overpower the slower speed
} else {
// Neighbour faster, overpower the incoming tree
if (Math.abs(oppositeSpeed) > Math.abs(speedOfCurrent)) {
float prevSpeed = currentTE.getSpeed();
currentTE.setSource(neighbourTE.getBlockPos());
currentTE.setSpeed(getConveyedSpeed(neighbourTE, currentTE));
currentTE.onSpeedChanged(prevSpeed);
currentTE.sendData();
propagateNewSource(currentTE);
return;
}
// Current faster, overpower the neighbours' tree
if (Math.abs(newSpeed) >= Math.abs(speedOfNeighbour)) {
// Do not overpower you own network -> cycle
if (!currentTE.hasNetwork() || currentTE.network.equals(neighbourTE.network)) {
float epsilon = Math.abs(speedOfNeighbour) / 256f / 256f;
if (Math.abs(newSpeed) > Math.abs(speedOfNeighbour) + epsilon)
world.destroyBlock(pos, true);
continue;
}
if (currentTE.hasSource() && currentTE.source.equals(neighbourTE.getBlockPos()))
currentTE.removeSource();
float prevSpeed = neighbourTE.getSpeed();
neighbourTE.setSource(currentTE.getBlockPos());
neighbourTE.setSpeed(getConveyedSpeed(currentTE, neighbourTE));
neighbourTE.onSpeedChanged(prevSpeed);
neighbourTE.sendData();
propagateNewSource(neighbourTE);
continue;
}
}
if (neighbourTE.getTheoreticalSpeed() == newSpeed)
continue;
float prevSpeed = neighbourTE.getSpeed();
neighbourTE.setSpeed(newSpeed);
neighbourTE.setSource(currentTE.getBlockPos());
neighbourTE.onSpeedChanged(prevSpeed);
neighbourTE.sendData();
propagateNewSource(neighbourTE);
}
}
/**
* Remove the given entity from the network.
*
* @param worldIn
* @param pos
* @param removedTE
*/
public static void handleRemoved(Level worldIn, BlockPos pos, KineticTileEntity removedTE) {
if (worldIn.isClientSide)
return;
if (removedTE == null)
return;
if (removedTE.getTheoreticalSpeed() == 0)
return;
for (BlockPos neighbourPos : getPotentialNeighbourLocations(removedTE)) {
BlockState neighbourState = worldIn.getBlockState(neighbourPos);
if (!(neighbourState.getBlock() instanceof IRotate))
continue;
BlockEntity tileEntity = worldIn.getBlockEntity(neighbourPos);
if (!(tileEntity instanceof KineticTileEntity))
continue;
final KineticTileEntity neighbourTE = (KineticTileEntity) tileEntity;
if (!neighbourTE.hasSource() || !neighbourTE.source.equals(pos))
continue;
propagateMissingSource(neighbourTE);
}
}
/**
* Clear the entire subnetwork depending on the given entity and find a new
* source
*
* @param updateTE
*/
private static void propagateMissingSource(KineticTileEntity updateTE) {
final Level world = updateTE.getLevel();
List<KineticTileEntity> potentialNewSources = new LinkedList<>();
List<BlockPos> frontier = new LinkedList<>();
frontier.add(updateTE.getBlockPos());
BlockPos missingSource = updateTE.hasSource() ? updateTE.source : null;
while (!frontier.isEmpty()) {
final BlockPos pos = frontier.remove(0);
BlockEntity tileEntity = world.getBlockEntity(pos);
if (!(tileEntity instanceof KineticTileEntity))
continue;
final KineticTileEntity currentTE = (KineticTileEntity) tileEntity;
currentTE.removeSource();
currentTE.sendData();
for (KineticTileEntity neighbourTE : getConnectedNeighbours(currentTE)) {
if (neighbourTE.getBlockPos()
.equals(missingSource))
continue;
if (!neighbourTE.hasSource())
continue;
if (!neighbourTE.source.equals(pos)) {
potentialNewSources.add(neighbourTE);
continue;
}
if (neighbourTE.isSource())
potentialNewSources.add(neighbourTE);
frontier.add(neighbourTE.getBlockPos());
}
}
for (KineticTileEntity newSource : potentialNewSources) {
if (newSource.hasSource() || newSource.isSource()) {
propagateNewSource(newSource);
return;
}
}
}
private static KineticTileEntity findConnectedNeighbour(KineticTileEntity currentTE, BlockPos neighbourPos) {
BlockState neighbourState = currentTE.getLevel()
.getBlockState(neighbourPos);
if (!(neighbourState.getBlock() instanceof IRotate))
return null;
if (!neighbourState.hasBlockEntity())
return null;
BlockEntity neighbourTE = currentTE.getLevel()
.getBlockEntity(neighbourPos);
if (!(neighbourTE instanceof KineticTileEntity))
return null;
KineticTileEntity neighbourKTE = (KineticTileEntity) neighbourTE;
if (!(neighbourKTE.getBlockState()
.getBlock() instanceof IRotate))
return null;
if (!isConnected(currentTE, neighbourKTE) && !isConnected(neighbourKTE, currentTE))
return null;
return neighbourKTE;
}
public static boolean isConnected(KineticTileEntity from, KineticTileEntity to) {
final BlockState stateFrom = from.getBlockState();
final BlockState stateTo = to.getBlockState();
return isLargeCogToSpeedController(stateFrom, stateTo, to.getBlockPos()
.subtract(from.getBlockPos())) || getRotationSpeedModifier(from, to) != 0
|| from.isCustomConnection(to, stateFrom, stateTo);
}
private static List<KineticTileEntity> getConnectedNeighbours(KineticTileEntity te) {
List<KineticTileEntity> neighbours = new LinkedList<>();
for (BlockPos neighbourPos : getPotentialNeighbourLocations(te)) {
final KineticTileEntity neighbourTE = findConnectedNeighbour(te, neighbourPos);
if (neighbourTE == null)
continue;
neighbours.add(neighbourTE);
}
return neighbours;
}
private static List<BlockPos> getPotentialNeighbourLocations(KineticTileEntity te) {
List<BlockPos> neighbours = new LinkedList<>();
if (!te.getLevel()
.isAreaLoaded(te.getBlockPos(), 1))
return neighbours;
for (Direction facing : Iterate.directions)
neighbours.add(te.getBlockPos()
.relative(facing));
BlockState blockState = te.getBlockState();
if (!(blockState.getBlock() instanceof IRotate))
return neighbours;
IRotate block = (IRotate) blockState.getBlock();
return te.addPropagationLocations(block, blockState, neighbours);
}
}

View file

@ -34,7 +34,7 @@ public class KineticEffectHandler {
if (world.isClientSide) {
if (overStressedTime > 0)
if (--overStressedTime == 0)
if (kte.isOverStressed()) {
if (kte.isOverstressed()) {
overStressedEffect = 1;
spawnEffect(ParticleTypes.SMOKE, 0.2f, 5);
} else {

View file

@ -56,10 +56,10 @@ public class KineticTileEntity extends SmartTileEntity
public @Nullable BlockPos source = null;
protected KineticEffectHandler effects;
protected float speed;
protected float theoreticalSpeed;
protected float capacity;
protected float stress;
protected boolean overStressed;
protected boolean overstressed;
protected boolean wasMoved;
private int flickerTally;
@ -224,76 +224,28 @@ public class KineticTileEntity extends SmartTileEntity
flickerTally = getFlickerScore() + 5;
}
@Override
public void setRemoved() {
super.setRemoved();
public void onOverstressedChanged(boolean previousOverstressed) {
if (isOverstressed())
effects.triggerOverStressedEffect();
}
@Override
protected void write(CompoundTag compound, boolean clientPacket) {
compound.putFloat("Speed", speed);
// if (needsSpeedUpdate())
// compound.putBoolean("NeedsSpeedUpdate", true);
//
// if (hasSource())
// compound.put("Source", NbtUtils.writeBlockPos(source));
// if (hasNetwork()) {
// CompoundTag networkTag = new CompoundTag();
// //networkTag.putLong("Id", this.network);
// networkTag.putFloat("Stress", stress);
// networkTag.putFloat("Capacity", capacity);
// networkTag.putInt("Size", networkSize);
//
// if (lastStressApplied != 0)
// networkTag.putFloat("AddedStress", lastStressApplied);
// if (lastCapacityProvided != 0)
// networkTag.putFloat("AddedCapacity", lastCapacityProvided);
//
// compound.put("Network", networkTag);
// }
if (clientPacket) {
compound.putFloat("Speed", theoreticalSpeed);
compound.putBoolean("Overstressed", overstressed);
}
super.write(compound, clientPacket);
}
// public boolean needsSpeedUpdate() {
// return updateSpeed;
// }
@Override
protected void read(CompoundTag compound, boolean clientPacket) {
//boolean overStressedBefore = overStressed;
//clearKineticInformation();
// DO NOT READ kinetic information when placed after movement
//if (wasMoved) {
// super.read(compound, clientPacket);
// return;
//}
if (clientPacket)
speed = compound.getFloat("Speed");
// if (compound.contains("Source"))
// source = NbtUtils.readBlockPos(compound.getCompound("Source"));
// if (compound.contains("Network")) {
// CompoundTag networkTag = compound.getCompound("Network");
// network = networkTag.getLong("Id");
// stress = networkTag.getFloat("Stress");
// capacity = networkTag.getFloat("Capacity");
// networkSize = networkTag.getInt("Size");
// lastStressApplied = networkTag.getFloat("AddedStress");
// lastCapacityProvided = networkTag.getFloat("AddedCapacity");
// overStressed = capacity < stress && StressImpact.isEnabled();
// }
updateFromSolver(compound.getFloat("Speed"), compound.getBoolean("Overstressed"));
super.read(compound, clientPacket);
// if (clientPacket && overStressedBefore != overStressed && speed != 0)
// effects.triggerOverStressedEffect();
if (clientPacket)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this));
}
@ -304,20 +256,34 @@ public class KineticTileEntity extends SmartTileEntity
}
public float getSpeed() {
if (overStressed)
return 0;
if (overstressed) return 0;
return getTheoreticalSpeed();
}
public float getTheoreticalSpeed() {
return speed;
return theoreticalSpeed;
}
public void setSpeed(float speed) {
float prevSpeed = this.speed;
this.speed = speed;
onSpeedChanged(prevSpeed);
sendData();
public void updateFromSolver(float theoreticalSpeed, boolean overstressed) {
float prevSpeed = getSpeed();
boolean send = false;
if (this.theoreticalSpeed != theoreticalSpeed) {
this.theoreticalSpeed = theoreticalSpeed;
send = true;
}
if (this.overstressed != overstressed) {
this.overstressed = overstressed;
onOverstressedChanged(!overstressed);
send = true;
}
if (getSpeed() != prevSpeed)
onSpeedChanged(prevSpeed);
if (send)
sendData();
}
public boolean hasSource() {
@ -409,16 +375,6 @@ public class KineticTileEntity extends SmartTileEntity
return;
}
// KineticTileEntity tileEntity = (KineticTileEntity) tileEntityIn;
// if (state.getBlock() instanceof KineticBlock
// && !((KineticBlock) state.getBlock()).areStatesKineticallyEquivalent(currentState, state)) {
// if (tileEntity.hasNetwork())
// tileEntity.getOrCreateNetwork()
// .remove(tileEntity);
// tileEntity.detachKinetics();
// tileEntity.removeSource();
// }
world.setBlock(pos, state, 3);
}
@ -429,7 +385,7 @@ public class KineticTileEntity extends SmartTileEntity
public boolean addToTooltip(List<Component> tooltip, boolean isPlayerSneaking) {
boolean notFastEnough = !isSpeedRequirementFulfilled() && getSpeed() != 0;
if (overStressed && AllConfigs.CLIENT.enableOverstressedTooltip.get()) {
if (overstressed && AllConfigs.CLIENT.enableOverstressedTooltip.get()) {
tooltip.add(componentSpacing.plainCopy()
.append(Lang.translate("gui.stressometer.overstressed")
.withStyle(GOLD)));
@ -487,8 +443,8 @@ public class KineticTileEntity extends SmartTileEntity
}
public void clearKineticInformation() {
speed = 0;
overStressed = false;
theoreticalSpeed = 0;
overstressed = false;
stress = 0;
capacity = 0;
lastStressApplied = 0;
@ -515,8 +471,8 @@ public class KineticTileEntity extends SmartTileEntity
return speed * 3 / 10f;
}
public boolean isOverStressed() {
return overStressed;
public boolean isOverstressed() {
return overstressed;
}
// Custom Propagation

View file

@ -78,7 +78,7 @@ public class FlywheelTileEntity extends GeneratingKineticTileEntity {
super.tick();
if (level.isClientSide) {
float targetSpeed = isVirtual() ? speed : getGeneratedSpeed();
float targetSpeed = isVirtual() ? theoreticalSpeed : getGeneratedSpeed();
visualSpeed.target(targetSpeed);
visualSpeed.tick();
angle += visualSpeed.value * 3 / 10f;

View file

@ -874,9 +874,9 @@ public abstract class Contraption {
}
ListTag paletteNBT = new ListTag();
for(int i = 0; i < palette.getSize(); ++i)
for(int i = 0; i < palette.getSize(); ++i)
paletteNBT.add(NbtUtils.writeBlockState(palette.values.byId(i)));
compound.put("Palette", paletteNBT);
compound.put("BlockList", blockList);
@ -891,7 +891,7 @@ public abstract class Contraption {
palette = new HashMapPalette<>(GameData.getBlockStateIDMap(), 16, (i, s) -> {
throw new IllegalStateException("Palette Map index exceeded maximum");
});
ListTag list = c.getList("Palette", 10);
palette.values.clear();
for (int i = 0; i < list.size(); ++i)
@ -926,8 +926,6 @@ public abstract class Contraption {
if (te == null)
return;
te.setLevel(world);
if (te instanceof KineticTileEntity)
((KineticTileEntity) te).setSpeed(0);
te.getBlockState();
if (movementBehaviour == null || !movementBehaviour.hasSpecialInstancedRendering())

View file

@ -78,7 +78,7 @@ public class ClockworkBearingTileEntity extends KineticTileEntity
assembleNextTick = false;
if (running) {
boolean canDisassemble = true;
if (speed == 0 && (canDisassemble || hourHand == null || hourHand.getContraption()
if (theoreticalSpeed == 0 && (canDisassemble || hourHand == null || hourHand.getContraption()
.getBlocks()
.isEmpty())) {
if (hourHand != null)

View file

@ -212,7 +212,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity
if (running) {
boolean canDisassemble = movementMode.get() == RotationMode.ROTATE_PLACE
|| (isNearInitialAngle() && movementMode.get() == RotationMode.ROTATE_PLACE_RETURNED);
if (speed == 0 && (canDisassemble || movedContraption == null || movedContraption.getContraption()
if (theoreticalSpeed == 0 && (canDisassemble || movedContraption == null || movedContraption.getContraption()
.getBlocks()
.isEmpty())) {
if (movedContraption != null)
@ -222,7 +222,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity
return;
}
} else {
if (speed == 0 && !isWindmill())
if (theoreticalSpeed == 0 && !isWindmill())
return;
assemble();
}

View file

@ -50,7 +50,7 @@ public class PulleyTileEntity extends LinearActuatorTileEntity {
if (!(level.getBlockState(worldPosition)
.getBlock() instanceof PulleyBlock))
return;
if (speed == 0)
if (theoreticalSpeed == 0)
return;
int maxLength = AllConfigs.SERVER.kinetics.maxRopeLength.get();
int i = 1;

View file

@ -74,7 +74,7 @@ public class PumpTileEntity extends KineticTileEntity {
if (!isVirtual())
return;
}
// if (pressureUpdate)
// updatePressureChange();
@ -100,8 +100,8 @@ public class PumpTileEntity extends KineticTileEntity {
if (previousSpeed == getSpeed())
return;
if (speed != 0)
reversed = speed < 0;
if (theoreticalSpeed != 0)
reversed = theoreticalSpeed < 0;
if (level.isClientSide && !isVirtual())
return;

View file

@ -2,7 +2,6 @@ package com.simibubi.create.content.contraptions.relays.advanced;
import java.util.List;
import com.simibubi.create.content.contraptions.RotationPropagator;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.components.motor.CreativeMotorTileEntity;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
@ -15,7 +14,6 @@ import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueBehaviour;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.Pair;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos;
@ -64,9 +62,10 @@ public class SpeedControllerTileEntity extends KineticTileEntity {
@Override
public void onUpdate(Level level, KineticSolver solver, KineticNode node) {
solver.getNode(node.getPos().above())
.filter(n -> node.getActiveStressOnlyConnections().anyMatch(m -> m == n))
.ifPresent(n -> n.setController(node, KineticControllerSerial.SPEED_CONTROLLER_COG));
BlockPos above = node.getPos().above();
if (isStressOnlyConnected(above)) {
solver.getNode(above).get().setController(node, KineticControllerSerial.SPEED_CONTROLLER_COG);
}
}
public static float getConveyedSpeed(KineticTileEntity cogWheel, KineticTileEntity speedControllerIn,

View file

@ -42,7 +42,7 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity {
return;
if (timer < currentInstructionDuration) {
timer++;
currentInstructionProgress += getInstruction(currentInstruction).getTickProgress(speed);
currentInstructionProgress += getInstruction(currentInstruction).getTickProgress(theoreticalSpeed);
return;
}
run(currentInstruction + 1);
@ -53,7 +53,7 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity {
super.onSpeedChanged(previousSpeed);
if (isIdle())
return;
float currentSpeed = Math.abs(speed);
float currentSpeed = Math.abs(theoreticalSpeed);
if (Math.abs(previousSpeed) == currentSpeed)
return;
Instruction instruction = getInstruction(currentInstruction);

View file

@ -3,7 +3,6 @@ package com.simibubi.create.content.contraptions.relays.encased;
import java.util.Random;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.RotationPropagator;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.foundation.block.ITE;
@ -58,7 +57,7 @@ public class GearshiftBlock extends AbstractEncasedShaftBlock implements ITE<Spl
public Class<SplitShaftTileEntity> getTileEntityClass() {
return SplitShaftTileEntity.class;
}
@Override
public BlockEntityType<? extends SplitShaftTileEntity> getTileEntityType() {
return AllTileEntities.GEARSHIFT.get();
@ -68,7 +67,7 @@ public class GearshiftBlock extends AbstractEncasedShaftBlock implements ITE<Spl
BlockEntity te = worldIn.getBlockEntity(pos);
if (te == null || !(te instanceof KineticTileEntity))
return;
RotationPropagator.handleRemoved(worldIn, pos, (KineticTileEntity) te);
//RotationPropagator.handleRemoved(worldIn, pos, (KineticTileEntity) te);
// Re-attach next tick
if (reAttachNextTick)
@ -81,6 +80,6 @@ public class GearshiftBlock extends AbstractEncasedShaftBlock implements ITE<Spl
if (te == null || !(te instanceof KineticTileEntity))
return;
KineticTileEntity kte = (KineticTileEntity) te;
RotationPropagator.handleAdded(worldIn, pos, kte);
//RotationPropagator.handleAdded(worldIn, pos, kte);
}
}

View file

@ -62,7 +62,7 @@ public class SpeedGaugeTileEntity extends GaugeTileEntity {
super.addToGoggleTooltip(tooltip, isPlayerSneaking);
tooltip.add(componentSpacing.plainCopy().append(Lang.translate("gui.speedometer.title").withStyle(ChatFormatting.GRAY)));
tooltip.add(componentSpacing.plainCopy().append(SpeedLevel.getFormattedSpeedText(speed, isOverStressed())));
tooltip.add(componentSpacing.plainCopy().append(SpeedLevel.getFormattedSpeedText(theoreticalSpeed, isOverstressed())));
return true;
}

View file

@ -28,7 +28,7 @@ public class StressGaugeTileEntity extends GaugeTileEntity {
if (!StressImpact.isEnabled())
dialTarget = 0;
else if (isOverStressed())
else if (isOverstressed())
dialTarget = 1.125f;
else if (maxStress == 0)
dialTarget = 0;

View file

@ -1,5 +1,6 @@
package com.simibubi.create.content.contraptions.solver;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.Pair;
import com.simibubi.create.foundation.utility.ResetableLazy;
@ -93,7 +94,9 @@ public class KineticNetwork {
conflictingCycles.add(Pair.of(from, to));
}
protected boolean isStopped() { return generators.isEmpty() || overstressed; }
public boolean isOverstressed() { return overstressed; }
public boolean isStopped() { return generators.isEmpty() || overstressed; }
/**
* Recalculates the speed at the root node of this network.
@ -203,7 +206,6 @@ public class KineticNetwork {
// just became overstressed
cur.overstressed = true;
cur.onRootSpeedChanged();
cur.members.forEach(KineticNode::stop);
}
} else {
if (cur.overstressed) {
@ -229,10 +231,7 @@ public class KineticNetwork {
assert(recalculateSpeedResult.isOk());
// if we're stopped, then all members' speeds will be 0, so no need to check for speeding nodes
if (isStopped()) {
members.forEach(KineticNode::stop);
return;
}
if (isStopped()) return;
if (rootSpeedChanged) {
// root speed changed, update all nodes starting from the main generator
@ -248,6 +247,8 @@ public class KineticNetwork {
}
private void bfs(KineticNode root, Consumer<KineticNode> onSpeeding, boolean followSource) {
float max = AllConfigs.SERVER.kinetics.maxRotationSpeed.get();
// update node speeds in a breadth-first order, checking for speeding nodes along the way
Set<KineticNode> visited = new HashSet<>();
List<KineticNode> frontier = new LinkedList<>();
@ -258,7 +259,7 @@ public class KineticNetwork {
if (!members.contains(cur) || visited.contains(cur)) continue;
visited.add(cur);
if (cur.tryUpdateSpeed().isOk()) {
if (Math.abs(cur.getSpeed()) <= max) {
cur.getActiveConnections()
.map(Pair::getFirst)
.filter(n -> !followSource || n.getSource() == cur)

View file

@ -32,8 +32,6 @@ public class KineticNode {
private @Nullable KineticNode source;
private KineticNetwork network;
private float speedRatio = 1;
private float speedCur;
private float speedNext;
private final BlockPos pos;
private final KineticConnections connections;
@ -114,8 +112,6 @@ public class KineticNode {
protected void onLoaded(KineticTileEntity entity) {
this.entity = entity;
network.onMemberLoaded(this);
if (speedCur != 0)
entity.setSpeed(speedCur);
}
protected void onUnloaded() {
@ -344,27 +340,9 @@ public class KineticNode {
propagateSource();
}
/**
* Updates the speed of this node based on its network's root speed and its own speed ratio.
* @return CONTRADICTION if the node's new speed exceeds the maximum value, and OK otherwise
*/
protected SolveResult tryUpdateSpeed() {
speedNext = getSpeed();
if (Math.abs(speedNext) > AllConfigs.SERVER.kinetics.maxRotationSpeed.get())
return SolveResult.CONTRADICTION;
return SolveResult.OK;
}
protected void stop() {
speedNext = 0;
}
protected void flushChangedSpeed() {
if (speedCur != speedNext) {
speedCur = speedNext;
if (entity != null) {
entity.setSpeed(speedCur);
}
if (entity != null) {
entity.updateFromSolver(getTheoreticalSpeed(), network.isOverstressed());
}
}