From 8f5a885bb0b8bbf2499ad4530bfe3ed12de37183 Mon Sep 17 00:00:00 2001 From: reidbhuntley Date: Fri, 24 Dec 2021 18:36:57 -0500 Subject: [PATCH] New approach --- .../contraptions/base/KineticTileEntity.java | 10 +- .../components/motor/CreativeMotorBlock.java | 10 +- .../relays/elementary/ShaftBlock.java | 15 +- .../contraptions/solver/AllPropertyTypes.java | 10 ++ .../contraptions/solver/Connection.java | 28 ---- .../contraptions/solver/ConnectionGoal.java | 43 ------ .../solver/ConstantSpeedRule.java | 21 +++ .../contraptions/solver/GeneratorGoal.java | 24 --- .../content/contraptions/solver/Goal.java | 17 --- .../solver/HalfShaftConnectionRule.java | 25 ++++ .../contraptions/solver/KineticSolver.java | 121 +++++++-------- .../content/contraptions/solver/Property.java | 46 ++++++ .../contraptions/solver/PropertyMap.java | 139 ++++++++++++++++++ .../contraptions/solver/RewriteRule.java | 76 ++++++++++ .../solver/ShaftConnectionRule.java | 26 ++++ .../solver/ShaftEqualSpeedRule.java | 40 +++++ .../content/contraptions/solver/Value.java | 21 --- 17 files changed, 456 insertions(+), 216 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/AllPropertyTypes.java delete mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/Connection.java delete mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/ConnectionGoal.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/ConstantSpeedRule.java delete mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/GeneratorGoal.java delete mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/Goal.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/HalfShaftConnectionRule.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/Property.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/PropertyMap.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/RewriteRule.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/ShaftConnectionRule.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/ShaftEqualSpeedRule.java delete mode 100644 src/main/java/com/simibubi/create/content/contraptions/solver/Value.java diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java index 44945670e..96b3240c2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java @@ -346,16 +346,24 @@ public class KineticTileEntity extends SmartTileEntity public void attachKinetics() { updateSpeed = false; - KineticSolver solver = KineticSolver.getSolver(level); + KineticSolver solver = KineticSolver.getSolver(level); BlockState state = getBlockState(); if (state.getBlock() instanceof SolverBlock sb) { + solver.removeAllRules(worldPosition); sb.created(solver, level, worldPosition); } + RotationPropagator.handleAdded(level, worldPosition, this); } public void detachKinetics() { + KineticSolver solver = KineticSolver.getSolver(level); + BlockState state = getBlockState(); + if (state.getBlock() instanceof SolverBlock) { + solver.removeAllRules(worldPosition); + } + RotationPropagator.handleRemoved(level, worldPosition, this); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorBlock.java index 530a5a082..8e611ff95 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/motor/CreativeMotorBlock.java @@ -3,7 +3,8 @@ package com.simibubi.create.content.contraptions.components.motor; import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.content.contraptions.solver.GeneratorGoal; +import com.simibubi.create.content.contraptions.solver.ConstantSpeedRule; +import com.simibubi.create.content.contraptions.solver.HalfShaftConnectionRule; import com.simibubi.create.content.contraptions.solver.KineticSolver; import com.simibubi.create.content.contraptions.solver.SolverBlock; import com.simibubi.create.foundation.block.ITE; @@ -76,6 +77,11 @@ public class CreativeMotorBlock extends DirectionalKineticBlock implements ITE te.generatedSpeed.getValue()).orElse(0); + + solver.addRule(pos, new HalfShaftConnectionRule(to)); + solver.addRule(pos, new ConstantSpeedRule(speed)); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java index 85768e425..1080d78b2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java @@ -7,8 +7,8 @@ import com.simibubi.create.AllShapes; import com.simibubi.create.content.contraptions.solver.KineticSolver; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock; -import com.simibubi.create.content.contraptions.solver.Connection; -import com.simibubi.create.content.contraptions.solver.ConnectionGoal; +import com.simibubi.create.content.contraptions.solver.ShaftConnectionRule; +import com.simibubi.create.content.contraptions.solver.ShaftEqualSpeedRule; import com.simibubi.create.content.contraptions.solver.SolverBlock; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; @@ -90,16 +90,13 @@ public class ShaftBlock extends AbstractShaftBlock implements SolverBlock { @Override public void created(KineticSolver solver, Level level, BlockPos pos) { BlockState state = level.getBlockState(pos); - Direction.Axis axis = state.getValue(AXIS); - Direction positive = Direction.fromAxisAndDirection(axis, Direction.AxisDirection.POSITIVE); + Direction negative = positive.getOpposite(); - Connection.Shaft c1 = new Connection.Shaft(pos, positive); - Connection.Shaft c2 = new Connection.Shaft(pos, positive.getOpposite()); - - solver.addGoal(new ConnectionGoal.EqualSpeed(c1)); - solver.addGoal(new ConnectionGoal.EqualSpeed(c2)); + solver.addRule(pos, new ShaftConnectionRule(axis)); + solver.addRule(pos, new ShaftEqualSpeedRule(positive)); + solver.addRule(pos, new ShaftEqualSpeedRule(negative)); } @MethodsReturnNonnullByDefault diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/AllPropertyTypes.java b/src/main/java/com/simibubi/create/content/contraptions/solver/AllPropertyTypes.java new file mode 100644 index 000000000..23e7f1d91 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/solver/AllPropertyTypes.java @@ -0,0 +1,10 @@ +package com.simibubi.create.content.contraptions.solver; + +import net.minecraft.core.Vec3i; + +import java.util.Set; + +public class AllPropertyTypes { + public static final Property.Type SPEED = new Property.Type<>(); + public static final Property.Type> SHAFT_CONNECTIONS = new Property.Type<>(); +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/Connection.java b/src/main/java/com/simibubi/create/content/contraptions/solver/Connection.java deleted file mode 100644 index 1a4915ff4..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/solver/Connection.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.simibubi.create.content.contraptions.solver; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; - -public abstract class Connection { - public final BlockPos from; - public final BlockPos to; - - public Connection(BlockPos from, BlockPos to) { - this.from = from; - this.to = to; - } - - public abstract boolean isCompatible(Connection that); - - public static final class Shaft extends Connection { - - public Shaft(BlockPos pos, Direction face) { - super(pos, pos.relative(face)); - } - - @Override - public boolean isCompatible(Connection that) { - return that instanceof Shaft; - } - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/ConnectionGoal.java b/src/main/java/com/simibubi/create/content/contraptions/solver/ConnectionGoal.java deleted file mode 100644 index aa5f68f26..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/solver/ConnectionGoal.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.simibubi.create.content.contraptions.solver; - -import net.minecraft.core.BlockPos; - -public abstract class ConnectionGoal implements Goal { - public final Connection connection; - - public ConnectionGoal(Connection connection) { - this.connection = connection; - } - - @Override - public void onAdded(KineticSolver.PropertyMap solver) { - solver.addConnection(connection); - } - - public static class EqualSpeed extends ConnectionGoal { - public EqualSpeed(Connection connection) { - super(connection); - } - - @Override - public BlockPos getPos() { - return connection.from; - } - - @Override - public SolveResult solve(KineticSolver.PropertyMap solver) { - if (solver.isComplete(connection)) { - Value toSpeed = solver.getOrCreateProperty(connection.to, "speed"); - Value fromSpeed = solver.getOrCreateProperty(connection.from, "speed"); - if (toSpeed instanceof Value.Known toValue && fromSpeed instanceof Value.Known fromValue) { - if (toValue.value != fromValue.value) { - return Goal.SolveResult.CONTRADICTION; - } - } else { - solver.setProperty(connection.to, "speed", fromSpeed); - } - } - return Goal.SolveResult.OK; - } - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/ConstantSpeedRule.java b/src/main/java/com/simibubi/create/content/contraptions/solver/ConstantSpeedRule.java new file mode 100644 index 000000000..b863e6b5d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/solver/ConstantSpeedRule.java @@ -0,0 +1,21 @@ +package com.simibubi.create.content.contraptions.solver; + +import java.util.Optional; + +public class ConstantSpeedRule implements RewriteRule.Descriptor { + private final float speed; + + public ConstantSpeedRule(float speed) { + this.speed = speed; + } + + @Override + public Property.Type getWrittenProperty() { + return AllPropertyTypes.SPEED; + } + + @Override + public Optional getRewrittenValue(RewriteRule.PropertyReader reader) { + return Optional.of(speed); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/GeneratorGoal.java b/src/main/java/com/simibubi/create/content/contraptions/solver/GeneratorGoal.java deleted file mode 100644 index 69e5d85c9..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/solver/GeneratorGoal.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.simibubi.create.content.contraptions.solver; - -import net.minecraft.core.BlockPos; - -public final class GeneratorGoal implements Goal { - public final BlockPos me; - public final float speed; - - public GeneratorGoal(BlockPos me, float speed) { - this.me = me; - this.speed = speed; - } - - @Override - public BlockPos getPos() { - return me; - } - - @Override - public SolveResult solve(KineticSolver.PropertyMap solver) { - solver.setProperty(me, "speed", new Value.Known(speed)); - return Goal.SolveResult.OK; - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/Goal.java b/src/main/java/com/simibubi/create/content/contraptions/solver/Goal.java deleted file mode 100644 index 2a4357756..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/solver/Goal.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.simibubi.create.content.contraptions.solver; - -import net.minecraft.core.BlockPos; - -public interface Goal { - BlockPos getPos(); - - SolveResult solve(KineticSolver.PropertyMap solver); - - default void onAdded(KineticSolver.PropertyMap solver) { - } - - enum SolveResult { - CONTRADICTION, - OK, - } -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/HalfShaftConnectionRule.java b/src/main/java/com/simibubi/create/content/contraptions/solver/HalfShaftConnectionRule.java new file mode 100644 index 000000000..52d34f1e8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/solver/HalfShaftConnectionRule.java @@ -0,0 +1,25 @@ +package com.simibubi.create.content.contraptions.solver; + +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; + +import java.util.Optional; +import java.util.Set; + +public class HalfShaftConnectionRule implements RewriteRule.Descriptor> { + private final Set connections; + + public HalfShaftConnectionRule(Direction dir) { + connections = Set.of(dir.getNormal()); + } + + @Override + public Property.Type> getWrittenProperty() { + return AllPropertyTypes.SHAFT_CONNECTIONS; + } + + @Override + public Optional> getRewrittenValue(RewriteRule.PropertyReader reader) { + return Optional.of(connections); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/KineticSolver.java b/src/main/java/com/simibubi/create/content/contraptions/solver/KineticSolver.java index 7f67255fd..03b3dfafd 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/solver/KineticSolver.java +++ b/src/main/java/com/simibubi/create/content/contraptions/solver/KineticSolver.java @@ -1,12 +1,10 @@ package com.simibubi.create.content.contraptions.solver; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import com.simibubi.create.foundation.utility.WorldAttached; @@ -23,89 +21,70 @@ public class KineticSolver { } private final PropertyMap properties = new PropertyMap(); + private final Map>> rules = new HashMap<>(); + private final HashSet> allRules = new HashSet<>(); - private final List goals = new ArrayList<>(); + private Set> rulesFrontier = new HashSet<>(); - public static class PropertyMap { - private final Map> properties = new HashMap<>(); - private final Map> connections = new HashMap<>(); + public RewriteRule addRule(BlockPos pos, RewriteRule.Descriptor ruleDesc) { + RewriteRule rule = new RewriteRule<>(ruleDesc); + RewriteRule.Tracker tracker = new RewriteRule.Tracker<>(rule, pos, properties::trackReader); + rules.computeIfAbsent(pos, $ -> new HashSet<>()).add(tracker); + allRules.add(tracker); + rulesFrontier.add(tracker); + return rule; + } - public Optional getProperty(BlockPos pos, String property) { - Map map = properties.get(pos); + public void removeRule(BlockPos pos, RewriteRule rule) { + Set> trackers = rules.get(pos); + if (trackers == null) return; + trackers.stream() + .filter(t -> t.rule == rule) + .findAny() + .ifPresent(tracker -> { + allRules.remove(tracker); + trackers.remove(tracker); + if (trackers.isEmpty()) { + rules.remove(pos); + } + properties.untrackReader(tracker); + rulesFrontier.addAll(properties.unwrite(tracker.writes)); + }); + } - if (map != null) { - return Optional.of(map.computeIfAbsent(property, $ -> new Value.Unknown())); - } else { - return Optional.empty(); - } + public void removeAllRules(BlockPos pos) { + Set> trackers = rules.remove(pos); + if (trackers == null) return; + for (RewriteRule.Tracker tracker: trackers) { + allRules.remove(tracker); + properties.untrackReader(tracker); } - - public Value getOrCreateProperty(BlockPos pos, String property) { - return properties.computeIfAbsent(pos, $ -> new HashMap<>()) - .computeIfAbsent(property, $ -> new Value.Unknown()); - } - - public void setProperty(BlockPos pos, String property, Value value) { - properties.computeIfAbsent(pos, $ -> new HashMap<>()) - .put(property, value); - } - - public boolean isComplete(Connection connection) { - Set connections = this.connections.get(connection.to); - - if (connections == null) return false; - - for (Connection other : connections) { - if (connection.isCompatible(other) && other.to.equals(connection.from)) { - return true; - } - } - - return false; - } - - public void addConnection(Connection connection) { - properties.computeIfAbsent(connection.from, $ -> new HashMap<>()); - connections.computeIfAbsent(connection.from, $ -> new HashSet<>()).add(connection); - } - - public void clear() { - properties.clear(); + for (RewriteRule.Tracker tracker: trackers) { + rulesFrontier.addAll(properties.unwrite(tracker.writes)); } } - private boolean needsUpdate; + public Set solve() { + Set contradictions = new HashSet<>(); - public List solve() { - if (!needsUpdate) return Collections.emptyList(); - needsUpdate = false; + while (!rulesFrontier.isEmpty()) { + Set> next = new HashSet<>(); - List troublemakers = new ArrayList<>(); + for (RewriteRule.Tracker rule : rulesFrontier) { + if (!allRules.contains(rule) || !rule.canRewrite()) continue; - outer: - while (true) { - properties.clear(); - - for (Goal goal : goals) { - Goal.SolveResult result = goal.solve(properties); - - switch (result) { - case CONTRADICTION -> { - troublemakers.add(goal.getPos()); - continue outer; - } - case OK -> {} + PropertyMap.WriteResult res = rule.rewrite(properties); + if (res instanceof PropertyMap.WriteResult.Ok ok) { + next.addAll(ok.readyToRewrite); + } else if (res instanceof PropertyMap.WriteResult.Contradiction) { + removeAllRules(rule.pos); + contradictions.add(rule.pos); } } - break; + + rulesFrontier = next; } - return troublemakers; - } - - public void addGoal(Goal goal) { - goals.add(goal); - needsUpdate = true; - goal.onAdded(properties); + return contradictions; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/Property.java b/src/main/java/com/simibubi/create/content/contraptions/solver/Property.java new file mode 100644 index 000000000..692daebdb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/solver/Property.java @@ -0,0 +1,46 @@ +package com.simibubi.create.content.contraptions.solver; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Vec3i; + +import java.util.Objects; + +public record Property(BlockPos pos, Type type) { + public static class Type { } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Property property = (Property) o; + return Objects.equals(pos, property.pos) && Objects.equals(type, property.type); + } + + @Override + public int hashCode() { + return Objects.hash(pos, type); + } + + public static record Relative(Vec3i offset, Type type) { + public Relative(Type type) { + this(Vec3i.ZERO, type); + } + + public Property toAbsolute(BlockPos pos) { + return new Property<>(pos.offset(offset), type); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Relative relative = (Relative) o; + return Objects.equals(offset, relative.offset) && Objects.equals(type, relative.type); + } + + @Override + public int hashCode() { + return Objects.hash(offset, type); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/PropertyMap.java b/src/main/java/com/simibubi/create/content/contraptions/solver/PropertyMap.java new file mode 100644 index 000000000..07823307c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/solver/PropertyMap.java @@ -0,0 +1,139 @@ +package com.simibubi.create.content.contraptions.solver; + +import net.minecraft.core.BlockPos; + +import javax.annotation.Nonnull; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class PropertyMap { + public static sealed class WriteResult { + public static final class Ok extends WriteResult { + public static final Ok V = new Ok(Set.of()); + public final Set> readyToRewrite; + public Ok(Set> readyToRewrite) { this.readyToRewrite = readyToRewrite; } + } + + public static final class Contradiction extends WriteResult { + public static final Contradiction V = new Contradiction(); + } + } + + private static class Counter { + public final Property key; + private T value; + private final Set> readers = new HashSet<>(); + + public Counter(Property key) { + this.key = key; + } + + public boolean isEmpty() { + return value == null; + } + + public boolean canDrop() { + return isEmpty() && readers.isEmpty(); + } + + public Optional read() { + return Optional.ofNullable(value); + } + + public WriteResult write(@Nonnull T newValue) { + WriteResult result = WriteResult.Ok.V; + if (isEmpty()) { + value = newValue; + // notify readers + readers.forEach(RewriteRule.Tracker::dependencyRemoved); + result = new WriteResult.Ok(readers.stream() + .filter(RewriteRule.Tracker::canRewrite) + .collect(Collectors.toSet())); + } else if (!value.equals(newValue)) { + return WriteResult.Contradiction.V; + } + return result; + } + + public void unwrite() { + if (isEmpty()) throw new IllegalStateException(); + value = null; + // notify readers + readers.forEach(RewriteRule.Tracker::dependencyAdded); + } + + public boolean trackReader(RewriteRule.Tracker reader) { + readers.add(reader); + return isEmpty(); + } + + public void untrackReader(RewriteRule.Tracker reader) { + readers.remove(reader); + } + } + + private final Map, Counter> properties = new HashMap<>(); + + public Optional read(Property property) { + Counter counter = (Counter) properties.get(property); + if (counter == null) return Optional.empty(); + return counter.read(); + } + + public WriteResult write(Property property, T value) { + Counter counter = (Counter) properties.computeIfAbsent(property, $ -> new Counter<>(property)); + return counter.write(value); + } + + public Set> unwrite(Property property) { + Counter init = properties.get(property); + if (init == null) return Set.of(); + + Set> toVisit = new HashSet<>(); + toVisit.add(init); + Set> visited = new HashSet<>(); + + while (!toVisit.isEmpty()) { + Set> next = new HashSet<>(); + + for (Counter c : toVisit) { + if (c.isEmpty() || visited.contains(c)) continue; + visited.add(c); + + c.unwrite(); + if (c.canDrop()) { + properties.put(c.key, null); + } + + c.readers.stream() + .map(r -> properties.get(r.writes)) + .filter(Objects::nonNull) + .forEachOrdered(toVisit::add); + } + + toVisit = next; + } + + return visited.stream().flatMap(c -> c.readers.stream()).collect(Collectors.toSet()); + } + + public int trackReader(RewriteRule.Tracker reader) { + int dependencies = 0; + for (Property p : reader.reads) { + dependencies += properties.computeIfAbsent(p, $ -> new Counter<>(p)).trackReader(reader) ? 1 : 0; + } + return dependencies; + } + + public void untrackReader(RewriteRule.Tracker reader) { + for (Property property : reader.reads) { + properties.get(property).untrackReader(reader); + } + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/RewriteRule.java b/src/main/java/com/simibubi/create/content/contraptions/solver/RewriteRule.java new file mode 100644 index 000000000..e5b8104c1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/solver/RewriteRule.java @@ -0,0 +1,76 @@ +package com.simibubi.create.content.contraptions.solver; + +import net.minecraft.core.BlockPos; + +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class RewriteRule { + private final Property.Type writes; + private final Set> reads; + private final Descriptor descriptor; + + public interface Descriptor { + Property.Type getWrittenProperty(); + + default Set> getReadProperties() { return Set.of(); } + + Optional getRewrittenValue(PropertyReader reader); + } + + public RewriteRule(Descriptor descriptor) { + this.descriptor = descriptor; + this.writes = descriptor.getWrittenProperty(); + this.reads = descriptor.getReadProperties(); + } + + record PropertyReader(BlockPos pos, PropertyMap map) { + public U read(Property.Relative property) { + return map.read(property.toAbsolute(pos)).get(); + } + } + + private PropertyMap.WriteResult rewrite(BlockPos pos, PropertyMap properties) { + return descriptor + .getRewrittenValue(new PropertyReader(pos, properties)) + .map(v -> properties.write(new Property<>(pos, writes), v)) + .orElse(PropertyMap.WriteResult.Ok.V); + } + + public static class Tracker { + public final RewriteRule rule; + public final BlockPos pos; + public final Property writes; + public final Set> reads; + private int dependencies; + + public Tracker(RewriteRule rule, BlockPos pos, Function, Integer> dependencies) { + this.rule = rule; + this.pos = pos; + this.writes = new Property<>(pos, rule.writes); + this.reads = rule.reads.stream().map(p -> p.toAbsolute(pos)).collect(Collectors.toSet()); + this.dependencies = dependencies.apply(this); + } + + public PropertyMap.WriteResult rewrite(PropertyMap properties) { + if (!canRewrite()) throw new IllegalStateException(); + return rule.rewrite(pos, properties); + } + + public void dependencyAdded() { + dependencies += 1; + } + + public void dependencyRemoved() { + if (dependencies == 0) throw new IllegalStateException(); + dependencies -= 1; + } + + public boolean canRewrite() { + return dependencies == 0; + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/ShaftConnectionRule.java b/src/main/java/com/simibubi/create/content/contraptions/solver/ShaftConnectionRule.java new file mode 100644 index 000000000..e6aa6b261 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/solver/ShaftConnectionRule.java @@ -0,0 +1,26 @@ +package com.simibubi.create.content.contraptions.solver; + +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; + +import java.util.Optional; +import java.util.Set; + +public class ShaftConnectionRule implements RewriteRule.Descriptor> { + private final Set connections; + + public ShaftConnectionRule(Direction.Axis axis) { + Direction positive = Direction.fromAxisAndDirection(axis, Direction.AxisDirection.POSITIVE); + connections = Set.of(positive.getNormal(), positive.getOpposite().getNormal()); + } + + @Override + public Property.Type> getWrittenProperty() { + return AllPropertyTypes.SHAFT_CONNECTIONS; + } + + @Override + public Optional> getRewrittenValue(RewriteRule.PropertyReader reader) { + return Optional.of(connections); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/ShaftEqualSpeedRule.java b/src/main/java/com/simibubi/create/content/contraptions/solver/ShaftEqualSpeedRule.java new file mode 100644 index 000000000..a54689d4e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/solver/ShaftEqualSpeedRule.java @@ -0,0 +1,40 @@ +package com.simibubi.create.content.contraptions.solver; + +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; + +import java.util.Optional; +import java.util.Set; + +public class ShaftEqualSpeedRule implements RewriteRule.Descriptor { + private final Vec3i to, from; + private final Property.Relative> otherConnections; + private final Property.Relative otherSpeed; + + public ShaftEqualSpeedRule(Direction dir) { + to = dir.getNormal(); + from = dir.getOpposite().getNormal(); + otherConnections = new Property.Relative<>(to, AllPropertyTypes.SHAFT_CONNECTIONS); + otherSpeed = new Property.Relative<>(to, AllPropertyTypes.SPEED); + } + + @Override + public Property.Type getWrittenProperty() { + return AllPropertyTypes.SPEED; + } + + @Override + public Set> getReadProperties() { + return Set.of(otherConnections, otherSpeed); + } + + @Override + public Optional getRewrittenValue(RewriteRule.PropertyReader reader) { + Set otherConnections = reader.read(this.otherConnections); + float otherSpeed = reader.read(this.otherSpeed); + + if (otherConnections.contains(from)) + return Optional.of(otherSpeed); + return Optional.empty(); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/solver/Value.java b/src/main/java/com/simibubi/create/content/contraptions/solver/Value.java deleted file mode 100644 index 60460c50a..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/solver/Value.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.simibubi.create.content.contraptions.solver; - -public sealed class Value { - public static final class Unknown extends Value { - private static int nextID = 0; - - public final int id; - - public Unknown() { - this.id = nextID++; - } - } - - public static final class Known extends Value { - public final float value; - - public Known(float value) { - this.value = value; - } - } -}