Rotation validation

- Contraptions can no longer speed up themselves when connected in a loop
- Components now validate from time to time if they still have a source
- Some minor refactoring in KineticTileEntity
- Empty networks are now being removed from the network space (fixes memory leak)
- Waterwheels no longer differentiate between a slight side-ways flow and a straight flow of water
This commit is contained in:
simibubi 2020-03-06 17:22:02 +01:00
parent fed4df515a
commit b89db104b8
20 changed files with 460 additions and 367 deletions

View file

@ -10,6 +10,7 @@ public class CKinetics extends ConfigBase {
public ConfigInt maxRotationSpeed = i(256, 64, "maxRotationSpeed", Comments.rpm, Comments.maxRotationSpeed); public ConfigInt maxRotationSpeed = i(256, 64, "maxRotationSpeed", Comments.rpm, Comments.maxRotationSpeed);
public ConfigEnum<DeployerAggroSetting> ignoreDeployerAttacks = public ConfigEnum<DeployerAggroSetting> ignoreDeployerAttacks =
e(DeployerAggroSetting.CREEPERS, "ignoreDeployerAttacks", Comments.ignoreDeployerAttacks); e(DeployerAggroSetting.CREEPERS, "ignoreDeployerAttacks", Comments.ignoreDeployerAttacks);
public ConfigInt kineticValidationFrequency = i(60, 5, "kineticValidationFrequency", Comments.kineticValidationFrequency);
public ConfigGroup fan = group(0, "encasedFan", "Encased Fan"); public ConfigGroup fan = group(0, "encasedFan", "Encased Fan");
public ConfigInt fanPushDistance = i(20, 5, "fanPushDistance", Comments.fanPushDistance); public ConfigInt fanPushDistance = i(20, 5, "fanPushDistance", Comments.fanPushDistance);
@ -71,6 +72,7 @@ public class CKinetics extends ConfigBase {
static String ignoreDeployerAttacks = "Select what mobs should ignore Deployers when attacked by them."; static String ignoreDeployerAttacks = "Select what mobs should ignore Deployers when attacked by them.";
static String waterWheelSpeed = "Rotation speed gained by a water wheel for each side with running water. (halved if not against blades)"; static String waterWheelSpeed = "Rotation speed gained by a water wheel for each side with running water. (halved if not against blades)";
static String disableStress = "Disable the Stress mechanic altogether."; static String disableStress = "Disable the Stress mechanic altogether.";
static String kineticValidationFrequency = "Game ticks between Kinetic Blocks checking whether their source is still valid.";
} }
public static enum DeployerAggroSetting { public static enum DeployerAggroSetting {

View file

@ -25,9 +25,9 @@ public class KineticNetwork {
members = new HashMap<>(); members = new HashMap<>();
} }
public void initFromTE(KineticTileEntity te) { public void initFromTE(float maxStress, float currentStress) {
unloadedStressCapacity = te.maxStress; unloadedStressCapacity = maxStress;
unloadedStress = te.currentStress; unloadedStress = currentStress;
initialized = true; initialized = true;
updateStress(); updateStress();
updateStressCapacity(); updateStressCapacity();
@ -42,16 +42,13 @@ public class KineticNetwork {
sources.put(te, capacity); sources.put(te, capacity);
} }
float stressApplied = te.getStressApplied(); float stressApplied = te.getStressApplied();
unloadedStress -= stressApplied * getStressMultiplierForSpeed(te.speed); unloadedStress -= stressApplied * getStressMultiplierForSpeed(te.getTheoreticalSpeed());
members.put(te, stressApplied); members.put(te, stressApplied);
} }
public void add(KineticTileEntity te) { public void add(KineticTileEntity te) {
if (members.containsKey(te)) if (members.containsKey(te))
return; return;
// Debug.debugChatAndShowStack(te.getType().getRegistryName().getPath() + " added to Network", 5);
if (te.isSource()) { if (te.isSource()) {
sources.put(te, te.getAddedStressCapacity()); sources.put(te, te.getAddedStressCapacity());
updateStressCapacity(); updateStressCapacity();
@ -75,9 +72,6 @@ public class KineticNetwork {
public void remove(KineticTileEntity te) { public void remove(KineticTileEntity te) {
if (!members.containsKey(te)) if (!members.containsKey(te))
return; return;
// Debug.debugChat(te.getType().getRegistryName().getPath() + " removed from Network");
if (te.isSource()) { if (te.isSource()) {
sources.remove(te); sources.remove(te);
updateStressCapacity(); updateStressCapacity();
@ -86,6 +80,9 @@ public class KineticNetwork {
members.remove(te); members.remove(te);
updateStress(); updateStress();
sync(); sync();
if (members.isEmpty())
TorquePropagator.networks.get(te.getWorld()).remove(this.id);
} }
public void sync() { public void sync() {
@ -101,21 +98,17 @@ public class KineticNetwork {
if (maxStress != newMaxStress) { if (maxStress != newMaxStress) {
maxStress = newMaxStress; maxStress = newMaxStress;
sync(); sync();
// Debug.debugChatAndShowStack("Current Stress level: " + currentStress + "/" + maxStress, 5);
} }
} }
public void updateStress() { public void updateStress() {
float presentStress = 0; float presentStress = 0;
for (KineticTileEntity te : members.keySet()) for (KineticTileEntity te : members.keySet())
presentStress += members.get(te) * getStressMultiplierForSpeed(te.speed); presentStress += members.get(te) * getStressMultiplierForSpeed(te.getTheoreticalSpeed());
float newStress = presentStress + unloadedStress; float newStress = presentStress + unloadedStress;
if (currentStress != newStress) { if (currentStress != newStress) {
currentStress = newStress; currentStress = newStress;
sync(); sync();
// Debug.debugChatAndShowStack("Current Stress level: " + currentStress + "/" + maxStress, 5);
} }
} }

View file

@ -14,6 +14,7 @@ import com.simibubi.create.modules.contraptions.base.IRotate;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.relays.advanced.SpeedControllerTileEntity; import com.simibubi.create.modules.contraptions.relays.advanced.SpeedControllerTileEntity;
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.modules.contraptions.relays.encased.DirectionalShaftHalvesTileEntity;
import com.simibubi.create.modules.contraptions.relays.encased.EncasedBeltBlock; import com.simibubi.create.modules.contraptions.relays.encased.EncasedBeltBlock;
import com.simibubi.create.modules.contraptions.relays.encased.SplitShaftTileEntity; import com.simibubi.create.modules.contraptions.relays.encased.SplitShaftTileEntity;
import com.simibubi.create.modules.contraptions.relays.gearbox.GearboxTileEntity; import com.simibubi.create.modules.contraptions.relays.gearbox.GearboxTileEntity;
@ -52,8 +53,8 @@ public class RotationPropagator {
if (axis.getCoordinate(diff.getX(), diff.getY(), diff.getZ()) != 0) if (axis.getCoordinate(diff.getX(), diff.getY(), diff.getZ()) != 0)
alignedAxes = false; alignedAxes = false;
boolean connectedByAxis = alignedAxes boolean connectedByAxis =
&& definitionFrom.hasShaftTowards(world, from.getPos(), stateFrom, direction) alignedAxes && definitionFrom.hasShaftTowards(world, from.getPos(), stateFrom, direction)
&& definitionTo.hasShaftTowards(world, to.getPos(), stateTo, direction.getOpposite()); && definitionTo.hasShaftTowards(world, to.getPos(), stateTo, direction.getOpposite());
boolean connectedByGears = definitionFrom.hasCogsTowards(world, from.getPos(), stateFrom, direction) boolean connectedByGears = definitionFrom.hasCogsTowards(world, from.getPos(), stateFrom, direction)
@ -130,9 +131,9 @@ public class RotationPropagator {
} }
private static float getAxisModifier(KineticTileEntity te, Direction direction) { private static float getAxisModifier(KineticTileEntity te, Direction direction) {
if (!te.hasSource()) if (!te.hasSource() || !(te instanceof DirectionalShaftHalvesTileEntity))
return 1; return 1;
Direction source = te.getSourceFacing(); Direction source = ((DirectionalShaftHalvesTileEntity) te).getSourceFacing();
if (te instanceof GearboxTileEntity) if (te instanceof GearboxTileEntity)
return direction.getAxis() == source.getAxis() ? direction == source ? 1 : -1 return direction.getAxis() == source.getAxis() ? direction == source ? 1 : -1
@ -180,7 +181,7 @@ public class RotationPropagator {
return; return;
if (!worldIn.isBlockPresent(pos)) if (!worldIn.isBlockPresent(pos))
return; return;
if (addedTE.speed != 0) { if (addedTE.getTheoreticalSpeed() != 0) {
propagateNewSource(addedTE); propagateNewSource(addedTE);
return; return;
} }
@ -188,16 +189,17 @@ public class RotationPropagator {
for (KineticTileEntity neighbourTE : getConnectedNeighbours(addedTE)) { for (KineticTileEntity neighbourTE : getConnectedNeighbours(addedTE)) {
final float speedModifier = getRotationSpeedModifier(neighbourTE, addedTE); final float speedModifier = getRotationSpeedModifier(neighbourTE, addedTE);
if (neighbourTE.speed == 0) float neighbourSpeed = neighbourTE.getTheoreticalSpeed();
if (neighbourSpeed == 0)
continue; continue;
if (neighbourTE.hasSource() && neighbourTE.getSource().equals(addedTE.getPos())) { if (neighbourTE.hasSource() && neighbourTE.getSource().equals(addedTE.getPos())) {
addedTE.setSpeed(neighbourTE.speed * speedModifier); addedTE.setSpeed(neighbourSpeed * speedModifier);
addedTE.onSpeedChanged(0); addedTE.onSpeedChanged(0);
addedTE.sendData(); addedTE.sendData();
continue; continue;
} }
addedTE.setSpeed(neighbourTE.speed * speedModifier); addedTE.setSpeed(neighbourSpeed * speedModifier);
addedTE.setSource(neighbourTE.getPos()); addedTE.setSource(neighbourTE.getPos());
addedTE.onSpeedChanged(0); addedTE.onSpeedChanged(0);
addedTE.sendData(); addedTE.sendData();
@ -209,23 +211,25 @@ public class RotationPropagator {
/** /**
* Search for sourceless networks attached to the given entity and update them. * Search for sourceless networks attached to the given entity and update them.
* *
* @param updateTE * @param currentTE
*/ */
private static void propagateNewSource(KineticTileEntity updateTE) { private static void propagateNewSource(KineticTileEntity currentTE) {
BlockPos pos = updateTE.getPos(); BlockPos pos = currentTE.getPos();
World world = updateTE.getWorld(); World world = currentTE.getWorld();
for (KineticTileEntity neighbourTE : getConnectedNeighbours(updateTE)) { for (KineticTileEntity neighbourTE : getConnectedNeighbours(currentTE)) {
float modFromTo = getRotationSpeedModifier(updateTE, neighbourTE); float modFromTo = getRotationSpeedModifier(currentTE, neighbourTE);
float modToFrom = getRotationSpeedModifier(neighbourTE, updateTE); float modToFrom = getRotationSpeedModifier(neighbourTE, currentTE);
final float newSpeed = updateTE.speed * modFromTo; float speedOfCurrent = currentTE.getTheoreticalSpeed();
float oppositeSpeed = neighbourTE.speed * modToFrom; float speedOfNeighbour = neighbourTE.getTheoreticalSpeed();
float newSpeed = speedOfCurrent * modFromTo;
float oppositeSpeed = speedOfNeighbour * modToFrom;
boolean incompatible = Math.signum(newSpeed) != Math.signum(neighbourTE.speed) boolean incompatible =
&& (newSpeed != 0 && neighbourTE.speed != 0); Math.signum(newSpeed) != Math.signum(speedOfNeighbour) && (newSpeed != 0 && speedOfNeighbour != 0);
boolean tooFast = Math.abs(newSpeed) > AllConfigs.SERVER.kinetics.maxRotationSpeed.get(); boolean tooFast = Math.abs(newSpeed) > AllConfigs.SERVER.kinetics.maxRotationSpeed.get();
boolean speedChangedTooOften = updateTE.speedChangeCounter > MAX_FLICKER_SCORE; boolean speedChangedTooOften = currentTE.getFlickerScore() > MAX_FLICKER_SCORE;
if (tooFast || speedChangedTooOften) { if (tooFast || speedChangedTooOften) {
world.destroyBlock(pos, true); world.destroyBlock(pos, true);
return; return;
@ -238,43 +242,45 @@ public class RotationPropagator {
} else { } else {
// Same direction: overpower the slower speed // Same direction: overpower the slower speed
if (Math.abs(oppositeSpeed) > Math.abs(updateTE.speed)) { if (Math.abs(oppositeSpeed) > Math.abs(speedOfCurrent)) {
// Neighbour faster, overpower the incoming tree // Neighbour faster, overpower the incoming tree
updateTE.setSource(neighbourTE.getPos()); currentTE.setSource(neighbourTE.getPos());
float prevSpeed = updateTE.getSpeed(); float prevSpeed = currentTE.getSpeed();
updateTE.setSpeed(neighbourTE.speed * getRotationSpeedModifier(neighbourTE, updateTE)); currentTE.setSpeed(speedOfNeighbour * getRotationSpeedModifier(neighbourTE, currentTE));
updateTE.onSpeedChanged(prevSpeed); currentTE.onSpeedChanged(prevSpeed);
updateTE.sendData(); currentTE.sendData();
propagateNewSource(updateTE); propagateNewSource(currentTE);
return; return;
} }
if (Math.abs(newSpeed) >= Math.abs(neighbourTE.speed)) {
if (Math.abs(newSpeed) > Math.abs(neighbourTE.speed) || updateTE.newNetworkID != null
&& !updateTE.newNetworkID.equals(neighbourTE.newNetworkID)) {
// Current faster, overpower the neighbours' tree
if (updateTE.hasSource() && updateTE.getSource().equals(neighbourTE.getPos())) { // Current faster, overpower the neighbours' tree
updateTE.removeSource(); if (Math.abs(newSpeed) >= Math.abs(speedOfNeighbour)) {
if (!currentTE.canOverPower(neighbourTE)) {
if (Math.abs(newSpeed) > Math.abs(speedOfNeighbour))
world.destroyBlock(pos, true);
continue;
} }
neighbourTE.setSource(updateTE.getPos()); if (currentTE.hasSource() && currentTE.getSource().equals(neighbourTE.getPos()))
currentTE.removeSource();
neighbourTE.setSource(currentTE.getPos());
float prevSpeed = neighbourTE.getSpeed(); float prevSpeed = neighbourTE.getSpeed();
neighbourTE.setSpeed(updateTE.speed * getRotationSpeedModifier(updateTE, neighbourTE)); neighbourTE.setSpeed(speedOfCurrent * getRotationSpeedModifier(currentTE, neighbourTE));
neighbourTE.onSpeedChanged(prevSpeed); neighbourTE.onSpeedChanged(prevSpeed);
neighbourTE.sendData(); neighbourTE.sendData();
propagateNewSource(neighbourTE); propagateNewSource(neighbourTE);
}
continue; continue;
} }
} }
if (neighbourTE.speed == newSpeed) if (neighbourTE.getTheoreticalSpeed() == newSpeed)
continue; continue;
float prevSpeed = neighbourTE.getSpeed(); float prevSpeed = neighbourTE.getSpeed();
neighbourTE.setSpeed(newSpeed); neighbourTE.setSpeed(newSpeed);
neighbourTE.setSource(updateTE.getPos()); neighbourTE.setSource(currentTE.getPos());
neighbourTE.onSpeedChanged(prevSpeed); neighbourTE.onSpeedChanged(prevSpeed);
neighbourTE.sendData(); neighbourTE.sendData();
propagateNewSource(neighbourTE); propagateNewSource(neighbourTE);
@ -294,7 +300,7 @@ public class RotationPropagator {
return; return;
if (removedTE == null) if (removedTE == null)
return; return;
if (removedTE.speed == 0) if (removedTE.getTheoreticalSpeed() == 0)
return; return;
for (BlockPos neighbourPos : getPotentialNeighbourLocations(removedTE)) { for (BlockPos neighbourPos : getPotentialNeighbourLocations(removedTE)) {

View file

@ -27,22 +27,15 @@ public class TorquePropagator {
UUID id = te.getNetworkID(); UUID id = te.getNetworkID();
KineticNetwork network; KineticNetwork network;
Map<UUID, KineticNetwork> map = networks.get(te.getWorld()); Map<UUID, KineticNetwork> map = networks.get(te.getWorld());
if (id == null) { if (id == null)
network = new KineticNetwork(); return null;
// Debug.debugChatAndShowStack(te.getType().getRegistryName().getPath() + " created new Network", 5);
te.newNetworkID = network.id;
te.updateNetwork = true;
map.put(id, network);
} else {
if (!map.containsKey(id)) { if (!map.containsKey(id)) {
network = new KineticNetwork(); network = new KineticNetwork();
network.id = te.getNetworkID(); network.id = te.getNetworkID();
map.put(id, network); map.put(id, network);
} }
network = map.get(id); network = map.get(id);
}
return network; return network;
} }

View file

@ -1,14 +1,17 @@
package com.simibubi.create.modules.contraptions.base; package com.simibubi.create.modules.contraptions.base;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import com.simibubi.create.modules.contraptions.KineticNetwork;
import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel; import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.BlockPos;
public abstract class GeneratingKineticTileEntity extends KineticTileEntity { public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
public boolean reActivateSource;
public GeneratingKineticTileEntity(TileEntityType<?> typeIn) { public GeneratingKineticTileEntity(TileEntityType<?> typeIn) {
super(typeIn); super(typeIn);
} }
@ -18,68 +21,108 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
} }
@Override @Override
public void reActivateSource() { public void removeSource() {
if (hasSource() && isSource())
reActivateSource = true;
super.removeSource();
}
@Override
public void setSource(BlockPos source) {
super.setSource(source);
KineticTileEntity sourceTe = (KineticTileEntity) world.getTileEntity(source);
if (reActivateSource && sourceTe != null && Math.abs(sourceTe.getSpeed()) >= Math.abs(getGeneratedSpeed()))
reActivateSource = false;
}
@Override
public void tick() {
super.tick();
if (reActivateSource) {
updateGeneratedRotation(); updateGeneratedRotation();
reActivateSource = false;
}
} }
public void updateGeneratedRotation() { public void updateGeneratedRotation() {
float speed = getGeneratedSpeed(); float speed = getGeneratedSpeed();
float prevSpeed = this.speed; float prevSpeed = this.speed;
if (this.speed != speed) { if (world.isRemote)
return;
if (!world.isRemote) { if (prevSpeed != speed) {
if (!hasSource()) {
SpeedLevel levelBefore = SpeedLevel.of(this.speed); SpeedLevel levelBefore = SpeedLevel.of(this.speed);
SpeedLevel levelafter = SpeedLevel.of(speed); SpeedLevel levelafter = SpeedLevel.of(speed);
if (levelBefore != levelafter) if (levelBefore != levelafter)
queueRotationIndicators(); effects.queueRotationIndicators();
} }
if (speed == 0) { applyNewSpeed(prevSpeed, speed);
if (hasSource())
notifyStressCapacityChange(0);
else {
detachKinetics();
setSpeed(speed);
newNetworkID = null;
updateNetwork = true;
}
} else if (this.speed == 0) {
setSpeed(speed);
newNetworkID = UUID.randomUUID();
updateNetwork = true;
attachKinetics();
} else {
if (hasSource()) {
if (Math.abs(this.speed) >= Math.abs(speed)) {
if (Math.signum(this.speed) == Math.signum(speed))
notifyStressCapacityChange(getAddedStressCapacity());
else
world.destroyBlock(pos, true);
} else {
detachKinetics();
setSpeed(speed);
source = Optional.empty();
newNetworkID = UUID.randomUUID();
updateNetwork = true;
attachKinetics();
}
} else {
detachKinetics();
setSpeed(speed);
attachKinetics();
}
}
} }
if (hasNetwork() && speed != 0) { if (hasNetwork() && speed != 0) {
getNetwork().updateCapacityFor(this, getAddedStressCapacity()); KineticNetwork network = getNetwork();
getNetwork().updateStressCapacity(); network.updateCapacityFor(this, getAddedStressCapacity());
getNetwork().updateStress(); network.updateStress();
} }
onSpeedChanged(prevSpeed); onSpeedChanged(prevSpeed);
sendData(); sendData();
} }
public void applyNewSpeed(float prevSpeed, float speed) {
// Speed changed to 0
if (speed == 0) {
if (hasSource() && hasNetwork()) {
getNetwork().updateCapacityFor(this, 0);
return;
}
detachKinetics();
setSpeed(speed);
newNetworkID = null;
updateNetwork = true;
return;
}
// Now turning - create a new Network
if (prevSpeed == 0) {
setSpeed(speed);
newNetworkID = UUID.randomUUID();
updateNetwork = true;
attachKinetics();
return;
}
// Change speed when overpowered by other generator
if (hasSource() && hasNetwork()) {
// Staying below Overpowered speed
if (Math.abs(prevSpeed) >= Math.abs(speed)) {
if (Math.signum(prevSpeed) != Math.signum(speed)) {
world.destroyBlock(pos, true);
return;
}
getNetwork().updateCapacityFor(this, getAddedStressCapacity());
return;
}
// Faster than attached network -> become the new source
detachKinetics();
setSpeed(speed);
source = null;
newNetworkID = UUID.randomUUID();
updateNetwork = true;
attachKinetics();
return;
}
// Reapply source
detachKinetics();
setSpeed(speed);
attachKinetics();
}
} }

View file

@ -112,7 +112,7 @@ public abstract class KineticBlock extends Block implements IRotate {
return; return;
KineticTileEntity kte = (KineticTileEntity) tileEntity; KineticTileEntity kte = (KineticTileEntity) tileEntity;
kte.queueRotationIndicators(); kte.effects.queueRotationIndicators();
} }
public float getParticleTargetRadius() { public float getParticleTargetRadius() {

View file

@ -0,0 +1,116 @@
package com.simibubi.create.modules.contraptions.base;
import java.util.Random;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel;
import com.simibubi.create.modules.contraptions.particle.RotationIndicatorParticleData;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
public class KineticEffectHandler {
int overStressedTime;
float overStressedEffect;
int particleSpawnCountdown;
KineticTileEntity kte;
public KineticEffectHandler(KineticTileEntity kte) {
this.kte = kte;
}
public void tick() {
World world = kte.getWorld();
if (world.isRemote) {
if (overStressedTime > 0)
if (--overStressedTime == 0)
if (kte.overStressed) {
overStressedEffect = 1;
spawnEffect(ParticleTypes.SMOKE, 0.2f, 5);
} else {
overStressedEffect = -1;
spawnEffect(ParticleTypes.CLOUD, .075f, 2);
}
if (overStressedEffect != 0) {
overStressedEffect -= overStressedEffect * .1f;
if (Math.abs(overStressedEffect) < 1 / 128f)
overStressedEffect = 0;
}
} else if (particleSpawnCountdown > 0) {
if (--particleSpawnCountdown == 0)
spawnRotationIndicators();
}
}
public void queueRotationIndicators() {
particleSpawnCountdown = 2;
}
public void spawnEffect(IParticleData particle, float maxMotion, int amount) {
World world = kte.getWorld();
if (world == null)
return;
if (!world.isRemote)
return;
Random r = world.rand;
for (int i = 0; i < amount; i++) {
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, r, maxMotion);
Vec3d position = VecHelper.getCenterOf(kte.getPos());
world.addParticle(particle, position.x, position.y, position.z, motion.x, motion.y, motion.z);
}
}
public void spawnRotationIndicators() {
float speed = kte.getSpeed();
if (speed == 0)
return;
BlockState state = kte.getBlockState();
Block block = state.getBlock();
if (!(block instanceof KineticBlock))
return;
KineticBlock kb = (KineticBlock) block;
float radius1 = kb.getParticleInitialRadius();
float radius2 = kb.getParticleTargetRadius();
Axis axis = kb.getRotationAxis(state);
BlockPos pos = kte.getPos();
World world = kte.getWorld();
if (axis == null)
return;
if (world == null)
return;
char axisChar = axis.name().charAt(0);
Vec3d vec = VecHelper.getCenterOf(pos);
SpeedLevel speedLevel = SpeedLevel.of(speed);
int color = speedLevel.getColor();
int particleSpeed = speedLevel.getParticleSpeed();
particleSpeed *= Math.signum(speed);
if (world instanceof ServerWorld) {
AllTriggers.triggerForNearbyPlayers(AllTriggers.ROTATION, world, pos, 5);
RotationIndicatorParticleData particleData =
new RotationIndicatorParticleData(color, particleSpeed, radius1, radius2, 10, axisChar);
((ServerWorld) world).spawnParticle(particleData, vec.x, vec.y, vec.z, 20, 0, 0, 0, 1);
}
}
public void triggerOverStressedEffect() {
overStressedTime = overStressedTime == 0 ? 2 : 0;
}
}

View file

@ -1,12 +1,7 @@
package com.simibubi.create.modules.contraptions.base; package com.simibubi.create.modules.contraptions.base;
import static net.minecraft.util.text.TextFormatting.GREEN;
import static net.minecraft.util.text.TextFormatting.WHITE;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.UUID; import java.util.UUID;
import com.simibubi.create.Create; import com.simibubi.create.Create;
@ -14,60 +9,113 @@ import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity; import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour; import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.KineticNetwork; import com.simibubi.create.modules.contraptions.KineticNetwork;
import com.simibubi.create.modules.contraptions.RotationPropagator; import com.simibubi.create.modules.contraptions.RotationPropagator;
import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel; import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel;
import com.simibubi.create.modules.contraptions.base.IRotate.StressImpact; import com.simibubi.create.modules.contraptions.base.IRotate.StressImpact;
import com.simibubi.create.modules.contraptions.particle.RotationIndicatorParticleData;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue; import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
public abstract class KineticTileEntity extends SmartTileEntity implements ITickableTileEntity { public abstract class KineticTileEntity extends SmartTileEntity implements ITickableTileEntity {
int particleSpawnCountdown; protected UUID networkID;
protected UUID newNetworkID;
protected float maxStress;
protected float currentStress;
protected boolean updateNetwork;
// Speed related protected KineticEffectHandler effects;
public float speed; protected BlockPos source;
protected Optional<BlockPos> source; protected float speed;
public boolean reActivateSource;
public int speedChangeCounter;
// Torque related
public float maxStress;
public float currentStress;
protected boolean overStressed; protected boolean overStressed;
public UUID networkID;
public UUID newNetworkID;
public boolean updateNetwork;
protected boolean initNetwork; protected boolean initNetwork;
// Client private int flickerTally;
int overStressedTime; private int validationCountdown;
float overStressedEffect;
public KineticTileEntity(TileEntityType<?> typeIn) { public KineticTileEntity(TileEntityType<?> typeIn) {
super(typeIn); super(typeIn);
speed = 0; effects = new KineticEffectHandler(this);
source = Optional.empty();
} }
@Override @Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) { public void tick() {
super.tick();
effects.tick();
if (world.isRemote)
return;
if (validationCountdown-- <= 0) {
validationCountdown = AllConfigs.SERVER.kinetics.kineticValidationFrequency.get();
validateKinetics();
}
if (getFlickerScore() > 0)
flickerTally = getFlickerScore() - 1;
if (initNetwork) {
initNetwork = false;
KineticNetwork network = getNetwork();
if (!network.initialized)
network.initFromTE(maxStress, currentStress);
network.addSilently(this);
}
if (updateNetwork) {
updateNetwork = false;
if (hasNetwork() && !networkID.equals(newNetworkID)) {
getNetwork().remove(this);
networkID = null;
maxStress = currentStress = 0;
overStressed = false;
}
if (newNetworkID != null) {
networkID = newNetworkID;
KineticNetwork network = getNetwork();
network.initialized = true;
network.add(this);
}
sendData();
}
}
private void validateKinetics() {
if (hasSource()) {
if (!world.isBlockPresent(source))
return;
KineticTileEntity sourceTe = (KineticTileEntity) world.getTileEntity(source);
if (sourceTe == null || sourceTe.speed == 0) {
removeSource();
detachKinetics();
return;
}
if (hasNetwork() && maxStress == 0) {
for (KineticTileEntity kineticTileEntity : getNetwork().members.keySet())
kineticTileEntity.removeSource();
return;
}
return;
}
if (speed != 0) {
if (getGeneratedSpeed() == 0)
setSpeed(0);
}
} }
public void sync(float maxStress, float currentStress) { public void sync(float maxStress, float currentStress) {
@ -100,46 +148,35 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
return stressEntries.get(path).get().floatValue(); return stressEntries.get(path).get().floatValue();
} }
protected void notifyStressChange(float stress) {
getNetwork().updateStressFor(this, stress);
}
@Override
public boolean hasFastRenderer() {
return true;
}
public void onSpeedChanged(float previousSpeed) { public void onSpeedChanged(float previousSpeed) {
boolean fromOrToZero = (previousSpeed == 0) != (getSpeed() == 0); boolean fromOrToZero = (previousSpeed == 0) != (getSpeed() == 0);
boolean directionSwap = !fromOrToZero && Math.signum(previousSpeed) != Math.signum(getSpeed()); boolean directionSwap = !fromOrToZero && Math.signum(previousSpeed) != Math.signum(getSpeed());
if (fromOrToZero || directionSwap) { if (fromOrToZero || directionSwap) {
speedChangeCounter += 5; flickerTally = getFlickerScore() + 5;
} }
} }
@Override @Override
public void remove() { public void remove() {
if (world.isRemote) { if (!world.isRemote) {
super.remove(); if (hasNetwork())
return;
}
if (hasNetwork()) {
getNetwork().remove(this); getNetwork().remove(this);
detachKinetics();
} }
RotationPropagator.handleRemoved(getWorld(), getPos(), this);
super.remove(); super.remove();
} }
@Override @Override
public CompoundNBT write(CompoundNBT compound) { public CompoundNBT write(CompoundNBT compound) {
compound.putFloat("Speed", speed); compound.putFloat("Speed", speed);
if (hasSource()) if (hasSource())
compound.put("Source", NBTUtil.writeBlockPos(getSource())); compound.put("Source", NBTUtil.writeBlockPos(source));
if (hasNetwork()) { if (hasNetwork()) {
compound.putFloat("MaxStress", maxStress); compound.putFloat("MaxStress", maxStress);
compound.putFloat("Stress", currentStress); compound.putFloat("Stress", currentStress);
compound.put("Id", NBTUtil.writeUniqueId(getNetworkID())); compound.put("Id", NBTUtil.writeUniqueId(networkID));
} }
return super.write(compound); return super.write(compound);
@ -147,23 +184,21 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
@Override @Override
public void read(CompoundNBT compound) { public void read(CompoundNBT compound) {
setSpeed(compound.getFloat("Speed")); speed = compound.getFloat("Speed");
setSource(null); source = null;
if (compound.contains("Source")) { networkID = newNetworkID = null;
CompoundNBT tagSource = compound.getCompound("Source"); overStressed = false;
setSource(NBTUtil.readBlockPos(tagSource));
} if (compound.contains("Source"))
source = NBTUtil.readBlockPos(compound.getCompound("Source"));
if (compound.contains("Id")) { if (compound.contains("Id")) {
maxStress = compound.getFloat("MaxStress"); maxStress = compound.getFloat("MaxStress");
currentStress = compound.getFloat("Stress"); currentStress = compound.getFloat("Stress");
overStressed = maxStress < currentStress && StressImpact.isEnabled(); overStressed = maxStress < currentStress && StressImpact.isEnabled();
setNetworkID(NBTUtil.readUniqueId(compound.getCompound("Id"))); networkID = NBTUtil.readUniqueId(compound.getCompound("Id"));
newNetworkID = networkID; newNetworkID = networkID;
initNetwork = true; initNetwork = true;
} else {
networkID = newNetworkID = null;
overStressed = false;
} }
super.read(compound); super.read(compound);
@ -174,7 +209,7 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
boolean overStressedBefore = overStressed; boolean overStressedBefore = overStressed;
super.readClientUpdate(tag); super.readClientUpdate(tag);
if (overStressedBefore != overStressed && speed != 0) if (overStressedBefore != overStressed && speed != 0)
overStressedTime = overStressedTime == 0 ? 2 : 0; effects.triggerOverStressedEffect();
} }
public boolean isSource() { public boolean isSource() {
@ -184,6 +219,10 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
public float getSpeed() { public float getSpeed() {
if (overStressed) if (overStressed)
return 0; return 0;
return getTheoreticalSpeed();
}
public float getTheoreticalSpeed() {
return speed; return speed;
} }
@ -196,31 +235,22 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
} }
public boolean hasSource() { public boolean hasSource() {
return source.isPresent(); return source != null;
} }
public BlockPos getSource() { public BlockPos getSource() {
return source.get(); return source;
}
public Direction getSourceFacing() {
BlockPos source = getSource().subtract(getPos());
return Direction.getFacingFromVector(source.getX(), source.getY(), source.getZ());
} }
public void setSource(BlockPos source) { public void setSource(BlockPos source) {
this.source = Optional.ofNullable(source); this.source = source;
if (world == null || world.isRemote) if (world == null || world.isRemote)
return; return;
if (source == null)
return;
KineticTileEntity sourceTe = (KineticTileEntity) world.getTileEntity(source);
if (sourceTe == null)
return;
if (reActivateSource && Math.abs(sourceTe.getSpeed()) >= Math.abs(getGeneratedSpeed())) { KineticTileEntity sourceTe = (KineticTileEntity) world.getTileEntity(source);
reActivateSource = false; if (sourceTe == null) {
removeSource();
return;
} }
newNetworkID = sourceTe.newNetworkID; newNetworkID = sourceTe.newNetworkID;
@ -228,10 +258,7 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
} }
public void removeSource() { public void removeSource() {
if (hasSource() && isSource()) source = null;
reActivateSource = true;
this.source = Optional.empty();
newNetworkID = null; newNetworkID = null;
updateNetwork = true; updateNetwork = true;
float prevSpeed = getSpeed(); float prevSpeed = getSpeed();
@ -247,10 +274,8 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
return networkID != null; return networkID != null;
} }
public void applyNewSpeed(float speed) { public boolean canOverPower(KineticTileEntity other) {
detachKinetics(); return newNetworkID != null && !newNetworkID.equals(other.newNetworkID);
this.speed = speed;
attachKinetics();
} }
public void attachKinetics() { public void attachKinetics() {
@ -269,79 +294,6 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
this.networkID = networkID; this.networkID = networkID;
} }
/**
* Callback for source blocks to re-apply their speed when an overpowering
* source is removed
*/
public void reActivateSource() {
}
@Override
public void tick() {
super.tick();
if (world.isRemote) {
if (overStressedTime > 0)
if (--overStressedTime == 0)
if (overStressed) {
overStressedEffect = 1;
spawnEffect(ParticleTypes.SMOKE, 0.2f, 5);
} else {
overStressedEffect = -1;
spawnEffect(ParticleTypes.CLOUD, .075f, 2);
}
if (overStressedEffect != 0) {
overStressedEffect -= overStressedEffect * .1f;
if (Math.abs(overStressedEffect) < 1 / 128f)
overStressedEffect = 0;
}
return;
}
if (speedChangeCounter > 0)
speedChangeCounter--;
if (particleSpawnCountdown > 0)
if (--particleSpawnCountdown == 0)
spawnRotationIndicators();
if (initNetwork) {
initNetwork = false;
KineticNetwork network = getNetwork();
if (!network.initialized)
network.initFromTE(this);
network.addSilently(this);
}
if (updateNetwork) {
updateNetwork = false;
if (hasNetwork() && !networkID.equals(newNetworkID)) {
getNetwork().remove(this);
networkID = null;
maxStress = currentStress = 0;
overStressed = false;
}
if (newNetworkID != null) {
networkID = newNetworkID;
KineticNetwork network = getNetwork();
network.initialized = true;
network.add(this);
}
sendData();
}
if (reActivateSource) {
reActivateSource();
reActivateSource = false;
}
}
public boolean isSpeedRequirementFulfilled() { public boolean isSpeedRequirementFulfilled() {
BlockState state = getBlockState(); BlockState state = getBlockState();
if (!(getBlockState().getBlock() instanceof IRotate)) if (!(getBlockState().getBlock() instanceof IRotate))
@ -357,60 +309,17 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
return true; return true;
} }
public void addDebugInformation(List<String> lines) { @Override
lines.add("Speed: " + GREEN + speed); public void addBehaviours(List<TileEntityBehaviour> behaviours) {
lines.add("Cost: " + GREEN + getStressApplied() + WHITE + "/" + GREEN + getAddedStressCapacity());
lines.add("Stress: " + GREEN + currentStress + WHITE + "/" + GREEN + maxStress);
} }
public void queueRotationIndicators() { @Override
// wait a few ticks for network jamming etc public boolean hasFastRenderer() {
particleSpawnCountdown = 2; return true;
} }
protected void spawnEffect(IParticleData particle, float maxMotion, int amount) { public int getFlickerScore() {
if (!hasWorld()) return flickerTally;
return;
if (!world.isRemote)
return;
Random r = getWorld().rand;
for (int i = 0; i < amount; i++) {
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, r, maxMotion);
Vec3d position = VecHelper.getCenterOf(pos);
this.getWorld().addParticle(particle, position.x, position.y, position.z, motion.x, motion.y, motion.z);
}
}
protected void spawnRotationIndicators() {
if (getSpeed() == 0)
return;
BlockState state = getBlockState();
Block block = state.getBlock();
if (!(block instanceof KineticBlock))
return;
KineticBlock kb = (KineticBlock) block;
float radius1 = kb.getParticleInitialRadius();
float radius2 = kb.getParticleTargetRadius();
Axis axis = kb.getRotationAxis(state);
if (axis == null)
return;
char axisChar = axis.name().charAt(0);
Vec3d vec = VecHelper.getCenterOf(pos);
SpeedLevel speedLevel = SpeedLevel.of(getSpeed());
int color = speedLevel.getColor();
int particleSpeed = speedLevel.getParticleSpeed();
particleSpeed *= Math.signum(getSpeed());
if (getWorld() instanceof ServerWorld) {
AllTriggers.triggerForNearbyPlayers(AllTriggers.ROTATION, world, pos, 5);
RotationIndicatorParticleData particleData =
new RotationIndicatorParticleData(color, particleSpeed, radius1, radius2, 10, axisChar);
((ServerWorld) getWorld()).spawnParticle(particleData, vec.x, vec.y, vec.z, 20, 0, 0, 0, 1);
}
} }
} }

View file

@ -24,8 +24,8 @@ public class KineticTileEntityRenderer extends SafeTileEntityRendererFast<Kineti
public static boolean rainbowMode = false; public static boolean rainbowMode = false;
@Override @Override
public void renderFast(KineticTileEntity te, double x, double y, double z, float partialTicks, public void renderFast(KineticTileEntity te, double x, double y, double z, float partialTicks, int destroyStage,
int destroyStage, BufferBuilder buffer) { BufferBuilder buffer) {
renderRotatingBuffer(te, getWorld(), getRotatedModel(te), x, y, z, buffer); renderRotatingBuffer(te, getWorld(), getRotatedModel(te), x, y, z, buffer);
} }
@ -68,11 +68,12 @@ public class KineticTileEntityRenderer extends SafeTileEntityRendererFast<Kineti
else else
buffer.color(white); buffer.color(white);
} else { } else {
if (te.overStressedEffect != 0) float overStressedEffect = te.effects.overStressedEffect;
if (te.overStressedEffect > 0) if (overStressedEffect != 0)
buffer.color(ColorHelper.mixColors(white, 0xFF0000, te.overStressedEffect)); if (overStressedEffect > 0)
buffer.color(ColorHelper.mixColors(white, 0xFF0000, overStressedEffect));
else else
buffer.color(ColorHelper.mixColors(white, 0x00FFBB, -te.overStressedEffect)); buffer.color(ColorHelper.mixColors(white, 0x00FFBB, -overStressedEffect));
else else
buffer.color(white); buffer.color(white);
} }

View file

@ -63,7 +63,7 @@ public class DeployerTileEntityRenderer extends SafeTileEntityRenderer<DeployerT
float yRot = AngleHelper.horizontalAngle(facing) + 180; float yRot = AngleHelper.horizontalAngle(facing) + 180;
float zRot = facing == Direction.UP ? 90 : facing == Direction.DOWN ? 270 : 0; float zRot = facing == Direction.UP ? 90 : facing == Direction.DOWN ? 270 : 0;
boolean displayMode = facing == Direction.UP && te.speed == 0 && !punching; boolean displayMode = facing == Direction.UP && te.getSpeed() == 0 && !punching;
GlStateManager.rotatef(yRot, 0, 1, 0); GlStateManager.rotatef(yRot, 0, 1, 0);
if (!displayMode) { if (!displayMode) {

View file

@ -86,7 +86,7 @@ public class SawBlock extends DirectionalAxisKineticBlock implements IWithTileEn
withTileEntityDo(worldIn, pos, te -> { withTileEntityDo(worldIn, pos, te -> {
if (te.getSpeed() == 0) if (te.getSpeed() == 0)
return; return;
entityIn.attackEntityFrom(damageSourceSaw, MathHelper.clamp(Math.abs(te.speed / 512f) + 1, 0, 20)); entityIn.attackEntityFrom(damageSourceSaw, MathHelper.clamp(Math.abs(te.getSpeed() / 512f) + 1, 0, 20));
}); });
} }

View file

@ -89,6 +89,7 @@ public class WaterWheelBlock extends HorizontalKineticBlock {
flowVec = flowVec.scale(f.getAxisDirection().getOffset()); flowVec = flowVec.scale(f.getAxisDirection().getOffset());
boolean clockwise = wf.getAxisDirection() == AxisDirection.POSITIVE; boolean clockwise = wf.getAxisDirection() == AxisDirection.POSITIVE;
int clockwiseMultiplier = 2; int clockwiseMultiplier = 2;
flowVec = new Vec3d(Math.signum(flowVec.x), Math.signum(flowVec.y), Math.signum(flowVec.z));
if (wf.getAxis() == Axis.Z) { if (wf.getAxis() == Axis.Z) {
if (f.getAxis() == Axis.Y) if (f.getAxis() == Axis.Y)

View file

@ -65,12 +65,13 @@ public class SpeedControllerTileEntity extends KineticTileEntity {
if (targetSpeed == 0) if (targetSpeed == 0)
return 0; return 0;
if (targetingController && cogWheel.speed == 0) float wheelSpeed = cogWheel.getTheoreticalSpeed();
if (targetingController && wheelSpeed == 0)
return 1; return 1;
if (!speedController.hasSource()) { if (!speedController.hasSource()) {
if (targetingController) if (targetingController)
return targetSpeed / cogWheel.speed; return targetSpeed / wheelSpeed;
return 1; return 1;
} }
@ -78,8 +79,8 @@ public class SpeedControllerTileEntity extends KineticTileEntity {
if (wheelPowersController) { if (wheelPowersController) {
if (targetingController) if (targetingController)
return targetSpeed / cogWheel.speed; return targetSpeed / wheelSpeed;
return cogWheel.speed / targetSpeed; return wheelSpeed / targetSpeed;
} }
if (targetingController) if (targetingController)

View file

@ -347,7 +347,7 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
return; return;
BeltTileEntity beltEntity = (BeltTileEntity) tileEntity; BeltTileEntity beltEntity = (BeltTileEntity) tileEntity;
BlockPos controller = beltEntity.getController(); BlockPos controller = beltEntity.getController();
beltEntity.setSource(null); beltEntity.removeSource();
beltEntity.remove(); beltEntity.remove();
int limit = 1000; int limit = 1000;
@ -368,7 +368,7 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
inv.eject(stack); inv.eject(stack);
} }
te.setSource(null); te.removeSource();
te.remove(); te.remove();
if (destroyedBlock.get(CASING)) if (destroyedBlock.get(CASING))

View file

@ -194,8 +194,8 @@ public class BeltConnectorItem extends BlockItem implements IAddedByOther {
if (axis != world.getBlockState(second).get(BlockStateProperties.AXIS)) if (axis != world.getBlockState(second).get(BlockStateProperties.AXIS))
return false; return false;
float speed1 = ((KineticTileEntity) world.getTileEntity(first)).speed; float speed1 = ((KineticTileEntity) world.getTileEntity(first)).getTheoreticalSpeed();
float speed2 = ((KineticTileEntity) world.getTileEntity(second)).speed; float speed2 = ((KineticTileEntity) world.getTileEntity(second)).getTheoreticalSpeed();
if (Math.signum(speed1) != Math.signum(speed2) && speed1 != 0 && speed2 != 0) if (Math.signum(speed1) != Math.signum(speed2) && speed1 != 0 && speed2 != 0)
return false; return false;

View file

@ -0,0 +1,20 @@
package com.simibubi.create.modules.contraptions.relays.encased;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
public class DirectionalShaftHalvesTileEntity extends KineticTileEntity {
public DirectionalShaftHalvesTileEntity(TileEntityType<?> typeIn) {
super(typeIn);
}
public Direction getSourceFacing() {
BlockPos source = getSource().subtract(getPos());
return Direction.getFacingFromVector(source.getX(), source.getY(), source.getZ());
}
}

View file

@ -1,11 +1,9 @@
package com.simibubi.create.modules.contraptions.relays.encased; package com.simibubi.create.modules.contraptions.relays.encased;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
public abstract class SplitShaftTileEntity extends KineticTileEntity { public abstract class SplitShaftTileEntity extends DirectionalShaftHalvesTileEntity {
public SplitShaftTileEntity(TileEntityType<?> typeIn) { public SplitShaftTileEntity(TileEntityType<?> typeIn) {
super(typeIn); super(typeIn);

View file

@ -133,13 +133,14 @@ public class GaugeInformationRenderer {
String _generatorStatsTitle = Lang.translate("gui.goggles.generator_stats"); String _generatorStatsTitle = Lang.translate("gui.goggles.generator_stats");
String _capacityProvided = Lang.translate("tooltip.capacityProvided"); String _capacityProvided = Lang.translate("tooltip.capacityProvided");
if (te.speed != te.getGeneratedSpeed() && te.speed != 0) float speed = te.getTheoreticalSpeed();
addedStressCapacity *= (te.getGeneratedSpeed() / te.speed); if (speed != te.getGeneratedSpeed() && speed != 0)
addedStressCapacity *= (te.getGeneratedSpeed() / speed);
tooltip.add(spacing + _generatorStatsTitle); tooltip.add(spacing + _generatorStatsTitle);
tooltip.add(spacing + GRAY + _capacityProvided); tooltip.add(spacing + GRAY + _capacityProvided);
float actualSpeed = Math.abs(te.speed); float actualSpeed = Math.abs(speed);
float relativeCap = 0; float relativeCap = 0;
if (actualSpeed != 0) if (actualSpeed != 0)
relativeCap = addedStressCapacity * actualSpeed; relativeCap = addedStressCapacity * actualSpeed;
@ -176,8 +177,8 @@ public class GaugeInformationRenderer {
} }
StressGaugeTileEntity stressGauge = (StressGaugeTileEntity) te; StressGaugeTileEntity stressGauge = (StressGaugeTileEntity) te;
List<String> stressLevels = Lang.translatedOptions("tooltip.stressImpact", "low", "medium", "high"); List<String> stressLevels = Lang.translatedOptions("tooltip.stressImpact", "low", "medium", "high");
double stress = stressGauge.currentStress; double stress = stressGauge.getNetworkStress();
double cap = stressGauge.maxStress; double cap = stressGauge.getNetworkCapacity();
double relStress = stress / (cap == 0 ? 1 : cap); double relStress = stress / (cap == 0 ? 1 : cap);
StressImpact impactId = relStress > 1 ? null StressImpact impactId = relStress > 1 ? null
: (relStress > .75f) ? StressImpact.HIGH : (relStress > .75f) ? StressImpact.HIGH
@ -199,17 +200,17 @@ public class GaugeInformationRenderer {
level += " (" + (int) (relStress * 100) + "%)"; level += " (" + (int) (relStress * 100) + "%)";
float actualSpeed = stressGauge.speed; float theoreticalSpeed = stressGauge.getTheoreticalSpeed();
if (actualSpeed == 0) if (theoreticalSpeed == 0)
level = DARK_GRAY + ItemDescription.makeProgressBar(3, -1) + _noRotation; level = DARK_GRAY + ItemDescription.makeProgressBar(3, -1) + _noRotation;
tooltip.add(spacing + GRAY + _stressGaugeTitle); tooltip.add(spacing + GRAY + _stressGaugeTitle);
tooltip.add(spacing + level); tooltip.add(spacing + level);
if (actualSpeed != 0) { if (theoreticalSpeed != 0) {
tooltip.add(spacing + GRAY + _capacity); tooltip.add(spacing + GRAY + _capacity);
String capacity = color + "" + format((cap - stress) / Math.abs(actualSpeed)) + _stressUnit + " " String capacity = color + "" + format((cap - stress) / Math.abs(theoreticalSpeed)) + _stressUnit + " "
+ DARK_GRAY + _atCurrentSpeed; + DARK_GRAY + _atCurrentSpeed;
String capacityAtBase = GRAY + "" + format(cap - stress) + _stressUnit + " " + DARK_GRAY + _baseValue; String capacityAtBase = GRAY + "" + format(cap - stress) + _stressUnit + " " + DARK_GRAY + _baseValue;
tooltip.add(spacing + " " + capacity); tooltip.add(spacing + " " + capacity);
@ -221,9 +222,10 @@ public class GaugeInformationRenderer {
if (!(te instanceof SpeedGaugeTileEntity)) if (!(te instanceof SpeedGaugeTileEntity))
return; return;
SpeedGaugeTileEntity speedGauge = (SpeedGaugeTileEntity) te; SpeedGaugeTileEntity speedGauge = (SpeedGaugeTileEntity) te;
boolean overstressed = speedGauge.currentStress > speedGauge.maxStress && speedGauge.speed != 0; float speed = speedGauge.getTheoreticalSpeed();
boolean overstressed = speedGauge.getSpeed() == 0 && speed != 0;
SpeedLevel speedLevel = SpeedLevel.of(speedGauge.speed); SpeedLevel speedLevel = SpeedLevel.of(speed);
String color = speedLevel.getTextColor() + ""; String color = speedLevel.getTextColor() + "";
if (overstressed) if (overstressed)
color = DARK_GRAY + "" + TextFormatting.STRIKETHROUGH; color = DARK_GRAY + "" + TextFormatting.STRIKETHROUGH;
@ -232,7 +234,7 @@ public class GaugeInformationRenderer {
int index = speedLevel.ordinal(); int index = speedLevel.ordinal();
String level = color + ItemDescription.makeProgressBar(3, index) String level = color + ItemDescription.makeProgressBar(3, index)
+ (speedLevel != SpeedLevel.NONE ? speedLevels.get(index) : ""); + (speedLevel != SpeedLevel.NONE ? speedLevels.get(index) : "");
level += " (" + format(Math.abs(speedGauge.speed)) + "" + _rpmUnit + ") "; level += " (" + format(Math.abs(speed)) + "" + _rpmUnit + ") ";
tooltip.add(spacing + GRAY + _speedGaugeTitle); tooltip.add(spacing + GRAY + _speedGaugeTitle);
tooltip.add(spacing + level); tooltip.add(spacing + level);

View file

@ -44,4 +44,12 @@ public class StressGaugeTileEntity extends GaugeTileEntity {
sync(maxStress, currentStress); sync(maxStress, currentStress);
} }
public float getNetworkStress() {
return currentStress;
}
public float getNetworkCapacity() {
return maxStress;
}
} }

View file

@ -1,9 +1,9 @@
package com.simibubi.create.modules.contraptions.relays.gearbox; package com.simibubi.create.modules.contraptions.relays.gearbox;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.relays.encased.DirectionalShaftHalvesTileEntity;
public class GearboxTileEntity extends KineticTileEntity { public class GearboxTileEntity extends DirectionalShaftHalvesTileEntity {
public GearboxTileEntity() { public GearboxTileEntity() {
super(AllTileEntities.GEARBOX.type); super(AllTileEntities.GEARBOX.type);