mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-01-25 20:38:11 +01:00
Continue work on solver
This commit is contained in:
parent
760bffe343
commit
69d33525f6
13 changed files with 294 additions and 98 deletions
|
@ -1,78 +0,0 @@
|
|||
package com.simibubi.create.content.contraptions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public class KineticSolver {
|
||||
|
||||
private final Map<BlockPos, Connection> connectionsFrom = new HashMap<>();
|
||||
private final Map<BlockPos, Connection> connectionsTo = new HashMap<>();
|
||||
|
||||
private final List<Goal> goals = new ArrayList<>();
|
||||
|
||||
private boolean needsUpdate;
|
||||
|
||||
public void solve() {
|
||||
if (!needsUpdate) return;
|
||||
needsUpdate = false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void addFact(BlockPos pos) {
|
||||
|
||||
}
|
||||
|
||||
public void addGoal(Goal goal) {
|
||||
goals.add(goal);
|
||||
needsUpdate = true;
|
||||
}
|
||||
|
||||
public interface SolverBlock {
|
||||
void created(KineticSolver solver, Level level, BlockPos pos);
|
||||
}
|
||||
|
||||
public static 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Goal {
|
||||
public final Connection connection;
|
||||
|
||||
public Goal(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
public static final class EqualSpeed extends Goal {
|
||||
public EqualSpeed(Connection connection) {
|
||||
super(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ public class RotationPropagator {
|
|||
* Determines the change in rotation between two attached kinetic entities. For
|
||||
* instance, an axis connection returns 1 while a 1-to-1 gear connection
|
||||
* reverses the rotation and therefore returns -1.
|
||||
*
|
||||
*
|
||||
* @param from
|
||||
* @param to
|
||||
* @return
|
||||
|
@ -201,21 +201,21 @@ public class RotationPropagator {
|
|||
|
||||
/**
|
||||
* Insert the added position to the kinetic network.
|
||||
*
|
||||
*
|
||||
* @param worldIn
|
||||
* @param pos
|
||||
*/
|
||||
public static void handleAdded(Level worldIn, BlockPos pos, KineticTileEntity addedTE) {
|
||||
if (worldIn.isClientSide)
|
||||
return;
|
||||
if (!worldIn.isLoaded(pos))
|
||||
return;
|
||||
propagateNewSource(addedTE);
|
||||
// if (worldIn.isClientSide)
|
||||
// return;
|
||||
// if (!worldIn.isLoaded(pos))
|
||||
// return;
|
||||
// propagateNewSource(addedTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for sourceless networks attached to the given entity and update them.
|
||||
*
|
||||
*
|
||||
* @param currentTE
|
||||
*/
|
||||
private static void propagateNewSource(KineticTileEntity currentTE) {
|
||||
|
@ -230,7 +230,7 @@ public class RotationPropagator {
|
|||
|
||||
if (newSpeed == 0 && oppositeSpeed == 0)
|
||||
continue;
|
||||
|
||||
|
||||
boolean incompatible =
|
||||
Math.signum(newSpeed) != Math.signum(speedOfNeighbour) && (newSpeed != 0 && speedOfNeighbour != 0);
|
||||
|
||||
|
@ -300,7 +300,7 @@ public class RotationPropagator {
|
|||
|
||||
/**
|
||||
* Remove the given entity from the network.
|
||||
*
|
||||
*
|
||||
* @param worldIn
|
||||
* @param pos
|
||||
* @param removedTE
|
||||
|
@ -333,7 +333,7 @@ public class RotationPropagator {
|
|||
/**
|
||||
* Clear the entire subnetwork depending on the given entity and find a new
|
||||
* source
|
||||
*
|
||||
*
|
||||
* @param updateTE
|
||||
*/
|
||||
private static void propagateMissingSource(KineticTileEntity updateTE) {
|
||||
|
|
|
@ -18,6 +18,8 @@ import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation;
|
|||
import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel;
|
||||
import com.simibubi.create.content.contraptions.relays.gearbox.GearboxBlock;
|
||||
import com.simibubi.create.content.contraptions.solver.KineticSolver;
|
||||
import com.simibubi.create.content.contraptions.solver.SolverBlock;
|
||||
import com.simibubi.create.foundation.block.BlockStressValues;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.item.TooltipHelper;
|
||||
|
@ -344,6 +346,12 @@ public class KineticTileEntity extends SmartTileEntity
|
|||
|
||||
public void attachKinetics() {
|
||||
updateSpeed = false;
|
||||
KineticSolver solver = KineticSolver.getSolver(level);
|
||||
|
||||
BlockState state = getBlockState();
|
||||
if (state.getBlock() instanceof SolverBlock sb) {
|
||||
sb.created(solver, level, worldPosition);
|
||||
}
|
||||
RotationPropagator.handleAdded(level, worldPosition, this);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@ 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.KineticSolver;
|
||||
import com.simibubi.create.content.contraptions.solver.SolverBlock;
|
||||
import com.simibubi.create.foundation.block.ITE;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -10,6 +13,7 @@ import net.minecraft.core.Direction;
|
|||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
@ -17,7 +21,7 @@ import net.minecraft.world.level.pathfinder.PathComputationType;
|
|||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
public class CreativeMotorBlock extends DirectionalKineticBlock implements ITE<CreativeMotorTileEntity> {
|
||||
public class CreativeMotorBlock extends DirectionalKineticBlock implements ITE<CreativeMotorTileEntity>, SolverBlock {
|
||||
|
||||
public CreativeMotorBlock(Properties properties) {
|
||||
super(properties);
|
||||
|
@ -54,7 +58,7 @@ public class CreativeMotorBlock extends DirectionalKineticBlock implements ITE<C
|
|||
public boolean hideStressImpact() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) {
|
||||
return false;
|
||||
|
@ -69,5 +73,9 @@ public class CreativeMotorBlock extends DirectionalKineticBlock implements ITE<C
|
|||
public BlockEntityType<? extends CreativeMotorTileEntity> getTileEntityType() {
|
||||
return AllTileEntities.MOTOR.get();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void created(KineticSolver solver, Level level, BlockPos pos) {
|
||||
solver.addGoal(new GeneratorGoal(pos, 16));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,12 @@ import java.util.function.Predicate;
|
|||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.content.contraptions.KineticSolver;
|
||||
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.SolverBlock;
|
||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
||||
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
||||
|
@ -27,7 +30,7 @@ import net.minecraft.world.phys.BlockHitResult;
|
|||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
public class ShaftBlock extends AbstractShaftBlock implements KineticSolver.SolverBlock {
|
||||
public class ShaftBlock extends AbstractShaftBlock implements SolverBlock {
|
||||
|
||||
private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper());
|
||||
|
||||
|
@ -92,11 +95,11 @@ public class ShaftBlock extends AbstractShaftBlock implements KineticSolver.Solv
|
|||
|
||||
Direction positive = Direction.fromAxisAndDirection(axis, Direction.AxisDirection.POSITIVE);
|
||||
|
||||
KineticSolver.Connection.Shaft c1 = new KineticSolver.Connection.Shaft(pos, positive);
|
||||
KineticSolver.Connection.Shaft c2 = new KineticSolver.Connection.Shaft(pos, positive.getOpposite());
|
||||
Connection.Shaft c1 = new Connection.Shaft(pos, positive);
|
||||
Connection.Shaft c2 = new Connection.Shaft(pos, positive.getOpposite());
|
||||
|
||||
solver.addGoal(new KineticSolver.Goal.EqualSpeed(c1));
|
||||
solver.addGoal(new KineticSolver.Goal.EqualSpeed(c2));
|
||||
solver.addGoal(new ConnectionGoal.EqualSpeed(c1));
|
||||
solver.addGoal(new ConnectionGoal.EqualSpeed(c2));
|
||||
}
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
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,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
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;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public class KineticSolver {
|
||||
|
||||
private static final WorldAttached<KineticSolver> SOLVERS = new WorldAttached<>($ -> new KineticSolver());
|
||||
|
||||
public static KineticSolver getSolver(Level level) {
|
||||
return SOLVERS.get(level);
|
||||
}
|
||||
|
||||
private final PropertyMap properties = new PropertyMap();
|
||||
|
||||
private final List<Goal> goals = new ArrayList<>();
|
||||
|
||||
public static class PropertyMap {
|
||||
private final Map<BlockPos, Map<String, Value>> properties = new HashMap<>();
|
||||
private final Map<BlockPos, Set<Connection>> connections = new HashMap<>();
|
||||
|
||||
public Optional<Value> getProperty(BlockPos pos, String property) {
|
||||
Map<String, Value> map = properties.get(pos);
|
||||
|
||||
if (map != null) {
|
||||
return Optional.of(map.computeIfAbsent(property, $ -> new Value.Unknown()));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
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<Connection> 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();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needsUpdate;
|
||||
|
||||
public List<BlockPos> solve() {
|
||||
if (!needsUpdate) return Collections.emptyList();
|
||||
needsUpdate = false;
|
||||
|
||||
List<BlockPos> troublemakers = new ArrayList<>();
|
||||
|
||||
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 -> {}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return troublemakers;
|
||||
}
|
||||
|
||||
public void addGoal(Goal goal) {
|
||||
goals.add(goal);
|
||||
needsUpdate = true;
|
||||
goal.onAdded(properties);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.simibubi.create.content.contraptions.solver;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public interface SolverBlock {
|
||||
void created(KineticSolver solver, Level level, BlockPos pos);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.tra
|
|||
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
|
||||
import com.simibubi.create.content.contraptions.fluids.recipe.FluidTransferRecipes;
|
||||
import com.simibubi.create.content.contraptions.fluids.recipe.PotionMixingRecipeManager;
|
||||
import com.simibubi.create.content.contraptions.solver.KineticSolver;
|
||||
import com.simibubi.create.content.contraptions.wrench.WrenchItem;
|
||||
import com.simibubi.create.content.curiosities.toolbox.ToolboxHandler;
|
||||
import com.simibubi.create.content.curiosities.weapons.PotatoProjectileTypeManager;
|
||||
|
@ -110,6 +111,8 @@ public class CommonEvents {
|
|||
CapabilityMinecartController.tick(world);
|
||||
CouplingPhysics.tick(world);
|
||||
LinkedControllerServerHandler.tick(world);
|
||||
|
||||
KineticSolver.getSolver(world).solve();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
|
Loading…
Reference in a new issue