Optimizing and Stabilizing Kinetic Networks

- Kinetic components can no longer overpower components of their own network, fixes speed-up cycles in certain arrangements
- Kinetic networks are now identified by the packed block position of the source
- Networks now get assigned to tileentities within the tick of them changing, fixes late overstress callbacks messing with some components
- Wrench now keeps the instance of kinetic TEs intact when rotating their blocks, it only updates their kinetic connections
- Kinetic blocks no longer carry over their rotation and source information when moved by pistons or rotated by bearings
- Fixed crash when pulley retracts without an attached structure
- Deployers now hold onto their stack of items if they match the filter
- Fixed Deployers duplicating activated blocks when not facing an axis-aligned direction
- Fixed belts not properly re-attaching the shafts left behind when destroyed
This commit is contained in:
simibubi 2020-03-06 23:25:13 +01:00
parent b89db104b8
commit ea5c77b2b2
31 changed files with 267 additions and 244 deletions

View File

@ -62,11 +62,15 @@ public class ColorHelper {
int b = color & 0xFF;
return new Vec3d(r, g, b).scale(1 / 256d);
}
public static int colorFromUUID(UUID uuid) {
if (uuid == null)
return 0x333333;
int rainbowColor = ColorHelper.rainbowColor((int) uuid.getLeastSignificantBits());
return colorFromLong(uuid.getLeastSignificantBits());
}
public static int colorFromLong(long l) {
int rainbowColor = ColorHelper.rainbowColor(String.valueOf(l).hashCode());
return ColorHelper.mixColors(rainbowColor, 0xFFFFFF, .5f);
}

View File

@ -25,7 +25,7 @@ public class KineticDebugger {
return;
World world = Minecraft.getInstance().world;
BlockPos toOutline = te.hasSource() ? te.getSource() : te.getPos();
BlockPos toOutline = te.hasSource() ? te.source : te.getPos();
VoxelShape shape = world.getBlockState(toOutline).getShape(world, toOutline);
TessellatorHelper.prepareForDrawing();

View File

@ -2,35 +2,32 @@ package com.simibubi.create.modules.contraptions;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
public class KineticNetwork {
public UUID id;
public Long id;
public boolean initialized;
private float maxStress;
private float currentStress;
private float unloadedStressCapacity;
private float unloadedStress;
public Map<KineticTileEntity, Float> sources;
public Map<KineticTileEntity, Float> members;
private float currentCapacity;
private float currentStress;
private float unloadedCapacity;
private float unloadedStress;
public KineticNetwork() {
id = UUID.randomUUID();
sources = new HashMap<>();
members = new HashMap<>();
}
public void initFromTE(float maxStress, float currentStress) {
unloadedStressCapacity = maxStress;
unloadedCapacity = maxStress;
unloadedStress = currentStress;
initialized = true;
updateStress();
updateStressCapacity();
updateCapacity();
}
public void addSilently(KineticTileEntity te) {
@ -38,7 +35,7 @@ public class KineticNetwork {
return;
if (te.isSource()) {
float capacity = te.getAddedStressCapacity();
unloadedStressCapacity -= capacity * getStressMultiplierForSpeed(te.getGeneratedSpeed());
unloadedCapacity -= capacity * getStressMultiplierForSpeed(te.getGeneratedSpeed());
sources.put(te, capacity);
}
float stressApplied = te.getStressApplied();
@ -49,19 +46,16 @@ public class KineticNetwork {
public void add(KineticTileEntity te) {
if (members.containsKey(te))
return;
if (te.isSource()) {
if (te.isSource())
sources.put(te, te.getAddedStressCapacity());
updateStressCapacity();
}
members.put(te, te.getStressApplied());
updateStress();
sync();
te.updateStressFromNetwork(currentCapacity, currentStress);
te.networkDirty = true;
}
public void updateCapacityFor(KineticTileEntity te, float capacity) {
sources.put(te, capacity);
updateStressCapacity();
updateCapacity();
}
public void updateStressFor(KineticTileEntity te, float stress) {
@ -72,46 +66,66 @@ public class KineticNetwork {
public void remove(KineticTileEntity te) {
if (!members.containsKey(te))
return;
if (te.isSource()) {
if (te.isSource())
sources.remove(te);
updateStressCapacity();
members.remove(te);
te.updateStressFromNetwork(0, 0);
if (members.isEmpty()) {
TorquePropagator.networks.get(te.getWorld()).remove(this.id);
return;
}
members.remove(te);
updateStress();
sync();
if (members.isEmpty())
TorquePropagator.networks.get(te.getWorld()).remove(this.id);
members.keySet().stream().findFirst().map(member -> member.networkDirty = true);
}
public void sync() {
for (KineticTileEntity te : members.keySet())
te.sync(maxStress, currentStress);
te.updateStressFromNetwork(currentCapacity, currentStress);
}
public void updateStressCapacity() {
float presentCapacity = 0;
for (KineticTileEntity te : sources.keySet())
presentCapacity += sources.get(te) * getStressMultiplierForSpeed(te.getGeneratedSpeed());
float newMaxStress = presentCapacity + unloadedStressCapacity;
if (maxStress != newMaxStress) {
maxStress = newMaxStress;
public void updateCapacity() {
float newMaxStress = calculateCapacity();
if (currentCapacity != newMaxStress) {
currentCapacity = newMaxStress;
sync();
}
}
public void updateStress() {
float presentStress = 0;
for (KineticTileEntity te : members.keySet())
presentStress += members.get(te) * getStressMultiplierForSpeed(te.getTheoreticalSpeed());
float newStress = presentStress + unloadedStress;
float newStress = calculateStress();
if (currentStress != newStress) {
currentStress = newStress;
sync();
}
}
public void updateNetwork() {
float newStress = calculateStress();
float newMaxStress = calculateCapacity();
if (currentStress != newStress || currentCapacity != newMaxStress) {
currentStress = newStress;
currentCapacity = newMaxStress;
sync();
}
}
public float calculateCapacity() {
float presentCapacity = 0;
for (KineticTileEntity te : sources.keySet())
presentCapacity += sources.get(te) * getStressMultiplierForSpeed(te.getGeneratedSpeed());
float newMaxStress = presentCapacity + unloadedCapacity;
return newMaxStress;
}
public float calculateStress() {
float presentStress = 0;
for (KineticTileEntity te : members.keySet())
presentStress += members.get(te) * getStressMultiplierForSpeed(te.getTheoreticalSpeed());
float newStress = presentStress + unloadedStress;
return newStress;
}
private float getStressMultiplierForSpeed(float speed) {
return Math.abs(speed);
}

View File

@ -192,7 +192,7 @@ public class RotationPropagator {
float neighbourSpeed = neighbourTE.getTheoreticalSpeed();
if (neighbourSpeed == 0)
continue;
if (neighbourTE.hasSource() && neighbourTE.getSource().equals(addedTE.getPos())) {
if (neighbourTE.hasSource() && neighbourTE.source.equals(addedTE.getPos())) {
addedTE.setSpeed(neighbourSpeed * speedModifier);
addedTE.onSpeedChanged(0);
addedTE.sendData();
@ -235,18 +235,19 @@ public class RotationPropagator {
return;
}
// Opposite directions
if (incompatible) {
// Opposite directions
world.destroyBlock(pos, true);
return;
} else {
// Same direction: overpower the slower speed
} else {
// Neighbour faster, overpower the incoming tree
if (Math.abs(oppositeSpeed) > Math.abs(speedOfCurrent)) {
// Neighbour faster, overpower the incoming tree
currentTE.setSource(neighbourTE.getPos());
float prevSpeed = currentTE.getSpeed();
currentTE.setSpeed(speedOfNeighbour * getRotationSpeedModifier(neighbourTE, currentTE));
currentTE.setSource(neighbourTE.getPos());
currentTE.onSpeedChanged(prevSpeed);
currentTE.sendData();
@ -256,18 +257,20 @@ public class RotationPropagator {
// Current faster, overpower the neighbours' tree
if (Math.abs(newSpeed) >= Math.abs(speedOfNeighbour)) {
if (!currentTE.canOverPower(neighbourTE)) {
// Do not overpower you own network -> cycle
if (!currentTE.hasNetwork() || currentTE.network.equals(neighbourTE.network)) {
if (Math.abs(newSpeed) > Math.abs(speedOfNeighbour))
world.destroyBlock(pos, true);
continue;
}
if (currentTE.hasSource() && currentTE.getSource().equals(neighbourTE.getPos()))
if (currentTE.hasSource() && currentTE.source.equals(neighbourTE.getPos()))
currentTE.removeSource();
neighbourTE.setSource(currentTE.getPos());
float prevSpeed = neighbourTE.getSpeed();
neighbourTE.setSpeed(speedOfCurrent * getRotationSpeedModifier(currentTE, neighbourTE));
neighbourTE.setSource(currentTE.getPos());
neighbourTE.onSpeedChanged(prevSpeed);
neighbourTE.sendData();
propagateNewSource(neighbourTE);
@ -309,7 +312,7 @@ public class RotationPropagator {
continue;
final KineticTileEntity neighbourTE = (KineticTileEntity) worldIn.getTileEntity(neighbourPos);
if (!neighbourTE.hasSource() || !neighbourTE.getSource().equals(pos))
if (!neighbourTE.hasSource() || !neighbourTE.source.equals(pos))
continue;
propagateMissingSource(neighbourTE);
@ -329,7 +332,7 @@ public class RotationPropagator {
List<KineticTileEntity> potentialNewSources = new LinkedList<>();
List<BlockPos> frontier = new LinkedList<>();
frontier.add(updateTE.getPos());
BlockPos missingSource = updateTE.hasSource() ? updateTE.getSource() : null;
BlockPos missingSource = updateTE.hasSource() ? updateTE.source : null;
while (!frontier.isEmpty()) {
final BlockPos pos = frontier.remove(0);
@ -344,7 +347,7 @@ public class RotationPropagator {
if (!neighbourTE.hasSource())
continue;
if (!neighbourTE.getSource().equals(pos)) {
if (!neighbourTE.source.equals(pos)) {
potentialNewSources.add(neighbourTE);
continue;
}

View File

@ -2,7 +2,6 @@ package com.simibubi.create.modules.contraptions;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import com.simibubi.create.Create;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
@ -11,7 +10,7 @@ import net.minecraft.world.IWorld;
public class TorquePropagator {
static Map<IWorld, Map<UUID, KineticNetwork>> networks = new HashMap<>();
static Map<IWorld, Map<Long, KineticNetwork>> networks = new HashMap<>();
public void onLoadWorld(IWorld world) {
networks.put(world, new HashMap<>());
@ -24,15 +23,15 @@ public class TorquePropagator {
}
public KineticNetwork getNetworkFor(KineticTileEntity te) {
UUID id = te.getNetworkID();
Long id = te.network;
KineticNetwork network;
Map<UUID, KineticNetwork> map = networks.get(te.getWorld());
Map<Long, KineticNetwork> map = networks.get(te.getWorld());
if (id == null)
return null;
if (!map.containsKey(id)) {
network = new KineticNetwork();
network.id = te.getNetworkID();
network.id = te.network;
map.put(id, network);
}
network = map.get(id);

View File

@ -90,13 +90,7 @@ public abstract class DirectionalAxisKineticBlock extends DirectionalKineticBloc
World world = context.getWorld();
Direction face = context.getFace();
if ((turnBackOnWrenched() ? face.getOpposite() : face) == state.get(FACING)) {
if (!world.isRemote) {
BlockPos pos = context.getPos();
world.removeTileEntity(pos);
world.setBlockState(pos, state.cycle(AXIS_ALONG_FIRST_COORDINATE), 3);
KineticTileEntity tileEntity = (KineticTileEntity) world.getTileEntity(pos);
tileEntity.attachKinetics();
}
KineticTileEntity.switchToBlockState(world, context.getPos(), state.cycle(AXIS_ALONG_FIRST_COORDINATE));
return ActionResultType.SUCCESS;
}
return super.onWrenched(state, context);

View File

@ -11,7 +11,6 @@ import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public abstract class DirectionalKineticBlock extends KineticBlock {
@ -56,14 +55,7 @@ public abstract class DirectionalKineticBlock extends KineticBlock {
BlockState with = state.with(FACING, facing);
if (!with.isValidPosition(world, context.getPos()))
return ActionResultType.PASS;
if (!world.isRemote) {
BlockPos pos = context.getPos();
world.removeTileEntity(pos);
world.setBlockState(pos, with, 3);
KineticTileEntity tileEntity = (KineticTileEntity) world.getTileEntity(pos);
tileEntity.attachKinetics();
}
KineticTileEntity.switchToBlockState(world, context.getPos(), with);
return ActionResultType.SUCCESS;
}

View File

@ -1,7 +1,5 @@
package com.simibubi.create.modules.contraptions.base;
import java.util.UUID;
import com.simibubi.create.modules.contraptions.KineticNetwork;
import com.simibubi.create.modules.contraptions.base.IRotate.SpeedLevel;
@ -17,7 +15,7 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
}
protected void notifyStressCapacityChange(float capacity) {
getNetwork().updateCapacityFor(this, capacity);
getOrCreateNetwork().updateCapacityFor(this, capacity);
}
@Override
@ -63,8 +61,9 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
}
if (hasNetwork() && speed != 0) {
KineticNetwork network = getNetwork();
network.updateCapacityFor(this, getAddedStressCapacity());
KineticNetwork network = getOrCreateNetwork();
notifyStressCapacityChange(getAddedStressCapacity());
getOrCreateNetwork().updateStressFor(this, getStressApplied());
network.updateStress();
}
@ -76,36 +75,32 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
// Speed changed to 0
if (speed == 0) {
if (hasSource() && hasNetwork()) {
getNetwork().updateCapacityFor(this, 0);
if (hasSource()) {
notifyStressCapacityChange(0);
getOrCreateNetwork().updateStressFor(this, getStressApplied());
return;
}
detachKinetics();
setSpeed(speed);
newNetworkID = null;
updateNetwork = true;
setSpeed(0);
setNetwork(null);
return;
}
// Now turning - create a new Network
if (prevSpeed == 0) {
setSpeed(speed);
newNetworkID = UUID.randomUUID();
updateNetwork = true;
setNetwork(createNetworkId());
attachKinetics();
return;
}
// Change speed when overpowered by other generator
if (hasSource() && hasNetwork()) {
if (hasSource()) {
// Staying below Overpowered speed
if (Math.abs(prevSpeed) >= Math.abs(speed)) {
if (Math.signum(prevSpeed) != Math.signum(speed)) {
if (Math.signum(prevSpeed) != Math.signum(speed))
world.destroyBlock(pos, true);
return;
}
getNetwork().updateCapacityFor(this, getAddedStressCapacity());
return;
}
@ -113,8 +108,7 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
detachKinetics();
setSpeed(speed);
source = null;
newNetworkID = UUID.randomUUID();
updateNetwork = true;
setNetwork(createNetworkId());
attachKinetics();
return;
}
@ -125,4 +119,8 @@ public abstract class GeneratingKineticTileEntity extends KineticTileEntity {
attachKinetics();
}
public Long createNetworkId() {
return pos.toLong();
}
}

View File

@ -1,7 +1,5 @@
package com.simibubi.create.modules.contraptions.base;
import com.simibubi.create.modules.contraptions.RotationPropagator;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItemUseContext;
@ -79,16 +77,7 @@ public abstract class HorizontalAxisKineticBlock extends KineticBlock {
World world = context.getWorld();
if (facing.getAxis() == state.get(HORIZONTAL_AXIS))
return ActionResultType.PASS;
if (!world.isRemote) {
BlockPos pos = context.getPos();
KineticTileEntity tileEntity = (KineticTileEntity) world.getTileEntity(pos);
if (tileEntity.hasNetwork())
tileEntity.getNetwork().remove(tileEntity);
RotationPropagator.handleRemoved(world, pos, tileEntity);
tileEntity.removeSource();
world.setBlockState(pos, state.cycle(HORIZONTAL_AXIS), 3);
tileEntity.attachKinetics();
}
KineticTileEntity.switchToBlockState(world, context.getPos(), state.cycle(HORIZONTAL_AXIS));
return ActionResultType.SUCCESS;
}

View File

@ -11,7 +11,6 @@ import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public abstract class HorizontalKineticBlock extends KineticBlock {
@ -61,13 +60,7 @@ public abstract class HorizontalKineticBlock extends KineticBlock {
World world = context.getWorld();
if (facing == state.get(HORIZONTAL_FACING))
return ActionResultType.PASS;
if (!world.isRemote) {
BlockPos pos = context.getPos();
world.removeTileEntity(pos);
world.setBlockState(pos, state.with(HORIZONTAL_FACING, facing), 3);
KineticTileEntity tileEntity = (KineticTileEntity) world.getTileEntity(pos);
tileEntity.attachKinetics();
}
KineticTileEntity.switchToBlockState(world, context.getPos(), state.with(HORIZONTAL_FACING, facing));
return ActionResultType.SUCCESS;
}

View File

@ -27,7 +27,7 @@ public abstract class KineticBlock extends Block implements IRotate {
public KineticBlock(Properties properties) {
super(properties);
}
@Override
public ToolType getHarvestTool(BlockState state) {
return null;
@ -38,10 +38,10 @@ public abstract class KineticBlock extends Block implements IRotate {
for (ToolType toolType : player.getHeldItemMainhand().getToolTypes()) {
if (isToolEffective(state, toolType))
return true;
}
}
return super.canHarvestBlock(state, world, pos, player);
}
@Override
public boolean isToolEffective(BlockState state, ToolType tool) {
return tool == ToolType.AXE || tool == ToolType.PICKAXE;
@ -79,6 +79,20 @@ public abstract class KineticBlock extends Block implements IRotate {
@Override
public abstract TileEntity createTileEntity(BlockState state, IBlockReader world);
@Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
if (isMoving) {
KineticTileEntity tileEntity = (KineticTileEntity) worldIn.getTileEntity(pos);
if (tileEntity == null)
return;
if (worldIn.isRemote())
return;
tileEntity.network = null;
tileEntity.source = null;
tileEntity.speed = 0;
}
}
@SuppressWarnings("deprecation")
@Override
public void updateNeighbors(BlockState stateIn, IWorld worldIn, BlockPos pos, int flags) {

View File

@ -2,7 +2,8 @@ package com.simibubi.create.modules.contraptions.base;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
import com.simibubi.create.Create;
import com.simibubi.create.config.AllConfigs;
@ -18,24 +19,24 @@ import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
public abstract class KineticTileEntity extends SmartTileEntity implements ITickableTileEntity {
protected UUID networkID;
protected UUID newNetworkID;
protected float maxStress;
protected float currentStress;
protected boolean updateNetwork;
public @Nullable Long network;
public @Nullable BlockPos source;
public boolean networkDirty;
protected KineticEffectHandler effects;
protected BlockPos source;
protected float speed;
protected float capacity;
protected float stress;
protected boolean overStressed;
protected boolean initNetwork;
private int flickerTally;
private int validationCountdown;
@ -45,6 +46,18 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
effects = new KineticEffectHandler(this);
}
@Override
public void initialize() {
super.initialize();
if (!hasNetwork())
return;
KineticNetwork network = getOrCreateNetwork();
if (!network.initialized)
network.initFromTE(capacity, stress);
network.addSilently(this);
}
@Override
public void tick() {
super.tick();
@ -61,33 +74,10 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
if (getFlickerScore() > 0)
flickerTally = getFlickerScore() - 1;
if (initNetwork) {
initNetwork = false;
KineticNetwork network = getNetwork();
if (!network.initialized)
network.initFromTE(maxStress, currentStress);
network.addSilently(this);
}
if (updateNetwork) {
updateNetwork = false;
if (hasNetwork() && !networkID.equals(newNetworkID)) {
getNetwork().remove(this);
networkID = null;
maxStress = currentStress = 0;
overStressed = false;
}
if (newNetworkID != null) {
networkID = newNetworkID;
KineticNetwork network = getNetwork();
network.initialized = true;
network.add(this);
}
sendData();
if (networkDirty) {
if (hasNetwork())
getOrCreateNetwork().updateNetwork();
networkDirty = false;
}
}
@ -103,25 +93,21 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
return;
}
if (hasNetwork() && maxStress == 0) {
for (KineticTileEntity kineticTileEntity : getNetwork().members.keySet())
kineticTileEntity.removeSource();
return;
}
return;
}
if (speed != 0) {
if (getGeneratedSpeed() == 0)
setSpeed(0);
speed = 0;
}
}
public void sync(float maxStress, float currentStress) {
this.maxStress = maxStress;
this.currentStress = currentStress;
public void updateStressFromNetwork(float maxStress, float currentStress) {
networkDirty = false;
this.capacity = maxStress;
this.stress = currentStress;
boolean overStressed = maxStress < currentStress && StressImpact.isEnabled();
if (overStressed != this.overStressed) {
if (speed != 0 && overStressed)
AllTriggers.triggerForNearbyPlayers(AllTriggers.OVERSTRESSED, world, pos, 8);
@ -160,7 +146,7 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
public void remove() {
if (!world.isRemote) {
if (hasNetwork())
getNetwork().remove(this);
getOrCreateNetwork().remove(this);
detachKinetics();
}
super.remove();
@ -174,9 +160,11 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
compound.put("Source", NBTUtil.writeBlockPos(source));
if (hasNetwork()) {
compound.putFloat("MaxStress", maxStress);
compound.putFloat("Stress", currentStress);
compound.put("Id", NBTUtil.writeUniqueId(networkID));
CompoundNBT networkTag = new CompoundNBT();
networkTag.putLong("Id", network);
networkTag.putFloat("Stress", stress);
networkTag.putFloat("Capacity", capacity);
compound.put("Network", networkTag);
}
return super.write(compound);
@ -185,20 +173,22 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
@Override
public void read(CompoundNBT compound) {
speed = compound.getFloat("Speed");
source = null;
networkID = newNetworkID = null;
network = null;
overStressed = false;
stress = 0;
capacity = 0;
if (compound.contains("Source"))
source = NBTUtil.readBlockPos(compound.getCompound("Source"));
if (compound.contains("Id")) {
maxStress = compound.getFloat("MaxStress");
currentStress = compound.getFloat("Stress");
overStressed = maxStress < currentStress && StressImpact.isEnabled();
networkID = NBTUtil.readUniqueId(compound.getCompound("Id"));
newNetworkID = networkID;
initNetwork = true;
if (compound.contains("Network")) {
CompoundNBT networkTag = compound.getCompound("Network");
network = networkTag.getLong("Id");
stress = networkTag.getFloat("Stress");
capacity = networkTag.getFloat("Capacity");
overStressed = capacity < stress && StressImpact.isEnabled();
}
super.read(compound);
@ -212,6 +202,10 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
effects.triggerOverStressedEffect();
}
public float getGeneratedSpeed() {
return 0;
}
public boolean isSource() {
return getGeneratedSpeed() != 0;
}
@ -226,10 +220,6 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
return speed;
}
public float getGeneratedSpeed() {
return 0;
}
public void setSpeed(float speed) {
this.speed = speed;
}
@ -238,10 +228,6 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
return source != null;
}
public BlockPos getSource() {
return source;
}
public void setSource(BlockPos source) {
this.source = source;
if (world == null || world.isRemote)
@ -253,29 +239,42 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
return;
}
newNetworkID = sourceTe.newNetworkID;
updateNetwork = true;
setNetwork(sourceTe.network);
}
public void removeSource() {
source = null;
newNetworkID = null;
updateNetwork = true;
float prevSpeed = getSpeed();
setSpeed(0);
speed = 0;
source = null;
setNetwork(null);
onSpeedChanged(prevSpeed);
}
public KineticNetwork getNetwork() {
public void setNetwork(@Nullable Long networkIn) {
if (network == networkIn)
return;
if (network != null)
getOrCreateNetwork().remove(this);
network = networkIn;
if (networkIn == null)
return;
network = networkIn;
KineticNetwork network = getOrCreateNetwork();
network.initialized = true;
network.add(this);
}
public KineticNetwork getOrCreateNetwork() {
return Create.torquePropagator.getNetworkFor(this);
}
public boolean hasNetwork() {
return networkID != null;
}
public boolean canOverPower(KineticTileEntity other) {
return newNetworkID != null && !newNetworkID.equals(other.newNetworkID);
return network != null;
}
public void attachKinetics() {
@ -286,14 +285,6 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
RotationPropagator.handleRemoved(world, pos, this);
}
public UUID getNetworkID() {
return networkID;
}
public void setNetworkID(UUID networkID) {
this.networkID = networkID;
}
public boolean isSpeedRequirementFulfilled() {
BlockState state = getBlockState();
if (!(getBlockState().getBlock() instanceof IRotate))
@ -309,6 +300,21 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
return true;
}
public static void switchToBlockState(World world, BlockPos pos, BlockState state) {
if (world.isRemote)
return;
TileEntity tileEntityIn = world.getTileEntity(pos);
if (!(tileEntityIn instanceof KineticTileEntity))
return;
KineticTileEntity tileEntity = (KineticTileEntity) tileEntityIn;
if (tileEntity.hasNetwork())
tileEntity.getOrCreateNetwork().remove(tileEntity);
tileEntity.detachKinetics();
tileEntity.removeSource();
world.setBlockState(pos, state, 3);
tileEntity.attachKinetics();
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
}

View File

@ -63,10 +63,7 @@ public class KineticTileEntityRenderer extends SafeTileEntityRendererFast<Kineti
int white = 0xFFFFFF;
if (KineticDebugger.isActive()) {
rainbowMode = true;
if (te.hasNetwork())
buffer.color(ColorHelper.colorFromUUID(te.getNetworkID()));
else
buffer.color(white);
buffer.color(te.hasNetwork() ? ColorHelper.colorFromLong(te.network) : white);
} else {
float overStressedEffect = te.effects.overStressedEffect;
if (overStressedEffect != 0)

View File

@ -11,7 +11,6 @@ import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public abstract class RotatedPillarKineticBlock extends KineticBlock {
@ -79,13 +78,7 @@ public abstract class RotatedPillarKineticBlock extends KineticBlock {
World world = context.getWorld();
if (axis == state.get(AXIS))
return ActionResultType.PASS;
if (!world.isRemote) {
BlockPos pos = context.getPos();
world.removeTileEntity(pos);
world.setBlockState(pos, state.with(AXIS, axis), 3);
KineticTileEntity tileEntity = (KineticTileEntity) world.getTileEntity(pos);
tileEntity.attachKinetics();
}
KineticTileEntity.switchToBlockState(world, context.getPos(), state.with(AXIS, axis));
return ActionResultType.SUCCESS;
}

View File

@ -61,7 +61,7 @@ public class DrillBlock extends DirectionalKineticBlock implements IPortableBloc
@Override
public PushReaction getPushReaction(BlockState state) {
return PushReaction.PUSH_ONLY;
return PushReaction.NORMAL;
}
@Override

View File

@ -19,6 +19,7 @@ import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.AbstractChassisBlock;
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity;
import com.simibubi.create.modules.contraptions.components.saw.SawBlock;
@ -111,8 +112,8 @@ public abstract class Contraption {
}
public void gatherStoredItems() {
List<IItemHandlerModifiable> list = storage.values().stream().map(MountedStorage::getItemHandler)
.collect(Collectors.toList());
List<IItemHandlerModifiable> list =
storage.values().stream().map(MountedStorage::getItemHandler).collect(Collectors.toList());
inventory = new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class));
}
@ -251,8 +252,8 @@ public abstract class Contraption {
CompoundNBT comp = (CompoundNBT) c;
storage.put(NBTUtil.readBlockPos(comp.getCompound("Pos")), new MountedStorage(comp.getCompound("Data")));
});
List<IItemHandlerModifiable> list = storage.values().stream().map(MountedStorage::getItemHandler)
.collect(Collectors.toList());
List<IItemHandlerModifiable> list =
storage.values().stream().map(MountedStorage::getItemHandler).collect(Collectors.toList());
inventory = new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class));
if (nbt.contains("BoundsFront"))
@ -358,6 +359,15 @@ public abstract class Contraption {
block.nbt.putInt("y", targetPos.getY());
block.nbt.putInt("z", targetPos.getZ());
tileEntity.read(block.nbt);
if (tileEntity instanceof KineticTileEntity) {
KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity;
kineticTileEntity.source = null;
kineticTileEntity.setSpeed(0);
kineticTileEntity.network = null;
kineticTileEntity.attachKinetics();
}
if (storage.containsKey(block.pos)) {
MountedStorage mountedStorage = storage.get(block.pos);
if (mountedStorage.isWorking())

View File

@ -165,7 +165,6 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
running = true;
angle = 0;
sendData();
updateGeneratedRotation();
}

View File

@ -226,10 +226,13 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme
}
protected void applyContraptionMotion() {
if (movedContraption.isStalled())
if (movedContraption == null)
return;
if (movedContraption.isStalled()) {
movedContraption.setContraptionMotion(Vec3d.ZERO);
else
movedContraption.setContraptionMotion(getMotionVector());
return;
}
movedContraption.setContraptionMotion(getMotionVector());
}
protected void applyContraptionPosition() {

View File

@ -44,7 +44,7 @@ public class DeployerBlock extends DirectionalAxisKineticBlock
@Override
public PushReaction getPushReaction(BlockState state) {
return PushReaction.PUSH_ONLY;
return PushReaction.NORMAL;
}
@Override

View File

@ -153,6 +153,8 @@ public class DeployerHandler {
RayTraceContext rayTraceContext =
new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE, FluidMode.NONE, player);
BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext);
if (result.getPos() != clickedPos)
result = new BlockRayTraceResult(result.getHitVec(), result.getFace(), clickedPos, result.isInside());
BlockState clickedState = world.getBlockState(clickedPos);
Direction face = result.getFace();
if (face == null)

View File

@ -272,8 +272,7 @@ public class DeployerTileEntity extends KineticTileEntity {
continue;
if (list == inv.mainInventory && i == inv.currentItem && filtering.test(itemstack))
if (itemstack.getCount() == 1)
continue;
continue;
itemstack = insert(itemstack, false);
if (!itemstack.isEmpty())

View File

@ -1,7 +1,6 @@
package com.simibubi.create.modules.contraptions.components.motor;
import java.util.List;
import java.util.UUID;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.config.AllConfigs;
@ -19,9 +18,6 @@ public class MotorTileEntity extends GeneratingKineticTileEntity {
public MotorTileEntity() {
super(AllTileEntities.MOTOR.type);
updateNetwork = true;
newNetworkID = UUID.randomUUID();
speed = DEFAULT_SPEED;
}
@Override
@ -42,6 +38,13 @@ public class MotorTileEntity extends GeneratingKineticTileEntity {
behaviours.add(generatedSpeed);
}
@Override
public void initialize() {
super.initialize();
if (!hasSource())
updateGeneratedRotation();
}
@Override
public float getGeneratedSpeed() {
return generatedSpeed.getValue();

View File

@ -102,7 +102,7 @@ public class SawBlock extends DirectionalAxisKineticBlock implements IWithTileEn
@Override
public PushReaction getPushReaction(BlockState state) {
return PushReaction.PUSH_ONLY;
return PushReaction.NORMAL;
}
public static boolean isHorizontal(BlockState state) {

View File

@ -50,6 +50,7 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
public void setFlow(Direction direction, float speed) {
flows.put(direction, speed);
markDirty();
}
@Override

View File

@ -44,7 +44,7 @@ public class SpeedControllerTileEntity extends KineticTileEntity {
private void updateTargetRotation() {
if (hasNetwork())
getNetwork().remove(this);
getOrCreateNetwork().remove(this);
RotationPropagator.handleRemoved(world, pos, this);
removeSource();
attachKinetics();
@ -75,7 +75,7 @@ public class SpeedControllerTileEntity extends KineticTileEntity {
return 1;
}
boolean wheelPowersController = speedController.getSource().equals(cogWheel.getPos());
boolean wheelPowersController = speedController.source.equals(cogWheel.getPos());
if (wheelPowersController) {
if (targetingController)

View File

@ -347,7 +347,6 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
return;
BeltTileEntity beltEntity = (BeltTileEntity) tileEntity;
BlockPos controller = beltEntity.getController();
beltEntity.removeSource();
beltEntity.remove();
int limit = 1000;
@ -368,7 +367,6 @@ public class BeltBlock extends HorizontalKineticBlock implements IHaveNoBlockIte
inv.eject(stack);
}
te.removeSource();
te.remove();
if (destroyedBlock.get(CASING))

View File

@ -5,6 +5,7 @@ import com.simibubi.create.foundation.utility.AllShapes;
import com.simibubi.create.modules.contraptions.base.RotatedPillarKineticBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.material.PushReaction;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
@ -22,6 +23,11 @@ public class ShaftBlock extends RotatedPillarKineticBlock {
public ShaftBlock(Properties properties) {
super(properties);
}
@Override
public PushReaction getPushReaction(BlockState state) {
return PushReaction.NORMAL;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {

View File

@ -7,14 +7,14 @@ import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
public class DirectionalShaftHalvesTileEntity extends KineticTileEntity {
public DirectionalShaftHalvesTileEntity(TileEntityType<?> typeIn) {
super(typeIn);
}
public Direction getSourceFacing() {
BlockPos source = getSource().subtract(getPos());
return Direction.getFacingFromVector(source.getX(), source.getY(), source.getZ());
BlockPos localSource = source.subtract(getPos());
return Direction.getFacingFromVector(localSource.getX(), localSource.getY(), localSource.getZ());
}
}

View File

@ -8,6 +8,7 @@ import com.simibubi.create.modules.contraptions.base.RotatedPillarKineticBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.PushReaction;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemUseContext;
import net.minecraft.state.BooleanProperty;
@ -40,6 +41,11 @@ public class EncasedBeltBlock extends RotatedPillarKineticBlock {
return false;
}
@Override
public PushReaction getPushReaction(BlockState state) {
return PushReaction.NORMAL;
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> builder) {
super.fillStateContainer(builder.add(PART, CONNECTED_ALONG_FIRST_COORDINATE));

View File

@ -11,8 +11,8 @@ public class StressGaugeTileEntity extends GaugeTileEntity {
}
@Override
public void sync(float maxStress, float currentStress) {
super.sync(maxStress, currentStress);
public void updateStressFromNetwork(float maxStress, float currentStress) {
super.updateStressFromNetwork(maxStress, currentStress);
if (!StressImpact.isEnabled())
dialTarget = 0;
@ -41,15 +41,15 @@ public class StressGaugeTileEntity extends GaugeTileEntity {
if (getSpeed() == 0)
dialTarget = 0;
else
sync(maxStress, currentStress);
updateStressFromNetwork(capacity, stress);
}
public float getNetworkStress() {
return currentStress;
return stress;
}
public float getNetworkCapacity() {
return maxStress;
return capacity;
}
}

View File

@ -31,7 +31,7 @@ public class GearboxTileEntityRenderer extends KineticTileEntityRenderer {
float angle = (time * te.getSpeed() * 3f / 10) % 360;
if (te.getSpeed() != 0 && te.hasSource()) {
BlockPos source = te.getSource().subtract(te.getPos());
BlockPos source = te.source.subtract(te.getPos());
Direction sourceFacing = Direction.getFacingFromVector(source.getX(), source.getY(), source.getZ());
if (sourceFacing.getAxis() == direction.getAxis())
angle *= sourceFacing == direction ? 1 : -1;