From 5655fa06098d5bdef578a67d83348b8a7e5d82cc Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri, 1 Nov 2019 01:09:38 +0100 Subject: [PATCH] Here to ruin the fun - Rotational sources can now be connected to each other if their speeds have the same direction. Sources with slower speeds will be overpowered by the others. - Added a skeleton for torque mechanics. Very janky and unfinished --- src/main/java/com/simibubi/create/Create.java | 3 + src/main/java/com/simibubi/create/Events.java | 2 + .../create/foundation/utility/Lang.java | 27 ++- .../modules/contraptions/KineticNetwork.java | 118 ++++++++++++ .../contraptions/RotationPropagator.java | 81 +++++++-- .../contraptions/TorquePropagator.java | 50 ++++++ .../contraptions/base/KineticTileEntity.java | 168 +++++++++++++++--- .../generators/MotorTileEntity.java | 18 +- .../generators/WaterWheelBlock.java | 4 +- .../generators/WaterWheelTileEntity.java | 23 ++- .../receivers/DrillTileEntity.java | 5 +- .../receivers/EncasedFanTileEntity.java | 23 ++- .../receivers/MechanicalMixerTileEntity.java | 4 +- .../receivers/MechanicalPressTileEntity.java | 5 +- .../MechanicalBearingTileEntity.java | 23 ++- .../MechanicalPistonTileEntity.java | 5 +- .../relays/GearboxTileEntityRenderer.java | 2 +- .../contraptions/relays/belt/BeltItem.java | 2 +- .../relays/belt/BeltTileEntity.java | 5 +- .../modules/logistics/FrequencyHandler.java | 4 +- .../assets/create/textures/block/scarf.png | Bin 0 -> 441 bytes .../assets/create/textures/gui/filter.pdn | Bin 0 -> 13643 bytes 22 files changed, 501 insertions(+), 71 deletions(-) create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/KineticNetwork.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/TorquePropagator.java create mode 100644 src/main/resources/assets/create/textures/block/scarf.png create mode 100644 src/main/resources/assets/create/textures/gui/filter.pdn diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 178a010d5..86f16c969 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -4,6 +4,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.simibubi.create.modules.ModuleLoadedCondition; +import com.simibubi.create.modules.contraptions.TorquePropagator; import com.simibubi.create.modules.contraptions.receivers.constructs.MovingConstructHandler; import com.simibubi.create.modules.logistics.FrequencyHandler; import com.simibubi.create.modules.logistics.management.LogisticalNetworkHandler; @@ -42,6 +43,7 @@ public class Create { public static FrequencyHandler frequencyHandler; public static MovingConstructHandler constructHandler; public static LogisticalNetworkHandler logisticalNetworkHandler; + public static TorquePropagator torquePropagator; public static LogisticianHandler logisticianHandler; public static ModConfig config; @@ -66,6 +68,7 @@ public class Create { frequencyHandler = new FrequencyHandler(); constructHandler = new MovingConstructHandler(); logisticalNetworkHandler = new LogisticalNetworkHandler(); + torquePropagator = new TorquePropagator(); CraftingHelper.register(new ModuleLoadedCondition.Serializer()); AllPackets.registerPackets(); diff --git a/src/main/java/com/simibubi/create/Events.java b/src/main/java/com/simibubi/create/Events.java index 145592020..e18411124 100644 --- a/src/main/java/com/simibubi/create/Events.java +++ b/src/main/java/com/simibubi/create/Events.java @@ -46,6 +46,7 @@ public class Events { Create.frequencyHandler.onLoadWorld(world); Create.constructHandler.onLoadWorld(world); Create.logisticalNetworkHandler.onLoadWorld(world); + Create.torquePropagator.onLoadWorld(world); } @SubscribeEvent @@ -54,6 +55,7 @@ public class Events { Create.frequencyHandler.onUnloadWorld(world); Create.constructHandler.onUnloadWorld(world); Create.logisticalNetworkHandler.onUnloadWorld(world); + Create.torquePropagator.onUnloadWorld(world); } @SubscribeEvent diff --git a/src/main/java/com/simibubi/create/foundation/utility/Lang.java b/src/main/java/com/simibubi/create/foundation/utility/Lang.java index a763c5ced..81196ba1a 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/Lang.java +++ b/src/main/java/com/simibubi/create/foundation/utility/Lang.java @@ -6,8 +6,12 @@ import java.util.Locale; import com.simibubi.create.Create; +import net.minecraft.client.Minecraft; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; public class Lang { @@ -18,11 +22,26 @@ public class Lang { private static TranslationTextComponent getTranslationComponent(String key, Object... args) { return new TranslationTextComponent(Create.ID + "." + key, args); } - + public static void sendStatus(PlayerEntity player, String key, Object... args) { player.sendStatusMessage(getTranslationComponent(key, args), true); } - + + // Deprecated so simi doensn't forget to remove debug calls + @OnlyIn(value = Dist.CLIENT) + @Deprecated + public static void debugChat(String message) { + if (Minecraft.getInstance().player != null) + Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(message), false); + } + + @OnlyIn(value = Dist.CLIENT) + @Deprecated + public static void debugMessage(String message) { + if (Minecraft.getInstance().player != null) + Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(message), true); + } + public static List translatedOptions(String prefix, String... keys) { List result = new ArrayList<>(keys.length); for (String key : keys) { @@ -30,9 +49,9 @@ public class Lang { } return result; } - + public static String asId(String name) { return name.toLowerCase(Locale.ENGLISH); } - + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/KineticNetwork.java b/src/main/java/com/simibubi/create/modules/contraptions/KineticNetwork.java new file mode 100644 index 000000000..583da6d5e --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/KineticNetwork.java @@ -0,0 +1,118 @@ +package com.simibubi.create.modules.contraptions; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.modules.contraptions.base.KineticTileEntity; + +public class KineticNetwork { + + public UUID id; + private float stressCapacityPool; + private float maxStress; + private float currentStress; + public boolean initialized; + + public Map sources; + public Set members; + + public KineticNetwork() { + id = UUID.randomUUID(); + maxStress = stressCapacityPool = 0; + setCurrentStress(0); + sources = new HashMap<>(); + members = new HashSet<>(); + } + + public void initFromTE(KineticTileEntity te) { + maxStress = stressCapacityPool = te.maxStress; + currentStress = te.currentStress; + initialized = true; + addSilently(te); + } + + public void addSilently(KineticTileEntity te) { + if (members.contains(te)) + return; + if (te.isSource()) { + float capacity = te.getAddedStressCapacity(); + stressCapacityPool -= capacity; + sources.put(te, capacity); + } + members.add(te); + } + + public void add(KineticTileEntity te) { + if (members.contains(te)) + return; + + Lang.debugChat(te.getType().getRegistryName().getPath() + " added to Network"); + + te.setNetworkID(this.id); + + if (te.isSource()) { + float capacity = te.getAddedStressCapacity(); + sources.put(te, capacity); + updateMaxStress(); + } + members.add(te); + setCurrentStress(getCurrentStress() + te.getStressApplied()); + sync(); + } + + public void updateCapacityFor(KineticTileEntity te, float capacity) { + sources.put(te, capacity); + updateMaxStress(); + } + + public void remove(KineticTileEntity te) { + if (!members.contains(te)) + return; + + Lang.debugChat(te.getType().getRegistryName().getPath() + " removed from Network"); + + if (te.isSource()) { + sources.remove(te); + updateMaxStress(); + } + members.remove(te); + setCurrentStress(getCurrentStress() - te.getStressApplied()); + sync(); + } + + public void sync() { + for (KineticTileEntity te : members) { + te.sync(id, getMaxStress(), getCurrentStress()); + } + } + + public float getMaxStress() { + return maxStress; + } + + private void updateMaxStress() { + float presentCapacity = 0; + for (Float cap : sources.values()) + presentCapacity += cap; + float newMaxStress = presentCapacity + stressCapacityPool; + if (maxStress != newMaxStress) { + maxStress = newMaxStress; + sync(); + } + Lang.debugChat("Current Stress level: " + currentStress + "/" + maxStress); + } + + public float getCurrentStress() { + return currentStress; + } + + public void setCurrentStress(float currentStress) { + this.currentStress = currentStress; + Lang.debugChat("Current Stress level: " + currentStress + "/" + maxStress); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/RotationPropagator.java b/src/main/java/com/simibubi/create/modules/contraptions/RotationPropagator.java index 39b037ba9..7781a6fc0 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/RotationPropagator.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/RotationPropagator.java @@ -173,8 +173,7 @@ public class RotationPropagator { return; if (!worldIn.isBlockPresent(pos)) return; - - if (addedTE.getSpeed() != 0) { + if (addedTE.speed != 0) { propagateNewSource(addedTE); return; } @@ -182,16 +181,16 @@ public class RotationPropagator { for (KineticTileEntity neighbourTE : getConnectedNeighbours(addedTE)) { final float speedModifier = getRotationSpeedModifier(neighbourTE, addedTE); - if (neighbourTE.getSpeed() == 0) + if (neighbourTE.speed == 0) continue; if (neighbourTE.hasSource() && neighbourTE.getSource().equals(addedTE.getPos())) { - addedTE.setSpeed(neighbourTE.getSpeed() * speedModifier); + addedTE.setSpeed(neighbourTE.speed * speedModifier); addedTE.onSpeedChanged(); addedTE.sendData(); continue; } - addedTE.setSpeed(neighbourTE.getSpeed() * speedModifier); + addedTE.setSpeed(neighbourTE.speed * speedModifier); addedTE.setSource(neighbourTE.getPos()); addedTE.onSpeedChanged(); addedTE.sendData(); @@ -210,18 +209,63 @@ public class RotationPropagator { World world = updateTE.getWorld(); for (KineticTileEntity neighbourTE : getConnectedNeighbours(updateTE)) { - final float newSpeed = updateTE.getSpeed() * getRotationSpeedModifier(updateTE, neighbourTE); + float modFromTo = getRotationSpeedModifier(updateTE, neighbourTE); + float modToFrom = getRotationSpeedModifier(neighbourTE, updateTE); + final float newSpeed = updateTE.speed * modFromTo; + float oppositeSpeed = neighbourTE.speed * modToFrom; - if ((neighbourTE.isSource()) - || neighbourTE.hasSource() && !neighbourTE.getSource().equals(updateTE.getPos())) { - if (neighbourTE.getSpeed() != newSpeed || Math.abs(newSpeed) > parameters.maxRotationSpeed.get()) { - world.destroyBlock(pos, true); - return; + boolean incompatible = Math.signum(newSpeed) != Math.signum(neighbourTE.speed) + && (newSpeed != 0 && neighbourTE.speed != 0); + + boolean tooFast = Math.abs(newSpeed) > parameters.maxRotationSpeed.get(); + if (tooFast) { + world.destroyBlock(pos, true); + return; + } + + boolean isSource = neighbourTE.isSource(); + boolean hasSource = neighbourTE.hasSource(); + boolean poweredBySomethingElse = isSource + || hasSource && !neighbourTE.getSource().equals(updateTE.getPos()); + + if (poweredBySomethingElse) { + if (neighbourTE.speed != newSpeed) { + if (incompatible) { + // Opposite directions + world.destroyBlock(pos, true); + return; + + } else { + // Same direction: overpower the slower speed + if (Math.abs(oppositeSpeed) > Math.abs(updateTE.speed)) { + // Neighbour faster, overpower the incoming tree + updateTE.setSource(neighbourTE.getPos()); + updateTE.setSpeed(neighbourTE.speed * getRotationSpeedModifier(neighbourTE, updateTE)); + updateTE.onSpeedChanged(); + updateTE.sendData(); + propagateNewSource(updateTE); + return; + } + if (Math.abs(newSpeed) > Math.abs(neighbourTE.speed)) { + // Current faster, overpower the neighbours' tree + + if (updateTE.hasSource() && updateTE.getSource().equals(neighbourTE.getPos())) { + updateTE.removeSource(); + } + + neighbourTE.setSource(updateTE.getPos()); + neighbourTE.setSpeed(updateTE.speed * getRotationSpeedModifier(updateTE, neighbourTE)); + neighbourTE.onSpeedChanged(); + neighbourTE.sendData(); + propagateNewSource(neighbourTE); + continue; + } + } } continue; } - if (neighbourTE.getSpeed() == newSpeed) + if (neighbourTE.speed == newSpeed) continue; neighbourTE.setSpeed(newSpeed); @@ -245,7 +289,7 @@ public class RotationPropagator { return; if (removedTE == null) return; - if (removedTE.getSpeed() == 0) + if (removedTE.speed == 0) return; for (BlockPos neighbourPos : getPotentialNeighbourLocations(removedTE)) { @@ -254,7 +298,7 @@ public class RotationPropagator { continue; final KineticTileEntity neighbourTE = (KineticTileEntity) worldIn.getTileEntity(neighbourPos); - if (!neighbourTE.hasSource() || !neighbourTE.getSource().equals(pos) || neighbourTE.isSource()) + if (!neighbourTE.hasSource() || !neighbourTE.getSource().equals(pos)) continue; propagateMissingSource(neighbourTE); @@ -283,11 +327,6 @@ public class RotationPropagator { currentTE.sendData(); for (KineticTileEntity neighbourTE : getConnectedNeighbours(currentTE)) { - if (neighbourTE.isSource()) { - potentialNewSources.add(neighbourTE); - continue; - } - if (!neighbourTE.hasSource()) continue; @@ -296,6 +335,10 @@ public class RotationPropagator { continue; } + if (neighbourTE.isSource()) { + potentialNewSources.add(neighbourTE); + } + frontier.add(neighbourTE.getPos()); } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/TorquePropagator.java b/src/main/java/com/simibubi/create/modules/contraptions/TorquePropagator.java new file mode 100644 index 000000000..83a715886 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/TorquePropagator.java @@ -0,0 +1,50 @@ +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; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.world.IWorld; + +public class TorquePropagator { + + static Map> networks = new HashMap<>(); + + public void onLoadWorld(IWorld world) { + networks.put(world, new HashMap<>()); + Create.logger.debug("Prepared Kinetic Network Space for " + world.getDimension().getType().getRegistryName()); + } + + public void onUnloadWorld(IWorld world) { + networks.remove(world); + Create.logger.debug("Removed Kinetic Network Space for " + world.getDimension().getType().getRegistryName()); + } + + public KineticNetwork getNetworkFor(KineticTileEntity te) { + UUID id = te.getNetworkID(); + KineticNetwork network; + Map map = networks.get(te.getWorld()); + if (id == null) { + network = new KineticNetwork(); + + //TODO + Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(te.getType().getRegistryName().getPath() + " created new Network"), false); + + map.put(id, network); + } else { + if (!map.containsKey(id)) { + network = new KineticNetwork(); + network.id = te.getNetworkID(); + map.put(id, network); + } + network = map.get(id); + } + return network; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java index 961436eb3..7d2561a34 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java @@ -2,70 +2,129 @@ package com.simibubi.create.modules.contraptions.base; import java.util.Optional; import java.util.Random; +import java.util.UUID; +import com.simibubi.create.Create; import com.simibubi.create.foundation.block.SyncedTileEntity; +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.modules.contraptions.KineticNetwork; import com.simibubi.create.modules.contraptions.RotationPropagator; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTUtil; import net.minecraft.particles.RedstoneParticleData; +import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -public abstract class KineticTileEntity extends SyncedTileEntity { +public abstract class KineticTileEntity extends SyncedTileEntity implements ITickableTileEntity { - protected float speed; - protected float force; + public float speed; protected Optional source; + public boolean reActivateSource; + + public float maxStress; + public float currentStress; + public UUID networkID; + protected boolean overStressed; + protected boolean initNetwork; public KineticTileEntity(TileEntityType typeIn) { super(typeIn); speed = 0; - force = 0; source = Optional.empty(); } - + + public void sync(UUID networkID, float maxStress, float currentStress) { + this.setNetworkID(networkID); + this.maxStress = maxStress; + this.currentStress = currentStress; + boolean overStressed = maxStress < currentStress; + if (overStressed != this.overStressed) { + + Lang.debugChat(getType().getRegistryName().getPath() + " jammed (" + currentStress + "/" + maxStress + ")"); + + this.overStressed = overStressed; + sendData(); + } + } + + public float getAddedStressCapacity() { + return 0; + } + + public float getStressApplied() { + return isSource() ? 0 : 1; + } + + protected void notifyStressChange(float diff) { + KineticNetwork network = getNetwork(); + network.setCurrentStress(network.getCurrentStress() + diff); + network.sync(); + } + + protected void notifyStressCapacityChange(float capacity) { + getNetwork().updateCapacityFor(this, capacity); + } + @Override public boolean hasFastRenderer() { return true; } - + public void onSpeedChanged() { +// if (isSource() && !world.isRemote) { +// if (networkID == null) +// getNetwork().add(this); +// } } - + @Override public void remove() { if (world.isRemote) { super.remove(); return; } + if (hasNetwork()) { + getNetwork().remove(this); + } RotationPropagator.handleRemoved(getWorld(), getPos(), this); super.remove(); } @Override public CompoundNBT write(CompoundNBT compound) { - compound.putFloat("Speed", getSpeed()); - compound.putFloat("Force", getForce()); - + compound.putFloat("Speed", speed); if (hasSource()) compound.put("Source", NBTUtil.writeBlockPos(getSource())); + if (hasNetwork()) { + compound.putFloat("MaxStress", maxStress); + compound.putFloat("Stress", currentStress); + compound.put("Id", NBTUtil.writeUniqueId(getNetworkID())); + } + return super.write(compound); } @Override public void read(CompoundNBT compound) { setSpeed(compound.getFloat("Speed")); - setForce(compound.getFloat("Force")); - setSource(null); if (compound.contains("Source")) { CompoundNBT tagSource = compound.getCompound("Source"); setSource(NBTUtil.readBlockPos(tagSource)); } + if (compound.contains("Id")) { + maxStress = compound.getFloat("MaxStress"); + currentStress = compound.getFloat("Stress"); + overStressed = maxStress < currentStress; + setNetworkID(NBTUtil.readUniqueId(compound.getCompound("Id"))); + initNetwork = true; + } + super.read(compound); } @@ -74,6 +133,8 @@ public abstract class KineticTileEntity extends SyncedTileEntity { } public float getSpeed() { + if (overStressed) + return 0; return speed; } @@ -90,14 +151,6 @@ public abstract class KineticTileEntity extends SyncedTileEntity { } } - public float getForce() { - return force; - } - - public void setForce(float force) { - this.force = force; - } - public boolean hasSource() { return source.isPresent(); } @@ -113,26 +166,95 @@ public abstract class KineticTileEntity extends SyncedTileEntity { public void setSource(BlockPos source) { this.source = Optional.ofNullable(source); + + if (world == null || world.isRemote) + return; + if (hasNetwork()) { + getNetwork().remove(this); + networkID = null; + } + if (source == null) + return; + KineticTileEntity sourceTe = (KineticTileEntity) world.getTileEntity(source); + if (sourceTe == null) + return; + Create.torquePropagator.getNetworkFor(sourceTe).add(this); } public void removeSource() { + if (hasSource() && isSource()) + reActivateSource = true; + this.source = Optional.empty(); + + if (hasNetwork() && !isSource()) { + getNetwork().remove(this); + networkID = null; + } + setSpeed(0); onSpeedChanged(); } - + + public KineticNetwork getNetwork() { + KineticNetwork networkFor = Create.torquePropagator.getNetworkFor(this); + if (!networkFor.initialized) { + networkFor.add(this); + networkFor.initialized = true; + } + return networkFor; + } + + public boolean hasNetwork() { + return networkID != null; + } + public void applyNewSpeed(float speed) { detachKinetics(); this.speed = speed; attachKinetics(); } - + public void attachKinetics() { RotationPropagator.handleAdded(world, pos, this); } - + public void detachKinetics() { RotationPropagator.handleRemoved(world, pos, this); } + public UUID getNetworkID() { + return networkID; + } + + public void setNetworkID(UUID networkID) { + this.networkID = networkID; + } + + /** + * Callback for source blocks to re-apply their speed when an overpowering + * source is removed + */ + public void reActivateSource() { + + } + + @Override + public void tick() { + if (reActivateSource) { + reActivateSource(); + reActivateSource = false; + } + + if (initNetwork) { + initNetwork = false; + KineticNetwork network = getNetwork(); + if (network.initialized) { + network.addSilently(this); + } else { + network.initFromTE(this); + } + } + } + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/generators/MotorTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/generators/MotorTileEntity.java index d1519b2cb..f859e518f 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/generators/MotorTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/generators/MotorTileEntity.java @@ -5,10 +5,9 @@ import com.simibubi.create.AllTileEntities; import com.simibubi.create.CreateConfig; import com.simibubi.create.modules.contraptions.base.KineticTileEntity; -import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.util.math.MathHelper; -public class MotorTileEntity extends KineticTileEntity implements ITickableTileEntity { +public class MotorTileEntity extends KineticTileEntity { public static final int DEFAULT_SPEED = 64; public int newSpeed; @@ -17,8 +16,14 @@ public class MotorTileEntity extends KineticTileEntity implements ITickableTileE public MotorTileEntity() { super(AllTileEntities.MOTOR.type); setSpeed(DEFAULT_SPEED); + lastModified = -1; } + @Override + public float getAddedStressCapacity() { + return 500; + } + @Override public boolean hasFastRenderer() { return true; @@ -34,6 +39,13 @@ public class MotorTileEntity extends KineticTileEntity implements ITickableTileE super.setSpeed(speed); newSpeed = (int) speed; } + + @Override + public void removeSource() { + float speed = this.speed; + super.removeSource(); + setSpeed(speed); + } public int getSpeedValue() { if (world.isRemote) @@ -56,6 +68,8 @@ public class MotorTileEntity extends KineticTileEntity implements ITickableTileE @Override public void tick() { + super.tick(); + if (!world.isRemote) return; if (lastModified == -1) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelBlock.java index 25dfc1928..36bbac595 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelBlock.java @@ -83,7 +83,7 @@ public class WaterWheelBlock extends HorizontalKineticBlock { flowVec = flowVec.scale(f.getAxisDirection().getOffset()); boolean clockwise = wf.getAxisDirection() == AxisDirection.POSITIVE; - int clockwiseMultiplier = 1; // No difference. Causes confusion + int clockwiseMultiplier = 2; if (wf.getAxis() == Axis.Z) { if (f.getAxis() == Axis.Y) @@ -103,6 +103,8 @@ public class WaterWheelBlock extends HorizontalKineticBlock { } private void updateWheelSpeed(IWorld world, BlockPos pos) { + if (world.isRemote()) + return; WaterWheelTileEntity te = (WaterWheelTileEntity) world.getTileEntity(pos); if (te == null) return; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelTileEntity.java index f6c2e152b..57bfc0d60 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/generators/WaterWheelTileEntity.java @@ -2,6 +2,7 @@ package com.simibubi.create.modules.contraptions.generators; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import com.simibubi.create.AllTileEntities; import com.simibubi.create.modules.contraptions.RotationPropagator; @@ -32,7 +33,7 @@ public class WaterWheelTileEntity extends KineticTileEntity { setFlow(d, compound.getCompound("Flows").getInt(d.getName())); } } - + @Override public AxisAlignedBB getRenderBoundingBox() { return new AxisAlignedBB(pos).grow(1); @@ -45,7 +46,7 @@ public class WaterWheelTileEntity extends KineticTileEntity { for (Direction d : Direction.values()) flows.putInt(d.getName(), this.flows.get(d)); compound.put("Flows", flows); - + return super.write(compound); } @@ -53,19 +54,27 @@ public class WaterWheelTileEntity extends KineticTileEntity { flows.put(direction, speed); } + @Override + public void reActivateSource() { + updateSpeed(); + } + public void updateSpeed() { float speed = 0; for (Integer i : flows.values()) speed += i; if (this.speed != speed) { + hasFlows = speed != 0; + notifyStressCapacityChange(getAddedStressCapacity()); + source = Optional.empty(); RotationPropagator.handleRemoved(world, pos, this); this.setSpeed(speed); - hasFlows = speed != 0; sendData(); RotationPropagator.handleAdded(world, pos, this); } + onSpeedChanged(); } @Override @@ -73,4 +82,12 @@ public class WaterWheelTileEntity extends KineticTileEntity { return hasFlows; } + @Override + public float getAddedStressCapacity() { + float torque = 0; + for (Integer i : flows.values()) + torque += i; + return Math.abs(torque); + } + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillTileEntity.java index 597087a7b..8c015ad8b 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillTileEntity.java @@ -15,7 +15,6 @@ import net.minecraft.fluid.IFluidState; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.math.AxisAlignedBB; @@ -25,7 +24,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.GameRules; import net.minecraft.world.server.ServerWorld; -public class DrillTileEntity extends KineticTileEntity implements ITickableTileEntity { +public class DrillTileEntity extends KineticTileEntity { private static final AtomicInteger NEXT_DRILL_ID = new AtomicInteger(); @@ -73,6 +72,8 @@ public class DrillTileEntity extends KineticTileEntity implements ITickableTileE @Override public void tick() { + super.tick(); + if (world.isRemote) return; if (speed == 0) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java index 2d1a0c6a8..b62bbda53 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/EncasedFanTileEntity.java @@ -6,6 +6,7 @@ import static net.minecraft.util.Direction.AxisDirection.NEGATIVE; import static net.minecraft.util.Direction.AxisDirection.POSITIVE; import java.util.List; +import java.util.Optional; import com.simibubi.create.AllBlockTags; import com.simibubi.create.AllBlocks; @@ -24,7 +25,6 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.item.ItemEntity; import net.minecraft.nbt.CompoundNBT; import net.minecraft.particles.ParticleTypes; -import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.Direction; import net.minecraft.util.SoundCategory; @@ -35,7 +35,7 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; -public class EncasedFanTileEntity extends KineticTileEntity implements ITickableTileEntity { +public class EncasedFanTileEntity extends KineticTileEntity { private static DamageSource damageSourceFire = new DamageSource("create.fan_fire").setDifficultyScaled() .setFireDamage(); @@ -91,14 +91,23 @@ public class EncasedFanTileEntity extends KineticTileEntity implements ITickable return isGenerator; } + @Override + public float getAddedStressCapacity() { + return 50; + } + public void updateGenerator() { boolean shouldGenerate = world.isBlockPowered(pos) && world.isBlockPresent(pos.down()) && blockBelowIsHot(); if (shouldGenerate == isGenerator) return; isGenerator = shouldGenerate; - if (isGenerator) + if (isGenerator) { + notifyStressCapacityChange(getAddedStressCapacity()); removeSource(); + } else { + notifyStressCapacityChange(0); + } applyNewSpeed(isGenerator ? CreateConfig.parameters.generatingFanSpeed.get() : 0); sendData(); } @@ -182,8 +191,16 @@ public class EncasedFanTileEntity extends KineticTileEntity implements ITickable updateFrontBlock(); } + @Override + public void reActivateSource() { + source = Optional.empty(); + applyNewSpeed(isGenerator ? CreateConfig.parameters.generatingFanSpeed.get() : 0); + } + @Override public void tick() { + super.tick(); + if (speed == 0 || isGenerator) return; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/MechanicalMixerTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/MechanicalMixerTileEntity.java index fc12ff9c3..2695d66e9 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/MechanicalMixerTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/MechanicalMixerTileEntity.java @@ -22,7 +22,6 @@ import net.minecraft.item.crafting.ShapelessRecipe; import net.minecraft.nbt.CompoundNBT; import net.minecraft.particles.ItemParticleData; import net.minecraft.particles.ParticleTypes; -import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction.Axis; import net.minecraft.util.NonNullList; @@ -35,7 +34,7 @@ import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemHandlerHelper; -public class MechanicalMixerTileEntity extends KineticTileEntity implements ITickableTileEntity { +public class MechanicalMixerTileEntity extends KineticTileEntity { public int runningTicks; public int processingTicks; @@ -132,6 +131,7 @@ public class MechanicalMixerTileEntity extends KineticTileEntity implements ITic @Override public void tick() { + super.tick(); if (world.isRemote && lastModified != -1) { if (lastModified++ > 10) { diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/MechanicalPressTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/MechanicalPressTileEntity.java index c4f5d0918..876247563 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/MechanicalPressTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/MechanicalPressTileEntity.java @@ -13,7 +13,6 @@ import net.minecraft.entity.item.ItemEntity; import net.minecraft.nbt.CompoundNBT; import net.minecraft.particles.ItemParticleData; import net.minecraft.particles.ParticleTypes; -import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvents; import net.minecraft.util.math.AxisAlignedBB; @@ -22,7 +21,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.wrapper.RecipeWrapper; -public class MechanicalPressTileEntity extends KineticTileEntity implements ITickableTileEntity { +public class MechanicalPressTileEntity extends KineticTileEntity { public static class PressingInv extends RecipeWrapper { public PressingInv() { @@ -85,6 +84,8 @@ public class MechanicalPressTileEntity extends KineticTileEntity implements ITic @Override public void tick() { + super.tick(); + if (!running) return; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalBearingTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalBearingTileEntity.java index 05819b281..00f35b07c 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalBearingTileEntity.java @@ -1,5 +1,7 @@ package com.simibubi.create.modules.contraptions.receivers.constructs; +import java.util.Optional; + import com.simibubi.create.AllTileEntities; import com.simibubi.create.modules.contraptions.RotationPropagator; import com.simibubi.create.modules.contraptions.base.KineticTileEntity; @@ -8,7 +10,6 @@ import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; @@ -18,7 +19,7 @@ import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -public class MechanicalBearingTileEntity extends KineticTileEntity implements ITickableTileEntity { +public class MechanicalBearingTileEntity extends KineticTileEntity { protected RotationConstruct movingConstruct; protected float angle; @@ -41,6 +42,11 @@ public class MechanicalBearingTileEntity extends KineticTileEntity implements IT public double getMaxRenderDistanceSquared() { return super.getMaxRenderDistanceSquared() * 16; } + + @Override + public float getAddedStressCapacity() { + return getWindmillSpeed() * 50; + } @Override public boolean isSource() { @@ -144,10 +150,16 @@ public class MechanicalBearingTileEntity extends KineticTileEntity implements IT getWorld().setBlockState(info.pos.add(pos), Blocks.AIR.getDefaultState(), 67); } + applyWindmillSpeed(); + } + + public void applyWindmillSpeed() { if (isWindmill) { RotationPropagator.handleRemoved(world, pos, this); + source = Optional.empty(); speed = getWindmillSpeed(); RotationPropagator.handleAdded(world, pos, this); + sendData(); } } @@ -176,9 +188,16 @@ public class MechanicalBearingTileEntity extends KineticTileEntity implements IT angle = 0; sendData(); } + + @Override + public void reActivateSource() { + applyWindmillSpeed(); + } @Override public void tick() { + super.tick(); + if (running && RotationConstruct.isFrozen()) disassembleConstruct(); diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntity.java index 19968f290..c9527b66a 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntity.java @@ -19,7 +19,6 @@ import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalP import net.minecraft.block.Blocks; import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.AxisAlignedBB; @@ -30,7 +29,7 @@ import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -public class MechanicalPistonTileEntity extends KineticTileEntity implements ITickableTileEntity { +public class MechanicalPistonTileEntity extends KineticTileEntity { protected PistonContraption movedContraption; protected float offset; @@ -189,6 +188,8 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi @Override public void tick() { + super.tick(); + if (!world.isRemote && assembleNextTick) { assembleNextTick = false; if (running) { diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/GearboxTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/GearboxTileEntityRenderer.java index 586eac9a1..da4088589 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/GearboxTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/GearboxTileEntityRenderer.java @@ -33,7 +33,7 @@ public class GearboxTileEntityRenderer extends KineticTileEntityRenderer { float offset = getRotationOffsetForPosition(te, pos, axis); float angle = (time * te.getSpeed()) % 360; - if (te.getSpeed() != 0) { + if (te.getSpeed() != 0 && te.hasSource()) { BlockPos source = te.getSource().subtract(te.getPos()); Direction sourceFacing = Direction.getFacingFromVector(source.getX(), source.getY(), source.getZ()); if (sourceFacing.getAxis() == direction.getAxis()) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltItem.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltItem.java index f44a34f02..a6a2c730d 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltItem.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltItem.java @@ -183,7 +183,7 @@ public class BeltItem extends Item { float speed1 = ((KineticTileEntity) world.getTileEntity(first)).getSpeed(); float speed2 = ((KineticTileEntity) world.getTileEntity(second)).getSpeed(); - if (speed1 != speed2 && speed1 != 0 && speed2 != 0) + if (Math.signum(speed1) != Math.signum(speed2) && speed1 != 0 && speed2 != 0) return false; BlockPos step = new BlockPos(Math.signum(diff.getX()), Math.signum(diff.getY()), Math.signum(diff.getZ())); diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java index 93bf50e8e..baa90e188 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java @@ -26,7 +26,6 @@ import net.minecraft.nbt.NBTUtil; import net.minecraft.potion.EffectInstance; import net.minecraft.potion.Effects; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; @@ -36,7 +35,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; -public class BeltTileEntity extends KineticTileEntity implements ITickableTileEntity { +public class BeltTileEntity extends KineticTileEntity { protected BlockPos controller; public Map passengers; @@ -140,6 +139,8 @@ public class BeltTileEntity extends KineticTileEntity implements ITickableTileEn @Override public void tick() { + super.tick(); + if (world != null && trackerUpdateTag != null) { attachmentTracker.readAndSearch(trackerUpdateTag, this); trackerUpdateTag = null; diff --git a/src/main/java/com/simibubi/create/modules/logistics/FrequencyHandler.java b/src/main/java/com/simibubi/create/modules/logistics/FrequencyHandler.java index 97db6644a..12a36701c 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/FrequencyHandler.java +++ b/src/main/java/com/simibubi/create/modules/logistics/FrequencyHandler.java @@ -50,12 +50,12 @@ public class FrequencyHandler { public void onLoadWorld(IWorld world) { connections.put(world, new HashMap<>()); - Create.logger.debug("Prepared Network Space for " + world.getDimension().getType().getRegistryName()); + Create.logger.debug("Prepared Redstone Network Space for " + world.getDimension().getType().getRegistryName()); } public void onUnloadWorld(IWorld world) { connections.remove(world); - Create.logger.debug("Removed Network Space for " + world.getDimension().getType().getRegistryName()); + Create.logger.debug("Removed Redstone Network Space for " + world.getDimension().getType().getRegistryName()); } private static Pair getNetworkKey(IHaveWireless actor) { diff --git a/src/main/resources/assets/create/textures/block/scarf.png b/src/main/resources/assets/create/textures/block/scarf.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb9dd313a9716af60f5baf18c2594ee23602e8f GIT binary patch literal 441 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sDEfH31!Z9ZwB20u?1#}Etu^+}n*!;YH$`pZtp)8J6+68Q=Z;jYEfV@%?{Q{L35}mJ~|AzV=_?r~(hu zi&rxpj<~m-PvA4+HGc7BelgE+`?)NSm-DPYkaXge#Q*>8yZKmi((Zn%zdxUu=NFF^ zPgcyT1j8BACouXkCn(I{_+Ym)q98l#?%dWk0(11aP?Z<&u`|FbD z>UJ?5yTRbd9A{*c*zs5XU`5+QmJk-v2R`gCKK6Rcq+2P3frx3xI#>g?d^G%ET*Ksb z_(kV`^@J8Xo`e?06CrhMaTdH@wKhC+c;Y4Y8G9Ia2=Xy|iy61AcQ|^=fy3y?)T44M z=8F3?Gu$&^U<_C^F>wNudi(@#hnfJdJ#0SwH$E|Szt7iqi)Yi{aKQIiw#8)C6DK!J h;Rt?z`oU2KhHH+`lUeI)4*`Rl!PC{xWt~$(69DovsNDbn literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/gui/filter.pdn b/src/main/resources/assets/create/textures/gui/filter.pdn new file mode 100644 index 0000000000000000000000000000000000000000..02d317356fa064554a6991611666b73ef382186b GIT binary patch literal 13643 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 NUH&fk_Ho04{{wx=7NP(E literal 0 HcmV?d00001