mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-01-11 23:07:13 +01:00
Handle speeding nodes
This commit is contained in:
parent
1c8f9232b7
commit
28a8358b22
6 changed files with 238 additions and 193 deletions
|
@ -67,7 +67,7 @@ public class KineticNetwork {
|
|||
sources.put(te, te.calculateAddedStressCapacity());
|
||||
members.put(te, te.calculateStressApplied());
|
||||
updateFromNetwork(te);
|
||||
te.networkDirty = true;
|
||||
//te.networkDirty = true;
|
||||
}
|
||||
|
||||
public void updateCapacityFor(KineticTileEntity te, float capacity) {
|
||||
|
@ -94,10 +94,10 @@ public class KineticNetwork {
|
|||
return;
|
||||
}
|
||||
|
||||
members.keySet()
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(member -> member.networkDirty = true);
|
||||
// members.keySet()
|
||||
// .stream()
|
||||
// .findFirst()
|
||||
// .map(member -> member.networkDirty = true);
|
||||
}
|
||||
|
||||
public void sync() {
|
||||
|
|
|
@ -31,7 +31,7 @@ public abstract class KineticBlock extends Block implements IRotate {
|
|||
BlockEntity tileEntity = worldIn.getBlockEntity(pos);
|
||||
if (tileEntity instanceof KineticTileEntity) {
|
||||
KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity;
|
||||
kineticTileEntity.preventSpeedUpdate = 0;
|
||||
//kineticTileEntity.preventSpeedUpdate = 0;
|
||||
|
||||
if (oldState.getBlock() != state.getBlock())
|
||||
return;
|
||||
|
@ -40,7 +40,7 @@ public abstract class KineticBlock extends Block implements IRotate {
|
|||
if (!areStatesKineticallyEquivalent(oldState, state))
|
||||
return;
|
||||
|
||||
kineticTileEntity.preventSpeedUpdate = 2;
|
||||
//kineticTileEntity.preventSpeedUpdate = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,15 +65,15 @@ public abstract class KineticBlock extends Block implements IRotate {
|
|||
return;
|
||||
KineticTileEntity kte = (KineticTileEntity) tileEntity;
|
||||
|
||||
if (kte.preventSpeedUpdate > 0) {
|
||||
kte.preventSpeedUpdate--;
|
||||
return;
|
||||
}
|
||||
// if (kte.preventSpeedUpdate > 0) {
|
||||
// kte.preventSpeedUpdate--;
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Remove previous information when block is added
|
||||
kte.warnOfMovement();
|
||||
kte.clearKineticInformation();
|
||||
kte.updateSpeed = true;
|
||||
// kte.updateSpeed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,11 +54,8 @@ import net.minecraftforge.fml.DistExecutor;
|
|||
public class KineticTileEntity extends SmartTileEntity
|
||||
implements IHaveGoggleInformation, IHaveHoveringInformation, FlywheelRendered {
|
||||
|
||||
public @Nullable Long network;
|
||||
public @Nullable BlockPos source;
|
||||
public boolean networkDirty;
|
||||
public boolean updateSpeed;
|
||||
public int preventSpeedUpdate;
|
||||
public @Nullable Long network = null;
|
||||
public @Nullable BlockPos source = null;
|
||||
|
||||
protected KineticEffectHandler effects;
|
||||
protected float speed;
|
||||
|
@ -96,18 +93,10 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
public KineticTileEntity(BlockEntityType<?> typeIn, BlockPos pos, BlockState state) {
|
||||
super(typeIn, pos, state);
|
||||
effects = new KineticEffectHandler(this);
|
||||
updateSpeed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
addToSolver();
|
||||
}
|
||||
|
@ -117,9 +106,6 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (!level.isClientSide && needsSpeedUpdate())
|
||||
attachKinetics();
|
||||
|
||||
super.tick();
|
||||
effects.tick();
|
||||
|
||||
|
@ -140,55 +126,49 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
|
||||
if (getFlickerScore() > 0)
|
||||
flickerTally = getFlickerScore() - 1;
|
||||
|
||||
if (networkDirty) {
|
||||
if (hasNetwork())
|
||||
getOrCreateNetwork().updateNetwork();
|
||||
networkDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateKinetics() {
|
||||
if (hasSource()) {
|
||||
if (!hasNetwork()) {
|
||||
removeSource();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!level.isLoaded(source))
|
||||
return;
|
||||
|
||||
BlockEntity tileEntity = level.getBlockEntity(source);
|
||||
KineticTileEntity sourceTe =
|
||||
tileEntity instanceof KineticTileEntity ? (KineticTileEntity) tileEntity : null;
|
||||
if (sourceTe == null || sourceTe.speed == 0) {
|
||||
removeSource();
|
||||
detachKinetics();
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (speed != 0) {
|
||||
if (getGeneratedSpeed() == 0)
|
||||
speed = 0;
|
||||
}
|
||||
// if (hasSource()) {
|
||||
// if (!hasNetwork()) {
|
||||
// removeSource();
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (!level.isLoaded(source))
|
||||
// return;
|
||||
//
|
||||
// BlockEntity tileEntity = level.getBlockEntity(source);
|
||||
// KineticTileEntity sourceTe =
|
||||
// tileEntity instanceof KineticTileEntity ? (KineticTileEntity) tileEntity : null;
|
||||
// if (sourceTe == null || sourceTe.speed == 0) {
|
||||
// removeSource();
|
||||
// detachKinetics();
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (speed != 0) {
|
||||
// if (getGeneratedSpeed() == 0)
|
||||
// speed = 0;
|
||||
// }
|
||||
}
|
||||
|
||||
public void updateFromNetwork(float maxStress, float currentStress, int networkSize) {
|
||||
networkDirty = false;
|
||||
this.capacity = maxStress;
|
||||
this.stress = currentStress;
|
||||
this.networkSize = networkSize;
|
||||
boolean overStressed = maxStress < currentStress && StressImpact.isEnabled();
|
||||
|
||||
if (overStressed != this.overStressed) {
|
||||
float prevSpeed = getSpeed();
|
||||
this.overStressed = overStressed;
|
||||
onSpeedChanged(prevSpeed);
|
||||
sendData();
|
||||
}
|
||||
// networkDirty = false;
|
||||
// this.capacity = maxStress;
|
||||
// this.stress = currentStress;
|
||||
// this.networkSize = networkSize;
|
||||
// boolean overStressed = maxStress < currentStress && StressImpact.isEnabled();
|
||||
//
|
||||
// if (overStressed != this.overStressed) {
|
||||
// float prevSpeed = getSpeed();
|
||||
// this.overStressed = overStressed;
|
||||
// onSpeedChanged(prevSpeed);
|
||||
// sendData();
|
||||
// }
|
||||
}
|
||||
|
||||
protected Block getStressConfigKey() {
|
||||
|
@ -222,9 +202,6 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
@Override
|
||||
protected void setRemovedNotDueToChunkUnload() {
|
||||
if (!level.isClientSide) {
|
||||
if (hasNetwork())
|
||||
getOrCreateNetwork().remove(this);
|
||||
detachKinetics();
|
||||
removeFromSolver();
|
||||
}
|
||||
super.setRemovedNotDueToChunkUnload();
|
||||
|
@ -234,33 +211,33 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
protected void write(CompoundTag compound, boolean clientPacket) {
|
||||
compound.putFloat("Speed", speed);
|
||||
|
||||
if (needsSpeedUpdate())
|
||||
compound.putBoolean("NeedsSpeedUpdate", true);
|
||||
// if (needsSpeedUpdate())
|
||||
// compound.putBoolean("NeedsSpeedUpdate", true);
|
||||
//
|
||||
// if (hasSource())
|
||||
// compound.put("Source", NbtUtils.writeBlockPos(source));
|
||||
|
||||
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 (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);
|
||||
// }
|
||||
|
||||
super.write(compound, clientPacket);
|
||||
}
|
||||
|
||||
public boolean needsSpeedUpdate() {
|
||||
return updateSpeed;
|
||||
}
|
||||
// public boolean needsSpeedUpdate() {
|
||||
// return updateSpeed;
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected void read(CompoundTag compound, boolean clientPacket) {
|
||||
|
@ -275,19 +252,19 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
|
||||
speed = compound.getFloat("Speed");
|
||||
|
||||
if (compound.contains("Source"))
|
||||
source = NbtUtils.readBlockPos(compound.getCompound("Source"));
|
||||
// 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();
|
||||
}
|
||||
// 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();
|
||||
// }
|
||||
|
||||
super.read(compound, clientPacket);
|
||||
|
||||
|
@ -325,45 +302,45 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
}
|
||||
|
||||
public void setSource(BlockPos source) {
|
||||
this.source = source;
|
||||
if (level == null || level.isClientSide)
|
||||
return;
|
||||
|
||||
BlockEntity tileEntity = level.getBlockEntity(source);
|
||||
if (!(tileEntity instanceof KineticTileEntity)) {
|
||||
removeSource();
|
||||
return;
|
||||
}
|
||||
|
||||
KineticTileEntity sourceTe = (KineticTileEntity) tileEntity;
|
||||
setNetwork(sourceTe.network);
|
||||
// this.source = source;
|
||||
// if (level == null || level.isClientSide)
|
||||
// return;
|
||||
//
|
||||
// BlockEntity tileEntity = level.getBlockEntity(source);
|
||||
// if (!(tileEntity instanceof KineticTileEntity)) {
|
||||
// removeSource();
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// KineticTileEntity sourceTe = (KineticTileEntity) tileEntity;
|
||||
// setNetwork(sourceTe.network);
|
||||
}
|
||||
|
||||
public void removeSource() {
|
||||
float prevSpeed = getSpeed();
|
||||
|
||||
speed = 0;
|
||||
source = null;
|
||||
setNetwork(null);
|
||||
|
||||
onSpeedChanged(prevSpeed);
|
||||
// float prevSpeed = getSpeed();
|
||||
//
|
||||
// speed = 0;
|
||||
// source = null;
|
||||
// setNetwork(null);
|
||||
//
|
||||
// onSpeedChanged(prevSpeed);
|
||||
}
|
||||
|
||||
public void setNetwork(@Nullable Long networkIn) {
|
||||
if (network == networkIn)
|
||||
return;
|
||||
if (network != null)
|
||||
getOrCreateNetwork().remove(this);
|
||||
|
||||
network = networkIn;
|
||||
|
||||
if (networkIn == null)
|
||||
return;
|
||||
|
||||
network = networkIn;
|
||||
KineticNetwork network = getOrCreateNetwork();
|
||||
network.initialized = true;
|
||||
network.add(this);
|
||||
// if (network == networkIn)
|
||||
// return;
|
||||
// if (network != null)
|
||||
// getOrCreateNetwork().remove(this);
|
||||
//
|
||||
// network = networkIn;
|
||||
//
|
||||
// if (networkIn == null)
|
||||
// return;
|
||||
//
|
||||
// network = networkIn;
|
||||
// KineticNetwork network = getOrCreateNetwork();
|
||||
// network.initialized = true;
|
||||
// network.add(this);
|
||||
}
|
||||
|
||||
public KineticNetwork getOrCreateNetwork() {
|
||||
|
@ -375,12 +352,12 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
}
|
||||
|
||||
public void attachKinetics() {
|
||||
updateSpeed = false;
|
||||
RotationPropagator.handleAdded(level, worldPosition, this);
|
||||
//updateSpeed = false;
|
||||
//RotationPropagator.handleAdded(level, worldPosition, this);
|
||||
}
|
||||
|
||||
public void detachKinetics() {
|
||||
RotationPropagator.handleRemoved(level, worldPosition, this);
|
||||
//RotationPropagator.handleRemoved(level, worldPosition, this);
|
||||
}
|
||||
|
||||
public boolean isSpeedRequirementFulfilled() {
|
||||
|
@ -413,15 +390,15 @@ 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();
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
@ -492,8 +469,6 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
|
||||
public void clearKineticInformation() {
|
||||
speed = 0;
|
||||
source = null;
|
||||
network = null;
|
||||
overStressed = false;
|
||||
stress = 0;
|
||||
capacity = 0;
|
||||
|
|
|
@ -2,7 +2,13 @@ package com.simibubi.create.content.contraptions.solver;
|
|||
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class KineticNetwork {
|
||||
|
@ -11,19 +17,16 @@ public class KineticNetwork {
|
|||
private final Set<KineticNode> generators = new HashSet<>();
|
||||
private final Set<Pair<KineticNode, KineticNode>> conflictingCycles = new HashSet<>();
|
||||
private float rootSpeed;
|
||||
private boolean speedDirty;
|
||||
|
||||
public KineticNetwork(KineticNode root) {
|
||||
addMember(root);
|
||||
rootSpeed = root.getGeneratedSpeed();
|
||||
speedDirty = false;
|
||||
}
|
||||
|
||||
public void addMember(KineticNode node) {
|
||||
members.add(node);
|
||||
if (node.isGenerator() && !generators.contains(node)) {
|
||||
if (node.isGenerator()) {
|
||||
generators.add(node);
|
||||
speedDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,14 +37,12 @@ public class KineticNetwork {
|
|||
} else {
|
||||
generators.remove(node);
|
||||
}
|
||||
speedDirty = true;
|
||||
}
|
||||
|
||||
public void removeMember(KineticNode node) {
|
||||
members.remove(node);
|
||||
if (node.isGenerator() && generators.contains(node)) {
|
||||
if (node.isGenerator()) {
|
||||
generators.remove(node);
|
||||
speedDirty = true;
|
||||
}
|
||||
conflictingCycles.removeIf(p -> p.getFirst() == node || p.getSecond() == node);
|
||||
}
|
||||
|
@ -55,34 +56,70 @@ public class KineticNetwork {
|
|||
return rootSpeed;
|
||||
}
|
||||
|
||||
public SolveResult recalculateSpeed() {
|
||||
if (!conflictingCycles.isEmpty() && !generators.isEmpty()) return SolveResult.CONTRADICTION;
|
||||
if (!speedDirty) return SolveResult.OK;
|
||||
/**
|
||||
* Recalculates the speed at the root of this network, and if it has changed, recalculates the speed of all
|
||||
* 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 sign = 0;
|
||||
for (KineticNode generator : generators) {
|
||||
float speedAtRoot = generator.getGeneratedSpeedAtRoot();
|
||||
if (newSpeed == 0) {
|
||||
sign = Math.signum(speedAtRoot);
|
||||
newSpeed = sign * speedAtRoot;
|
||||
} else {
|
||||
if (Math.signum(speedAtRoot) != sign)
|
||||
return SolveResult.CONTRADICTION;
|
||||
newSpeed = Math.max(newSpeed, sign * speedAtRoot);
|
||||
} else if (Math.signum(speedAtRoot) != sign) {
|
||||
// generators are turning against each other
|
||||
return SolveResult.CONTRADICTION;
|
||||
}
|
||||
newSpeed = Math.max(newSpeed, sign * speedAtRoot);
|
||||
}
|
||||
newSpeed *= sign;
|
||||
|
||||
if (rootSpeed != newSpeed) {
|
||||
if (!Mth.equal(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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package com.simibubi.create.content.contraptions.solver;
|
||||
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -38,13 +40,16 @@ public class KineticNode {
|
|||
this.generatedSpeed = state.getGeneratedSpeed();
|
||||
|
||||
this.network = new KineticNetwork(this);
|
||||
onSpeedUpdated();
|
||||
}
|
||||
|
||||
public KineticConnections getConnections() {
|
||||
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() {
|
||||
return connections.getDirections().stream()
|
||||
.map(d -> nodeAccessor.apply(entity.getBlockPos().offset(d))
|
||||
|
@ -68,9 +73,10 @@ public class KineticNode {
|
|||
}
|
||||
|
||||
public void setGeneratedSpeed(float newSpeed) {
|
||||
if (Mth.equal(generatedSpeed, newSpeed)) return;
|
||||
generatedSpeed = newSpeed;
|
||||
network.updateMember(this);
|
||||
if (network.recalculateSpeed().isContradiction())
|
||||
if (network.recalculateSpeed(this, false).isContradiction())
|
||||
onPopBlock();
|
||||
}
|
||||
|
||||
|
@ -78,7 +84,6 @@ public class KineticNode {
|
|||
this.network.removeMember(this);
|
||||
this.network = network;
|
||||
network.addMember(this);
|
||||
onSpeedUpdated();
|
||||
}
|
||||
|
||||
private void setSource(KineticNode from, float ratio) {
|
||||
|
@ -93,21 +98,18 @@ public class KineticNode {
|
|||
.stream()
|
||||
.findAny()
|
||||
.ifPresent(n -> {
|
||||
if (n.propagateSource().isContradiction())
|
||||
if (n.propagateSource(this).isContradiction())
|
||||
onPopBlock();
|
||||
});
|
||||
}
|
||||
|
||||
public void onRemoved() {
|
||||
network.removeMember(this);
|
||||
for (KineticNode neighbor : getActiveConnections().keySet()) {
|
||||
if (neighbor.source != this) continue;
|
||||
neighbor.rerootHere();
|
||||
}
|
||||
network.recalculateSpeed();
|
||||
}
|
||||
|
||||
private SolveResult propagateSource() {
|
||||
/**
|
||||
* Propagates this node's source and network to any connected nodes that aren't yet part of the same network, then
|
||||
* repeats this recursively with the connected nodes in a breadth-first order.
|
||||
* @param checkRoot Node to start searching from when looking for nodes that started speeding because of this call
|
||||
* @return whether or not this propagation caused a contradiction in the kinetic network
|
||||
*/
|
||||
private SolveResult propagateSource(KineticNode checkRoot) {
|
||||
List<KineticNode> frontier = new LinkedList<>();
|
||||
frontier.add(this);
|
||||
|
||||
|
@ -116,30 +118,53 @@ public class KineticNode {
|
|||
for (Map.Entry<KineticNode, Float> entry : cur.getActiveConnections().entrySet()) {
|
||||
KineticNode next = entry.getKey();
|
||||
float ratio = entry.getValue();
|
||||
|
||||
if (next == cur.source) continue;
|
||||
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);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
next.setSource(cur, ratio);
|
||||
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() {
|
||||
source = null;
|
||||
speedRatio = 1;
|
||||
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;
|
||||
if (Math.abs(speedNext) > AllConfigs.SERVER.kinetics.maxRotationSpeed.get())
|
||||
return SolveResult.CONTRADICTION;
|
||||
return SolveResult.OK;
|
||||
}
|
||||
|
||||
public void flushChangedSpeed() {
|
||||
|
@ -155,4 +180,8 @@ public class KineticNode {
|
|||
entity.getLevel().destroyBlock(entity.getBlockPos(), true);
|
||||
}
|
||||
|
||||
public boolean isSourceOf(KineticNode other) {
|
||||
return other.source == this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,11 @@ public class KineticSolver {
|
|||
removeNode(entity);
|
||||
KineticNode node = new KineticNode(entity, this::getNode);
|
||||
nodes.put(entity.getBlockPos(), node);
|
||||
node.onAdded();
|
||||
if (node.tryUpdateSpeed().isOk()) {
|
||||
node.onAdded();
|
||||
} else {
|
||||
node.onPopBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateNode(KineticTileEntity entity) {
|
||||
|
|
Loading…
Reference in a new issue