Handle speeding nodes

This commit is contained in:
reidbhuntley 2021-12-28 20:44:09 -05:00
parent 1c8f9232b7
commit 28a8358b22
6 changed files with 238 additions and 193 deletions

View file

@ -67,7 +67,7 @@ public class KineticNetwork {
sources.put(te, te.calculateAddedStressCapacity()); sources.put(te, te.calculateAddedStressCapacity());
members.put(te, te.calculateStressApplied()); members.put(te, te.calculateStressApplied());
updateFromNetwork(te); updateFromNetwork(te);
te.networkDirty = true; //te.networkDirty = true;
} }
public void updateCapacityFor(KineticTileEntity te, float capacity) { public void updateCapacityFor(KineticTileEntity te, float capacity) {
@ -94,10 +94,10 @@ public class KineticNetwork {
return; return;
} }
members.keySet() // members.keySet()
.stream() // .stream()
.findFirst() // .findFirst()
.map(member -> member.networkDirty = true); // .map(member -> member.networkDirty = true);
} }
public void sync() { public void sync() {

View file

@ -31,7 +31,7 @@ public abstract class KineticBlock extends Block implements IRotate {
BlockEntity tileEntity = worldIn.getBlockEntity(pos); BlockEntity tileEntity = worldIn.getBlockEntity(pos);
if (tileEntity instanceof KineticTileEntity) { if (tileEntity instanceof KineticTileEntity) {
KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity; KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity;
kineticTileEntity.preventSpeedUpdate = 0; //kineticTileEntity.preventSpeedUpdate = 0;
if (oldState.getBlock() != state.getBlock()) if (oldState.getBlock() != state.getBlock())
return; return;
@ -40,7 +40,7 @@ public abstract class KineticBlock extends Block implements IRotate {
if (!areStatesKineticallyEquivalent(oldState, state)) if (!areStatesKineticallyEquivalent(oldState, state))
return; return;
kineticTileEntity.preventSpeedUpdate = 2; //kineticTileEntity.preventSpeedUpdate = 2;
} }
} }
@ -65,15 +65,15 @@ public abstract class KineticBlock extends Block implements IRotate {
return; return;
KineticTileEntity kte = (KineticTileEntity) tileEntity; KineticTileEntity kte = (KineticTileEntity) tileEntity;
if (kte.preventSpeedUpdate > 0) { // if (kte.preventSpeedUpdate > 0) {
kte.preventSpeedUpdate--; // kte.preventSpeedUpdate--;
return; // return;
} // }
// Remove previous information when block is added // Remove previous information when block is added
kte.warnOfMovement(); kte.warnOfMovement();
kte.clearKineticInformation(); kte.clearKineticInformation();
kte.updateSpeed = true; // kte.updateSpeed = true;
} }
@Override @Override

View file

@ -54,11 +54,8 @@ import net.minecraftforge.fml.DistExecutor;
public class KineticTileEntity extends SmartTileEntity public class KineticTileEntity extends SmartTileEntity
implements IHaveGoggleInformation, IHaveHoveringInformation, FlywheelRendered { implements IHaveGoggleInformation, IHaveHoveringInformation, FlywheelRendered {
public @Nullable Long network; public @Nullable Long network = null;
public @Nullable BlockPos source; public @Nullable BlockPos source = null;
public boolean networkDirty;
public boolean updateSpeed;
public int preventSpeedUpdate;
protected KineticEffectHandler effects; protected KineticEffectHandler effects;
protected float speed; protected float speed;
@ -96,18 +93,10 @@ public class KineticTileEntity extends SmartTileEntity
public KineticTileEntity(BlockEntityType<?> typeIn, BlockPos pos, BlockState state) { public KineticTileEntity(BlockEntityType<?> typeIn, BlockPos pos, BlockState state) {
super(typeIn, pos, state); super(typeIn, pos, state);
effects = new KineticEffectHandler(this); effects = new KineticEffectHandler(this);
updateSpeed = true;
} }
@Override @Override
public void initialize() { public void initialize() {
if (hasNetwork() && !level.isClientSide) {
KineticNetwork network = getOrCreateNetwork();
if (!network.initialized)
network.initFromTE(capacity, stress, networkSize);
network.addSilently(this, lastCapacityProvided, lastStressApplied);
}
if (!level.isClientSide) { if (!level.isClientSide) {
addToSolver(); addToSolver();
} }
@ -117,9 +106,6 @@ public class KineticTileEntity extends SmartTileEntity
@Override @Override
public void tick() { public void tick() {
if (!level.isClientSide && needsSpeedUpdate())
attachKinetics();
super.tick(); super.tick();
effects.tick(); effects.tick();
@ -140,55 +126,49 @@ public class KineticTileEntity extends SmartTileEntity
if (getFlickerScore() > 0) if (getFlickerScore() > 0)
flickerTally = getFlickerScore() - 1; flickerTally = getFlickerScore() - 1;
if (networkDirty) {
if (hasNetwork())
getOrCreateNetwork().updateNetwork();
networkDirty = false;
}
} }
private void validateKinetics() { private void validateKinetics() {
if (hasSource()) { // if (hasSource()) {
if (!hasNetwork()) { // if (!hasNetwork()) {
removeSource(); // removeSource();
return; // return;
} // }
//
if (!level.isLoaded(source)) // if (!level.isLoaded(source))
return; // return;
//
BlockEntity tileEntity = level.getBlockEntity(source); // BlockEntity tileEntity = level.getBlockEntity(source);
KineticTileEntity sourceTe = // KineticTileEntity sourceTe =
tileEntity instanceof KineticTileEntity ? (KineticTileEntity) tileEntity : null; // tileEntity instanceof KineticTileEntity ? (KineticTileEntity) tileEntity : null;
if (sourceTe == null || sourceTe.speed == 0) { // if (sourceTe == null || sourceTe.speed == 0) {
removeSource(); // removeSource();
detachKinetics(); // detachKinetics();
return; // return;
} // }
//
return; // return;
} // }
//
if (speed != 0) { // if (speed != 0) {
if (getGeneratedSpeed() == 0) // if (getGeneratedSpeed() == 0)
speed = 0; // speed = 0;
} // }
} }
public void updateFromNetwork(float maxStress, float currentStress, int networkSize) { public void updateFromNetwork(float maxStress, float currentStress, int networkSize) {
networkDirty = false; // networkDirty = false;
this.capacity = maxStress; // this.capacity = maxStress;
this.stress = currentStress; // this.stress = currentStress;
this.networkSize = networkSize; // this.networkSize = networkSize;
boolean overStressed = maxStress < currentStress && StressImpact.isEnabled(); // boolean overStressed = maxStress < currentStress && StressImpact.isEnabled();
//
if (overStressed != this.overStressed) { // if (overStressed != this.overStressed) {
float prevSpeed = getSpeed(); // float prevSpeed = getSpeed();
this.overStressed = overStressed; // this.overStressed = overStressed;
onSpeedChanged(prevSpeed); // onSpeedChanged(prevSpeed);
sendData(); // sendData();
} // }
} }
protected Block getStressConfigKey() { protected Block getStressConfigKey() {
@ -222,9 +202,6 @@ public class KineticTileEntity extends SmartTileEntity
@Override @Override
protected void setRemovedNotDueToChunkUnload() { protected void setRemovedNotDueToChunkUnload() {
if (!level.isClientSide) { if (!level.isClientSide) {
if (hasNetwork())
getOrCreateNetwork().remove(this);
detachKinetics();
removeFromSolver(); removeFromSolver();
} }
super.setRemovedNotDueToChunkUnload(); super.setRemovedNotDueToChunkUnload();
@ -234,33 +211,33 @@ public class KineticTileEntity extends SmartTileEntity
protected void write(CompoundTag compound, boolean clientPacket) { protected void write(CompoundTag compound, boolean clientPacket) {
compound.putFloat("Speed", speed); compound.putFloat("Speed", speed);
if (needsSpeedUpdate()) // if (needsSpeedUpdate())
compound.putBoolean("NeedsSpeedUpdate", true); // compound.putBoolean("NeedsSpeedUpdate", true);
//
// if (hasSource())
// compound.put("Source", NbtUtils.writeBlockPos(source));
if (hasSource()) // if (hasNetwork()) {
compound.put("Source", NbtUtils.writeBlockPos(source)); // CompoundTag networkTag = new CompoundTag();
// //networkTag.putLong("Id", this.network);
if (hasNetwork()) { // networkTag.putFloat("Stress", stress);
CompoundTag networkTag = new CompoundTag(); // networkTag.putFloat("Capacity", capacity);
networkTag.putLong("Id", this.network); // networkTag.putInt("Size", networkSize);
networkTag.putFloat("Stress", stress); //
networkTag.putFloat("Capacity", capacity); // if (lastStressApplied != 0)
networkTag.putInt("Size", networkSize); // networkTag.putFloat("AddedStress", lastStressApplied);
// if (lastCapacityProvided != 0)
if (lastStressApplied != 0) // networkTag.putFloat("AddedCapacity", lastCapacityProvided);
networkTag.putFloat("AddedStress", lastStressApplied); //
if (lastCapacityProvided != 0) // compound.put("Network", networkTag);
networkTag.putFloat("AddedCapacity", lastCapacityProvided); // }
compound.put("Network", networkTag);
}
super.write(compound, clientPacket); super.write(compound, clientPacket);
} }
public boolean needsSpeedUpdate() { // public boolean needsSpeedUpdate() {
return updateSpeed; // return updateSpeed;
} // }
@Override @Override
protected void read(CompoundTag compound, boolean clientPacket) { protected void read(CompoundTag compound, boolean clientPacket) {
@ -275,19 +252,19 @@ public class KineticTileEntity extends SmartTileEntity
speed = compound.getFloat("Speed"); speed = compound.getFloat("Speed");
if (compound.contains("Source")) // if (compound.contains("Source"))
source = NbtUtils.readBlockPos(compound.getCompound("Source")); // source = NbtUtils.readBlockPos(compound.getCompound("Source"));
if (compound.contains("Network")) { // if (compound.contains("Network")) {
CompoundTag networkTag = compound.getCompound("Network"); // CompoundTag networkTag = compound.getCompound("Network");
network = networkTag.getLong("Id"); // network = networkTag.getLong("Id");
stress = networkTag.getFloat("Stress"); // stress = networkTag.getFloat("Stress");
capacity = networkTag.getFloat("Capacity"); // capacity = networkTag.getFloat("Capacity");
networkSize = networkTag.getInt("Size"); // networkSize = networkTag.getInt("Size");
lastStressApplied = networkTag.getFloat("AddedStress"); // lastStressApplied = networkTag.getFloat("AddedStress");
lastCapacityProvided = networkTag.getFloat("AddedCapacity"); // lastCapacityProvided = networkTag.getFloat("AddedCapacity");
overStressed = capacity < stress && StressImpact.isEnabled(); // overStressed = capacity < stress && StressImpact.isEnabled();
} // }
super.read(compound, clientPacket); super.read(compound, clientPacket);
@ -325,45 +302,45 @@ public class KineticTileEntity extends SmartTileEntity
} }
public void setSource(BlockPos source) { public void setSource(BlockPos source) {
this.source = source; // this.source = source;
if (level == null || level.isClientSide) // if (level == null || level.isClientSide)
return; // return;
//
BlockEntity tileEntity = level.getBlockEntity(source); // BlockEntity tileEntity = level.getBlockEntity(source);
if (!(tileEntity instanceof KineticTileEntity)) { // if (!(tileEntity instanceof KineticTileEntity)) {
removeSource(); // removeSource();
return; // return;
} // }
//
KineticTileEntity sourceTe = (KineticTileEntity) tileEntity; // KineticTileEntity sourceTe = (KineticTileEntity) tileEntity;
setNetwork(sourceTe.network); // setNetwork(sourceTe.network);
} }
public void removeSource() { public void removeSource() {
float prevSpeed = getSpeed(); // float prevSpeed = getSpeed();
//
speed = 0; // speed = 0;
source = null; // source = null;
setNetwork(null); // setNetwork(null);
//
onSpeedChanged(prevSpeed); // onSpeedChanged(prevSpeed);
} }
public void setNetwork(@Nullable Long networkIn) { public void setNetwork(@Nullable Long networkIn) {
if (network == networkIn) // if (network == networkIn)
return; // return;
if (network != null) // if (network != null)
getOrCreateNetwork().remove(this); // getOrCreateNetwork().remove(this);
//
network = networkIn; // network = networkIn;
//
if (networkIn == null) // if (networkIn == null)
return; // return;
//
network = networkIn; // network = networkIn;
KineticNetwork network = getOrCreateNetwork(); // KineticNetwork network = getOrCreateNetwork();
network.initialized = true; // network.initialized = true;
network.add(this); // network.add(this);
} }
public KineticNetwork getOrCreateNetwork() { public KineticNetwork getOrCreateNetwork() {
@ -375,12 +352,12 @@ public class KineticTileEntity extends SmartTileEntity
} }
public void attachKinetics() { public void attachKinetics() {
updateSpeed = false; //updateSpeed = false;
RotationPropagator.handleAdded(level, worldPosition, this); //RotationPropagator.handleAdded(level, worldPosition, this);
} }
public void detachKinetics() { public void detachKinetics() {
RotationPropagator.handleRemoved(level, worldPosition, this); //RotationPropagator.handleRemoved(level, worldPosition, this);
} }
public boolean isSpeedRequirementFulfilled() { public boolean isSpeedRequirementFulfilled() {
@ -413,15 +390,15 @@ public class KineticTileEntity extends SmartTileEntity
return; return;
} }
KineticTileEntity tileEntity = (KineticTileEntity) tileEntityIn; // KineticTileEntity tileEntity = (KineticTileEntity) tileEntityIn;
if (state.getBlock() instanceof KineticBlock // if (state.getBlock() instanceof KineticBlock
&& !((KineticBlock) state.getBlock()).areStatesKineticallyEquivalent(currentState, state)) { // && !((KineticBlock) state.getBlock()).areStatesKineticallyEquivalent(currentState, state)) {
if (tileEntity.hasNetwork()) // if (tileEntity.hasNetwork())
tileEntity.getOrCreateNetwork() // tileEntity.getOrCreateNetwork()
.remove(tileEntity); // .remove(tileEntity);
tileEntity.detachKinetics(); // tileEntity.detachKinetics();
tileEntity.removeSource(); // tileEntity.removeSource();
} // }
world.setBlock(pos, state, 3); world.setBlock(pos, state, 3);
} }
@ -492,8 +469,6 @@ public class KineticTileEntity extends SmartTileEntity
public void clearKineticInformation() { public void clearKineticInformation() {
speed = 0; speed = 0;
source = null;
network = null;
overStressed = false; overStressed = false;
stress = 0; stress = 0;
capacity = 0; capacity = 0;

View file

@ -2,7 +2,13 @@ package com.simibubi.create.content.contraptions.solver;
import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.Pair;
import net.minecraft.util.Mth;
import javax.annotation.Nullable;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set; import java.util.Set;
public class KineticNetwork { public class KineticNetwork {
@ -11,19 +17,16 @@ public class KineticNetwork {
private final Set<KineticNode> generators = new HashSet<>(); private final Set<KineticNode> generators = new HashSet<>();
private final Set<Pair<KineticNode, KineticNode>> conflictingCycles = new HashSet<>(); private final Set<Pair<KineticNode, KineticNode>> conflictingCycles = new HashSet<>();
private float rootSpeed; private float rootSpeed;
private boolean speedDirty;
public KineticNetwork(KineticNode root) { public KineticNetwork(KineticNode root) {
addMember(root); addMember(root);
rootSpeed = root.getGeneratedSpeed(); rootSpeed = root.getGeneratedSpeed();
speedDirty = false;
} }
public void addMember(KineticNode node) { public void addMember(KineticNode node) {
members.add(node); members.add(node);
if (node.isGenerator() && !generators.contains(node)) { if (node.isGenerator()) {
generators.add(node); generators.add(node);
speedDirty = true;
} }
} }
@ -34,14 +37,12 @@ public class KineticNetwork {
} else { } else {
generators.remove(node); generators.remove(node);
} }
speedDirty = true;
} }
public void removeMember(KineticNode node) { public void removeMember(KineticNode node) {
members.remove(node); members.remove(node);
if (node.isGenerator() && generators.contains(node)) { if (node.isGenerator()) {
generators.remove(node); generators.remove(node);
speedDirty = true;
} }
conflictingCycles.removeIf(p -> p.getFirst() == node || p.getSecond() == node); conflictingCycles.removeIf(p -> p.getFirst() == node || p.getSecond() == node);
} }
@ -55,34 +56,70 @@ public class KineticNetwork {
return rootSpeed; return rootSpeed;
} }
public SolveResult recalculateSpeed() { /**
if (!conflictingCycles.isEmpty() && !generators.isEmpty()) return SolveResult.CONTRADICTION; * Recalculates the speed at the root of this network, and if it has changed, recalculates the speed of all
if (!speedDirty) return SolveResult.OK; * KineticNodes in the network and pops any nodes whose speed has increased above the speed limit.
* @param checkRoot Node to start performing a breadth-first from in order to find and pop speeding nodes. If null,
* speeding nodes are ignored.
* @param forced If true, will check for speeding nodes from checkRoot even if the root speed has not changed.
* @return CONTRADICTION if the network currently has a cycle with conflicting speed ratios or
* has generators turning against each other, and OK otherwise.
*/
public SolveResult recalculateSpeed(@Nullable KineticNode checkRoot, boolean forced) {
if (!conflictingCycles.isEmpty() && !generators.isEmpty()) {
// cycle with conflicting speed ratios is present
return SolveResult.CONTRADICTION;
}
// find the generator that would maximize the root speed
float newSpeed = 0; float newSpeed = 0;
float sign = 0; float sign = 0;
for (KineticNode generator : generators) { for (KineticNode generator : generators) {
float speedAtRoot = generator.getGeneratedSpeedAtRoot(); float speedAtRoot = generator.getGeneratedSpeedAtRoot();
if (newSpeed == 0) { if (newSpeed == 0) {
sign = Math.signum(speedAtRoot); sign = Math.signum(speedAtRoot);
newSpeed = sign * speedAtRoot; } else if (Math.signum(speedAtRoot) != sign) {
} else { // generators are turning against each other
if (Math.signum(speedAtRoot) != sign)
return SolveResult.CONTRADICTION; return SolveResult.CONTRADICTION;
newSpeed = Math.max(newSpeed, sign * speedAtRoot);
} }
newSpeed = Math.max(newSpeed, sign * speedAtRoot);
} }
newSpeed *= sign; newSpeed *= sign;
if (rootSpeed != newSpeed) { if (!Mth.equal(rootSpeed, newSpeed)) {
rootSpeed = newSpeed; rootSpeed = newSpeed;
for (KineticNode member : members) {
member.onSpeedUpdated(); if (checkRoot == null) {
members.forEach(KineticNode::tryUpdateSpeed);
} else {
updateNodeSpeeds(checkRoot, false);
} }
} else if (forced) {
updateNodeSpeeds(checkRoot, true);
} }
speedDirty = false;
return SolveResult.OK; return SolveResult.OK;
} }
private void updateNodeSpeeds(KineticNode root, boolean followSources) {
Set<KineticNode> visited = new HashSet<>();
List<KineticNode> frontier = new LinkedList<>();
frontier.add(root);
// update node speeds in a breadth-first order, starting at root
while (!frontier.isEmpty()) {
KineticNode cur = frontier.remove(0);
visited.add(cur);
if (cur.tryUpdateSpeed().isOk()) {
for (KineticNode next : cur.getActiveConnections().keySet()) {
if (!(visited.contains(next) || (followSources && !cur.isSourceOf(next))))
frontier.add(next);
}
} else {
// stop searching on this branch once a speeding node is found
cur.onPopBlock();
}
}
}
} }

View file

@ -1,9 +1,11 @@
package com.simibubi.create.content.contraptions.solver; package com.simibubi.create.content.contraptions.solver;
import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.Pair;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -38,13 +40,16 @@ public class KineticNode {
this.generatedSpeed = state.getGeneratedSpeed(); this.generatedSpeed = state.getGeneratedSpeed();
this.network = new KineticNetwork(this); this.network = new KineticNetwork(this);
onSpeedUpdated();
} }
public KineticConnections getConnections() { public KineticConnections getConnections() {
return connections; return connections;
} }
/**
* @return a map where the keys are every node with a compatible connection to this node, and the values are the
* speed ratios of those connections
*/
public Map<KineticNode, Float> getActiveConnections() { public Map<KineticNode, Float> getActiveConnections() {
return connections.getDirections().stream() return connections.getDirections().stream()
.map(d -> nodeAccessor.apply(entity.getBlockPos().offset(d)) .map(d -> nodeAccessor.apply(entity.getBlockPos().offset(d))
@ -68,9 +73,10 @@ public class KineticNode {
} }
public void setGeneratedSpeed(float newSpeed) { public void setGeneratedSpeed(float newSpeed) {
if (Mth.equal(generatedSpeed, newSpeed)) return;
generatedSpeed = newSpeed; generatedSpeed = newSpeed;
network.updateMember(this); network.updateMember(this);
if (network.recalculateSpeed().isContradiction()) if (network.recalculateSpeed(this, false).isContradiction())
onPopBlock(); onPopBlock();
} }
@ -78,7 +84,6 @@ public class KineticNode {
this.network.removeMember(this); this.network.removeMember(this);
this.network = network; this.network = network;
network.addMember(this); network.addMember(this);
onSpeedUpdated();
} }
private void setSource(KineticNode from, float ratio) { private void setSource(KineticNode from, float ratio) {
@ -93,21 +98,18 @@ public class KineticNode {
.stream() .stream()
.findAny() .findAny()
.ifPresent(n -> { .ifPresent(n -> {
if (n.propagateSource().isContradiction()) if (n.propagateSource(this).isContradiction())
onPopBlock(); onPopBlock();
}); });
} }
public void onRemoved() { /**
network.removeMember(this); * Propagates this node's source and network to any connected nodes that aren't yet part of the same network, then
for (KineticNode neighbor : getActiveConnections().keySet()) { * repeats this recursively with the connected nodes in a breadth-first order.
if (neighbor.source != this) continue; * @param checkRoot Node to start searching from when looking for nodes that started speeding because of this call
neighbor.rerootHere(); * @return whether or not this propagation caused a contradiction in the kinetic network
} */
network.recalculateSpeed(); private SolveResult propagateSource(KineticNode checkRoot) {
}
private SolveResult propagateSource() {
List<KineticNode> frontier = new LinkedList<>(); List<KineticNode> frontier = new LinkedList<>();
frontier.add(this); frontier.add(this);
@ -116,30 +118,53 @@ public class KineticNode {
for (Map.Entry<KineticNode, Float> entry : cur.getActiveConnections().entrySet()) { for (Map.Entry<KineticNode, Float> entry : cur.getActiveConnections().entrySet()) {
KineticNode next = entry.getKey(); KineticNode next = entry.getKey();
float ratio = entry.getValue(); float ratio = entry.getValue();
if (next == cur.source) continue; if (next == cur.source) continue;
if (next.network == network) { if (next.network == network) {
if (next.speedRatio != cur.speedRatio * ratio) { if (!Mth.equal(next.speedRatio, cur.speedRatio * ratio)) {
// we found a cycle with conflicting speed ratios
network.markConflictingCycle(cur, next); network.markConflictingCycle(cur, next);
} }
continue; continue;
} }
next.setSource(cur, ratio); next.setSource(cur, ratio);
frontier.add(next); frontier.add(next);
} }
} }
return network.recalculateSpeed(); return network.recalculateSpeed(checkRoot, true);
}
public void onRemoved() {
network.removeMember(this);
for (KineticNode neighbor : getActiveConnections().keySet()) {
if (neighbor.source != this) continue;
neighbor.rerootHere();
}
network.recalculateSpeed(null, false);
} }
private void rerootHere() { private void rerootHere() {
source = null; source = null;
speedRatio = 1; speedRatio = 1;
setNetwork(new KineticNetwork(this)); setNetwork(new KineticNetwork(this));
propagateSource(); if (tryUpdateSpeed().isOk()) {
propagateSource(this);
} else {
onPopBlock();
}
} }
public void onSpeedUpdated() { /**
* 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 = network.getRootSpeed() * speedRatio; speedNext = network.getRootSpeed() * speedRatio;
if (Math.abs(speedNext) > AllConfigs.SERVER.kinetics.maxRotationSpeed.get())
return SolveResult.CONTRADICTION;
return SolveResult.OK;
} }
public void flushChangedSpeed() { public void flushChangedSpeed() {
@ -155,4 +180,8 @@ public class KineticNode {
entity.getLevel().destroyBlock(entity.getBlockPos(), true); entity.getLevel().destroyBlock(entity.getBlockPos(), true);
} }
public boolean isSourceOf(KineticNode other) {
return other.source == this;
}
} }

View file

@ -24,7 +24,11 @@ public class KineticSolver {
removeNode(entity); removeNode(entity);
KineticNode node = new KineticNode(entity, this::getNode); KineticNode node = new KineticNode(entity, this::getNode);
nodes.put(entity.getBlockPos(), node); nodes.put(entity.getBlockPos(), node);
if (node.tryUpdateSpeed().isOk()) {
node.onAdded(); node.onAdded();
} else {
node.onPopBlock();
}
} }
public void updateNode(KineticTileEntity entity) { public void updateNode(KineticTileEntity entity) {