mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-02-11 12:55:00 +01:00
Persistence is key
This commit is contained in:
parent
f4514b3e5e
commit
44d59fe793
7 changed files with 376 additions and 89 deletions
|
@ -4,6 +4,7 @@ import static net.minecraft.ChatFormatting.GOLD;
|
||||||
import static net.minecraft.ChatFormatting.GRAY;
|
import static net.minecraft.ChatFormatting.GRAY;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@ -78,14 +79,6 @@ public class KineticTileEntity extends SmartTileEntity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addToSolver() {
|
|
||||||
KineticSolver.getSolver(level).addNode(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeFromSolver() {
|
|
||||||
KineticSolver.getSolver(level).removeNode(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public KineticConnections getConnections() {
|
public KineticConnections getConnections() {
|
||||||
return connections;
|
return connections;
|
||||||
}
|
}
|
||||||
|
@ -102,6 +95,10 @@ public class KineticTileEntity extends SmartTileEntity
|
||||||
return getDefaultStressCapacity();
|
return getDefaultStressCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isStressConstant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public float getDefaultStressImpact() {
|
public float getDefaultStressImpact() {
|
||||||
return (float) BlockStressValues.getImpact(getStressConfigKey());
|
return (float) BlockStressValues.getImpact(getStressConfigKey());
|
||||||
}
|
}
|
||||||
|
@ -110,11 +107,18 @@ public class KineticTileEntity extends SmartTileEntity
|
||||||
return (float) BlockStressValues.getCapacity(getStressConfigKey());
|
return (float) BlockStressValues.getCapacity(getStressConfigKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Float> isConnected(BlockPos to) {
|
||||||
|
return KineticSolver.getSolver(level).isConnected(this.getBlockPos(), to);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStressOnlyConnected(BlockPos to) {
|
||||||
|
return KineticSolver.getSolver(level).isStressOnlyConnected(this.getBlockPos(), to);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
if (!level.isClientSide) {
|
if (!level.isClientSide) {
|
||||||
addToSolver();
|
KineticSolver.getSolver(level).addNode(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.initialize();
|
super.initialize();
|
||||||
|
@ -125,7 +129,7 @@ public class KineticTileEntity extends SmartTileEntity
|
||||||
super.tick();
|
super.tick();
|
||||||
effects.tick();
|
effects.tick();
|
||||||
|
|
||||||
if (!level.isClientSide && !isRemoved()) {
|
if (!level.isClientSide) {
|
||||||
KineticSolver.getSolver(level).updateNode(this);
|
KineticSolver.getSolver(level).updateNode(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +148,29 @@ public class KineticTileEntity extends SmartTileEntity
|
||||||
flickerTally = getFlickerScore() - 1;
|
flickerTally = getFlickerScore() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setRemovedNotDueToChunkUnload() {
|
||||||
|
if (!level.isClientSide) {
|
||||||
|
KineticSolver.getSolver(level).removeNode(this);
|
||||||
|
}
|
||||||
|
super.setRemovedNotDueToChunkUnload();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChunkUnloaded() {
|
||||||
|
super.onChunkUnloaded();
|
||||||
|
if (!level.isClientSide) {
|
||||||
|
preKineticsUnloaded();
|
||||||
|
KineticSolver solver = KineticSolver.getSolver(level);
|
||||||
|
solver.updateNode(this);
|
||||||
|
solver.unloadNode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void preKineticsUnloaded() {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void validateKinetics() {
|
private void validateKinetics() {
|
||||||
// if (hasSource()) {
|
// if (hasSource()) {
|
||||||
// if (!hasNetwork()) {
|
// if (!hasNetwork()) {
|
||||||
|
@ -215,14 +242,6 @@ public class KineticTileEntity extends SmartTileEntity
|
||||||
super.setRemoved();
|
super.setRemoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setRemovedNotDueToChunkUnload() {
|
|
||||||
if (!level.isClientSide) {
|
|
||||||
removeFromSolver();
|
|
||||||
}
|
|
||||||
super.setRemovedNotDueToChunkUnload();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void write(CompoundTag compound, boolean clientPacket) {
|
protected void write(CompoundTag compound, boolean clientPacket) {
|
||||||
compound.putFloat("Speed", speed);
|
compound.putFloat("Speed", speed);
|
||||||
|
|
|
@ -29,10 +29,10 @@ public class SimpleKineticTileEntity extends KineticTileEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getGeneratedSpeed() {
|
public float getGeneratedSpeed() {
|
||||||
Block block = getBlockState().getBlock();
|
BlockPos belowPos = getBlockPos().below();
|
||||||
BlockEntity below = level.getBlockEntity(getBlockPos().below());
|
if (isStressOnlyConnected(belowPos)
|
||||||
if (block instanceof ICogWheel cog && cog.isLargeCog()
|
&& level.getBlockEntity(belowPos) instanceof SpeedControllerTileEntity controller
|
||||||
&& below instanceof SpeedControllerTileEntity controller && controller.getSpeed() != 0)
|
&& controller.getSpeed() != 0)
|
||||||
return controller.getTargetSpeed();
|
return controller.getTargetSpeed();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,24 @@
|
||||||
package com.simibubi.create.content.contraptions.solver;
|
package com.simibubi.create.content.contraptions.solver;
|
||||||
|
|
||||||
|
import com.google.common.collect.Interner;
|
||||||
|
import com.google.common.collect.Interners;
|
||||||
import com.simibubi.create.foundation.utility.DirectionHelper;
|
import com.simibubi.create.foundation.utility.DirectionHelper;
|
||||||
import com.simibubi.create.foundation.utility.LazyMap;
|
import com.simibubi.create.foundation.utility.LazyMap;
|
||||||
import com.simibubi.create.content.contraptions.solver.KineticConnections.Type;
|
import com.simibubi.create.content.contraptions.solver.KineticConnections.Type;
|
||||||
|
import com.simibubi.create.content.contraptions.solver.KineticConnections.Types;
|
||||||
import com.simibubi.create.content.contraptions.solver.KineticConnections.Entry;
|
import com.simibubi.create.content.contraptions.solver.KineticConnections.Entry;
|
||||||
|
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.Direction.Axis;
|
import net.minecraft.core.Direction.Axis;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
|
import net.minecraft.util.StringRepresentable;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.AXIS;
|
|
||||||
|
|
||||||
public class AllConnections {
|
public class AllConnections {
|
||||||
|
|
||||||
public static record ValueType(Object value) implements Type {
|
|
||||||
@Override
|
|
||||||
public boolean compatible(Type other) {
|
|
||||||
return this == other;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> LazyMap<T, Type> map() {
|
|
||||||
return new LazyMap<>(ValueType::new);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final LazyMap<Axis, Type>
|
|
||||||
TYPE_SHAFT = ValueType.map(),
|
|
||||||
TYPE_LARGE_COG = ValueType.map(),
|
|
||||||
TYPE_SMALL_COG = ValueType.map(),
|
|
||||||
TYPE_SPEED_CONTROLLER_TOP = ValueType.map();
|
|
||||||
|
|
||||||
|
|
||||||
private static Direction pos(Axis axis) {
|
private static Direction pos(Axis axis) {
|
||||||
return Direction.get(Direction.AxisDirection.POSITIVE, axis);
|
return Direction.get(Direction.AxisDirection.POSITIVE, axis);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +31,7 @@ public class AllConnections {
|
||||||
int fromDiff = from.choose(diff.getX(), diff.getY(), diff.getZ());
|
int fromDiff = from.choose(diff.getX(), diff.getY(), diff.getZ());
|
||||||
int toDiff = to.choose(diff.getX(), diff.getY(), diff.getZ());
|
int toDiff = to.choose(diff.getX(), diff.getY(), diff.getZ());
|
||||||
float ratio = fromDiff > 0 ^ toDiff > 0 ? -1 : 1;
|
float ratio = fromDiff > 0 ^ toDiff > 0 ? -1 : 1;
|
||||||
return new Entry(diff, TYPE_LARGE_COG.apply(from), TYPE_LARGE_COG.apply(to), ratio);
|
return new Entry(diff, Type.of(Types.LARGE_COG, from), Type.of(Types.LARGE_COG, to), ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Optional<Axis> oppAxis(Axis axis) {
|
private static Optional<Axis> oppAxis(Axis axis) {
|
||||||
|
@ -63,14 +47,14 @@ public class AllConnections {
|
||||||
|
|
||||||
public static final LazyMap<Direction, KineticConnections>
|
public static final LazyMap<Direction, KineticConnections>
|
||||||
HALF_SHAFT = new LazyMap<>(dir ->
|
HALF_SHAFT = new LazyMap<>(dir ->
|
||||||
new KineticConnections(new Entry(dir.getNormal(), TYPE_SHAFT.apply(dir.getAxis()))));
|
new KineticConnections(new Entry(dir.getNormal(), Type.of(Types.SHAFT, dir.getAxis()))));
|
||||||
|
|
||||||
public static final LazyMap<Axis, KineticConnections>
|
public static final LazyMap<Axis, KineticConnections>
|
||||||
FULL_SHAFT = new LazyMap<>(axis -> HALF_SHAFT.apply(pos(axis)).merge(HALF_SHAFT.apply(neg(axis)))),
|
FULL_SHAFT = new LazyMap<>(axis -> HALF_SHAFT.apply(pos(axis)).merge(HALF_SHAFT.apply(neg(axis)))),
|
||||||
|
|
||||||
LARGE_COG = new LazyMap<>(axis -> {
|
LARGE_COG = new LazyMap<>(axis -> {
|
||||||
Type large = TYPE_LARGE_COG.apply(axis);
|
Type large = Type.of(Types.LARGE_COG, axis);
|
||||||
Type small = TYPE_SMALL_COG.apply(axis);
|
Type small = Type.of(Types.SMALL_COG, axis);
|
||||||
|
|
||||||
List<Entry> out = new LinkedList<>();
|
List<Entry> out = new LinkedList<>();
|
||||||
Direction cur = DirectionHelper.getPositivePerpendicular(axis);
|
Direction cur = DirectionHelper.getPositivePerpendicular(axis);
|
||||||
|
@ -83,15 +67,15 @@ public class AllConnections {
|
||||||
}
|
}
|
||||||
|
|
||||||
oppAxis(axis).ifPresent(opp -> {
|
oppAxis(axis).ifPresent(opp -> {
|
||||||
Type sc = TYPE_SPEED_CONTROLLER_TOP.apply(opp);
|
Type sc = Type.of(Types.SPEED_CONTROLLER_TOP, opp);
|
||||||
out.add(new Entry(Direction.DOWN.getNormal(), large, sc).stressOnly());
|
out.add(new Entry(Direction.DOWN.getNormal(), large, sc).stressOnly());
|
||||||
});
|
});
|
||||||
return new KineticConnections(out);
|
return new KineticConnections(out);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
SMALL_COG = new LazyMap<>(axis -> {
|
SMALL_COG = new LazyMap<>(axis -> {
|
||||||
Type large = TYPE_LARGE_COG.apply(axis);
|
Type large = Type.of(Types.LARGE_COG, axis);
|
||||||
Type small = TYPE_SMALL_COG.apply(axis);
|
Type small = Type.of(Types.SMALL_COG, axis);
|
||||||
|
|
||||||
List<Entry> out = new LinkedList<>();
|
List<Entry> out = new LinkedList<>();
|
||||||
Direction cur = DirectionHelper.getPositivePerpendicular(axis);
|
Direction cur = DirectionHelper.getPositivePerpendicular(axis);
|
||||||
|
@ -110,8 +94,8 @@ public class AllConnections {
|
||||||
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 -> {
|
SPEED_CONTROLLER = new LazyMap<>(axis -> {
|
||||||
Type sc = TYPE_SPEED_CONTROLLER_TOP.apply(axis);
|
Type sc = Type.of(Types.SPEED_CONTROLLER_TOP, axis);
|
||||||
Type large = TYPE_LARGE_COG.apply(oppAxis(axis).get());
|
Type large = Type.of(Types.LARGE_COG, oppAxis(axis).get());
|
||||||
Vec3i up = Direction.UP.getNormal();
|
Vec3i up = Direction.UP.getNormal();
|
||||||
return new KineticConnections(new Entry(up, sc, large).stressOnly()).merge(FULL_SHAFT.apply(axis));
|
return new KineticConnections(new Entry(up, sc, large).stressOnly()).merge(FULL_SHAFT.apply(axis));
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
package com.simibubi.create.content.contraptions.solver;
|
package com.simibubi.create.content.contraptions.solver;
|
||||||
|
|
||||||
|
import com.google.common.collect.Interner;
|
||||||
|
import com.google.common.collect.Interners;
|
||||||
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
|
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.util.StringRepresentable;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -15,8 +23,51 @@ import java.util.stream.Stream;
|
||||||
|
|
||||||
public class KineticConnections {
|
public class KineticConnections {
|
||||||
|
|
||||||
public interface Type {
|
public enum Types {
|
||||||
boolean compatible(Type other);
|
SHAFT, LARGE_COG, SMALL_COG, SPEED_CONTROLLER_TOP
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Type {
|
||||||
|
private final Types name;
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
private Type(Types name, String value) {
|
||||||
|
this.name = name;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static Interner<Type> cachedTypes = Interners.newStrongInterner();
|
||||||
|
|
||||||
|
public static Type of(Types name, String value) {
|
||||||
|
return cachedTypes.intern(new Type(name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type of(Types name, StringRepresentable value) {
|
||||||
|
return of(name, value.getSerializedName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Type type1 = (Type) o;
|
||||||
|
return name == type1.name && Objects.equals(value, type1.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag save(CompoundTag tag) {
|
||||||
|
NBTHelper.writeEnum(tag, "Name", name);
|
||||||
|
tag.putString("Value", value);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type load(CompoundTag tag) {
|
||||||
|
return Type.of(NBTHelper.readEnum(tag, "Name", Types.class), tag.getString("Value"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static record Entry(Vec3i offset, Value value) {
|
public static record Entry(Vec3i offset, Value value) {
|
||||||
|
@ -74,7 +125,7 @@ public class KineticConnections {
|
||||||
|
|
||||||
if (fromValue.isStressOnly() || toValue.isStressOnly()) return Optional.empty();
|
if (fromValue.isStressOnly() || toValue.isStressOnly()) return Optional.empty();
|
||||||
|
|
||||||
if (fromValue.from.compatible(toValue.to) && fromValue.to.compatible(toValue.from)
|
if (fromValue.from.equals(toValue.to) && fromValue.to.equals(toValue.from)
|
||||||
&& (Mth.equal(fromValue.ratio, 1/toValue.ratio) || (Mth.equal(toValue.ratio, 1/fromValue.ratio))))
|
&& (Mth.equal(fromValue.ratio, 1/toValue.ratio) || (Mth.equal(toValue.ratio, 1/fromValue.ratio))))
|
||||||
return Optional.of(fromValue.ratio);
|
return Optional.of(fromValue.ratio);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
@ -89,7 +140,7 @@ public class KineticConnections {
|
||||||
|
|
||||||
if (!fromValue.isStressOnly() || !toValue.isStressOnly()) return false;
|
if (!fromValue.isStressOnly() || !toValue.isStressOnly()) return false;
|
||||||
|
|
||||||
return fromValue.from.compatible(toValue.to) && fromValue.to.compatible(toValue.from);
|
return fromValue.from.equals(toValue.to) && fromValue.to.equals(toValue.from);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -116,5 +167,32 @@ public class KineticConnections {
|
||||||
return connections.values().stream().anyMatch(Value::isStressOnly);
|
return connections.values().stream().anyMatch(Value::isStressOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CompoundTag save(CompoundTag tag) {
|
||||||
|
ListTag connectionsTags = new ListTag();
|
||||||
|
for (Map.Entry<Vec3i, Value> entry : connections.entrySet()) {
|
||||||
|
CompoundTag entryTag = new CompoundTag();
|
||||||
|
entryTag.put("Off", NBTHelper.writeVec3i(entry.getKey()));
|
||||||
|
entryTag.put("From", entry.getValue().from().save(new CompoundTag()));
|
||||||
|
entryTag.put("To", entry.getValue().to().save(new CompoundTag()));
|
||||||
|
entryTag.putFloat("Ratio", entry.getValue().ratio());
|
||||||
|
connectionsTags.add(entryTag);
|
||||||
|
}
|
||||||
|
tag.put("Connections", connectionsTags);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KineticConnections load(CompoundTag tag) {
|
||||||
|
Map<Vec3i, Value> connections = new HashMap<>();
|
||||||
|
tag.getList("Connections", Tag.TAG_COMPOUND).forEach(c -> {
|
||||||
|
CompoundTag comp = (CompoundTag) c;
|
||||||
|
Vec3i offset = NBTHelper.readVec3i(comp.getList("Off", Tag.TAG_INT));
|
||||||
|
Type from = Type.load(comp.getCompound("From"));
|
||||||
|
Type to = Type.load(comp.getCompound("To"));
|
||||||
|
float ratio = comp.getFloat("Ratio");
|
||||||
|
connections.put(offset, new Value(from, to, ratio));
|
||||||
|
});
|
||||||
|
return new KineticConnections(connections);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,12 +47,15 @@ public class KineticNetwork {
|
||||||
if (node.isGenerator() && !generators.contains(node)) {
|
if (node.isGenerator() && !generators.contains(node)) {
|
||||||
generators.add(node);
|
generators.add(node);
|
||||||
rootSpeedDirty = true;
|
rootSpeedDirty = true;
|
||||||
rootSpeedChanged = true;
|
|
||||||
}
|
}
|
||||||
if (node.hasStressImpact()) onMemberStressImpactUpdated();
|
if (node.hasStressImpact()) onMemberStressImpactUpdated();
|
||||||
if (node.hasStressCapacity()) onMemberStressCapacityUpdated();
|
if (node.hasStressCapacity()) onMemberStressCapacityUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onMemberLoaded(KineticNode node) {
|
||||||
|
potentialNewBranches.add(node);
|
||||||
|
}
|
||||||
|
|
||||||
public void onMemberGeneratedSpeedUpdated(KineticNode node) {
|
public void onMemberGeneratedSpeedUpdated(KineticNode node) {
|
||||||
if (node.isGenerator()) {
|
if (node.isGenerator()) {
|
||||||
generators.add(node);
|
generators.add(node);
|
||||||
|
@ -60,7 +63,7 @@ public class KineticNetwork {
|
||||||
generators.remove(node);
|
generators.remove(node);
|
||||||
}
|
}
|
||||||
rootSpeedDirty = true;
|
rootSpeedDirty = true;
|
||||||
rootSpeedChanged = true;
|
onMemberStressCapacityUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onMemberStressImpactUpdated() {
|
public void onMemberStressImpactUpdated() {
|
||||||
|
@ -75,7 +78,6 @@ public class KineticNetwork {
|
||||||
if (node.isGenerator() && generators.contains(node)) {
|
if (node.isGenerator() && generators.contains(node)) {
|
||||||
generators.remove(node);
|
generators.remove(node);
|
||||||
rootSpeedDirty = true;
|
rootSpeedDirty = true;
|
||||||
rootSpeedChanged = true;
|
|
||||||
}
|
}
|
||||||
if (node.hasStressImpact()) onMemberStressImpactUpdated();
|
if (node.hasStressImpact()) onMemberStressImpactUpdated();
|
||||||
if (node.hasStressCapacity()) onMemberStressCapacityUpdated();
|
if (node.hasStressCapacity()) onMemberStressCapacityUpdated();
|
||||||
|
@ -131,7 +133,11 @@ public class KineticNetwork {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootTheoreticalSpeed = newSpeed * sign;
|
if (rootTheoreticalSpeed != newSpeed * sign) {
|
||||||
|
rootTheoreticalSpeed = newSpeed * sign;
|
||||||
|
onRootSpeedChanged();
|
||||||
|
}
|
||||||
|
|
||||||
mainGenerator = newGenerator;
|
mainGenerator = newGenerator;
|
||||||
rootSpeedDirty = false;
|
rootSpeedDirty = false;
|
||||||
|
|
||||||
|
@ -150,6 +156,11 @@ public class KineticNetwork {
|
||||||
return isStopped() ? 0 : rootTheoreticalSpeed;
|
return isStopped() ? 0 : rootTheoreticalSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onRootSpeedChanged() {
|
||||||
|
rootSpeedChanged = true;
|
||||||
|
onMemberStressImpactUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
public void untick() {
|
public void untick() {
|
||||||
ticked = false;
|
ticked = false;
|
||||||
}
|
}
|
||||||
|
@ -180,13 +191,13 @@ public class KineticNetwork {
|
||||||
} else if (nowOverstressed) {
|
} else if (nowOverstressed) {
|
||||||
if (!cur.overstressed) {
|
if (!cur.overstressed) {
|
||||||
cur.overstressed = true;
|
cur.overstressed = true;
|
||||||
rootSpeedChanged = true;
|
cur.onRootSpeedChanged();
|
||||||
cur.members.forEach(KineticNode::stop);
|
cur.members.forEach(KineticNode::stop);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cur.overstressed) {
|
if (cur.overstressed) {
|
||||||
cur.overstressed = false;
|
cur.overstressed = false;
|
||||||
rootSpeedChanged = true;
|
cur.onRootSpeedChanged();
|
||||||
cur.bulldozeContradictingMembers(newNetworks);
|
cur.bulldozeContradictingMembers(newNetworks);
|
||||||
cur.updateMemberSpeeds(newNetworks);
|
cur.updateMemberSpeeds(newNetworks);
|
||||||
}
|
}
|
||||||
|
@ -201,16 +212,16 @@ public class KineticNetwork {
|
||||||
* @param newNetworks a List that any new networks created during this call will be added to
|
* @param newNetworks a List that any new networks created during this call will be added to
|
||||||
*/
|
*/
|
||||||
private void updateMemberSpeeds(List<KineticNetwork> newNetworks) {
|
private void updateMemberSpeeds(List<KineticNetwork> newNetworks) {
|
||||||
|
SolveResult recalculateSpeedResult = tryRecalculateSpeed();
|
||||||
|
// generators should not be turning against each other or have conflicting cycles by now
|
||||||
|
assert(recalculateSpeedResult.isOk());
|
||||||
|
|
||||||
// if we're stopped, then all members' speeds will be 0, so no need to check for speeding nodes
|
// if we're stopped, then all members' speeds will be 0, so no need to check for speeding nodes
|
||||||
if (isStopped()) {
|
if (isStopped()) {
|
||||||
members.forEach(KineticNode::stop);
|
members.forEach(KineticNode::stop);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SolveResult recalculateSpeedResult = tryRecalculateSpeed();
|
|
||||||
// generators should not be turning against each other or have conflicting cycles by now
|
|
||||||
assert(recalculateSpeedResult.isOk());
|
|
||||||
|
|
||||||
if (rootSpeedChanged) {
|
if (rootSpeedChanged) {
|
||||||
// root speed changed, update all nodes starting from the main generator
|
// root speed changed, update all nodes starting from the main generator
|
||||||
rootSpeedChanged = false;
|
rootSpeedChanged = false;
|
||||||
|
@ -220,8 +231,8 @@ public class KineticNetwork {
|
||||||
potentialNewBranches.stream()
|
potentialNewBranches.stream()
|
||||||
.filter(n -> !potentialNewBranches.contains(n.getSource()))
|
.filter(n -> !potentialNewBranches.contains(n.getSource()))
|
||||||
.forEach(n -> bfs(n, newNetworks, true));
|
.forEach(n -> bfs(n, newNetworks, true));
|
||||||
potentialNewBranches.clear();
|
|
||||||
}
|
}
|
||||||
|
potentialNewBranches.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bfs(KineticNode root, List<KineticNetwork> newNetworks, boolean followSource) {
|
private void bfs(KineticNode root, List<KineticNetwork> newNetworks, boolean followSource) {
|
||||||
|
|
|
@ -5,6 +5,8 @@ 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.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.NbtUtils;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -12,39 +14,90 @@ import javax.annotation.Nullable;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class KineticNode {
|
public class KineticNode {
|
||||||
|
|
||||||
private final Function<BlockPos, Optional<KineticNode>> nodeAccessor;
|
private final KineticSolver solver;
|
||||||
private final KineticTileEntity entity;
|
private @Nullable KineticTileEntity entity;
|
||||||
|
|
||||||
private @Nullable KineticNode source;
|
private @Nullable KineticNode source;
|
||||||
private KineticNetwork network;
|
private KineticNetwork network;
|
||||||
private float speedRatio = 1;
|
private float speedRatio = 1;
|
||||||
|
private float speedCur;
|
||||||
|
private float speedNext;
|
||||||
|
|
||||||
|
private final BlockPos pos;
|
||||||
private final KineticConnections connections;
|
private final KineticConnections connections;
|
||||||
private float generatedSpeed;
|
private float generatedSpeed;
|
||||||
private float stressCapacity;
|
private float stressCapacity;
|
||||||
private float stressImpact;
|
private float stressImpact;
|
||||||
|
private final boolean constantStress;
|
||||||
|
|
||||||
private float speedCur;
|
public KineticNode(KineticSolver solver, KineticTileEntity entity) {
|
||||||
private float speedNext;
|
this.solver = solver;
|
||||||
|
|
||||||
public KineticNode(KineticTileEntity entity, Function<BlockPos, Optional<KineticNode>> nodeAccessor) {
|
|
||||||
this.nodeAccessor = nodeAccessor;
|
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
|
|
||||||
|
this.pos = entity.getBlockPos();
|
||||||
this.connections = entity.getConnections();
|
this.connections = entity.getConnections();
|
||||||
this.generatedSpeed = entity.getGeneratedSpeed();
|
this.generatedSpeed = entity.getGeneratedSpeed();
|
||||||
this.stressImpact = entity.getStressImpact();
|
this.stressImpact = entity.getStressImpact();
|
||||||
this.stressCapacity = entity.getStressCapacity();
|
this.stressCapacity = entity.getStressCapacity();
|
||||||
|
this.constantStress = entity.isStressConstant();
|
||||||
|
|
||||||
this.network = new KineticNetwork(this);
|
this.network = new KineticNetwork(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private KineticNode(KineticSolver solver, BlockPos pos, KineticConnections connections, float generatedSpeed,
|
||||||
|
float stressCapacity, float stressImpact, boolean constantStress) {
|
||||||
|
this.solver = solver;
|
||||||
|
|
||||||
|
this.pos = pos;
|
||||||
|
this.connections = connections;
|
||||||
|
this.generatedSpeed = generatedSpeed;
|
||||||
|
this.stressImpact = stressImpact;
|
||||||
|
this.stressCapacity = stressCapacity;
|
||||||
|
this.constantStress = constantStress;
|
||||||
|
|
||||||
|
this.network = new KineticNetwork(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag save(CompoundTag tag) {
|
||||||
|
tag.put("Pos", NbtUtils.writeBlockPos(pos));
|
||||||
|
tag.put("Connections", connections.save(new CompoundTag()));
|
||||||
|
tag.putFloat("Generated", generatedSpeed);
|
||||||
|
tag.putFloat("Capacity", stressCapacity);
|
||||||
|
tag.putFloat("Impact", stressImpact);
|
||||||
|
if (constantStress)
|
||||||
|
tag.putBoolean("ConstantStress", true);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KineticNode load(KineticSolver solver, CompoundTag tag) {
|
||||||
|
BlockPos pos = NbtUtils.readBlockPos(tag.getCompound("Pos"));
|
||||||
|
KineticConnections connections = KineticConnections.load(tag.getCompound("Connections"));
|
||||||
|
float generatedSpeed = tag.getFloat("Generated");
|
||||||
|
float stressCapacity = tag.getFloat("Capacity");
|
||||||
|
float stressImpact = tag.getFloat("Impact");
|
||||||
|
boolean constantStress = tag.getBoolean("ConstantStress");
|
||||||
|
return new KineticNode(solver, pos, connections, generatedSpeed, stressCapacity, stressImpact, constantStress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoaded() {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onLoaded(KineticTileEntity entity) {
|
||||||
|
this.entity = entity;
|
||||||
|
network.onMemberLoaded(this);
|
||||||
|
if (speedCur != 0) entity.setSpeed(speedCur);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onUnloaded() {
|
||||||
|
this.entity = null;
|
||||||
|
}
|
||||||
|
|
||||||
public KineticConnections getConnections() {
|
public KineticConnections getConnections() {
|
||||||
return connections;
|
return connections;
|
||||||
}
|
}
|
||||||
|
@ -53,13 +106,17 @@ public class KineticNode {
|
||||||
return network;
|
return network;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BlockPos getPos() {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a Stream containing a pair for each compatible connection with this node, where the first value is
|
* @return a Stream containing a pair for each compatible connection with this node, where the first value is
|
||||||
* the connecting node and the second value is the speed ratio of the connection
|
* the connecting node and the second value is the speed ratio of the connection
|
||||||
*/
|
*/
|
||||||
public Stream<Pair<KineticNode, Float>> getActiveConnections() {
|
public Stream<Pair<KineticNode, Float>> getActiveConnections() {
|
||||||
return connections.getDirections().stream()
|
return connections.getDirections().stream()
|
||||||
.map(d -> nodeAccessor.apply(entity.getBlockPos().offset(d))
|
.map(d -> solver.getNode(pos.offset(d))
|
||||||
.map(n -> connections.checkConnection(n.connections, d)
|
.map(n -> connections.checkConnection(n.connections, d)
|
||||||
.map(r -> Pair.of(n, r))))
|
.map(r -> Pair.of(n, r))))
|
||||||
.flatMap(Optional::stream)
|
.flatMap(Optional::stream)
|
||||||
|
@ -72,7 +129,7 @@ public class KineticNode {
|
||||||
|
|
||||||
public Stream<KineticNetwork> getActiveStressOnlyConnections() {
|
public Stream<KineticNetwork> getActiveStressOnlyConnections() {
|
||||||
return connections.getDirections().stream()
|
return connections.getDirections().stream()
|
||||||
.map(d -> nodeAccessor.apply(entity.getBlockPos().offset(d))
|
.map(d -> solver.getNode(pos.offset(d))
|
||||||
.filter(n -> connections.checkStressOnlyConnection(n.connections, d)))
|
.filter(n -> connections.checkStressOnlyConnection(n.connections, d)))
|
||||||
.flatMap(Optional::stream)
|
.flatMap(Optional::stream)
|
||||||
.map(KineticNode::getNetwork);
|
.map(KineticNode::getNetwork);
|
||||||
|
@ -86,10 +143,15 @@ public class KineticNode {
|
||||||
return generatedSpeed != 0;
|
return generatedSpeed != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onUpdated() {
|
public boolean onUpdated() {
|
||||||
|
if (entity == null) return false;
|
||||||
|
|
||||||
|
boolean changed = false;
|
||||||
|
|
||||||
float generatedSpeedNew = entity.getGeneratedSpeed();
|
float generatedSpeedNew = entity.getGeneratedSpeed();
|
||||||
if (this.generatedSpeed != generatedSpeedNew) {
|
if (this.generatedSpeed != generatedSpeedNew) {
|
||||||
this.generatedSpeed = generatedSpeedNew;
|
this.generatedSpeed = generatedSpeedNew;
|
||||||
|
changed = true;
|
||||||
network.onMemberGeneratedSpeedUpdated(this);
|
network.onMemberGeneratedSpeedUpdated(this);
|
||||||
if (network.tryRecalculateSpeed().isContradiction()) {
|
if (network.tryRecalculateSpeed().isContradiction()) {
|
||||||
popBlock();
|
popBlock();
|
||||||
|
@ -99,14 +161,18 @@ public class KineticNode {
|
||||||
float stressImpactNew = entity.getStressImpact();
|
float stressImpactNew = entity.getStressImpact();
|
||||||
if (this.stressImpact != stressImpactNew) {
|
if (this.stressImpact != stressImpactNew) {
|
||||||
this.stressImpact = stressImpactNew;
|
this.stressImpact = stressImpactNew;
|
||||||
|
changed = true;
|
||||||
network.onMemberStressImpactUpdated();
|
network.onMemberStressImpactUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
float stressCapacityNew = entity.getStressCapacity();
|
float stressCapacityNew = entity.getStressCapacity();
|
||||||
if (this.stressCapacity != stressCapacityNew) {
|
if (this.stressCapacity != stressCapacityNew) {
|
||||||
this.stressCapacity = stressCapacityNew;
|
this.stressCapacity = stressCapacityNew;
|
||||||
|
changed = true;
|
||||||
network.onMemberStressCapacityUpdated();
|
network.onMemberStressCapacityUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasStressCapacity() {
|
public boolean hasStressCapacity() {
|
||||||
|
@ -122,11 +188,11 @@ public class KineticNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getStressCapacity() {
|
public float getStressCapacity() {
|
||||||
return Math.abs(stressCapacity * generatedSpeed);
|
return constantStress ? stressCapacity : stressCapacity * Math.abs(generatedSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getTotalStressImpact(float speedAtRoot) {
|
public float getTotalStressImpact(float speedAtRoot) {
|
||||||
return Math.abs(stressImpact * getTheoreticalSpeed(speedAtRoot));
|
return constantStress ? stressImpact : stressImpact * Math.abs(getTheoreticalSpeed(speedAtRoot));
|
||||||
}
|
}
|
||||||
|
|
||||||
private SolveResult setNetwork(KineticNetwork network) {
|
private SolveResult setNetwork(KineticNetwork network) {
|
||||||
|
@ -233,13 +299,18 @@ public class KineticNode {
|
||||||
public void flushChangedSpeed() {
|
public void flushChangedSpeed() {
|
||||||
if (speedCur != speedNext) {
|
if (speedCur != speedNext) {
|
||||||
speedCur = speedNext;
|
speedCur = speedNext;
|
||||||
entity.setSpeed(speedCur);
|
if (entity != null) {
|
||||||
|
entity.setSpeed(speedCur);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void popBlock() {
|
public void popBlock() {
|
||||||
// this should cause the node to get removed from the solver and lead to onRemoved() being called
|
if (entity != null) {
|
||||||
entity.getLevel().destroyBlock(entity.getBlockPos(), true);
|
solver.removeAndPopNow(entity);
|
||||||
|
} else {
|
||||||
|
solver.removeAndQueuePop(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,30 +10,108 @@ import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||||
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
import com.simibubi.create.foundation.utility.WorldAttached;
|
import com.simibubi.create.foundation.utility.WorldAttached;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Vec3i;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import net.minecraft.nbt.NbtUtils;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.saveddata.SavedData;
|
||||||
|
|
||||||
public class KineticSolver {
|
import org.checkerframework.checker.units.qual.C;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
private static final WorldAttached<KineticSolver> SOLVERS = new WorldAttached<>($ -> new KineticSolver());
|
public class KineticSolver extends SavedData {
|
||||||
|
|
||||||
|
public static final String DATA_FILE_NAME = "kinetics";
|
||||||
|
|
||||||
|
private static final WorldAttached<KineticSolver> SOLVERS = new WorldAttached<>(levelAccessor -> {
|
||||||
|
if (levelAccessor instanceof ServerLevel level)
|
||||||
|
return level.getDataStorage().computeIfAbsent(KineticSolver::load, KineticSolver::new, DATA_FILE_NAME);
|
||||||
|
return new KineticSolver();
|
||||||
|
});
|
||||||
|
|
||||||
public static KineticSolver getSolver(Level level) {
|
public static KineticSolver getSolver(Level level) {
|
||||||
return SOLVERS.get(level);
|
return SOLVERS.get(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<BlockPos, KineticNode> nodes = new HashMap<>();
|
private final Map<BlockPos, KineticNode> nodes = new HashMap<>();
|
||||||
|
private final Set<BlockPos> popQueue = new HashSet<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull CompoundTag save(@NotNull CompoundTag tag) {
|
||||||
|
ListTag popQueueTag = new ListTag();
|
||||||
|
for (BlockPos pos : popQueue) {
|
||||||
|
popQueueTag.add(NbtUtils.writeBlockPos(pos));
|
||||||
|
}
|
||||||
|
tag.put("PopQueue", popQueueTag);
|
||||||
|
|
||||||
|
ListTag nodesTag = new ListTag();
|
||||||
|
for (KineticNode node : nodes.values()) {
|
||||||
|
nodesTag.add(node.save(new CompoundTag()));
|
||||||
|
}
|
||||||
|
tag.put("Nodes", nodesTag);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KineticSolver load(CompoundTag tag) {
|
||||||
|
KineticSolver out = new KineticSolver();
|
||||||
|
|
||||||
|
tag.getList("PopQueue", Tag.TAG_COMPOUND).forEach(c ->
|
||||||
|
out.popQueue.add(NbtUtils.readBlockPos((CompoundTag) c)));
|
||||||
|
|
||||||
|
tag.getList("Nodes", Tag.TAG_COMPOUND).forEach(c ->
|
||||||
|
out.addUnloadedNode(KineticNode.load(out, (CompoundTag) c)));
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addUnloadedNode(KineticNode node) {
|
||||||
|
KineticNode nodePrev = nodes.remove(node.getPos());
|
||||||
|
if (nodePrev != null) nodePrev.onRemoved();
|
||||||
|
|
||||||
|
nodes.put(node.getPos(), node);
|
||||||
|
node.onAdded();
|
||||||
|
}
|
||||||
|
|
||||||
public void addNode(KineticTileEntity entity) {
|
public void addNode(KineticTileEntity entity) {
|
||||||
removeNode(entity);
|
BlockPos pos = entity.getBlockPos();
|
||||||
KineticNode node = new KineticNode(entity, this::getNode);
|
if (popQueue.contains(pos)) {
|
||||||
nodes.put(entity.getBlockPos(), node);
|
popQueue.remove(pos);
|
||||||
|
popBlock(entity.getLevel(), pos);
|
||||||
|
setDirty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KineticNode nodePrev = nodes.get(pos);
|
||||||
|
if (nodePrev != null) {
|
||||||
|
if (nodePrev.isLoaded()) {
|
||||||
|
nodes.remove(pos);
|
||||||
|
nodePrev.onRemoved();
|
||||||
|
} else {
|
||||||
|
// a node exists here but is unloaded, so just load it with this entity instead of replacing
|
||||||
|
nodePrev.onLoaded(entity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KineticNode node = new KineticNode(this, entity);
|
||||||
|
nodes.put(pos, node);
|
||||||
node.onAdded();
|
node.onAdded();
|
||||||
|
setDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateNode(KineticTileEntity entity) {
|
public void updateNode(KineticTileEntity entity) {
|
||||||
KineticNode node = nodes.get(entity.getBlockPos());
|
KineticNode node = nodes.get(entity.getBlockPos());
|
||||||
|
if (node == null) return;
|
||||||
|
|
||||||
if (!node.getConnections().equals(entity.getConnections())) {
|
if (!node.getConnections().equals(entity.getConnections())) {
|
||||||
// connections changed, so things could've been disconnected
|
// connections changed, so things could've been disconnected
|
||||||
|
@ -41,17 +119,49 @@ public class KineticSolver {
|
||||||
addNode(entity);
|
addNode(entity);
|
||||||
} else {
|
} else {
|
||||||
// connections are the same, so just update in case other properties changed
|
// connections are the same, so just update in case other properties changed
|
||||||
node.onUpdated();
|
if (node.onUpdated()) {
|
||||||
|
setDirty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void unloadNode(KineticTileEntity entity) {
|
||||||
|
KineticNode node = nodes.get(entity.getBlockPos());
|
||||||
|
if (node != null) node.onUnloaded();
|
||||||
|
}
|
||||||
|
|
||||||
protected Optional<KineticNode> getNode(BlockPos pos) {
|
protected Optional<KineticNode> getNode(BlockPos pos) {
|
||||||
return Optional.ofNullable(nodes.get(pos));
|
return Optional.ofNullable(nodes.get(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeNode(KineticTileEntity entity) {
|
public void removeNode(KineticTileEntity entity) {
|
||||||
KineticNode node = nodes.remove(entity.getBlockPos());
|
KineticNode node = nodes.remove(entity.getBlockPos());
|
||||||
if (node != null) node.onRemoved();
|
if (node != null) {
|
||||||
|
node.onRemoved();
|
||||||
|
setDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeAndQueuePop(BlockPos pos) {
|
||||||
|
KineticNode node = nodes.remove(pos);
|
||||||
|
if (node != null) {
|
||||||
|
popQueue.add(pos);
|
||||||
|
node.onRemoved();
|
||||||
|
setDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeAndPopNow(KineticTileEntity entity) {
|
||||||
|
KineticNode node = nodes.remove(entity.getBlockPos());
|
||||||
|
if (node != null) {
|
||||||
|
popBlock(entity.getLevel(), entity.getBlockPos());
|
||||||
|
node.onRemoved();
|
||||||
|
setDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void popBlock(Level level, BlockPos pos) {
|
||||||
|
level.destroyBlock(pos, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick() {
|
public void tick() {
|
||||||
|
@ -69,4 +179,18 @@ public class KineticSolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Float> isConnected(BlockPos from, BlockPos to) {
|
||||||
|
return getNode(from).flatMap(fromNode ->
|
||||||
|
getNode(to).flatMap(toNode ->
|
||||||
|
fromNode.getConnections()
|
||||||
|
.checkConnection(toNode.getConnections(), to.subtract(from))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStressOnlyConnected(BlockPos from, BlockPos to) {
|
||||||
|
return getNode(from).flatMap(fromNode ->
|
||||||
|
getNode(to).map(toNode ->
|
||||||
|
fromNode.getConnections()
|
||||||
|
.checkStressOnlyConnection(toNode.getConnections(), to.subtract(from)))
|
||||||
|
).orElse(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue