mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-01-26 04:48:22 +01:00
Curse of the Speed Controller
This commit is contained in:
parent
1fed398e8f
commit
f4514b3e5e
9 changed files with 216 additions and 76 deletions
|
@ -1,5 +1,7 @@
|
|||
package com.simibubi.create.content.contraptions.base;
|
||||
|
||||
import com.simibubi.create.content.contraptions.solver.AllConnections;
|
||||
import com.simibubi.create.content.contraptions.solver.KineticConnections;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -61,6 +63,11 @@ public abstract class HorizontalAxisKineticBlock extends KineticBlock {
|
|||
return state.getValue(HORIZONTAL_AXIS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KineticConnections getInitialConnections(BlockState state) {
|
||||
return AllConnections.FULL_SHAFT.apply(state.getValue(HORIZONTAL_AXIS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) {
|
||||
return face.getAxis() == state.getValue(HORIZONTAL_AXIS);
|
||||
|
|
|
@ -10,6 +10,8 @@ import com.simibubi.create.AllTileEntities;
|
|||
import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel;
|
||||
import com.simibubi.create.content.contraptions.solver.AllConnections;
|
||||
import com.simibubi.create.content.contraptions.solver.KineticConnections;
|
||||
import com.simibubi.create.foundation.block.ITE;
|
||||
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
||||
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
||||
|
@ -43,6 +45,11 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements
|
|||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KineticConnections getInitialConnections(BlockState state) {
|
||||
return AllConnections.SPEED_CONTROLLER.apply(state.getValue(HORIZONTAL_AXIS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
BlockState above = context.getLevel()
|
||||
|
@ -111,7 +118,7 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock implements
|
|||
public Class<SpeedControllerTileEntity> getTileEntityClass() {
|
||||
return SpeedControllerTileEntity.class;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockEntityType<? extends SpeedControllerTileEntity> getTileEntityType() {
|
||||
return AllTileEntities.ROTATION_SPEED_CONTROLLER.get();
|
||||
|
|
|
@ -49,11 +49,14 @@ public class SpeedControllerTileEntity extends KineticTileEntity {
|
|||
targetSpeed.value = DEFAULT_SPEED;
|
||||
targetSpeed.moveText(new Vec3(9, 0, 10));
|
||||
targetSpeed.withUnit(i -> Lang.translate("generic.unit.rpm"));
|
||||
targetSpeed.withCallback(i -> this.updateTargetRotation());
|
||||
targetSpeed.withStepFunction(CreativeMotorTileEntity::step);
|
||||
behaviours.add(targetSpeed);
|
||||
}
|
||||
|
||||
public float getTargetSpeed() {
|
||||
return targetSpeed.getValue();
|
||||
}
|
||||
|
||||
private void updateTargetRotation() {
|
||||
if (hasNetwork())
|
||||
getOrCreateNetwork().remove(this);
|
||||
|
@ -123,7 +126,7 @@ public class SpeedControllerTileEntity extends KineticTileEntity {
|
|||
return true;
|
||||
}
|
||||
|
||||
private class ControllerValueBoxTransform extends ValueBoxTransform.Sided {
|
||||
private static class ControllerValueBoxTransform extends ValueBoxTransform.Sided {
|
||||
|
||||
@Override
|
||||
protected Vec3 getSouthLocation() {
|
||||
|
|
|
@ -2,7 +2,11 @@ package com.simibubi.create.content.contraptions.relays.elementary;
|
|||
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
|
||||
import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerTileEntity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
@ -23,4 +27,13 @@ public class SimpleKineticTileEntity extends KineticTileEntity {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getGeneratedSpeed() {
|
||||
Block block = getBlockState().getBlock();
|
||||
BlockEntity below = level.getBlockEntity(getBlockPos().below());
|
||||
if (block instanceof ICogWheel cog && cog.isLargeCog()
|
||||
&& below instanceof SpeedControllerTileEntity controller && controller.getSpeed() != 0)
|
||||
return controller.getTargetSpeed();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import net.minecraft.core.Vec3i;
|
|||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.AXIS;
|
||||
|
||||
|
@ -30,7 +31,8 @@ public class AllConnections {
|
|||
public static final LazyMap<Axis, Type>
|
||||
TYPE_SHAFT = ValueType.map(),
|
||||
TYPE_LARGE_COG = ValueType.map(),
|
||||
TYPE_SMALL_COG = ValueType.map();
|
||||
TYPE_SMALL_COG = ValueType.map(),
|
||||
TYPE_SPEED_CONTROLLER_TOP = ValueType.map();
|
||||
|
||||
|
||||
private static Direction pos(Axis axis) {
|
||||
|
@ -48,6 +50,14 @@ public class AllConnections {
|
|||
return new Entry(diff, TYPE_LARGE_COG.apply(from), TYPE_LARGE_COG.apply(to), ratio);
|
||||
}
|
||||
|
||||
private static Optional<Axis> oppAxis(Axis axis) {
|
||||
return switch (axis) {
|
||||
case X -> Optional.of(Axis.Z);
|
||||
case Z -> Optional.of(Axis.X);
|
||||
default -> Optional.empty();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public static final KineticConnections EMPTY = new KineticConnections();
|
||||
|
||||
|
@ -61,6 +71,7 @@ public class AllConnections {
|
|||
LARGE_COG = new LazyMap<>(axis -> {
|
||||
Type large = TYPE_LARGE_COG.apply(axis);
|
||||
Type small = TYPE_SMALL_COG.apply(axis);
|
||||
|
||||
List<Entry> out = new LinkedList<>();
|
||||
Direction cur = DirectionHelper.getPositivePerpendicular(axis);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -70,12 +81,18 @@ public class AllConnections {
|
|||
out.add(new Entry(cur.getNormal().relative(next), large, small, -2));
|
||||
cur = next;
|
||||
}
|
||||
|
||||
oppAxis(axis).ifPresent(opp -> {
|
||||
Type sc = TYPE_SPEED_CONTROLLER_TOP.apply(opp);
|
||||
out.add(new Entry(Direction.DOWN.getNormal(), large, sc).stressOnly());
|
||||
});
|
||||
return new KineticConnections(out);
|
||||
}),
|
||||
|
||||
SMALL_COG = new LazyMap<>(axis -> {
|
||||
Type large = TYPE_LARGE_COG.apply(axis);
|
||||
Type small = TYPE_SMALL_COG.apply(axis);
|
||||
|
||||
List<Entry> out = new LinkedList<>();
|
||||
Direction cur = DirectionHelper.getPositivePerpendicular(axis);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -84,11 +101,19 @@ public class AllConnections {
|
|||
out.add(new Entry(cur.getNormal().relative(next), small, large, -0.5f));
|
||||
cur = next;
|
||||
}
|
||||
|
||||
return new KineticConnections(out);
|
||||
}),
|
||||
|
||||
LARGE_COG_FULL_SHAFT = new LazyMap<>(axis -> LARGE_COG.apply(axis).merge(FULL_SHAFT.apply(axis))),
|
||||
|
||||
SMALL_COG_FULL_SHAFT = new LazyMap<>(axis -> SMALL_COG.apply(axis).merge(FULL_SHAFT.apply(axis)));
|
||||
SMALL_COG_FULL_SHAFT = new LazyMap<>(axis -> SMALL_COG.apply(axis).merge(FULL_SHAFT.apply(axis))),
|
||||
|
||||
SPEED_CONTROLLER = new LazyMap<>(axis -> {
|
||||
Type sc = TYPE_SPEED_CONTROLLER_TOP.apply(axis);
|
||||
Type large = TYPE_LARGE_COG.apply(oppAxis(axis).get());
|
||||
Vec3i up = Direction.UP.getNormal();
|
||||
return new KineticConnections(new Entry(up, sc, large).stressOnly()).merge(FULL_SHAFT.apply(axis));
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -32,9 +32,16 @@ public class KineticConnections {
|
|||
public Entry(Vec3i offset, Type type) {
|
||||
this(offset, type, type, 1);
|
||||
}
|
||||
public Entry stressOnly() {
|
||||
return new Entry(offset, new Value(value.from, value.to, 0));
|
||||
}
|
||||
}
|
||||
|
||||
private static record Value(Type from, Type to, float ratio) { }
|
||||
private static record Value(Type from, Type to, float ratio) {
|
||||
public boolean isStressOnly() {
|
||||
return ratio == 0;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<Vec3i, Value> connections;
|
||||
|
||||
|
@ -65,12 +72,26 @@ public class KineticConnections {
|
|||
Value toValue = to.connections.get(offset.multiply(-1));
|
||||
if (toValue == null) return Optional.empty();
|
||||
|
||||
if (fromValue.isStressOnly() || toValue.isStressOnly()) return Optional.empty();
|
||||
|
||||
if (fromValue.from.compatible(toValue.to) && fromValue.to.compatible(toValue.from)
|
||||
&& (Mth.equal(fromValue.ratio, 1/toValue.ratio) || (Mth.equal(toValue.ratio, 1/fromValue.ratio))))
|
||||
return Optional.of(fromValue.ratio);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public boolean checkStressOnlyConnection(KineticConnections to, Vec3i offset) {
|
||||
Value fromValue = connections.get(offset);
|
||||
if (fromValue == null) return false;
|
||||
|
||||
Value toValue = to.connections.get(offset.multiply(-1));
|
||||
if (toValue == null) return false;
|
||||
|
||||
if (!fromValue.isStressOnly() || !toValue.isStressOnly()) return false;
|
||||
|
||||
return fromValue.from.compatible(toValue.to) && fromValue.to.compatible(toValue.from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -91,5 +112,9 @@ public class KineticConnections {
|
|||
return new KineticConnections(out);
|
||||
}
|
||||
|
||||
public boolean hasStressOnlyConnections() {
|
||||
return connections.values().stream().anyMatch(Value::isStressOnly);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.simibubi.create.content.contraptions.solver;
|
|||
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import com.simibubi.create.foundation.utility.ResetableLazy;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
@ -15,46 +17,71 @@ public class KineticNetwork {
|
|||
private final Set<KineticNode> members = new HashSet<>();
|
||||
private final Set<KineticNode> generators = new HashSet<>();
|
||||
private final Set<Pair<KineticNode, KineticNode>> conflictingCycles = new HashSet<>();
|
||||
|
||||
private float rootTheoreticalSpeed;
|
||||
private @Nullable KineticNode mainGenerator;
|
||||
private boolean rootSpeedDirty;
|
||||
private @Nullable KineticNode mainGenerator;
|
||||
|
||||
private boolean overstressed;
|
||||
|
||||
private float rootSpeedCur;
|
||||
private float rootSpeedPrev;
|
||||
private boolean rootSpeedChanged;
|
||||
private final Set<KineticNode> potentialNewBranches = new HashSet<>();
|
||||
|
||||
private final ResetableLazy<Float> totalStressImpact = ResetableLazy.of(() ->
|
||||
(float) members.stream().mapToDouble(n -> n.getTotalStressImpact(rootTheoreticalSpeed)).sum());
|
||||
private final ResetableLazy<Float> totalStressCapacity = ResetableLazy.of(() ->
|
||||
(float) members.stream().mapToDouble(KineticNode::getStressCapacity).sum());
|
||||
|
||||
private boolean ticked;
|
||||
private final Set<KineticNode> stressConnectors = new HashSet<>();
|
||||
|
||||
public KineticNetwork(KineticNode root) {
|
||||
addMember(root);
|
||||
}
|
||||
|
||||
public void addMember(KineticNode node) {
|
||||
members.add(node);
|
||||
potentialNewBranches.add(node);
|
||||
if (node.getConnections().hasStressOnlyConnections()) stressConnectors.add(node);
|
||||
|
||||
if (node.isGenerator() && !generators.contains(node)) {
|
||||
generators.add(node);
|
||||
rootSpeedDirty = true;
|
||||
rootSpeedChanged = true;
|
||||
}
|
||||
|
||||
potentialNewBranches.add(node);
|
||||
if (node.hasStressImpact()) onMemberStressImpactUpdated();
|
||||
if (node.hasStressCapacity()) onMemberStressCapacityUpdated();
|
||||
}
|
||||
|
||||
public void updateMember(KineticNode node) {
|
||||
if (!members.contains(node)) throw new IllegalArgumentException();
|
||||
|
||||
public void onMemberGeneratedSpeedUpdated(KineticNode node) {
|
||||
if (node.isGenerator()) {
|
||||
generators.add(node);
|
||||
} else {
|
||||
generators.remove(node);
|
||||
}
|
||||
rootSpeedDirty = true;
|
||||
rootSpeedChanged = true;
|
||||
}
|
||||
|
||||
public void onMemberStressImpactUpdated() {
|
||||
totalStressImpact.reset();
|
||||
}
|
||||
|
||||
public void onMemberStressCapacityUpdated() {
|
||||
totalStressCapacity.reset();
|
||||
}
|
||||
|
||||
public void removeMember(KineticNode node) {
|
||||
members.remove(node);
|
||||
if (node.isGenerator() && generators.contains(node)) {
|
||||
generators.remove(node);
|
||||
rootSpeedDirty = true;
|
||||
rootSpeedChanged = true;
|
||||
}
|
||||
if (node.hasStressImpact()) onMemberStressImpactUpdated();
|
||||
if (node.hasStressCapacity()) onMemberStressCapacityUpdated();
|
||||
|
||||
members.remove(node);
|
||||
stressConnectors.remove(node);
|
||||
conflictingCycles.removeIf(p -> p.getFirst() == node || p.getSecond() == node);
|
||||
}
|
||||
|
||||
|
@ -105,73 +132,88 @@ public class KineticNetwork {
|
|||
}
|
||||
|
||||
rootTheoreticalSpeed = newSpeed * sign;
|
||||
if (!overstressed) {
|
||||
rootSpeedCur = rootTheoreticalSpeed;
|
||||
}
|
||||
|
||||
mainGenerator = newGenerator;
|
||||
rootSpeedDirty = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a List of new networks created during this function call
|
||||
*/
|
||||
public List<KineticNetwork> tick() {
|
||||
List<KineticNetwork> newNetworks = updateMemberSpeeds();
|
||||
public float getTotalStressImpact() {
|
||||
return totalStressImpact.get();
|
||||
}
|
||||
|
||||
if (generators.isEmpty()) {
|
||||
overstressed = false;
|
||||
members.forEach(KineticNode::stop);
|
||||
members.forEach(KineticNode::flushChangedSpeed);
|
||||
return newNetworks;
|
||||
public float getTotalStressCapacity() {
|
||||
return totalStressCapacity.get();
|
||||
}
|
||||
|
||||
private float getRootSpeed() {
|
||||
return isStopped() ? 0 : rootTheoreticalSpeed;
|
||||
}
|
||||
|
||||
public void untick() {
|
||||
ticked = false;
|
||||
}
|
||||
|
||||
public void tick(List<KineticNetwork> newNetworks) {
|
||||
if (ticked) return;
|
||||
|
||||
Set<KineticNetwork> stressConnected = stressConnectors.stream()
|
||||
.flatMap(KineticNode::getActiveStressOnlyConnections)
|
||||
.collect(Collectors.toSet());
|
||||
stressConnected.add(this);
|
||||
|
||||
float stressImpact = 0;
|
||||
float stressCapacity = 0;
|
||||
|
||||
for (KineticNetwork cur : stressConnected) {
|
||||
cur.ticked = true;
|
||||
cur.updateMemberSpeeds(newNetworks);
|
||||
stressImpact += cur.getTotalStressImpact();
|
||||
stressCapacity += cur.getTotalStressCapacity();
|
||||
}
|
||||
|
||||
float stressImpact = (float) members.stream().mapToDouble(n -> n.getTotalStressImpact(rootTheoreticalSpeed)).sum();
|
||||
float stressCapacity = (float) members.stream().mapToDouble(KineticNode::getStressCapacity).sum();
|
||||
boolean nowOverstressed = stressImpact > stressCapacity;
|
||||
|
||||
if (stressImpact > stressCapacity) {
|
||||
if (!overstressed) {
|
||||
overstressed = true;
|
||||
rootSpeedCur = 0;
|
||||
members.forEach(KineticNode::stop);
|
||||
}
|
||||
} else {
|
||||
if (overstressed) {
|
||||
overstressed = false;
|
||||
rootSpeedCur = rootTheoreticalSpeed;
|
||||
newNetworks.addAll(bulldozeContradictingMembers());
|
||||
newNetworks.addAll(updateMemberSpeeds());
|
||||
for (KineticNetwork cur : stressConnected) {
|
||||
if (cur.generators.isEmpty()) {
|
||||
cur.overstressed = false;
|
||||
} else if (nowOverstressed) {
|
||||
if (!cur.overstressed) {
|
||||
cur.overstressed = true;
|
||||
rootSpeedChanged = true;
|
||||
cur.members.forEach(KineticNode::stop);
|
||||
}
|
||||
} else {
|
||||
if (cur.overstressed) {
|
||||
cur.overstressed = false;
|
||||
rootSpeedChanged = true;
|
||||
cur.bulldozeContradictingMembers(newNetworks);
|
||||
cur.updateMemberSpeeds(newNetworks);
|
||||
}
|
||||
}
|
||||
|
||||
cur.members.forEach(KineticNode::flushChangedSpeed);
|
||||
}
|
||||
|
||||
members.forEach(KineticNode::flushChangedSpeed);
|
||||
return newNetworks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the speed of every member, starting from the main generator and popping off speeding nodes along the way
|
||||
* @return a List of new networks created during this function call
|
||||
* @param newNetworks a List that any new networks created during this call will be added to
|
||||
*/
|
||||
private List<KineticNetwork> updateMemberSpeeds() {
|
||||
boolean rootSpeedChanged = rootSpeedPrev != rootSpeedCur;
|
||||
rootSpeedPrev = rootSpeedCur;
|
||||
|
||||
private void updateMemberSpeeds(List<KineticNetwork> newNetworks) {
|
||||
// if we're stopped, then all members' speeds will be 0, so no need to check for speeding nodes
|
||||
if (isStopped()) {
|
||||
members.forEach(KineticNode::stop);
|
||||
return new LinkedList<>();
|
||||
return;
|
||||
}
|
||||
|
||||
SolveResult recalculateSpeedResult = tryRecalculateSpeed();
|
||||
// generators should not be turning against each other or have conflicting cycles by now
|
||||
assert(recalculateSpeedResult.isOk());
|
||||
|
||||
List<KineticNetwork> newNetworks = new LinkedList<>();
|
||||
|
||||
if (rootSpeedChanged) {
|
||||
// root speed changed, update all nodes starting from the main generator
|
||||
rootSpeedChanged = false;
|
||||
bfs(mainGenerator, newNetworks, false);
|
||||
} else if (!potentialNewBranches.isEmpty()) {
|
||||
// new nodes added, update only the new network branches
|
||||
|
@ -180,8 +222,6 @@ public class KineticNetwork {
|
|||
.forEach(n -> bfs(n, newNetworks, true));
|
||||
potentialNewBranches.clear();
|
||||
}
|
||||
|
||||
return newNetworks;
|
||||
}
|
||||
|
||||
private void bfs(KineticNode root, List<KineticNetwork> newNetworks, boolean followSource) {
|
||||
|
@ -195,7 +235,7 @@ public class KineticNetwork {
|
|||
if (!members.contains(cur) || visited.contains(cur)) continue;
|
||||
visited.add(cur);
|
||||
|
||||
if (cur.tryUpdateSpeed(rootSpeedCur).isOk()) {
|
||||
if (cur.tryUpdateSpeed(getRootSpeed()).isOk()) {
|
||||
cur.getActiveConnections()
|
||||
.map(Pair::getFirst)
|
||||
.filter(n -> !followSource || n.getSource() == cur)
|
||||
|
@ -208,7 +248,7 @@ public class KineticNetwork {
|
|||
}
|
||||
}
|
||||
|
||||
private List<KineticNetwork> bulldozeContradictingMembers() {
|
||||
private void bulldozeContradictingMembers(List<KineticNetwork> newNetworks) {
|
||||
/*
|
||||
This method is necessary to handle the edge case where contradicting nodes have been added to the network while
|
||||
it was overstressed and now that it's moving again we need to pop them. Here we can't just stop following a
|
||||
|
@ -216,10 +256,8 @@ public class KineticNetwork {
|
|||
just pop all potentially contradicting nodes off and hope no one cares
|
||||
*/
|
||||
|
||||
List<KineticNetwork> newNetworks = new LinkedList<>();
|
||||
|
||||
// generators running against network
|
||||
float sign = Math.signum(rootSpeedCur);
|
||||
float sign = Math.signum(rootTheoreticalSpeed);
|
||||
List<KineticNode> runningAgainst = generators.stream()
|
||||
.filter(n -> Math.signum(n.getGeneratedSpeedAtRoot()) != sign)
|
||||
.collect(Collectors.toList());
|
||||
|
@ -230,8 +268,6 @@ public class KineticNetwork {
|
|||
.map(Pair::getFirst)
|
||||
.collect(Collectors.toList());
|
||||
cycles.forEach(n -> { n.popBlock(); newNetworks.add(n.getNetwork()); });
|
||||
|
||||
return newNetworks;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ public class KineticNode {
|
|||
|
||||
this.connections = entity.getConnections();
|
||||
this.generatedSpeed = entity.getGeneratedSpeed();
|
||||
this.stressCapacity = entity.getStressCapacity();
|
||||
this.stressImpact = entity.getStressImpact();
|
||||
this.stressCapacity = entity.getStressCapacity();
|
||||
|
||||
this.network = new KineticNetwork(this);
|
||||
}
|
||||
|
@ -70,6 +70,14 @@ public class KineticNode {
|
|||
return getActiveConnections().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Stream<KineticNetwork> getActiveStressOnlyConnections() {
|
||||
return connections.getDirections().stream()
|
||||
.map(d -> nodeAccessor.apply(entity.getBlockPos().offset(d))
|
||||
.filter(n -> connections.checkStressOnlyConnection(n.connections, d)))
|
||||
.flatMap(Optional::stream)
|
||||
.map(KineticNode::getNetwork);
|
||||
}
|
||||
|
||||
public float getGeneratedSpeedAtRoot() {
|
||||
return generatedSpeed / speedRatio;
|
||||
}
|
||||
|
@ -79,17 +87,34 @@ public class KineticNode {
|
|||
}
|
||||
|
||||
public void onUpdated() {
|
||||
float newSpeed = entity.getGeneratedSpeed();
|
||||
if (generatedSpeed != newSpeed) {
|
||||
generatedSpeed = newSpeed;
|
||||
network.updateMember(this);
|
||||
float generatedSpeedNew = entity.getGeneratedSpeed();
|
||||
if (this.generatedSpeed != generatedSpeedNew) {
|
||||
this.generatedSpeed = generatedSpeedNew;
|
||||
network.onMemberGeneratedSpeedUpdated(this);
|
||||
if (network.tryRecalculateSpeed().isContradiction()) {
|
||||
popBlock();
|
||||
}
|
||||
}
|
||||
|
||||
stressImpact = entity.getStressImpact();
|
||||
stressCapacity = entity.getStressCapacity();
|
||||
float stressImpactNew = entity.getStressImpact();
|
||||
if (this.stressImpact != stressImpactNew) {
|
||||
this.stressImpact = stressImpactNew;
|
||||
network.onMemberStressImpactUpdated();
|
||||
}
|
||||
|
||||
float stressCapacityNew = entity.getStressCapacity();
|
||||
if (this.stressCapacity != stressCapacityNew) {
|
||||
this.stressCapacity = stressCapacityNew;
|
||||
network.onMemberStressCapacityUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasStressCapacity() {
|
||||
return stressCapacity != 0;
|
||||
}
|
||||
|
||||
public boolean hasStressImpact() {
|
||||
return stressImpact != 0;
|
||||
}
|
||||
|
||||
public float getTheoreticalSpeed(float speedAtRoot) {
|
||||
|
@ -111,7 +136,7 @@ public class KineticNode {
|
|||
return network.tryRecalculateSpeed();
|
||||
}
|
||||
|
||||
public KineticNode getSource() {
|
||||
public @Nullable KineticNode getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,17 +55,16 @@ public class KineticSolver {
|
|||
}
|
||||
|
||||
public void tick() {
|
||||
Set<KineticNetwork> visited = new HashSet<>();
|
||||
Set<KineticNetwork> networks = nodes.values().stream().map(KineticNode::getNetwork).collect(Collectors.toSet());
|
||||
networks.forEach(KineticNetwork::untick);
|
||||
|
||||
List<KineticNetwork> frontier = new LinkedList<>();
|
||||
|
||||
Set<KineticNetwork> networks = nodes.values().stream().map(KineticNode::getNetwork).collect(Collectors.toSet());
|
||||
for (KineticNetwork network : networks) {
|
||||
frontier.add(network);
|
||||
while (!frontier.isEmpty()) {
|
||||
KineticNetwork cur = frontier.remove(0);
|
||||
if (visited.contains(cur)) continue;
|
||||
visited.add(cur);
|
||||
frontier.addAll(cur.tick());
|
||||
cur.tick(frontier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue