mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-03-03 22:34:42 +01:00
Fundamentals of Fluid Transfer
- Fixed some inconsistencies with a tanks' fluidhandler invalidation when resized - Patched crashes in present fluid handling of the basin - Tanks now slightly shade horizontal faces of the contained liquid - Tanks no longer resend data every tick when filled gradually - Introduced a new lerped value type with better design decisions - Refactored Smart tileentity serialization to better support custom overrides in contained behaviours - Pumps propagate flows in the pipe networks in front and behind itself. - Pumps collect all possible in and outputs across the reachable pipe graph as endpoints - Flows move across multiple branches of a pipe network when both are equally viable - Open-ended pipes are treated as endpoints and leak fluid into and out of a block space - Open endpoints serialize stateful information about fluid units gathered and held at the interface - Open endpoints turn a fluid block into 1000 fluid units and back - Open endpoints undo their transaction when their flow changes from pull to push - Open endpoints cannot pull fluids back when a full liquid block was not placed yet - Open endpoints waterlog blocks when the provided fluid is water - A collision response is triggered when different types of fluids meet at open endpoints - Fluids are transferred instantly by the throughput of a completed flow per tick - Pumps cut flows when vital pipes are removed - Pumps do not lose progress of finished flows when an unrelated part of the pipe network changes - Pumps do not lose progress of finished flows when reversed - Pumps distribute their throughput across available input flows evenly - Pumps distribute gathered input fluid across outputs evenly - Pumps expose furthest reachable pipefaces to other pumps for chained transfer - Chained pumps with fully overlapping flow sections provide their endpoints at the entrance of the other pump - Chained pumps with overlapping flow sections participate in two shared endpoints, one for each pump dominating the contested region - Chained pumps with overlapping flow only transfer via the optimal of the two possible endpoints based on their speeds - Chained pumps of equal speed pick one of the two available endpoints deterministically - Pumps transfer without flows when no pipe is between the pump and the endpoint - Pumps serialize and recover stateful information about held fluid units at open endpoints - Chained pumps do not actively transfer when both are partaking with push flows (or both pulling) - A pull flow originating from an inter-pump endpoint only commences when the corresponding push flow is completed - Chained pumps re-determine the optimal flow when the speed of one is changed at runtime - Throughput of chained pumps is determined by their weakest link in terms of speed - Endpoints created for chained pumps is treated equally to other available endpoints when fluid is distributed - Pipes do not contain a physical amount of fluid. - Pipes never hold serialized vital stateful information about fluid transfer. - Pipes synchronize local flow progress and fluid type to clients - Flows in a pipe progress with the speed of the network flow - A networks flow speed depends on the speed of the aggregated pump - Pipe flows of different flow graphs of different pumps interact with each other - A collision response is triggered when two different types of fluid meet within a pipe - Pipes spawn particles to illustrate contained flows/liquids of flows - The fluid transfer role is exposed through a TE behaviour with some callbacks and properties - Open endpoints show particles when interacting with in-world fluids
This commit is contained in:
parent
8e349380a5
commit
2040d66c3e
94 changed files with 3282 additions and 937 deletions
|
@ -11,6 +11,7 @@ public enum AllSpecialTextures {
|
||||||
BLANK("blank.png"),
|
BLANK("blank.png"),
|
||||||
CHECKERED("checkerboard.png"),
|
CHECKERED("checkerboard.png"),
|
||||||
THIN_CHECKERED("thin_checkerboard.png"),
|
THIN_CHECKERED("thin_checkerboard.png"),
|
||||||
|
CUTOUT_CHECKERED("cutout_checkerboard.png"),
|
||||||
HIGHLIGHT_CHECKERED("highlighted_checkerboard.png"),
|
HIGHLIGHT_CHECKERED("highlighted_checkerboard.png"),
|
||||||
SELECTION("selection.png"),
|
SELECTION("selection.png"),
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pul
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity;
|
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.components.turntable.TurntableTileEntity;
|
import com.simibubi.create.content.contraptions.components.turntable.TurntableTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.components.waterwheel.WaterWheelTileEntity;
|
import com.simibubi.create.content.contraptions.components.waterwheel.WaterWheelTileEntity;
|
||||||
|
import com.simibubi.create.content.contraptions.fluids.FluidPipeTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidTankRenderer;
|
import com.simibubi.create.content.contraptions.fluids.FluidTankRenderer;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidTankTileEntity;
|
import com.simibubi.create.content.contraptions.fluids.FluidTankTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.fluids.PumpRenderer;
|
import com.simibubi.create.content.contraptions.fluids.PumpRenderer;
|
||||||
|
@ -57,7 +58,11 @@ import com.simibubi.create.content.contraptions.relays.advanced.sequencer.Sequen
|
||||||
import com.simibubi.create.content.contraptions.relays.belt.BeltRenderer;
|
import com.simibubi.create.content.contraptions.relays.belt.BeltRenderer;
|
||||||
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
|
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.relays.elementary.SimpleKineticTileEntity;
|
import com.simibubi.create.content.contraptions.relays.elementary.SimpleKineticTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.relays.encased.*;
|
import com.simibubi.create.content.contraptions.relays.encased.AdjustablePulleyTileEntity;
|
||||||
|
import com.simibubi.create.content.contraptions.relays.encased.ClutchTileEntity;
|
||||||
|
import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftRenderer;
|
||||||
|
import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftTileEntity;
|
||||||
|
import com.simibubi.create.content.contraptions.relays.encased.SplitShaftRenderer;
|
||||||
import com.simibubi.create.content.contraptions.relays.gauge.GaugeRenderer;
|
import com.simibubi.create.content.contraptions.relays.gauge.GaugeRenderer;
|
||||||
import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity;
|
import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity;
|
import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity;
|
||||||
|
@ -86,7 +91,12 @@ import com.simibubi.create.content.logistics.block.mechanicalArm.ArmRenderer;
|
||||||
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity;
|
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity;
|
||||||
import com.simibubi.create.content.logistics.block.packager.PackagerRenderer;
|
import com.simibubi.create.content.logistics.block.packager.PackagerRenderer;
|
||||||
import com.simibubi.create.content.logistics.block.packager.PackagerTileEntity;
|
import com.simibubi.create.content.logistics.block.packager.PackagerTileEntity;
|
||||||
import com.simibubi.create.content.logistics.block.redstone.*;
|
import com.simibubi.create.content.logistics.block.redstone.AnalogLeverRenderer;
|
||||||
|
import com.simibubi.create.content.logistics.block.redstone.AnalogLeverTileEntity;
|
||||||
|
import com.simibubi.create.content.logistics.block.redstone.NixieTubeRenderer;
|
||||||
|
import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity;
|
||||||
|
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkTileEntity;
|
||||||
|
import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchTileEntity;
|
||||||
import com.simibubi.create.content.logistics.block.transposer.LinkedTransposerTileEntity;
|
import com.simibubi.create.content.logistics.block.transposer.LinkedTransposerTileEntity;
|
||||||
import com.simibubi.create.content.logistics.block.transposer.TransposerTileEntity;
|
import com.simibubi.create.content.logistics.block.transposer.TransposerTileEntity;
|
||||||
import com.simibubi.create.content.schematics.block.SchematicTableTileEntity;
|
import com.simibubi.create.content.schematics.block.SchematicTableTileEntity;
|
||||||
|
@ -95,6 +105,7 @@ import com.simibubi.create.content.schematics.block.SchematicannonTileEntity;
|
||||||
import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer;
|
import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer;
|
||||||
import com.tterrag.registrate.util.entry.TileEntityEntry;
|
import com.tterrag.registrate.util.entry.TileEntityEntry;
|
||||||
import com.tterrag.registrate.util.nullness.NonNullFunction;
|
import com.tterrag.registrate.util.nullness.NonNullFunction;
|
||||||
|
|
||||||
import net.minecraft.tileentity.TileEntityType;
|
import net.minecraft.tileentity.TileEntityType;
|
||||||
|
|
||||||
public class AllTileEntities {
|
public class AllTileEntities {
|
||||||
|
@ -191,6 +202,11 @@ public class AllTileEntities {
|
||||||
.renderer(() -> PumpRenderer::new)
|
.renderer(() -> PumpRenderer::new)
|
||||||
.register();
|
.register();
|
||||||
|
|
||||||
|
public static final TileEntityEntry<FluidPipeTileEntity> FLUID_PIPE = Create.registrate()
|
||||||
|
.tileEntity("fluid_pipe", (NonNullFunction<TileEntityType<FluidPipeTileEntity>, ? extends FluidPipeTileEntity>) FluidPipeTileEntity::new)
|
||||||
|
.validBlocks(AllBlocks.FLUID_PIPE)
|
||||||
|
.register();
|
||||||
|
|
||||||
public static final TileEntityEntry<FluidTankTileEntity> FLUID_TANK = Create.registrate()
|
public static final TileEntityEntry<FluidTankTileEntity> FLUID_TANK = Create.registrate()
|
||||||
.tileEntity("fluid_tank", (NonNullFunction<TileEntityType<FluidTankTileEntity>, ? extends FluidTankTileEntity>) FluidTankTileEntity::new)
|
.tileEntity("fluid_tank", (NonNullFunction<TileEntityType<FluidTankTileEntity>, ? extends FluidTankTileEntity>) FluidTankTileEntity::new)
|
||||||
.validBlocks(AllBlocks.FLUID_TANK)
|
.validBlocks(AllBlocks.FLUID_TANK)
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class KineticDebugger {
|
||||||
VoxelShape shape = world.getBlockState(toOutline)
|
VoxelShape shape = world.getBlockState(toOutline)
|
||||||
.getRenderShape(world, toOutline);
|
.getRenderShape(world, toOutline);
|
||||||
|
|
||||||
if (te.getTheoreticalSpeed() != 0)
|
if (te.getTheoreticalSpeed() != 0 && !shape.isEmpty())
|
||||||
CreateClient.outliner.chaseAABB("kineticSource", shape.getBoundingBox()
|
CreateClient.outliner.chaseAABB("kineticSource", shape.getBoundingBox()
|
||||||
.offset(toOutline))
|
.offset(toOutline))
|
||||||
.lineWidth(1 / 16f)
|
.lineWidth(1 / 16f)
|
||||||
|
|
|
@ -178,7 +178,7 @@ public abstract class KineticTileEntity extends SmartTileEntity
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
protected void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putFloat("Speed", speed);
|
compound.putFloat("Speed", speed);
|
||||||
|
|
||||||
if (needsSpeedUpdate())
|
if (needsSpeedUpdate())
|
||||||
|
@ -202,7 +202,7 @@ public abstract class KineticTileEntity extends SmartTileEntity
|
||||||
compound.put("Network", networkTag);
|
compound.put("Network", networkTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean needsSpeedUpdate() {
|
public boolean needsSpeedUpdate() {
|
||||||
|
@ -210,12 +210,13 @@ public abstract class KineticTileEntity extends SmartTileEntity
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
boolean overStressedBefore = overStressed;
|
||||||
clearKineticInformation();
|
clearKineticInformation();
|
||||||
|
|
||||||
// DO NOT READ kinetic information when placed after movement
|
// DO NOT READ kinetic information when placed after movement
|
||||||
if (wasMoved) {
|
if (wasMoved) {
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,14 +236,9 @@ public abstract class KineticTileEntity extends SmartTileEntity
|
||||||
overStressed = capacity < stress && StressImpact.isEnabled();
|
overStressed = capacity < stress && StressImpact.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (clientPacket && overStressedBefore != overStressed && speed != 0)
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
|
||||||
boolean overStressedBefore = overStressed;
|
|
||||||
super.readClientUpdate(tag);
|
|
||||||
if (overStressedBefore != overStressed && speed != 0)
|
|
||||||
effects.triggerOverStressedEffect();
|
effects.triggerOverStressedEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,21 +58,21 @@ public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putInt("Progress", destroyProgress);
|
compound.putInt("Progress", destroyProgress);
|
||||||
compound.putInt("NextTick", ticksUntilNextProgress);
|
compound.putInt("NextTick", ticksUntilNextProgress);
|
||||||
if (breakingPos != null)
|
if (breakingPos != null)
|
||||||
compound.put("Breaking", NBTUtil.writeBlockPos(breakingPos));
|
compound.put("Breaking", NBTUtil.writeBlockPos(breakingPos));
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
destroyProgress = compound.getInt("Progress");
|
destroyProgress = compound.getInt("Progress");
|
||||||
ticksUntilNextProgress = compound.getInt("NextTick");
|
ticksUntilNextProgress = compound.getInt("NextTick");
|
||||||
if (compound.contains("Breaking"))
|
if (compound.contains("Breaking"))
|
||||||
breakingPos = NBTUtil.readBlockPos(compound.getCompound("Breaking"));
|
breakingPos = NBTUtil.readBlockPos(compound.getCompound("Breaking"));
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.simibubi.create.content.contraptions.components.actors;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
|
|
||||||
|
|
||||||
import net.minecraft.world.server.ServerWorld;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
import net.minecraftforge.common.util.FakePlayer;
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
|
|
@ -41,21 +41,21 @@ public class CuckooClockTileEntity extends KineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
if (sendAnimationUpdate)
|
super.read(compound, clientPacket);
|
||||||
NBTHelper.writeEnum(compound, "Animation", animationType);
|
if (clientPacket && compound.contains("Animation")) {
|
||||||
sendAnimationUpdate = false;
|
animationType = NBTHelper.readEnum(compound, "Animation", Animation.class);
|
||||||
return super.writeToClient(compound);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
|
||||||
if (tag.contains("Animation")) {
|
|
||||||
animationType = NBTHelper.readEnum(tag, "Animation", Animation.class);
|
|
||||||
animationProgress.lastValue = 0;
|
animationProgress.lastValue = 0;
|
||||||
animationProgress.value = 0;
|
animationProgress.value = 0;
|
||||||
}
|
}
|
||||||
super.readClientUpdate(tag);
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
if (clientPacket && sendAnimationUpdate)
|
||||||
|
NBTHelper.writeEnum(compound, "Animation", animationType);
|
||||||
|
sendAnimationUpdate = false;
|
||||||
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -123,7 +123,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.put("Inventory", inventory.serializeNBT());
|
compound.put("Inventory", inventory.serializeNBT());
|
||||||
|
|
||||||
CompoundNBT inputNBT = new CompoundNBT();
|
CompoundNBT inputNBT = new CompoundNBT();
|
||||||
|
@ -138,43 +138,19 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
|
||||||
compound.putInt("CountDown", countDown);
|
compound.putInt("CountDown", countDown);
|
||||||
compound.putBoolean("Cover", covered);
|
compound.putBoolean("Cover", covered);
|
||||||
|
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (clientPacket && reRender) {
|
||||||
public CompoundNBT writeToClient(CompoundNBT tag) {
|
compound.putBoolean("Redraw", true);
|
||||||
if (reRender) {
|
|
||||||
tag.putBoolean("Redraw", true);
|
|
||||||
reRender = false;
|
reRender = false;
|
||||||
}
|
}
|
||||||
return super.writeToClient(tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
if (tag.contains("Redraw"))
|
|
||||||
world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16);
|
|
||||||
|
|
||||||
Phase phaseBefore = phase;
|
Phase phaseBefore = phase;
|
||||||
GroupedItems before = this.groupedItems;
|
GroupedItems before = this.groupedItems;
|
||||||
|
|
||||||
super.readClientUpdate(tag);
|
|
||||||
|
|
||||||
if (phaseBefore != phase && phase == Phase.CRAFTING)
|
|
||||||
groupedItemsBeforeCraft = before;
|
|
||||||
if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) {
|
|
||||||
Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING);
|
|
||||||
Vec3d vec = new Vec3d(facing.getDirectionVec()).scale(.75)
|
|
||||||
.add(VecHelper.getCenterOf(pos));
|
|
||||||
Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState());
|
|
||||||
vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(1));
|
|
||||||
world.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void read(CompoundNBT compound) {
|
|
||||||
inventory.deserializeNBT(compound.getCompound("Inventory"));
|
inventory.deserializeNBT(compound.getCompound("Inventory"));
|
||||||
input.read(compound.getCompound("ConnectedInput"));
|
input.read(compound.getCompound("ConnectedInput"));
|
||||||
groupedItems = GroupedItems.read(compound.getCompound("GroupedItems"));
|
groupedItems = GroupedItems.read(compound.getCompound("GroupedItems"));
|
||||||
|
@ -186,7 +162,22 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
|
||||||
this.phase = phase;
|
this.phase = phase;
|
||||||
countDown = compound.getInt("CountDown");
|
countDown = compound.getInt("CountDown");
|
||||||
covered = compound.getBoolean("Cover");
|
covered = compound.getBoolean("Cover");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
|
|
||||||
|
if (!clientPacket)
|
||||||
|
return;
|
||||||
|
if (compound.contains("Redraw"))
|
||||||
|
world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16);
|
||||||
|
if (phaseBefore != phase && phase == Phase.CRAFTING)
|
||||||
|
groupedItemsBeforeCraft = before;
|
||||||
|
if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) {
|
||||||
|
Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING);
|
||||||
|
Vec3d vec = new Vec3d(facing.getDirectionVec()).scale(.75)
|
||||||
|
.add(VecHelper.getCenterOf(pos));
|
||||||
|
Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState());
|
||||||
|
vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(1));
|
||||||
|
world.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -293,7 +284,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
|
||||||
Vec3d vec = facingVec.scale(.65)
|
Vec3d vec = facingVec.scale(.65)
|
||||||
.add(VecHelper.getCenterOf(pos));
|
.add(VecHelper.getCenterOf(pos));
|
||||||
Vec3d offset = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
|
Vec3d offset = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
|
||||||
.mul(VecHelper.planeByNormal(facingVec))
|
.mul(VecHelper.axisAlingedPlaneOf(facingVec))
|
||||||
.normalize()
|
.normalize()
|
||||||
.scale(progress * .5f)
|
.scale(progress * .5f)
|
||||||
.add(vec);
|
.add(vec);
|
||||||
|
@ -307,7 +298,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
Vec3d randVec = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
|
Vec3d randVec = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
|
||||||
.mul(VecHelper.planeByNormal(facingVec))
|
.mul(VecHelper.axisAlingedPlaneOf(facingVec))
|
||||||
.normalize()
|
.normalize()
|
||||||
.scale(.25f);
|
.scale(.25f);
|
||||||
Vec3d offset2 = randVec.add(vec);
|
Vec3d offset2 = randVec.add(vec);
|
||||||
|
|
|
@ -38,15 +38,15 @@ public class HandCrankTileEntity extends GeneratingKineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putInt("InUse", inUse);
|
compound.putInt("InUse", inUse);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
inUse = compound.getInt("InUse");
|
inUse = compound.getInt("InUse");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -215,19 +215,17 @@ public class CrushingWheelControllerTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
if (hasEntity())
|
if (hasEntity())
|
||||||
compound.put("Entity", NBTUtil.writeUniqueId(entityUUID));
|
compound.put("Entity", NBTUtil.writeUniqueId(entityUUID));
|
||||||
compound.put("Inventory", inventory.serializeNBT());
|
compound.put("Inventory", inventory.serializeNBT());
|
||||||
compound.putFloat("Speed", crushingspeed);
|
compound.putFloat("Speed", crushingspeed);
|
||||||
|
super.write(compound, clientPacket);
|
||||||
return super.write(compound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
|
|
||||||
if (compound.contains("Entity") && !isFrozen() && !isOccupied()) {
|
if (compound.contains("Entity") && !isFrozen() && !isOccupied()) {
|
||||||
entityUUID = NBTUtil.readUniqueId(compound.getCompound("Entity"));
|
entityUUID = NBTUtil.readUniqueId(compound.getCompound("Entity"));
|
||||||
this.searchForEntity = true;
|
this.searchForEntity = true;
|
||||||
|
|
|
@ -51,8 +51,7 @@ import net.minecraftforge.items.ItemHandlerHelper;
|
||||||
|
|
||||||
public class DeployerTileEntity extends KineticTileEntity {
|
public class DeployerTileEntity extends KineticTileEntity {
|
||||||
|
|
||||||
private static final List<Pair<BlockPos, Direction>> EXTRACTING_LOCATIONS = Arrays
|
private static final List<Pair<BlockPos, Direction>> EXTRACTING_LOCATIONS = Arrays.asList(Direction.values())
|
||||||
.asList(Direction.values())
|
|
||||||
.stream()
|
.stream()
|
||||||
.map(d -> Pair.of(BlockPos.ZERO.offset(d), d.getOpposite()))
|
.map(d -> Pair.of(BlockPos.ZERO.offset(d), d.getOpposite()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
@ -167,7 +166,8 @@ public class DeployerTileEntity extends KineticTileEntity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filtering.getFilter().isEmpty() && stack.isEmpty())
|
if (filtering.getFilter()
|
||||||
|
.isEmpty() && stack.isEmpty())
|
||||||
extracting.extract(1);
|
extracting.extract(1);
|
||||||
|
|
||||||
Direction facing = getBlockState().get(FACING);
|
Direction facing = getBlockState().get(FACING);
|
||||||
|
@ -182,12 +182,16 @@ public class DeployerTileEntity extends KineticTileEntity {
|
||||||
|
|
||||||
state = State.EXPANDING;
|
state = State.EXPANDING;
|
||||||
Vec3d movementVector = getMovementVector();
|
Vec3d movementVector = getMovementVector();
|
||||||
Vec3d rayOrigin = VecHelper.getCenterOf(pos).add(movementVector.scale(3 / 2f));
|
Vec3d rayOrigin = VecHelper.getCenterOf(pos)
|
||||||
Vec3d rayTarget = VecHelper.getCenterOf(pos).add(movementVector.scale(5 / 2f));
|
.add(movementVector.scale(3 / 2f));
|
||||||
|
Vec3d rayTarget = VecHelper.getCenterOf(pos)
|
||||||
|
.add(movementVector.scale(5 / 2f));
|
||||||
RayTraceContext rayTraceContext =
|
RayTraceContext rayTraceContext =
|
||||||
new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE, FluidMode.NONE, player);
|
new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE, FluidMode.NONE, player);
|
||||||
BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext);
|
BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext);
|
||||||
reach = (float) (.5f + Math.min(result.getHitVec().subtract(rayOrigin).length(), .75f));
|
reach = (float) (.5f + Math.min(result.getHitVec()
|
||||||
|
.subtract(rayOrigin)
|
||||||
|
.length(), .75f));
|
||||||
|
|
||||||
timer = 1000;
|
timer = 1000;
|
||||||
sendData();
|
sendData();
|
||||||
|
@ -226,7 +230,9 @@ public class DeployerTileEntity extends KineticTileEntity {
|
||||||
if (!(otherTile instanceof DeployerTileEntity))
|
if (!(otherTile instanceof DeployerTileEntity))
|
||||||
return false;
|
return false;
|
||||||
DeployerTileEntity deployerTile = (DeployerTileEntity) otherTile;
|
DeployerTileEntity deployerTile = (DeployerTileEntity) otherTile;
|
||||||
if (world.getBlockState(otherDeployer).get(FACING).getOpposite() != facing || deployerTile.mode != Mode.PUNCH)
|
if (world.getBlockState(otherDeployer)
|
||||||
|
.get(FACING)
|
||||||
|
.getOpposite() != facing || deployerTile.mode != Mode.PUNCH)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
boop = true;
|
boop = true;
|
||||||
|
@ -295,13 +301,15 @@ public class DeployerTileEntity extends KineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void tryDisposeOfItems() {
|
protected void tryDisposeOfItems() {
|
||||||
boolean noInv = extracting.getInventories().isEmpty();
|
boolean noInv = extracting.getInventories()
|
||||||
|
.isEmpty();
|
||||||
for (Iterator<ItemStack> iterator = overflowItems.iterator(); iterator.hasNext();) {
|
for (Iterator<ItemStack> iterator = overflowItems.iterator(); iterator.hasNext();) {
|
||||||
ItemStack itemStack = iterator.next();
|
ItemStack itemStack = iterator.next();
|
||||||
|
|
||||||
if (noInv) {
|
if (noInv) {
|
||||||
Vec3d offset = getMovementVector();
|
Vec3d offset = getMovementVector();
|
||||||
Vec3d outPos = VecHelper.getCenterOf(pos).add(offset.scale(-.65f));
|
Vec3d outPos = VecHelper.getCenterOf(pos)
|
||||||
|
.add(offset.scale(-.65f));
|
||||||
Vec3d motion = offset.scale(-.25f);
|
Vec3d motion = offset.scale(-.25f);
|
||||||
ItemEntity e = new ItemEntity(world, outPos.x, outPos.y, outPos.z, itemStack.copy());
|
ItemEntity e = new ItemEntity(world, outPos.x, outPos.y, outPos.z, itemStack.copy());
|
||||||
e.setMotion(motion);
|
e.setMotion(motion);
|
||||||
|
@ -328,11 +336,12 @@ public class DeployerTileEntity extends KineticTileEntity {
|
||||||
protected Vec3d getMovementVector() {
|
protected Vec3d getMovementVector() {
|
||||||
if (!AllBlocks.DEPLOYER.has(getBlockState()))
|
if (!AllBlocks.DEPLOYER.has(getBlockState()))
|
||||||
return Vec3d.ZERO;
|
return Vec3d.ZERO;
|
||||||
return new Vec3d(getBlockState().get(FACING).getDirectionVec());
|
return new Vec3d(getBlockState().get(FACING)
|
||||||
|
.getDirectionVec());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
state = NBTHelper.readEnum(compound, "State", State.class);
|
state = NBTHelper.readEnum(compound, "State", State.class);
|
||||||
mode = NBTHelper.readEnum(compound, "Mode", Mode.class);
|
mode = NBTHelper.readEnum(compound, "Mode", Mode.class);
|
||||||
timer = compound.getInt("Timer");
|
timer = compound.getInt("Timer");
|
||||||
|
@ -340,49 +349,46 @@ public class DeployerTileEntity extends KineticTileEntity {
|
||||||
overflowItems = NBTHelper.readItemList(compound.getList("Overflow", NBT.TAG_COMPOUND));
|
overflowItems = NBTHelper.readItemList(compound.getList("Overflow", NBT.TAG_COMPOUND));
|
||||||
if (compound.contains("HeldItem"))
|
if (compound.contains("HeldItem"))
|
||||||
heldItem = ItemStack.read(compound.getCompound("HeldItem"));
|
heldItem = ItemStack.read(compound.getCompound("HeldItem"));
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
|
|
||||||
|
if (!clientPacket)
|
||||||
|
return;
|
||||||
|
reach = compound.getFloat("Reach");
|
||||||
|
if (compound.contains("Particle")) {
|
||||||
|
ItemStack particleStack = ItemStack.read(compound.getCompound("Particle"));
|
||||||
|
SandPaperItem.spawnParticles(VecHelper.getCenterOf(pos)
|
||||||
|
.add(getMovementVector().scale(2f)), particleStack, this.world);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
NBTHelper.writeEnum(compound, "Mode", mode);
|
NBTHelper.writeEnum(compound, "Mode", mode);
|
||||||
NBTHelper.writeEnum(compound, "State", state);
|
NBTHelper.writeEnum(compound, "State", state);
|
||||||
compound.putInt("Timer", timer);
|
compound.putInt("Timer", timer);
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
compound.put("HeldItem", player.getHeldItemMainhand().serializeNBT());
|
compound.put("HeldItem", player.getHeldItemMainhand()
|
||||||
|
.serializeNBT());
|
||||||
ListNBT invNBT = new ListNBT();
|
ListNBT invNBT = new ListNBT();
|
||||||
player.inventory.write(invNBT);
|
player.inventory.write(invNBT);
|
||||||
compound.put("Inventory", invNBT);
|
compound.put("Inventory", invNBT);
|
||||||
compound.put("Overflow", NBTHelper.writeItemList(overflowItems));
|
compound.put("Overflow", NBTHelper.writeItemList(overflowItems));
|
||||||
}
|
}
|
||||||
return super.write(compound);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
super.write(compound, clientPacket);
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
|
||||||
|
if (!clientPacket)
|
||||||
|
return;
|
||||||
compound.putFloat("Reach", reach);
|
compound.putFloat("Reach", reach);
|
||||||
if (player != null) {
|
if (player == null)
|
||||||
compound.put("HeldItem", player.getHeldItemMainhand().serializeNBT());
|
return;
|
||||||
|
compound.put("HeldItem", player.getHeldItemMainhand()
|
||||||
|
.serializeNBT());
|
||||||
if (player.spawnedItemEffects != null) {
|
if (player.spawnedItemEffects != null) {
|
||||||
compound.put("Particle", player.spawnedItemEffects.serializeNBT());
|
compound.put("Particle", player.spawnedItemEffects.serializeNBT());
|
||||||
player.spawnedItemEffects = null;
|
player.spawnedItemEffects = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.writeToClient(compound);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
|
||||||
reach = tag.getFloat("Reach");
|
|
||||||
if (tag.contains("Particle")) {
|
|
||||||
ItemStack particleStack = ItemStack.read(tag.getCompound("Particle"));
|
|
||||||
SandPaperItem
|
|
||||||
.spawnParticles(VecHelper.getCenterOf(pos).add(getMovementVector().scale(2f)), particleStack,
|
|
||||||
this.world);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.readClientUpdate(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IItemHandlerModifiable createHandler() {
|
private IItemHandlerModifiable createHandler() {
|
||||||
return new DeployerItemHandler(this);
|
return new DeployerItemHandler(this);
|
||||||
|
|
|
@ -165,7 +165,7 @@ public class AirCurrent {
|
||||||
.get(BlockStateProperties.FACING);
|
.get(BlockStateProperties.FACING);
|
||||||
pushing = source.getAirFlowDirection() == direction;
|
pushing = source.getAirFlowDirection() == direction;
|
||||||
Vec3d directionVec = new Vec3d(direction.getDirectionVec());
|
Vec3d directionVec = new Vec3d(direction.getDirectionVec());
|
||||||
Vec3d planeVec = VecHelper.planeByNormal(directionVec);
|
Vec3d planeVec = VecHelper.axisAlingedPlaneOf(directionVec);
|
||||||
|
|
||||||
// 4 Rays test for holes in the shapes blocking the flow
|
// 4 Rays test for holes in the shapes blocking the flow
|
||||||
float offsetDistance = .25f;
|
float offsetDistance = .25f;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlo
|
||||||
import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity;
|
import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity;
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
import com.simibubi.create.foundation.config.CKinetics;
|
import com.simibubi.create.foundation.config.CKinetics;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
import net.minecraft.state.properties.BlockStateProperties;
|
import net.minecraft.state.properties.BlockStateProperties;
|
||||||
|
@ -30,21 +31,17 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
super.readClientUpdate(tag);
|
super.read(compound, clientPacket);
|
||||||
|
isGenerator = compound.getBoolean("Generating");
|
||||||
|
if (clientPacket)
|
||||||
airCurrent.rebuild();
|
airCurrent.rebuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
super.read(compound);
|
|
||||||
isGenerator = compound.getBoolean("Generating");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
|
||||||
compound.putBoolean("Generating", isGenerator);
|
compound.putBoolean("Generating", isGenerator);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -77,10 +74,12 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity {
|
||||||
return false;
|
return false;
|
||||||
BlockState checkState = world.getBlockState(pos.down());
|
BlockState checkState = world.getBlockState(pos.down());
|
||||||
|
|
||||||
if (!checkState.getBlock().isIn(AllBlockTags.FAN_HEATERS.tag))
|
if (!checkState.getBlock()
|
||||||
|
.isIn(AllBlockTags.FAN_HEATERS.tag))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (checkState.has(BlazeBurnerBlock.HEAT_LEVEL) && !checkState.get(BlazeBurnerBlock.HEAT_LEVEL).isAtLeast(BlazeBurnerBlock.HeatLevel.FADING))
|
if (checkState.has(BlazeBurnerBlock.HEAT_LEVEL) && !checkState.get(BlazeBurnerBlock.HEAT_LEVEL)
|
||||||
|
.isAtLeast(BlazeBurnerBlock.HeatLevel.FADING))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (checkState.has(BlockStateProperties.LIT) && !checkState.get(BlockStateProperties.LIT))
|
if (checkState.has(BlockStateProperties.LIT) && !checkState.get(BlockStateProperties.LIT))
|
||||||
|
|
|
@ -38,26 +38,30 @@ public class NozzleTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
protected void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
super.write(compound, clientPacket);
|
||||||
|
if (!clientPacket)
|
||||||
|
return;
|
||||||
compound.putFloat("Range", range);
|
compound.putFloat("Range", range);
|
||||||
compound.putBoolean("Pushing", pushing);
|
compound.putBoolean("Pushing", pushing);
|
||||||
return super.writeToClient(compound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
range = tag.getFloat("Range");
|
super.read(compound, clientPacket);
|
||||||
pushing = tag.getBoolean("Pushing");
|
if (!clientPacket)
|
||||||
super.readClientUpdate(tag);
|
return;
|
||||||
|
range = compound.getFloat("Range");
|
||||||
|
pushing = compound.getBoolean("Pushing");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
fanPos = pos.offset(getBlockState().get(NozzleBlock.FACING).getOpposite());
|
fanPos = pos.offset(getBlockState().get(NozzleBlock.FACING)
|
||||||
|
.getOpposite());
|
||||||
super.initialize();
|
super.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +78,8 @@ public class NozzleTileEntity extends SmartTileEntity {
|
||||||
if (world.rand.nextInt(
|
if (world.rand.nextInt(
|
||||||
MathHelper.clamp((AllConfigs.SERVER.kinetics.fanPushDistance.get() - (int) range), 1, 10)) == 0) {
|
MathHelper.clamp((AllConfigs.SERVER.kinetics.fanPushDistance.get() - (int) range), 1, 10)) == 0) {
|
||||||
Vec3d start = VecHelper.offsetRandomly(center, world.rand, pushing ? 1 : range / 2);
|
Vec3d start = VecHelper.offsetRandomly(center, world.rand, pushing ? 1 : range / 2);
|
||||||
Vec3d motion = center.subtract(start).normalize()
|
Vec3d motion = center.subtract(start)
|
||||||
|
.normalize()
|
||||||
.scale(MathHelper.clamp(range * (pushing ? .025f : 1f), 0, .5f) * (pushing ? -1 : 1));
|
.scale(MathHelper.clamp(range * (pushing ? .025f : 1f), 0, .5f) * (pushing ? -1 : 1));
|
||||||
world.addParticle(ParticleTypes.POOF, start.x, start.y, start.z, motion.x, motion.y, motion.z);
|
world.addParticle(ParticleTypes.POOF, start.x, start.y, start.z, motion.x, motion.y, motion.z);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +87,8 @@ public class NozzleTileEntity extends SmartTileEntity {
|
||||||
|
|
||||||
for (Iterator<Entity> iterator = pushingEntities.iterator(); iterator.hasNext();) {
|
for (Iterator<Entity> iterator = pushingEntities.iterator(); iterator.hasNext();) {
|
||||||
Entity entity = iterator.next();
|
Entity entity = iterator.next();
|
||||||
Vec3d diff = entity.getPositionVec().subtract(center);
|
Vec3d diff = entity.getPositionVec()
|
||||||
|
.subtract(center);
|
||||||
|
|
||||||
if (!(entity instanceof PlayerEntity) && world.isRemote)
|
if (!(entity instanceof PlayerEntity) && world.isRemote)
|
||||||
continue;
|
continue;
|
||||||
|
@ -98,8 +104,10 @@ public class NozzleTileEntity extends SmartTileEntity {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float factor = (entity instanceof ItemEntity) ? 1 / 128f : 1 / 32f;
|
float factor = (entity instanceof ItemEntity) ? 1 / 128f : 1 / 32f;
|
||||||
Vec3d pushVec = diff.normalize().scale((range - distance) * (pushing ? 1 : -1));
|
Vec3d pushVec = diff.normalize()
|
||||||
entity.setMotion(entity.getMotion().add(pushVec.scale(factor)));
|
.scale((range - distance) * (pushing ? 1 : -1));
|
||||||
|
entity.setMotion(entity.getMotion()
|
||||||
|
.add(pushVec.scale(factor)));
|
||||||
entity.fallDistance = 0;
|
entity.fallDistance = 0;
|
||||||
entity.velocityChanged = true;
|
entity.velocityChanged = true;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +133,8 @@ public class NozzleTileEntity extends SmartTileEntity {
|
||||||
return 0;
|
return 0;
|
||||||
if (fan.getSpeed() == 0)
|
if (fan.getSpeed() == 0)
|
||||||
return 0;
|
return 0;
|
||||||
pushing = fan.getAirFlowDirection() == fan.getBlockState().get(EncasedFanBlock.FACING);
|
pushing = fan.getAirFlowDirection() == fan.getBlockState()
|
||||||
|
.get(EncasedFanBlock.FACING);
|
||||||
return fan.getMaxDistance();
|
return fan.getMaxDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +149,8 @@ public class NozzleTileEntity extends SmartTileEntity {
|
||||||
AxisAlignedBB bb = new AxisAlignedBB(center, center).grow(range / 2f);
|
AxisAlignedBB bb = new AxisAlignedBB(center, center).grow(range / 2f);
|
||||||
|
|
||||||
for (Entity entity : world.getEntitiesWithinAABB(Entity.class, bb)) {
|
for (Entity entity : world.getEntitiesWithinAABB(Entity.class, bb)) {
|
||||||
Vec3d diff = entity.getPositionVec().subtract(center);
|
Vec3d diff = entity.getPositionVec()
|
||||||
|
.subtract(center);
|
||||||
|
|
||||||
double distance = diff.length();
|
double distance = diff.length();
|
||||||
if (distance > range || entity.isSneaking()
|
if (distance > range || entity.isSneaking()
|
||||||
|
@ -179,7 +189,8 @@ public class NozzleTileEntity extends SmartTileEntity {
|
||||||
private boolean canSee(Entity entity) {
|
private boolean canSee(Entity entity) {
|
||||||
RayTraceContext context = new RayTraceContext(entity.getPositionVec(), VecHelper.getCenterOf(pos),
|
RayTraceContext context = new RayTraceContext(entity.getPositionVec(), VecHelper.getCenterOf(pos),
|
||||||
BlockMode.COLLIDER, FluidMode.NONE, entity);
|
BlockMode.COLLIDER, FluidMode.NONE, entity);
|
||||||
return pos.equals(world.rayTraceBlocks(context).getPos());
|
return pos.equals(world.rayTraceBlocks(context)
|
||||||
|
.getPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,30 +53,21 @@ public class FlywheelTileEntity extends GeneratingKineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
return super.writeToClient(compound);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
|
||||||
super.readClientUpdate(tag);
|
|
||||||
visualSpeed.withSpeed(1 / 32f).target(getGeneratedSpeed());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
|
||||||
compound.putFloat("GeneratedSpeed", generatedSpeed);
|
compound.putFloat("GeneratedSpeed", generatedSpeed);
|
||||||
compound.putFloat("GeneratedCapacity", generatedCapacity);
|
compound.putFloat("GeneratedCapacity", generatedCapacity);
|
||||||
compound.putInt("Cooldown", stoppingCooldown);
|
compound.putInt("Cooldown", stoppingCooldown);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
generatedSpeed = compound.getFloat("GeneratedSpeed");
|
generatedSpeed = compound.getFloat("GeneratedSpeed");
|
||||||
generatedCapacity = compound.getFloat("GeneratedCapacity");
|
generatedCapacity = compound.getFloat("GeneratedCapacity");
|
||||||
stoppingCooldown = compound.getInt("Cooldown");
|
stoppingCooldown = compound.getInt("Cooldown");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
|
if (clientPacket)
|
||||||
|
visualSpeed.withSpeed(1 / 32f).target(getGeneratedSpeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -116,19 +116,19 @@ public class MillstoneTileEntity extends KineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putInt("Timer", timer);
|
compound.putInt("Timer", timer);
|
||||||
compound.put("InputInventory", inputInv.serializeNBT());
|
compound.put("InputInventory", inputInv.serializeNBT());
|
||||||
compound.put("OutputInventory", outputInv.serializeNBT());
|
compound.put("OutputInventory", outputInv.serializeNBT());
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
timer = compound.getInt("Timer");
|
timer = compound.getInt("Timer");
|
||||||
inputInv.deserializeNBT(compound.getCompound("InputInventory"));
|
inputInv.deserializeNBT(compound.getCompound("InputInventory"));
|
||||||
outputInv.deserializeNBT(compound.getCompound("OutputInventory"));
|
outputInv.deserializeNBT(compound.getCompound("OutputInventory"));
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getProcessingSpeed() {
|
public int getProcessingSpeed() {
|
||||||
|
|
|
@ -109,17 +109,17 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
running = compound.getBoolean("Running");
|
running = compound.getBoolean("Running");
|
||||||
runningTicks = compound.getInt("Ticks");
|
runningTicks = compound.getInt("Ticks");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putBoolean("Running", running);
|
compound.putBoolean("Running", running);
|
||||||
compound.putInt("Ticks", runningTicks);
|
compound.putInt("Ticks", runningTicks);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -15,6 +15,7 @@ import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||||
import com.simibubi.create.foundation.item.ItemHelper;
|
import com.simibubi.create.foundation.item.ItemHelper;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour;
|
import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour;
|
||||||
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
@ -25,7 +26,6 @@ import net.minecraft.item.crafting.ICraftingRecipe;
|
||||||
import net.minecraft.item.crafting.IRecipe;
|
import net.minecraft.item.crafting.IRecipe;
|
||||||
import net.minecraft.item.crafting.Ingredient;
|
import net.minecraft.item.crafting.Ingredient;
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
import net.minecraft.nbt.ListNBT;
|
|
||||||
import net.minecraft.particles.ItemParticleData;
|
import net.minecraft.particles.ItemParticleData;
|
||||||
import net.minecraft.particles.ParticleTypes;
|
import net.minecraft.particles.ParticleTypes;
|
||||||
import net.minecraft.tileentity.TileEntityType;
|
import net.minecraft.tileentity.TileEntityType;
|
||||||
|
@ -85,37 +85,30 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
running = compound.getBoolean("Running");
|
running = compound.getBoolean("Running");
|
||||||
mode = Mode.values()[compound.getInt("Mode")];
|
mode = Mode.values()[compound.getInt("Mode")];
|
||||||
finished = compound.getBoolean("Finished");
|
finished = compound.getBoolean("Finished");
|
||||||
runningTicks = compound.getInt("Ticks");
|
runningTicks = compound.getInt("Ticks");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
|
|
||||||
|
if (clientPacket) {
|
||||||
|
NBTHelper.iterateCompoundList(compound.getList("ParticleItems", NBT.TAG_COMPOUND),
|
||||||
|
c -> pressedItems.add(ItemStack.read(c)));
|
||||||
|
spawnParticles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putBoolean("Running", running);
|
compound.putBoolean("Running", running);
|
||||||
compound.putInt("Mode", mode.ordinal());
|
compound.putInt("Mode", mode.ordinal());
|
||||||
compound.putBoolean("Finished", finished);
|
compound.putBoolean("Finished", finished);
|
||||||
compound.putInt("Ticks", runningTicks);
|
compound.putInt("Ticks", runningTicks);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (clientPacket)
|
||||||
public CompoundNBT writeToClient(CompoundNBT tag) {
|
compound.put("ParticleItems", NBTHelper.writeCompoundList(pressedItems, ItemStack::serializeNBT));
|
||||||
ListNBT particleItems = new ListNBT();
|
|
||||||
pressedItems.forEach(stack -> particleItems.add(stack.serializeNBT()));
|
|
||||||
tag.put("ParticleItems", particleItems);
|
|
||||||
return super.writeToClient(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
|
||||||
super.readClientUpdate(tag);
|
|
||||||
ListNBT particleItems = tag.getList("ParticleItems", NBT.TAG_COMPOUND);
|
|
||||||
particleItems.forEach(nbt -> pressedItems.add(ItemStack.read((CompoundNBT) nbt)));
|
|
||||||
spawnParticles();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -301,7 +294,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
|
||||||
|
|
||||||
CombinedItemFluidList remaining = new CombinedItemFluidList();
|
CombinedItemFluidList remaining = new CombinedItemFluidList();
|
||||||
inputs.forEachItemStack(stack -> remaining.add(stack.copy()));
|
inputs.forEachItemStack(stack -> remaining.add(stack.copy()));
|
||||||
basinFluidInv.ifPresent(fluidInv -> ((CombinedFluidHandler) fluidInv).forEachTank(fluidStack -> remaining.add(fluidStack.copy())));
|
basinFluidInv.ifPresent(
|
||||||
|
fluidInv -> ((CombinedFluidHandler) fluidInv).forEachTank(fluidStack -> remaining.add(fluidStack.copy())));
|
||||||
|
|
||||||
Ingredients: for (Ingredient ingredient : ingredients) {
|
Ingredients: for (Ingredient ingredient : ingredients) {
|
||||||
for (ItemStack stack : remaining.getItemStacks()) {
|
for (ItemStack stack : remaining.getItemStacks()) {
|
||||||
|
|
|
@ -94,15 +94,15 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.put("Inventory", inventory.serializeNBT());
|
compound.put("Inventory", inventory.serializeNBT());
|
||||||
compound.putInt("RecipeIndex", recipeIndex);
|
compound.putInt("RecipeIndex", recipeIndex);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
inventory.deserializeNBT(compound.getCompound("Inventory"));
|
inventory.deserializeNBT(compound.getCompound("Inventory"));
|
||||||
recipeIndex = compound.getInt("RecipeIndex");
|
recipeIndex = compound.getInt("RecipeIndex");
|
||||||
}
|
}
|
||||||
|
|
|
@ -797,7 +797,7 @@ public abstract class Contraption {
|
||||||
|
|
||||||
Vec3d vec = new Vec3d(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis)
|
Vec3d vec = new Vec3d(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis)
|
||||||
.getDirectionVec());
|
.getDirectionVec());
|
||||||
Vec3d planeByNormal = VecHelper.planeByNormal(vec);
|
Vec3d planeByNormal = VecHelper.axisAlingedPlaneOf(vec);
|
||||||
Vec3d min = vec.mul(bb.minX, bb.minY, bb.minZ)
|
Vec3d min = vec.mul(bb.minX, bb.minY, bb.minZ)
|
||||||
.add(planeByNormal.scale(-maxDiff));
|
.add(planeByNormal.scale(-maxDiff));
|
||||||
Vec3d max = vec.mul(bb.maxX, bb.maxY, bb.maxZ)
|
Vec3d max = vec.mul(bb.maxX, bb.maxY, bb.maxZ)
|
||||||
|
|
|
@ -476,7 +476,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
BearingContraption bc = (BearingContraption) getContraption();
|
BearingContraption bc = (BearingContraption) getContraption();
|
||||||
Direction facing = bc.getFacing();
|
Direction facing = bc.getFacing();
|
||||||
Vec3d activeAreaOffset = actor.getActiveAreaOffset(context);
|
Vec3d activeAreaOffset = actor.getActiveAreaOffset(context);
|
||||||
if (activeAreaOffset.mul(VecHelper.planeByNormal(new Vec3d(facing.getDirectionVec())))
|
if (activeAreaOffset.mul(VecHelper.axisAlingedPlaneOf(new Vec3d(facing.getDirectionVec())))
|
||||||
.equals(Vec3d.ZERO)) {
|
.equals(Vec3d.ZERO)) {
|
||||||
if (VecHelper.onSameAxis(blockInfo.pos, BlockPos.ZERO, facing.getAxis())) {
|
if (VecHelper.onSameAxis(blockInfo.pos, BlockPos.ZERO, facing.getAxis())) {
|
||||||
context.motion = new Vec3d(facing.getDirectionVec()).scale(facing.getAxis()
|
context.motion = new Vec3d(facing.getDirectionVec()).scale(facing.getAxis()
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||||
import org.apache.commons.lang3.mutable.MutableObject;
|
import org.apache.commons.lang3.mutable.MutableObject;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket;
|
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket;
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
import com.simibubi.create.foundation.utility.RaycastHelper;
|
import com.simibubi.create.foundation.utility.RaycastHelper;
|
|
@ -227,26 +227,26 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT tag) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
tag.putBoolean("Running", running);
|
compound.putBoolean("Running", running);
|
||||||
tag.putFloat("HourAngle", hourAngle);
|
compound.putFloat("HourAngle", hourAngle);
|
||||||
tag.putFloat("MinuteAngle", minuteAngle);
|
compound.putFloat("MinuteAngle", minuteAngle);
|
||||||
return super.write(tag);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
running = tag.getBoolean("Running");
|
|
||||||
hourAngle = tag.getFloat("HourAngle");
|
|
||||||
minuteAngle = tag.getFloat("MinuteAngle");
|
|
||||||
super.read(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
|
||||||
float hourAngleBefore = hourAngle;
|
float hourAngleBefore = hourAngle;
|
||||||
float minuteAngleBefore = minuteAngle;
|
float minuteAngleBefore = minuteAngle;
|
||||||
super.readClientUpdate(tag);
|
|
||||||
|
running = compound.getBoolean("Running");
|
||||||
|
hourAngle = compound.getFloat("HourAngle");
|
||||||
|
minuteAngle = compound.getFloat("MinuteAngle");
|
||||||
|
super.read(compound, clientPacket);
|
||||||
|
|
||||||
|
if (!clientPacket)
|
||||||
|
return;
|
||||||
|
|
||||||
if (running) {
|
if (running) {
|
||||||
clientHourAngleDiff = AngleHelper.getShortestAngleDiff(hourAngleBefore, hourAngle);
|
clientHourAngleDiff = AngleHelper.getShortestAngleDiff(hourAngleBefore, hourAngle);
|
||||||
clientMinuteAngleDiff = AngleHelper.getShortestAngleDiff(minuteAngleBefore, minuteAngle);
|
clientMinuteAngleDiff = AngleHelper.getShortestAngleDiff(minuteAngleBefore, minuteAngle);
|
||||||
|
|
|
@ -102,27 +102,25 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT tag) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
tag.putBoolean("Running", running);
|
compound.putBoolean("Running", running);
|
||||||
tag.putBoolean("Windmill", isWindmill);
|
compound.putBoolean("Windmill", isWindmill);
|
||||||
tag.putFloat("Angle", angle);
|
compound.putFloat("Angle", angle);
|
||||||
tag.putFloat("LastGenerated", lastGeneratedSpeed);
|
compound.putFloat("LastGenerated", lastGeneratedSpeed);
|
||||||
return super.write(tag);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
running = tag.getBoolean("Running");
|
|
||||||
isWindmill = tag.getBoolean("Windmill");
|
|
||||||
angle = tag.getFloat("Angle");
|
|
||||||
lastGeneratedSpeed = tag.getFloat("LastGenerated");
|
|
||||||
super.read(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
|
||||||
float angleBefore = angle;
|
float angleBefore = angle;
|
||||||
super.readClientUpdate(tag);
|
running = compound.getBoolean("Running");
|
||||||
|
isWindmill = compound.getBoolean("Windmill");
|
||||||
|
angle = compound.getFloat("Angle");
|
||||||
|
lastGeneratedSpeed = compound.getFloat("LastGenerated");
|
||||||
|
super.read(compound, clientPacket);
|
||||||
|
|
||||||
|
if (!clientPacket)
|
||||||
|
return;
|
||||||
if (running) {
|
if (running) {
|
||||||
clientAngleDiff = AngleHelper.getShortestAngleDiff(angleBefore, angle);
|
clientAngleDiff = AngleHelper.getShortestAngleDiff(angleBefore, angle);
|
||||||
angle = angleBefore;
|
angle = angleBefore;
|
||||||
|
|
|
@ -81,7 +81,7 @@ public class SuperGlueItem extends Item {
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public static void spawnParticles(World world, BlockPos pos, Direction direction, boolean fullBlock) {
|
public static void spawnParticles(World world, BlockPos pos, Direction direction, boolean fullBlock) {
|
||||||
Vec3d vec = new Vec3d(direction.getDirectionVec());
|
Vec3d vec = new Vec3d(direction.getDirectionVec());
|
||||||
Vec3d plane = VecHelper.planeByNormal(vec);
|
Vec3d plane = VecHelper.axisAlingedPlaneOf(vec);
|
||||||
Vec3d facePos = VecHelper.getCenterOf(pos)
|
Vec3d facePos = VecHelper.getCenterOf(pos)
|
||||||
.add(vec.scale(.5f));
|
.add(vec.scale(.5f));
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||||
import com.simibubi.create.AllItems;
|
import com.simibubi.create.AllItems;
|
||||||
import com.simibubi.create.Create;
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||||
|
import com.simibubi.create.foundation.utility.MatrixStacker;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
@ -63,7 +64,9 @@ public class SuperGlueRenderer extends EntityRenderer<SuperGlueEntity> {
|
||||||
Direction face = entity.getFacingDirection();
|
Direction face = entity.getFacingDirection();
|
||||||
|
|
||||||
ms.push();
|
ms.push();
|
||||||
AngleHelper.applyRotation(face, ms);
|
MatrixStacker.of(ms)
|
||||||
|
.rotateY(AngleHelper.horizontalAngle(face))
|
||||||
|
.rotateX(AngleHelper.verticalAngle(face));
|
||||||
Entry peek = ms.peek();
|
Entry peek = ms.peek();
|
||||||
|
|
||||||
Vec3d[][] quads = { quad1, quad2 };
|
Vec3d[][] quads = { quad1, quad2 };
|
||||||
|
@ -87,7 +90,7 @@ public class SuperGlueRenderer extends EntityRenderer<SuperGlueEntity> {
|
||||||
Vec3d diff = new Vec3d(Direction.SOUTH.getDirectionVec());
|
Vec3d diff = new Vec3d(Direction.SOUTH.getDirectionVec());
|
||||||
Vec3d extension = diff.normalize()
|
Vec3d extension = diff.normalize()
|
||||||
.scale(1 / 32f - 1 / 128f);
|
.scale(1 / 32f - 1 / 128f);
|
||||||
Vec3d plane = VecHelper.planeByNormal(diff);
|
Vec3d plane = VecHelper.axisAlingedPlaneOf(diff);
|
||||||
Axis axis = Direction.getFacingFromVector(diff.x, diff.y, diff.z)
|
Axis axis = Direction.getFacingFromVector(diff.x, diff.y, diff.z)
|
||||||
.getAxis();
|
.getAxis();
|
||||||
|
|
||||||
|
|
|
@ -145,50 +145,38 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT tag) {
|
protected void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
tag.putBoolean("Running", running);
|
compound.putBoolean("Running", running);
|
||||||
tag.putBoolean("Waiting", waitingForSpeedChange);
|
compound.putBoolean("Waiting", waitingForSpeedChange);
|
||||||
tag.putFloat("Offset", offset);
|
compound.putFloat("Offset", offset);
|
||||||
return super.write(tag);
|
super.write(compound, clientPacket);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (clientPacket && forceMove) {
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
|
||||||
if (forceMove) {
|
|
||||||
compound.putBoolean("ForceMovement", forceMove);
|
compound.putBoolean("ForceMovement", forceMove);
|
||||||
forceMove = false;
|
forceMove = false;
|
||||||
}
|
}
|
||||||
return super.writeToClient(compound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
running = tag.getBoolean("Running");
|
boolean forceMovement = compound.contains("ForceMovement");
|
||||||
waitingForSpeedChange = tag.getBoolean("Waiting");
|
|
||||||
offset = tag.getFloat("Offset");
|
|
||||||
super.read(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
|
||||||
boolean forceMovement = tag.contains("ForceMovement");
|
|
||||||
float offsetBefore = offset;
|
float offsetBefore = offset;
|
||||||
super.readClientUpdate(tag);
|
|
||||||
|
|
||||||
if (forceMovement) {
|
running = compound.getBoolean("Running");
|
||||||
if (movedContraption != null) {
|
waitingForSpeedChange = compound.getBoolean("Waiting");
|
||||||
|
offset = compound.getFloat("Offset");
|
||||||
|
super.read(compound, clientPacket);
|
||||||
|
|
||||||
|
if (!clientPacket)
|
||||||
|
return;
|
||||||
|
if (forceMovement)
|
||||||
applyContraptionPosition();
|
applyContraptionPosition();
|
||||||
}
|
else if (running) {
|
||||||
} else {
|
|
||||||
if (running) {
|
|
||||||
clientOffsetDiff = offset - offsetBefore;
|
clientOffsetDiff = offset - offsetBefore;
|
||||||
offset = offsetBefore;
|
offset = offsetBefore;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!running)
|
if (!running)
|
||||||
movedContraption = null;
|
movedContraption = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void disassemble();
|
public abstract void disassemble();
|
||||||
|
|
|
@ -29,15 +29,15 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
extensionLength = tag.getInt("ExtensionLength");
|
extensionLength = compound.getInt("ExtensionLength");
|
||||||
super.read(tag);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT tag) {
|
protected void write(CompoundNBT tag, boolean clientPacket) {
|
||||||
tag.putInt("ExtensionLength", extensionLength);
|
tag.putInt("ExtensionLength", extensionLength);
|
||||||
return super.write(tag);
|
super.write(tag, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -8,6 +8,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pis
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform;
|
import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform;
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
|
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.IWaterLoggable;
|
import net.minecraft.block.IWaterLoggable;
|
||||||
|
@ -168,15 +169,15 @@ public class PulleyTileEntity extends LinearActuatorTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
initialOffset = tag.getInt("InitialOffset");
|
initialOffset = compound.getInt("InitialOffset");
|
||||||
super.read(tag);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT tag) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
tag.putInt("InitialOffset", initialOffset);
|
compound.putInt("InitialOffset", initialOffset);
|
||||||
return super.write(tag);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,8 +24,8 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
if (compound.contains("Flows")) {
|
if (compound.contains("Flows")) {
|
||||||
for (Direction d : Direction.values())
|
for (Direction d : Direction.values())
|
||||||
setFlow(d, compound.getCompound("Flows")
|
setFlow(d, compound.getCompound("Flows")
|
||||||
|
@ -39,13 +39,13 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
CompoundNBT flows = new CompoundNBT();
|
CompoundNBT flows = new CompoundNBT();
|
||||||
for (Direction d : Direction.values())
|
for (Direction d : Direction.values())
|
||||||
flows.putFloat(d.getName(), this.flows.get(d));
|
flows.putFloat(d.getName(), this.flows.get(d));
|
||||||
compound.put("Flows", flows);
|
compound.put("Flows", flows);
|
||||||
|
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFlow(Direction direction, float speed) {
|
public void setFlow(Direction direction, float speed) {
|
||||||
|
|
|
@ -87,17 +87,20 @@ public class CombinedFluidHandler implements IFluidHandler {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public FluidStack drain(int maxDrain, FluidAction action) {
|
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||||
|
|
||||||
FluidStack stack = new FluidStack(tanks[0].getFluid(), 0);
|
FluidStack stack = new FluidStack(tanks[0].getFluid(), 0);
|
||||||
|
|
||||||
for (int i = 0; i < tanks.length; i++) {
|
for (int i = 0; i < tanks.length; i++) {
|
||||||
if (tanks[i].isFluidEqual(stack)) {
|
if (stack.isEmpty() || tanks[i].isFluidEqual(stack)) {
|
||||||
int newDrainAmount = MathHelper.clamp(stack.getAmount() + tanks[i].getAmount(), 0, maxDrain);
|
int newDrainAmount = MathHelper.clamp(stack.getAmount() + tanks[i].getAmount(), 0, maxDrain);
|
||||||
if (action == FluidAction.EXECUTE) {
|
if (action == FluidAction.EXECUTE) {
|
||||||
tanks[i].shrink(newDrainAmount - stack.getAmount());
|
tanks[i].shrink(newDrainAmount - stack.getAmount());
|
||||||
if (tanks[i].isEmpty())
|
if (tanks[i].isEmpty())
|
||||||
tanks[i] = FluidStack.EMPTY;
|
tanks[i] = FluidStack.EMPTY;
|
||||||
}
|
}
|
||||||
|
if (stack.isEmpty())
|
||||||
|
stack = tanks[i].copy();
|
||||||
|
if (stack.isEmpty())
|
||||||
|
continue;
|
||||||
stack.setAmount(newDrainAmount);
|
stack.setAmount(newDrainAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,355 @@
|
||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.IWorld;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
|
|
||||||
|
public class FluidNetwork {
|
||||||
|
|
||||||
|
BlockFace pumpLocation;
|
||||||
|
Map<BlockPos, Pair<Integer, Map<Direction, Boolean>>> pipeGraph;
|
||||||
|
List<FluidNetworkFlow> flows;
|
||||||
|
Set<FluidNetworkEndpoint> targets;
|
||||||
|
Set<BlockFace> rangeEndpoints;
|
||||||
|
Map<BlockFace, FluidStack> previousFlow;
|
||||||
|
|
||||||
|
boolean connectToPumps;
|
||||||
|
int waitForUnloadedNetwork;
|
||||||
|
|
||||||
|
public FluidNetwork() {
|
||||||
|
pipeGraph = new HashMap<>();
|
||||||
|
flows = new ArrayList<>();
|
||||||
|
targets = new HashSet<>();
|
||||||
|
rangeEndpoints = new HashSet<>();
|
||||||
|
previousFlow = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasEndpoints() {
|
||||||
|
for (FluidNetworkFlow pipeFlow : flows)
|
||||||
|
if (pipeFlow.hasValidTargets())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<FluidNetworkEndpoint> getEndpoints(boolean pulling) {
|
||||||
|
if (!pulling) {
|
||||||
|
for (FluidNetworkFlow pipeFlow : flows)
|
||||||
|
return pipeFlow.outputEndpoints;
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FluidNetworkEndpoint> list = new ArrayList<>();
|
||||||
|
for (FluidNetworkFlow pipeFlow : flows) {
|
||||||
|
if (!pipeFlow.hasValidTargets())
|
||||||
|
continue;
|
||||||
|
list.add(pipeFlow.source);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick(IWorld world, PumpTileEntity pumpTE) {
|
||||||
|
if (connectToPumps) {
|
||||||
|
connectToOtherFNs(world, pumpTE);
|
||||||
|
connectToPumps = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tickFlows(IWorld world, PumpTileEntity pumpTE, boolean pulling, float speed) {
|
||||||
|
if (connectToPumps)
|
||||||
|
return;
|
||||||
|
initFlows(pumpTE, pulling);
|
||||||
|
previousFlow.clear();
|
||||||
|
flows.forEach(ep -> ep.tick(world, speed));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initFlows(PumpTileEntity pumpTE, boolean pulling) {
|
||||||
|
if (targets.isEmpty())
|
||||||
|
return;
|
||||||
|
if (!flows.isEmpty())
|
||||||
|
return;
|
||||||
|
World world = pumpTE.getWorld();
|
||||||
|
if (pulling) {
|
||||||
|
targets.forEach(ne -> flows.add(new FluidNetworkFlow(this, ne, world, pulling)));
|
||||||
|
} else {
|
||||||
|
PumpEndpoint pumpEndpoint = new PumpEndpoint(pumpLocation.getOpposite(), pumpTE);
|
||||||
|
flows.add(new FluidNetworkFlow(this, pumpEndpoint, world, pulling));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connectToOtherFNs(IWorld world, PumpTileEntity pump) {
|
||||||
|
List<Pair<Integer, BlockPos>> frontier = new ArrayList<>();
|
||||||
|
Set<BlockPos> visited = new HashSet<>();
|
||||||
|
int maxDistance = FluidPropagator.getPumpRange() * 2;
|
||||||
|
frontier.add(Pair.of(-1, pumpLocation.getPos()));
|
||||||
|
|
||||||
|
while (!frontier.isEmpty()) {
|
||||||
|
Pair<Integer, BlockPos> entry = frontier.remove(0);
|
||||||
|
int distance = entry.getFirst();
|
||||||
|
BlockPos currentPos = entry.getSecond();
|
||||||
|
|
||||||
|
if (!world.isAreaLoaded(currentPos, 0))
|
||||||
|
continue;
|
||||||
|
if (visited.contains(currentPos))
|
||||||
|
continue;
|
||||||
|
visited.add(currentPos);
|
||||||
|
|
||||||
|
List<Direction> connections;
|
||||||
|
if (currentPos.equals(pumpLocation.getPos())) {
|
||||||
|
connections = ImmutableList.of(pumpLocation.getFace());
|
||||||
|
} else {
|
||||||
|
BlockState currentState = world.getBlockState(currentPos);
|
||||||
|
FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, currentPos);
|
||||||
|
if (pipe == null)
|
||||||
|
continue;
|
||||||
|
connections = FluidPropagator.getPipeConnections(currentState, pipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Direction face : connections) {
|
||||||
|
BlockFace blockFace = new BlockFace(currentPos, face);
|
||||||
|
BlockPos connectedPos = blockFace.getConnectedPos();
|
||||||
|
BlockState connectedState = world.getBlockState(connectedPos);
|
||||||
|
|
||||||
|
if (connectedPos.equals(pumpLocation.getPos()))
|
||||||
|
continue;
|
||||||
|
if (!world.isAreaLoaded(connectedPos, 0))
|
||||||
|
continue;
|
||||||
|
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
||||||
|
.getAxis() == face.getAxis()) {
|
||||||
|
TileEntity tileEntity = world.getTileEntity(connectedPos);
|
||||||
|
if (tileEntity instanceof PumpTileEntity) {
|
||||||
|
PumpTileEntity otherPump = (PumpTileEntity) tileEntity;
|
||||||
|
if (otherPump.networks == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
otherPump.networks.forEach(fn -> {
|
||||||
|
int nearest = Integer.MAX_VALUE;
|
||||||
|
BlockFace argNearest = null;
|
||||||
|
for (BlockFace pumpEndpoint : fn.rangeEndpoints) {
|
||||||
|
if (pumpEndpoint.isEquivalent(pumpLocation)) {
|
||||||
|
argNearest = pumpEndpoint;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Pair<Integer, Map<Direction, Boolean>> pair =
|
||||||
|
pipeGraph.get(pumpEndpoint.getConnectedPos());
|
||||||
|
if (pair == null)
|
||||||
|
continue;
|
||||||
|
Integer distanceFromPump = pair.getFirst();
|
||||||
|
Map<Direction, Boolean> pipeConnections = pair.getSecond();
|
||||||
|
|
||||||
|
if (!pipeConnections.containsKey(pumpEndpoint.getOppositeFace()))
|
||||||
|
continue;
|
||||||
|
if (nearest <= distanceFromPump)
|
||||||
|
continue;
|
||||||
|
nearest = distanceFromPump;
|
||||||
|
argNearest = pumpEndpoint;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (argNearest != null) {
|
||||||
|
InterPumpEndpoint endpoint = new InterPumpEndpoint(world, argNearest.getOpposite(),
|
||||||
|
pump, otherPump, pumpLocation, fn.pumpLocation);
|
||||||
|
targets.add(endpoint);
|
||||||
|
fn.targets.add(endpoint.opposite(world));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (visited.contains(connectedPos))
|
||||||
|
continue;
|
||||||
|
if (distance > maxDistance)
|
||||||
|
continue;
|
||||||
|
FluidPipeBehaviour targetPipe = FluidPropagator.getPipe(world, connectedPos);
|
||||||
|
if (targetPipe == null)
|
||||||
|
continue;
|
||||||
|
if (targetPipe.isConnectedTo(connectedState, face.getOpposite()))
|
||||||
|
frontier.add(Pair.of(distance + 1, connectedPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void assemble(IWorld world, PumpTileEntity pumpTE, BlockFace pumpLocation) {
|
||||||
|
Map<BlockFace, OpenEndedPipe> openEnds = pumpTE.getOpenEnds(pumpLocation.getFace());
|
||||||
|
openEnds.values()
|
||||||
|
.forEach(OpenEndedPipe::markStale);
|
||||||
|
|
||||||
|
this.pumpLocation = pumpLocation;
|
||||||
|
if (!collectEndpoint(world, pumpLocation, openEnds, 0)) {
|
||||||
|
|
||||||
|
List<Pair<Integer, BlockPos>> frontier = new ArrayList<>();
|
||||||
|
Set<BlockPos> visited = new HashSet<>();
|
||||||
|
int maxDistance = FluidPropagator.getPumpRange();
|
||||||
|
frontier.add(Pair.of(0, pumpLocation.getConnectedPos()));
|
||||||
|
|
||||||
|
while (!frontier.isEmpty()) {
|
||||||
|
Pair<Integer, BlockPos> entry = frontier.remove(0);
|
||||||
|
int distance = entry.getFirst();
|
||||||
|
BlockPos currentPos = entry.getSecond();
|
||||||
|
|
||||||
|
if (!world.isAreaLoaded(currentPos, 0))
|
||||||
|
continue;
|
||||||
|
if (visited.contains(currentPos))
|
||||||
|
continue;
|
||||||
|
visited.add(currentPos);
|
||||||
|
BlockState currentState = world.getBlockState(currentPos);
|
||||||
|
FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, currentPos);
|
||||||
|
if (pipe == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (Direction face : FluidPropagator.getPipeConnections(currentState, pipe)) {
|
||||||
|
BlockFace blockFace = new BlockFace(currentPos, face);
|
||||||
|
BlockPos connectedPos = blockFace.getConnectedPos();
|
||||||
|
|
||||||
|
if (connectedPos.equals(pumpLocation.getPos())) {
|
||||||
|
addEntry(blockFace.getPos(), blockFace.getFace(), true, distance);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!world.isAreaLoaded(connectedPos, 0))
|
||||||
|
continue;
|
||||||
|
if (collectEndpoint(world, blockFace, openEnds, distance))
|
||||||
|
continue;
|
||||||
|
if (FluidPropagator.getPipe(world, connectedPos) == null)
|
||||||
|
continue;
|
||||||
|
if (visited.contains(connectedPos))
|
||||||
|
continue;
|
||||||
|
if (distance + 1 >= maxDistance) {
|
||||||
|
rangeEndpoints.add(blockFace);
|
||||||
|
addEntry(currentPos, face, false, distance);
|
||||||
|
FluidPropagator.showBlockFace(blockFace)
|
||||||
|
.lineWidth(1 / 8f)
|
||||||
|
.colored(0xff0000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
addConnection(connectedPos, currentPos, face.getOpposite(), distance);
|
||||||
|
frontier.add(Pair.of(distance + 1, connectedPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<BlockFace> staleEnds = new HashSet<>();
|
||||||
|
openEnds.entrySet()
|
||||||
|
.forEach(e -> {
|
||||||
|
if (e.getValue()
|
||||||
|
.isStale())
|
||||||
|
staleEnds.add(e.getKey());
|
||||||
|
});
|
||||||
|
staleEnds.forEach(openEnds::remove);
|
||||||
|
|
||||||
|
connectToPumps = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FluidNetworkEndpoint reuseOrCreateOpenEnd(IWorld world, Map<BlockFace, OpenEndedPipe> openEnds,
|
||||||
|
BlockFace toCreate) {
|
||||||
|
OpenEndedPipe openEndedPipe = null;
|
||||||
|
if (openEnds.containsKey(toCreate)) {
|
||||||
|
openEndedPipe = openEnds.get(toCreate);
|
||||||
|
openEndedPipe.unmarkStale();
|
||||||
|
} else {
|
||||||
|
openEndedPipe = new OpenEndedPipe(toCreate);
|
||||||
|
openEnds.put(toCreate, openEndedPipe);
|
||||||
|
}
|
||||||
|
return new FluidNetworkEndpoint(world, toCreate, openEndedPipe.getCapability());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean collectEndpoint(IWorld world, BlockFace blockFace, Map<BlockFace, OpenEndedPipe> openEnds,
|
||||||
|
int distance) {
|
||||||
|
BlockPos connectedPos = blockFace.getConnectedPos();
|
||||||
|
BlockState connectedState = world.getBlockState(connectedPos);
|
||||||
|
|
||||||
|
// other pipe, no endpoint
|
||||||
|
FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, connectedPos);
|
||||||
|
if (pipe != null && pipe.isConnectedTo(connectedState, blockFace.getOppositeFace()))
|
||||||
|
return false;
|
||||||
|
TileEntity tileEntity = world.getTileEntity(connectedPos);
|
||||||
|
|
||||||
|
// fluid handler endpoint
|
||||||
|
Direction face = blockFace.getFace();
|
||||||
|
if (tileEntity != null) {
|
||||||
|
LazyOptional<IFluidHandler> capability =
|
||||||
|
tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face.getOpposite());
|
||||||
|
if (capability.isPresent()) {
|
||||||
|
targets.add(new FluidNetworkEndpoint(world, blockFace, capability));
|
||||||
|
addEntry(blockFace.getPos(), face, false, distance);
|
||||||
|
FluidPropagator.showBlockFace(blockFace)
|
||||||
|
.colored(0x00b7c2)
|
||||||
|
.lineWidth(1 / 8f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// open endpoint
|
||||||
|
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
||||||
|
.getAxis() == face.getAxis()) {
|
||||||
|
rangeEndpoints.add(blockFace);
|
||||||
|
addEntry(blockFace.getPos(), face, false, distance);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!FluidPropagator.isOpenEnd(world, blockFace.getPos(), face))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
targets.add(reuseOrCreateOpenEnd(world, openEnds, blockFace));
|
||||||
|
addEntry(blockFace.getPos(), face, false, distance);
|
||||||
|
FluidPropagator.showBlockFace(blockFace)
|
||||||
|
.colored(0xb700c2)
|
||||||
|
.lineWidth(1 / 8f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addConnection(BlockPos from, BlockPos to, Direction direction, int distance) {
|
||||||
|
addEntry(from, direction, true, distance);
|
||||||
|
addEntry(to, direction.getOpposite(), false, distance + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addEntry(BlockPos pos, Direction direction, boolean outbound, int distance) {
|
||||||
|
if (!pipeGraph.containsKey(pos))
|
||||||
|
pipeGraph.put(pos, Pair.of(distance, new HashMap<>()));
|
||||||
|
pipeGraph.get(pos)
|
||||||
|
.getSecond()
|
||||||
|
.put(direction, outbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reAssemble(IWorld world, PumpTileEntity pumpTE, BlockFace pumpLocation) {
|
||||||
|
rangeEndpoints.clear();
|
||||||
|
targets.clear();
|
||||||
|
pipeGraph.clear();
|
||||||
|
assemble(world, pumpTE, pumpLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(IWorld world) {
|
||||||
|
clearFlows(world, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearFlows(IWorld world, boolean saveState) {
|
||||||
|
for (FluidNetworkFlow networkFlow : flows) {
|
||||||
|
if (!networkFlow.getFluidStack()
|
||||||
|
.isEmpty())
|
||||||
|
networkFlow.addToSkippedConnections(world);
|
||||||
|
networkFlow.resetFlow(world);
|
||||||
|
}
|
||||||
|
flows.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.world.IWorld;
|
||||||
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||||
|
|
||||||
|
class FluidNetworkEndpoint {
|
||||||
|
BlockFace location;
|
||||||
|
protected LazyOptional<IFluidHandler> handler;
|
||||||
|
|
||||||
|
public FluidNetworkEndpoint(IWorld world, BlockFace location, LazyOptional<IFluidHandler> handler) {
|
||||||
|
this.location = location;
|
||||||
|
this.handler = handler;
|
||||||
|
this.handler.addListener($ -> onHandlerInvalidated(world));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onHandlerInvalidated(IWorld world) {
|
||||||
|
IFluidHandler tank = handler.orElse(null);
|
||||||
|
if (tank != null)
|
||||||
|
return;
|
||||||
|
TileEntity tileEntity = world.getTileEntity(location.getConnectedPos());
|
||||||
|
if (tileEntity == null)
|
||||||
|
return;
|
||||||
|
LazyOptional<IFluidHandler> capability =
|
||||||
|
tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, location.getOppositeFace());
|
||||||
|
if (capability.isPresent()) {
|
||||||
|
handler = capability;
|
||||||
|
handler.addListener($ -> onHandlerInvalidated(world));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidStack provideFluid() {
|
||||||
|
IFluidHandler tank = provideHandler().orElse(null);
|
||||||
|
if (tank == null)
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
return tank.drain(1, FluidAction.SIMULATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LazyOptional<IFluidHandler> provideHandler() {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class PumpEndpoint extends FluidNetworkEndpoint {
|
||||||
|
|
||||||
|
PumpTileEntity pumpTE;
|
||||||
|
|
||||||
|
public PumpEndpoint(BlockFace location, PumpTileEntity pumpTE) {
|
||||||
|
super(pumpTE.getWorld(), location, LazyOptional.empty());
|
||||||
|
this.pumpTE = pumpTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHandlerInvalidated(IWorld world) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack provideFluid() {
|
||||||
|
return pumpTE.providedFluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class InterPumpEndpoint extends FluidNetworkEndpoint {
|
||||||
|
|
||||||
|
Couple<Pair<BlockFace, WeakReference<PumpTileEntity>>> pumps;
|
||||||
|
|
||||||
|
private InterPumpEndpoint(IWorld world, BlockFace location, LazyOptional<IFluidHandler> handler) {
|
||||||
|
super(world, location, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InterPumpEndpoint(IWorld world, BlockFace location, PumpTileEntity source, PumpTileEntity interfaced,
|
||||||
|
BlockFace sourcePos, BlockFace interfacedPos) {
|
||||||
|
this(world, location, LazyOptional.empty());
|
||||||
|
handler = LazyOptional.of(() -> new InterPumpFluidHandler(this));
|
||||||
|
pumps = Couple.create(Pair.of(sourcePos, new WeakReference<>(source)),
|
||||||
|
Pair.of(interfacedPos, new WeakReference<>(interfaced)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public InterPumpEndpoint opposite(IWorld world) {
|
||||||
|
InterPumpEndpoint interPumpEndpoint = new InterPumpEndpoint(world, this.location.getOpposite(), handler);
|
||||||
|
interPumpEndpoint.pumps = pumps.copy();
|
||||||
|
return interPumpEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Couple<Pair<BlockFace, WeakReference<PumpTileEntity>>> getPumps() {
|
||||||
|
return pumps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPulling(boolean first) {
|
||||||
|
Pair<BlockFace, WeakReference<PumpTileEntity>> pair = getPumps().get(first);
|
||||||
|
PumpTileEntity pumpTileEntity = pair.getSecond()
|
||||||
|
.get();
|
||||||
|
if (pumpTileEntity == null || pumpTileEntity.isRemoved())
|
||||||
|
return false;
|
||||||
|
return pumpTileEntity.isPullingOnSide(pumpTileEntity.isFront(pair.getFirst()
|
||||||
|
.getFace()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTransferSpeed(boolean first) {
|
||||||
|
PumpTileEntity pumpTileEntity = getPumps().get(first)
|
||||||
|
.getSecond()
|
||||||
|
.get();
|
||||||
|
if (pumpTileEntity == null || pumpTileEntity.isRemoved())
|
||||||
|
return 0;
|
||||||
|
return pumpTileEntity.getFluidTransferSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LazyOptional<IFluidHandler> provideHandler() {
|
||||||
|
if (isPulling(true) == isPulling(false))
|
||||||
|
return LazyOptional.empty();
|
||||||
|
if (getTransferSpeed(true) > getTransferSpeed(false))
|
||||||
|
return LazyOptional.empty();
|
||||||
|
return super.provideHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack provideFluid() {
|
||||||
|
if (!provideHandler().isPresent())
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
|
||||||
|
Couple<Pair<BlockFace, WeakReference<PumpTileEntity>>> pumps = getPumps();
|
||||||
|
for (boolean current : Iterate.trueAndFalse) {
|
||||||
|
if (isPulling(current))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Pair<BlockFace, WeakReference<PumpTileEntity>> pair = pumps.get(current);
|
||||||
|
BlockFace blockFace = pair.getFirst();
|
||||||
|
PumpTileEntity pumpTileEntity = pair.getSecond()
|
||||||
|
.get();
|
||||||
|
if (pumpTileEntity == null)
|
||||||
|
continue;
|
||||||
|
if (pumpTileEntity.networks == null)
|
||||||
|
continue;
|
||||||
|
FluidNetwork fluidNetwork = pumpTileEntity.networks.get(pumpTileEntity.isFront(blockFace.getFace()));
|
||||||
|
for (FluidNetworkFlow fluidNetworkFlow : fluidNetwork.flows) {
|
||||||
|
for (FluidNetworkEndpoint fne : fluidNetworkFlow.outputEndpoints) {
|
||||||
|
if (!(fne instanceof InterPumpEndpoint))
|
||||||
|
continue;
|
||||||
|
InterPumpEndpoint ipe = (InterPumpEndpoint) fne;
|
||||||
|
if (!ipe.location.isEquivalent(location))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FluidStack heldFluid = fluidNetworkFlow.fluidStack;
|
||||||
|
if (heldFluid.isEmpty())
|
||||||
|
return heldFluid;
|
||||||
|
FluidStack copy = heldFluid.copy();
|
||||||
|
copy.setAmount(1);
|
||||||
|
return heldFluid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,304 @@
|
||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.IWorld;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
|
||||||
|
class FluidNetworkFlow {
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
static interface PipeFlowConsumer {
|
||||||
|
void accept(FluidPipeBehaviour pipe, Direction face, boolean inbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private final FluidNetwork activePipeNetwork;
|
||||||
|
FluidNetworkEndpoint source;
|
||||||
|
FluidStack fluidStack;
|
||||||
|
Set<BlockFace> flowPointers;
|
||||||
|
|
||||||
|
Set<FluidNetworkEndpoint> outputEndpoints;
|
||||||
|
boolean pumpReached;
|
||||||
|
|
||||||
|
boolean pulling;
|
||||||
|
float speed;
|
||||||
|
|
||||||
|
public FluidNetworkFlow(FluidNetwork activePipeNetwork, FluidNetworkEndpoint source, IWorld world,
|
||||||
|
boolean pulling) {
|
||||||
|
this.activePipeNetwork = activePipeNetwork;
|
||||||
|
this.source = source;
|
||||||
|
this.pulling = pulling;
|
||||||
|
flowPointers = new HashSet<>();
|
||||||
|
outputEndpoints = new HashSet<>();
|
||||||
|
fluidStack = FluidStack.EMPTY;
|
||||||
|
tick(world, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetFlow(IWorld world) {
|
||||||
|
fluidStack = FluidStack.EMPTY;
|
||||||
|
flowPointers.clear();
|
||||||
|
outputEndpoints.clear();
|
||||||
|
pumpReached = false;
|
||||||
|
forEachPipeFlow(world, (pipe, face, inbound) -> pipe.removeFlow(this, face, inbound));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addToSkippedConnections(IWorld world) {
|
||||||
|
forEachPipeFlow(world, (pipe, face, inbound) -> {
|
||||||
|
if (!pipe.fluid.isFluidEqual(fluidStack))
|
||||||
|
return;
|
||||||
|
BlockFace blockFace = new BlockFace(pipe.getPos(), face);
|
||||||
|
this.activePipeNetwork.previousFlow.put(blockFace, pipe.fluid);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void forEachPipeFlow(IWorld world, FluidNetworkFlow.PipeFlowConsumer consumer) {
|
||||||
|
Set<BlockFace> flowPointers = new HashSet<>();
|
||||||
|
flowPointers.add(getSource());
|
||||||
|
|
||||||
|
// Update all branches of this flow, and create new ones if necessary
|
||||||
|
while (!flowPointers.isEmpty()) {
|
||||||
|
List<BlockFace> toAdd = new ArrayList<>();
|
||||||
|
for (Iterator<BlockFace> iterator = flowPointers.iterator(); iterator.hasNext();) {
|
||||||
|
BlockFace flowPointer = iterator.next();
|
||||||
|
BlockPos currentPos = flowPointer.getPos();
|
||||||
|
FluidPipeBehaviour pipe = getPipeInTree(world, currentPos);
|
||||||
|
if (pipe == null) {
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Map<Direction, Boolean> directions = this.activePipeNetwork.pipeGraph.get(currentPos)
|
||||||
|
.getSecond();
|
||||||
|
for (Entry<Direction, Boolean> entry : directions.entrySet()) {
|
||||||
|
boolean inbound = entry.getValue() != pulling;
|
||||||
|
Direction face = entry.getKey();
|
||||||
|
if (inbound && face != flowPointer.getFace())
|
||||||
|
continue;
|
||||||
|
consumer.accept(pipe, face, inbound);
|
||||||
|
if (inbound)
|
||||||
|
continue;
|
||||||
|
toAdd.add(new BlockFace(currentPos.offset(face), face.getOpposite()));
|
||||||
|
}
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
flowPointers.addAll(toAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tick(IWorld world, float speed) {
|
||||||
|
boolean skipping = speed == 0;
|
||||||
|
Map<BlockFace, FluidStack> previousFlow = this.activePipeNetwork.previousFlow;
|
||||||
|
if (skipping && previousFlow.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.speed = speed;
|
||||||
|
FluidStack provideFluid = source.provideFluid();
|
||||||
|
if (!fluidStack.isEmpty() && !fluidStack.isFluidEqual(provideFluid)) {
|
||||||
|
resetFlow(world);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fluidStack = provideFluid;
|
||||||
|
|
||||||
|
// There is currently no unfinished flow being followed
|
||||||
|
if (flowPointers.isEmpty()) {
|
||||||
|
|
||||||
|
// The fluid source has run out -> reset
|
||||||
|
if (fluidStack.isEmpty()) {
|
||||||
|
if (hasValidTargets())
|
||||||
|
resetFlow(world);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep the flows if all is well
|
||||||
|
if (hasValidTargets())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Start a new flow from or towards the pump
|
||||||
|
BlockFace source = getSource();
|
||||||
|
if (tryConnectTo(world, source.getOpposite()))
|
||||||
|
return;
|
||||||
|
flowPointers.add(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean skipped = false;
|
||||||
|
Set<BlockFace> pausedPointers = new HashSet<>();
|
||||||
|
|
||||||
|
do {
|
||||||
|
skipped = false;
|
||||||
|
List<BlockFace> toAdd = null;
|
||||||
|
|
||||||
|
// Update all branches of this flow, and create new ones if necessary
|
||||||
|
for (Iterator<BlockFace> iterator = flowPointers.iterator(); iterator.hasNext();) {
|
||||||
|
BlockFace flowPointer = iterator.next();
|
||||||
|
BlockPos currentPos = flowPointer.getPos();
|
||||||
|
|
||||||
|
if (pausedPointers.contains(flowPointer))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FluidPipeBehaviour pipe = getPipeInTree(world, currentPos);
|
||||||
|
if (pipe == null) {
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Direction, Boolean> directions = this.activePipeNetwork.pipeGraph.get(currentPos)
|
||||||
|
.getSecond();
|
||||||
|
boolean inboundComplete = false;
|
||||||
|
boolean allFlowsComplete = true;
|
||||||
|
BlockState state = world.getBlockState(currentPos);
|
||||||
|
|
||||||
|
// First loop only inbound flows of a pipe to see if they have reached the
|
||||||
|
// center
|
||||||
|
for (boolean inboundPass : Iterate.trueAndFalse) {
|
||||||
|
if (!inboundPass && !inboundComplete)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// For all connections of the pipe tree of the pump
|
||||||
|
for (Entry<Direction, Boolean> entry : directions.entrySet()) {
|
||||||
|
Boolean awayFromPump = entry.getValue();
|
||||||
|
Direction direction = entry.getKey();
|
||||||
|
boolean inbound = awayFromPump != pulling;
|
||||||
|
|
||||||
|
if (inboundPass && direction != flowPointer.getFace())
|
||||||
|
continue;
|
||||||
|
if (!inboundPass && inbound)
|
||||||
|
continue;
|
||||||
|
if (!pipe.canTransferToward(fluidStack, state, direction, inbound))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BlockFace blockface = new BlockFace(currentPos, direction);
|
||||||
|
|
||||||
|
if (!pipe.hasStartedFlow(this, direction, inbound))
|
||||||
|
pipe.addFlow(this, direction, inbound);
|
||||||
|
if (skipping && canSkip(previousFlow, blockface)) {
|
||||||
|
pipe.skipFlow(direction, inbound);
|
||||||
|
FluidPropagator.showBlockFace(blockface)
|
||||||
|
.colored(0x0)
|
||||||
|
.lineWidth(1 / 8f);
|
||||||
|
skipped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pipe.hasCompletedFlow(direction, inbound)) {
|
||||||
|
allFlowsComplete = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inboundPass) {
|
||||||
|
inboundComplete = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outward pass, check if any target was reached
|
||||||
|
tryConnectTo(world, blockface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allFlowsComplete && !skipping)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Create a new flow branch at each outward pipe connection
|
||||||
|
for (Entry<Direction, Boolean> entry : directions.entrySet()) {
|
||||||
|
if (entry.getValue() != pulling)
|
||||||
|
continue;
|
||||||
|
Direction face = entry.getKey();
|
||||||
|
BlockFace addedBlockFace = new BlockFace(currentPos.offset(face), face.getOpposite());
|
||||||
|
if (skipping && !canSkip(previousFlow, addedBlockFace)) {
|
||||||
|
allFlowsComplete = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (toAdd == null)
|
||||||
|
toAdd = new ArrayList<>();
|
||||||
|
toAdd.add(addedBlockFace);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allFlowsComplete && skipping) {
|
||||||
|
pausedPointers.add(flowPointer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator.remove();
|
||||||
|
|
||||||
|
} // End of branch loop
|
||||||
|
|
||||||
|
if (toAdd != null)
|
||||||
|
flowPointers.addAll(toAdd);
|
||||||
|
|
||||||
|
} while (skipping && skipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canSkip(Map<BlockFace, FluidStack> previousFlow, BlockFace blockface) {
|
||||||
|
return previousFlow.containsKey(blockface) && previousFlow.get(blockface)
|
||||||
|
.isFluidEqual(fluidStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean tryConnectTo(IWorld world, BlockFace blockface) {
|
||||||
|
// Pulling flow, target is the pump
|
||||||
|
if (pulling) {
|
||||||
|
if (!this.activePipeNetwork.pumpLocation.getOpposite()
|
||||||
|
.equals(blockface))
|
||||||
|
return false;
|
||||||
|
pumpReached = true;
|
||||||
|
TileEntity targetTE = world.getTileEntity(this.activePipeNetwork.pumpLocation.getPos());
|
||||||
|
if (targetTE instanceof PumpTileEntity)
|
||||||
|
((PumpTileEntity) targetTE).setProvidedFluid(fluidStack);
|
||||||
|
FluidPropagator.showBlockFace(this.activePipeNetwork.pumpLocation)
|
||||||
|
.colored(0x799351)
|
||||||
|
.lineWidth(1 / 8f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pushing flow, targets are the endpoints
|
||||||
|
for (FluidNetworkEndpoint networkEndpoint : this.activePipeNetwork.targets) {
|
||||||
|
if (!networkEndpoint.location.isEquivalent(blockface))
|
||||||
|
continue;
|
||||||
|
outputEndpoints.add(networkEndpoint);
|
||||||
|
FluidPropagator.showBlockFace(blockface)
|
||||||
|
.colored(0x799351)
|
||||||
|
.lineWidth(1 / 8f);
|
||||||
|
return !(networkEndpoint instanceof InterPumpEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockFace getSource() {
|
||||||
|
return pulling ? source.location : this.activePipeNetwork.pumpLocation.getOpposite();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FluidPipeBehaviour getPipeInTree(IWorld world, BlockPos currentPos) {
|
||||||
|
if (!world.isAreaLoaded(currentPos, 0))
|
||||||
|
return null;
|
||||||
|
if (!this.activePipeNetwork.pipeGraph.containsKey(currentPos))
|
||||||
|
return null;
|
||||||
|
return TileEntityBehaviour.get(world, currentPos, FluidPipeBehaviour.TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasValidTargets() {
|
||||||
|
return pumpReached || !outputEndpoints.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSpeed() {
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidStack getFluidStack() {
|
||||||
|
return fluidStack;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,478 @@
|
||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.simibubi.create.AllSpecialTextures;
|
||||||
|
import com.simibubi.create.CreateClient;
|
||||||
|
import com.simibubi.create.content.contraptions.KineticDebugger;
|
||||||
|
import com.simibubi.create.foundation.fluid.FluidHelper;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
import com.simibubi.create.foundation.utility.LerpedFloat;
|
||||||
|
import com.simibubi.create.foundation.utility.LerpedFloat.Chaser;
|
||||||
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.fluid.Fluid;
|
||||||
|
import net.minecraft.fluid.Fluids;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.nbt.ListNBT;
|
||||||
|
import net.minecraft.particles.BlockParticleData;
|
||||||
|
import net.minecraft.particles.IParticleData;
|
||||||
|
import net.minecraft.particles.ParticleTypes;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.common.util.Constants.NBT;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fml.DistExecutor;
|
||||||
|
|
||||||
|
public abstract class FluidPipeBehaviour extends TileEntityBehaviour {
|
||||||
|
|
||||||
|
public static BehaviourType<FluidPipeBehaviour> TYPE = new BehaviourType<>();
|
||||||
|
|
||||||
|
// Direction -> (inboundflows{}, outwardflows{})
|
||||||
|
Map<Direction, Couple<PipeFlows>> allFlows;
|
||||||
|
FluidStack fluid;
|
||||||
|
Couple<FluidStack> collision;
|
||||||
|
|
||||||
|
public FluidPipeBehaviour(SmartTileEntity te) {
|
||||||
|
super(te);
|
||||||
|
allFlows = new IdentityHashMap<>();
|
||||||
|
fluid = FluidStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BehaviourType<?> getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyNetwork() {
|
||||||
|
FluidPropagator.propagateChangedPipe(this.getWorld(), tileEntity.getPos(), tileEntity.getBlockState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canTransferToward(FluidStack fluid, BlockState state, Direction direction, boolean inbound) {
|
||||||
|
return isConnectedTo(state, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean isConnectedTo(BlockState state, Direction direction);
|
||||||
|
|
||||||
|
public float getRimRadius(BlockState state, Direction direction) {
|
||||||
|
return 1 / 4f + 1 / 64f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasStartedFlow(FluidNetworkFlow flow, Direction face, boolean inbound) {
|
||||||
|
return allFlows.containsKey(face) && allFlows.get(face)
|
||||||
|
.get(inbound)
|
||||||
|
.hasFlow(flow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasCompletedFlow(Direction face, boolean inbound) {
|
||||||
|
return allFlows.containsKey(face) && allFlows.get(face)
|
||||||
|
.get(inbound)
|
||||||
|
.isCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(CompoundNBT compound, boolean client) {
|
||||||
|
compound.put("Fluid", fluid.writeToNBT(new CompoundNBT()));
|
||||||
|
ListNBT flows = new ListNBT();
|
||||||
|
for (Direction face : Iterate.directions)
|
||||||
|
for (boolean inbound : Iterate.trueAndFalse) {
|
||||||
|
LerpedFloat flowProgress = getFlowProgress(face, inbound);
|
||||||
|
if (flowProgress == null)
|
||||||
|
continue;
|
||||||
|
CompoundNBT nbt = new CompoundNBT();
|
||||||
|
NBTHelper.writeEnum(nbt, "Face", face);
|
||||||
|
nbt.putBoolean("In", inbound);
|
||||||
|
nbt.put("Progress", flowProgress.writeNBT());
|
||||||
|
flows.add(nbt);
|
||||||
|
}
|
||||||
|
compound.put("Flows", flows);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(CompoundNBT compound, boolean client) {
|
||||||
|
fluid = FluidStack.loadFluidStackFromNBT(compound.getCompound("Fluid"));
|
||||||
|
|
||||||
|
if (client) {
|
||||||
|
for (Direction face : Iterate.directions)
|
||||||
|
if (allFlows.containsKey(face))
|
||||||
|
allFlows.get(face)
|
||||||
|
.forEach(pf -> pf.progress = null);
|
||||||
|
}
|
||||||
|
|
||||||
|
NBTHelper.iterateCompoundList(compound.getList("Flows", NBT.TAG_COMPOUND), nbt -> {
|
||||||
|
Direction face = NBTHelper.readEnum(nbt, "Face", Direction.class);
|
||||||
|
boolean inbound = nbt.getBoolean("In");
|
||||||
|
LerpedFloat progress = createFlowProgress(0);
|
||||||
|
progress.readNBT(nbt.getCompound("Progress"), false);
|
||||||
|
addFlow(null, face, inbound);
|
||||||
|
setFlowProgress(face, inbound, progress);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!client)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (Direction face : Iterate.directions) {
|
||||||
|
if (!allFlows.containsKey(face))
|
||||||
|
return;
|
||||||
|
Couple<PipeFlows> couple = allFlows.get(face);
|
||||||
|
if (couple.get(true).progress == null && couple.get(false).progress == null)
|
||||||
|
allFlows.remove(face);
|
||||||
|
if (allFlows.isEmpty())
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFlow(@Nullable FluidNetworkFlow flow, Direction face, boolean inbound) {
|
||||||
|
if (flow != null) {
|
||||||
|
FluidStack fluid = flow.getFluidStack();
|
||||||
|
if (!this.fluid.isEmpty() && !fluid.isFluidEqual(this.fluid)) {
|
||||||
|
collision = Couple.create(this.fluid, fluid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.fluid = fluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allFlows.containsKey(face)) {
|
||||||
|
allFlows.put(face, Couple.create(PipeFlows::new));
|
||||||
|
if (inbound)
|
||||||
|
spawnSplashOnRim(face);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flow != null) {
|
||||||
|
PipeFlows flows = allFlows.get(face)
|
||||||
|
.get(inbound);
|
||||||
|
flows.addFlow(flow);
|
||||||
|
contentsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFlow(FluidNetworkFlow flow, Direction face, boolean inbound) {
|
||||||
|
if (!allFlows.containsKey(face))
|
||||||
|
return;
|
||||||
|
Couple<PipeFlows> couple = allFlows.get(face);
|
||||||
|
couple.get(inbound)
|
||||||
|
.removeFlow(flow);
|
||||||
|
if (!couple.get(true)
|
||||||
|
.isActive()
|
||||||
|
&& !couple.get(false)
|
||||||
|
.isActive())
|
||||||
|
allFlows.remove(face);
|
||||||
|
if (allFlows.isEmpty())
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlowProgress(Direction face, boolean inbound, LerpedFloat progress) {
|
||||||
|
if (!allFlows.containsKey(face))
|
||||||
|
return;
|
||||||
|
allFlows.get(face)
|
||||||
|
.get(inbound).progress = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LerpedFloat getFlowProgress(Direction face, boolean inbound) {
|
||||||
|
if (!allFlows.containsKey(face))
|
||||||
|
return null;
|
||||||
|
return allFlows.get(face)
|
||||||
|
.get(inbound).progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skipFlow(Direction face, boolean inbound) {
|
||||||
|
if (!allFlows.containsKey(face))
|
||||||
|
return;
|
||||||
|
Couple<PipeFlows> couple = allFlows.get(face);
|
||||||
|
couple.get(inbound)
|
||||||
|
.skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
allFlows.clear();
|
||||||
|
fluid = FluidStack.EMPTY;
|
||||||
|
contentsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawnParticles() {
|
||||||
|
DistExecutor.runWhenOn(Dist.CLIENT, () -> this::spawnParticlesInner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawnSplashOnRim(Direction face) {
|
||||||
|
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> spawnSplashOnRimInner(face));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int MAX_PARTICLE_RENDER_DISTANCE = 20;
|
||||||
|
public static final int SPLASH_PARTICLE_AMOUNT = 10;
|
||||||
|
public static final float IDLE_PARTICLE_SPAWN_CHANCE = 1 / 100f;
|
||||||
|
public static final Random r = new Random();
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private void spawnParticlesInner() {
|
||||||
|
if (!isRenderEntityWithinDistance())
|
||||||
|
return;
|
||||||
|
if (fluid.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
World world = Minecraft.getInstance().world;
|
||||||
|
BlockPos pos = tileEntity.getPos();
|
||||||
|
BlockState state = world.getBlockState(pos);
|
||||||
|
|
||||||
|
for (Direction face : Iterate.directions) {
|
||||||
|
boolean open = FluidPropagator.isOpenEnd(world, pos, face);
|
||||||
|
if (isConnectedTo(state, face)) {
|
||||||
|
if (open) {
|
||||||
|
spawnPouringLiquid(world, state, fluid, face, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (r.nextFloat() < IDLE_PARTICLE_SPAWN_CHANCE)
|
||||||
|
spawnRimParticles(world, state, fluid, face, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private void spawnSplashOnRimInner(Direction face) {
|
||||||
|
if (!isRenderEntityWithinDistance())
|
||||||
|
return;
|
||||||
|
if (fluid.isEmpty())
|
||||||
|
return;
|
||||||
|
World world = Minecraft.getInstance().world;
|
||||||
|
BlockPos pos = tileEntity.getPos();
|
||||||
|
BlockState state = world.getBlockState(pos);
|
||||||
|
spawnRimParticles(world, state, fluid, face, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private void spawnRimParticles(World world, BlockState state, FluidStack fluid, Direction side, int amount) {
|
||||||
|
BlockPos pos = tileEntity.getPos();
|
||||||
|
if (FluidPropagator.isOpenEnd(world, pos, side)) {
|
||||||
|
spawnPouringLiquid(world, state, fluid, side, amount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IParticleData particle = null;
|
||||||
|
if (FluidHelper.isWater(fluid.getFluid()))
|
||||||
|
particle = ParticleTypes.DRIPPING_WATER;
|
||||||
|
if (FluidHelper.isLava(fluid.getFluid()))
|
||||||
|
particle = ParticleTypes.DRIPPING_LAVA;
|
||||||
|
// TODO: Generic drip particle type for forge fluids
|
||||||
|
|
||||||
|
if (particle == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float rimRadius = getRimRadius(state, side);
|
||||||
|
Vec3d directionVec = new Vec3d(side.getDirectionVec());
|
||||||
|
|
||||||
|
for (int i = 0; i < amount; i++) {
|
||||||
|
Vec3d vec = VecHelper.offsetRandomly(Vec3d.ZERO, r, 1)
|
||||||
|
.normalize();
|
||||||
|
vec = VecHelper.clampComponentWise(vec, rimRadius)
|
||||||
|
.mul(VecHelper.axisAlingedPlaneOf(directionVec))
|
||||||
|
.add(directionVec.scale(.45 + r.nextFloat() / 16f));
|
||||||
|
Vec3d m = vec;
|
||||||
|
vec = vec.add(VecHelper.getCenterOf(pos));
|
||||||
|
|
||||||
|
world.addOptionalParticle(particle, vec.x, vec.y - 1 / 16f, vec.z, m.x, m.y, m.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private void spawnPouringLiquid(World world, BlockState state, FluidStack fluid, Direction side, int amount) {
|
||||||
|
IParticleData particle = new BlockParticleData(ParticleTypes.BLOCK, fluid.getFluid()
|
||||||
|
.getDefaultState()
|
||||||
|
.getBlockState());
|
||||||
|
float rimRadius = getRimRadius(state, side);
|
||||||
|
Vec3d directionVec = new Vec3d(side.getDirectionVec());
|
||||||
|
|
||||||
|
Couple<PipeFlows> couple = allFlows.get(side);
|
||||||
|
if (couple == null)
|
||||||
|
return;
|
||||||
|
couple.forEachWithContext((flow, inbound) -> {
|
||||||
|
if (flow.progress == null)
|
||||||
|
return;
|
||||||
|
for (int i = 0; i < amount; i++) {
|
||||||
|
Vec3d vec = VecHelper.offsetRandomly(Vec3d.ZERO, r, rimRadius);
|
||||||
|
vec = vec.mul(VecHelper.axisAlingedPlaneOf(directionVec))
|
||||||
|
.add(directionVec.scale(.5 + r.nextFloat() / 4f));
|
||||||
|
Vec3d m = vec;
|
||||||
|
Vec3d centerOf = VecHelper.getCenterOf(tileEntity.getPos());
|
||||||
|
vec = vec.add(centerOf);
|
||||||
|
if (inbound) {
|
||||||
|
vec = vec.add(m);
|
||||||
|
m = centerOf.add(directionVec.scale(.5)).subtract(vec).scale(3);
|
||||||
|
}
|
||||||
|
world.addOptionalParticle(particle, vec.x, vec.y - 1 / 16f, vec.z, m.x, m.y, m.z);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private boolean isRenderEntityWithinDistance() {
|
||||||
|
Entity renderViewEntity = Minecraft.getInstance()
|
||||||
|
.getRenderViewEntity();
|
||||||
|
if (renderViewEntity == null)
|
||||||
|
return false;
|
||||||
|
Vec3d center = VecHelper.getCenterOf(tileEntity.getPos());
|
||||||
|
if (renderViewEntity.getPositionVec()
|
||||||
|
.distanceTo(center) > MAX_PARTICLE_RENDER_DISTANCE)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AxisAlignedBB smallCenter = new AxisAlignedBB(BlockPos.ZERO).shrink(.25);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
boolean isRemote = getWorld().isRemote;
|
||||||
|
|
||||||
|
allFlows.values()
|
||||||
|
.forEach(c -> c.forEach(pf -> pf.tick(isRemote)));
|
||||||
|
|
||||||
|
if (isRemote) {
|
||||||
|
clientTick();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collision != null) {
|
||||||
|
FluidReactions.handlePipeFlowCollision(getWorld(), tileEntity.getPos(), collision.getFirst(),
|
||||||
|
collision.getSecond());
|
||||||
|
collision = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clientTick() {
|
||||||
|
spawnParticles();
|
||||||
|
|
||||||
|
if (!KineticDebugger.isActive())
|
||||||
|
return;
|
||||||
|
if (fluid.isEmpty())
|
||||||
|
return;
|
||||||
|
for (Entry<Direction, Couple<PipeFlows>> entry : allFlows.entrySet()) {
|
||||||
|
Direction face = entry.getKey();
|
||||||
|
Vec3d directionVec = new Vec3d(face.getDirectionVec());
|
||||||
|
float size = 1 / 4f;
|
||||||
|
boolean extended = !isConnectedTo(tileEntity.getBlockState(), face.getOpposite());
|
||||||
|
float length = extended ? .75f : .5f;
|
||||||
|
|
||||||
|
entry.getValue()
|
||||||
|
.forEachWithContext((flow, inbound) -> {
|
||||||
|
if (flow.progress == null)
|
||||||
|
return;
|
||||||
|
float value = flow.progress.getValue();
|
||||||
|
Vec3d start = directionVec.scale(inbound ? .5 : .5f - length);
|
||||||
|
Vec3d offset = directionVec.scale(length * (inbound ? -1 : 1))
|
||||||
|
.scale(value);
|
||||||
|
|
||||||
|
Vec3d scale = new Vec3d(1, 1, 1).subtract(directionVec.scale(face.getAxisDirection()
|
||||||
|
.getOffset()))
|
||||||
|
.scale(size);
|
||||||
|
AxisAlignedBB bb =
|
||||||
|
new AxisAlignedBB(start, start.add(offset)).offset(VecHelper.getCenterOf(tileEntity.getPos()))
|
||||||
|
.grow(scale.x, scale.y, scale.z);
|
||||||
|
|
||||||
|
int color = 0x7fdbda;
|
||||||
|
if (!fluid.isEmpty()) {
|
||||||
|
Fluid fluid2 = fluid.getFluid();
|
||||||
|
if (fluid2 == Fluids.WATER)
|
||||||
|
color = 0x1D4D9B;
|
||||||
|
if (fluid2 == Fluids.LAVA)
|
||||||
|
color = 0xFF773D;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateClient.outliner.chaseAABB(Pair.of(this, face), bb)
|
||||||
|
.withFaceTexture(AllSpecialTextures.CUTOUT_CHECKERED)
|
||||||
|
.colored(color)
|
||||||
|
.lineWidth(1 / 16f);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void contentsChanged() {
|
||||||
|
tileEntity.markDirty();
|
||||||
|
tileEntity.sendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LerpedFloat createFlowProgress(double speed) {
|
||||||
|
return LerpedFloat.linear()
|
||||||
|
.startWithValue(0)
|
||||||
|
.chase(1, speed, Chaser.LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PipeFlows {
|
||||||
|
LerpedFloat progress;
|
||||||
|
Set<FluidNetworkFlow> participants;
|
||||||
|
float bestFlowStrength;
|
||||||
|
|
||||||
|
void addFlow(FluidNetworkFlow flow) {
|
||||||
|
if (participants == null)
|
||||||
|
participants = new HashSet<>();
|
||||||
|
participants.add(flow);
|
||||||
|
|
||||||
|
if (progress == null) {
|
||||||
|
progress = createFlowProgress(flow.getSpeed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasFlow(FluidNetworkFlow flow) {
|
||||||
|
return participants != null && participants.contains(flow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tick(boolean onClient) {
|
||||||
|
if (progress == null)
|
||||||
|
return;
|
||||||
|
if (!onClient) {
|
||||||
|
if (participants == null)
|
||||||
|
return;
|
||||||
|
bestFlowStrength = 0;
|
||||||
|
for (FluidNetworkFlow networkFlow : participants)
|
||||||
|
bestFlowStrength = Math.max(bestFlowStrength, networkFlow.getSpeed());
|
||||||
|
if (isCompleted())
|
||||||
|
return;
|
||||||
|
if (progress.updateChaseSpeed(bestFlowStrength))
|
||||||
|
contentsChanged();
|
||||||
|
}
|
||||||
|
progress.tickChaser();
|
||||||
|
}
|
||||||
|
|
||||||
|
void skip() {
|
||||||
|
progress = LerpedFloat.linear()
|
||||||
|
.startWithValue(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeFlow(FluidNetworkFlow flow) {
|
||||||
|
if (participants == null)
|
||||||
|
return;
|
||||||
|
participants.remove(flow);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isActive() {
|
||||||
|
return participants != null && !participants.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isCompleted() {
|
||||||
|
return progress != null && progress.getValue() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,15 +1,24 @@
|
||||||
package com.simibubi.create.content.contraptions.fluids;
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.simibubi.create.AllTileEntities;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.FlowingFluidBlock;
|
||||||
import net.minecraft.block.IWaterLoggable;
|
import net.minecraft.block.IWaterLoggable;
|
||||||
import net.minecraft.block.SixWayBlock;
|
import net.minecraft.block.SixWayBlock;
|
||||||
import net.minecraft.fluid.Fluids;
|
import net.minecraft.fluid.Fluids;
|
||||||
import net.minecraft.fluid.IFluidState;
|
import net.minecraft.fluid.IFluidState;
|
||||||
import net.minecraft.item.BlockItemUseContext;
|
import net.minecraft.item.BlockItemUseContext;
|
||||||
|
import net.minecraft.network.DebugPacketSender;
|
||||||
import net.minecraft.state.StateContainer.Builder;
|
import net.minecraft.state.StateContainer.Builder;
|
||||||
import net.minecraft.state.properties.BlockStateProperties;
|
import net.minecraft.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.Direction.Axis;
|
import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraft.util.Direction.AxisDirection;
|
import net.minecraft.util.Direction.AxisDirection;
|
||||||
|
@ -17,10 +26,11 @@ import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.IBlockReader;
|
import net.minecraft.world.IBlockReader;
|
||||||
import net.minecraft.world.ILightReader;
|
import net.minecraft.world.ILightReader;
|
||||||
import net.minecraft.world.IWorld;
|
import net.minecraft.world.IWorld;
|
||||||
|
import net.minecraft.world.TickPriority;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.server.ServerWorld;
|
||||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
|
public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
|
||||||
|
|
||||||
public FluidPipeBlock(Properties properties) {
|
public FluidPipeBlock(Properties properties) {
|
||||||
|
@ -28,18 +38,78 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
|
||||||
this.setDefaultState(super.getDefaultState().with(BlockStateProperties.WATERLOGGED, false));
|
this.setDefaultState(super.getDefaultState().with(BlockStateProperties.WATERLOGGED, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasTileEntity(BlockState state) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
|
||||||
|
return AllTileEntities.FLUID_PIPE.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||||
|
boolean blockTypeChanged = state.getBlock() != newState.getBlock();
|
||||||
|
if (blockTypeChanged && !world.isRemote)
|
||||||
|
FluidPropagator.propagateChangedPipe(world, pos, state);
|
||||||
|
if (state.hasTileEntity() && (blockTypeChanged || !newState.hasTileEntity()))
|
||||||
|
world.removeTileEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean isMoving) {
|
||||||
|
if (world.isRemote)
|
||||||
|
return;
|
||||||
|
if (state != oldState)
|
||||||
|
world.getPendingBlockTicks()
|
||||||
|
.scheduleTick(pos, this, 1, TickPriority.HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void neighborChanged(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos neighborPos,
|
||||||
|
boolean isMoving) {
|
||||||
|
DebugPacketSender.func_218806_a(world, pos);
|
||||||
|
if (world.isRemote)
|
||||||
|
return;
|
||||||
|
if (otherBlock instanceof FluidPipeBlock)
|
||||||
|
return;
|
||||||
|
if (otherBlock instanceof PumpBlock)
|
||||||
|
return;
|
||||||
|
if (otherBlock instanceof FlowingFluidBlock)
|
||||||
|
return;
|
||||||
|
if (!isStraightPipe(state))
|
||||||
|
return;
|
||||||
|
for (Direction d : Iterate.directions) {
|
||||||
|
if (!pos.offset(d)
|
||||||
|
.equals(neighborPos))
|
||||||
|
continue;
|
||||||
|
if (!isOpenAt(state, d))
|
||||||
|
return;
|
||||||
|
world.getPendingBlockTicks()
|
||||||
|
.scheduleTick(pos, this, 1, TickPriority.HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random r) {
|
||||||
|
FluidPropagator.propagateChangedPipe(world, pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isPipe(BlockState state) {
|
public static boolean isPipe(BlockState state) {
|
||||||
return state.getBlock() instanceof FluidPipeBlock;
|
return state.getBlock() instanceof FluidPipeBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isTank(BlockState state, IBlockReader world, BlockPos pos, Direction blockFace) {
|
public static boolean hasFluidCapability(BlockState state, IBlockReader world, BlockPos pos, Direction blockFace) {
|
||||||
return state.hasTileEntity() && world.getTileEntity(pos).getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, blockFace.getOpposite()).isPresent();
|
return state.hasTileEntity() && world.getTileEntity(pos)
|
||||||
|
.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, blockFace.getOpposite())
|
||||||
|
.isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: more generic pipe connection handling. Ideally without marker interface
|
|
||||||
public static boolean canConnectTo(ILightReader world, BlockPos pos, BlockState neighbour, Direction blockFace) {
|
public static boolean canConnectTo(ILightReader world, BlockPos pos, BlockState neighbour, Direction blockFace) {
|
||||||
if (isPipe(neighbour) || isTank(neighbour, world, pos, blockFace))
|
if (isPipe(neighbour) || hasFluidCapability(neighbour, world, pos, blockFace))
|
||||||
return true;
|
return true;
|
||||||
|
// TODO: more generic pipe connection handling.
|
||||||
return neighbour.getBlock() instanceof PumpBlock && blockFace.getAxis() == neighbour.get(PumpBlock.FACING)
|
return neighbour.getBlock() instanceof PumpBlock && blockFace.getAxis() == neighbour.get(PumpBlock.FACING)
|
||||||
.getAxis();
|
.getAxis();
|
||||||
}
|
}
|
||||||
|
@ -47,7 +117,7 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
|
||||||
public static boolean shouldDrawRim(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
public static boolean shouldDrawRim(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
||||||
if (!isPipe(state))
|
if (!isPipe(state))
|
||||||
return false;
|
return false;
|
||||||
if (!state.get(FACING_TO_PROPERTY_MAP.get(direction)))
|
if (!isOpenAt(state, direction))
|
||||||
return false;
|
return false;
|
||||||
BlockPos offsetPos = pos.offset(direction);
|
BlockPos offsetPos = pos.offset(direction);
|
||||||
BlockState facingState = world.getBlockState(offsetPos);
|
BlockState facingState = world.getBlockState(offsetPos);
|
||||||
|
@ -58,7 +128,7 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
|
||||||
return true;
|
return true;
|
||||||
if (!isCornerOrEndPipe(world, pos, state))
|
if (!isCornerOrEndPipe(world, pos, state))
|
||||||
return false;
|
return false;
|
||||||
if (isStraightPipe(world, offsetPos, facingState))
|
if (isStraightPipe(facingState))
|
||||||
return true;
|
return true;
|
||||||
if (!shouldDrawCasing(world, pos, state) && shouldDrawCasing(world, offsetPos, facingState))
|
if (!shouldDrawCasing(world, pos, state) && shouldDrawCasing(world, offsetPos, facingState))
|
||||||
return true;
|
return true;
|
||||||
|
@ -67,18 +137,22 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isCornerOrEndPipe(ILightReader world, BlockPos pos, BlockState state) {
|
private static boolean isOpenAt(BlockState state, Direction direction) {
|
||||||
return isPipe(state) && !isStraightPipe(world, pos, state) && !shouldDrawCasing(world, pos, state);
|
return state.get(FACING_TO_PROPERTY_MAP.get(direction));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isStraightPipe(ILightReader world, BlockPos pos, BlockState state) {
|
public static boolean isCornerOrEndPipe(ILightReader world, BlockPos pos, BlockState state) {
|
||||||
|
return isPipe(state) && !isStraightPipe(state) && !shouldDrawCasing(world, pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStraightPipe(BlockState state) {
|
||||||
if (!isPipe(state))
|
if (!isPipe(state))
|
||||||
return false;
|
return false;
|
||||||
boolean axisFound = false;
|
boolean axisFound = false;
|
||||||
for (Axis axis : Iterate.axes) {
|
for (Axis axis : Iterate.axes) {
|
||||||
Direction d1 = Direction.getFacingFromAxis(AxisDirection.NEGATIVE, axis);
|
Direction d1 = Direction.getFacingFromAxis(AxisDirection.NEGATIVE, axis);
|
||||||
Direction d2 = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);
|
Direction d2 = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);
|
||||||
if (state.get(FACING_TO_PROPERTY_MAP.get(d1)) && state.get(FACING_TO_PROPERTY_MAP.get(d2)))
|
if (isOpenAt(state, d1) && isOpenAt(state, d2))
|
||||||
if (axisFound)
|
if (axisFound)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
|
@ -93,7 +167,7 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
|
||||||
for (Axis axis : Iterate.axes) {
|
for (Axis axis : Iterate.axes) {
|
||||||
int connections = 0;
|
int connections = 0;
|
||||||
for (Direction direction : Iterate.directions)
|
for (Direction direction : Iterate.directions)
|
||||||
if (direction.getAxis() != axis && state.get(FACING_TO_PROPERTY_MAP.get(direction)))
|
if (direction.getAxis() != axis && isOpenAt(state, direction))
|
||||||
connections++;
|
connections++;
|
||||||
if (connections > 2)
|
if (connections > 2)
|
||||||
return true;
|
return true;
|
||||||
|
@ -109,16 +183,19 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
||||||
IFluidState ifluidstate = context.getWorld().getFluidState(context.getPos());
|
IFluidState ifluidstate = context.getWorld()
|
||||||
|
.getFluidState(context.getPos());
|
||||||
return updateBlockState(getDefaultState(), context.getNearestLookingDirection(), null, context.getWorld(),
|
return updateBlockState(getDefaultState(), context.getNearestLookingDirection(), null, context.getWorld(),
|
||||||
context.getPos()).with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
|
context.getPos()).with(BlockStateProperties.WATERLOGGED,
|
||||||
|
Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState,
|
public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState,
|
||||||
IWorld world, BlockPos pos, BlockPos neighbourPos) {
|
IWorld world, BlockPos pos, BlockPos neighbourPos) {
|
||||||
if (state.get(BlockStateProperties.WATERLOGGED)) {
|
if (state.get(BlockStateProperties.WATERLOGGED)) {
|
||||||
world.getPendingFluidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
|
world.getPendingFluidTicks()
|
||||||
|
.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
|
||||||
}
|
}
|
||||||
return updateBlockState(state, direction, direction.getOpposite(), world, pos);
|
return updateBlockState(state, direction, direction.getOpposite(), world, pos);
|
||||||
}
|
}
|
||||||
|
@ -134,7 +211,7 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
|
||||||
// See if it has enough connections
|
// See if it has enough connections
|
||||||
Direction connectedDirection = null;
|
Direction connectedDirection = null;
|
||||||
for (Direction d : Iterate.directions) {
|
for (Direction d : Iterate.directions) {
|
||||||
if (state.get(FACING_TO_PROPERTY_MAP.get(d))) {
|
if (isOpenAt(state, d)) {
|
||||||
if (connectedDirection != null)
|
if (connectedDirection != null)
|
||||||
return state;
|
return state;
|
||||||
connectedDirection = d;
|
connectedDirection = d;
|
||||||
|
@ -152,6 +229,7 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IFluidState getFluidState(BlockState state) {
|
public IFluidState getFluidState(BlockState state) {
|
||||||
return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : Fluids.EMPTY.getDefaultState();
|
return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false)
|
||||||
|
: Fluids.EMPTY.getDefaultState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.tileentity.TileEntityType;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
|
||||||
|
public class FluidPipeTileEntity extends SmartTileEntity {
|
||||||
|
|
||||||
|
FluidPipeBehaviour behaviour;
|
||||||
|
|
||||||
|
public FluidPipeTileEntity(TileEntityType<?> tileEntityTypeIn) {
|
||||||
|
super(tileEntityTypeIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||||
|
behaviour = new StandardPipeBehaviour(this);
|
||||||
|
behaviours.add(behaviour);
|
||||||
|
}
|
||||||
|
|
||||||
|
class StandardPipeBehaviour extends FluidPipeBehaviour {
|
||||||
|
|
||||||
|
public StandardPipeBehaviour(SmartTileEntity te) {
|
||||||
|
super(te);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConnectedTo(BlockState state, Direction direction) {
|
||||||
|
return FluidPipeBlock.isPipe(state) && state.get(FluidPipeBlock.FACING_TO_PROPERTY_MAP.get(direction));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.mutable.MutableObject;
|
||||||
|
|
||||||
|
import com.simibubi.create.AllBlocks;
|
||||||
|
import com.simibubi.create.CreateClient;
|
||||||
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.IBlockReader;
|
||||||
|
import net.minecraft.world.IWorld;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.fml.DistExecutor;
|
||||||
|
|
||||||
|
public class FluidPropagator {
|
||||||
|
|
||||||
|
public static FluidPipeBehaviour getPipe(IBlockReader reader, BlockPos pos) {
|
||||||
|
return TileEntityBehaviour.get(reader, pos, FluidPipeBehaviour.TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isOpenEnd(IBlockReader reader, BlockPos pos, Direction side) {
|
||||||
|
BlockPos connectedPos = pos.offset(side);
|
||||||
|
BlockState connectedState = reader.getBlockState(connectedPos);
|
||||||
|
FluidPipeBehaviour pipe = FluidPropagator.getPipe(reader, connectedPos);
|
||||||
|
if (pipe != null && pipe.isConnectedTo(connectedState, side.getOpposite()))
|
||||||
|
return false;
|
||||||
|
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
||||||
|
.getAxis() == side.getAxis())
|
||||||
|
return false;
|
||||||
|
if (Block.hasSolidSide(connectedState, reader, connectedPos, side.getOpposite()))
|
||||||
|
return false;
|
||||||
|
if (!(connectedState.getMaterial()
|
||||||
|
.isReplaceable() && connectedState.getBlockHardness(reader, connectedPos) != -1)
|
||||||
|
&& !connectedState.has(BlockStateProperties.WATERLOGGED))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void propagateChangedPipe(IWorld world, BlockPos pipePos, BlockState pipeState) {
|
||||||
|
List<BlockPos> frontier = new ArrayList<>();
|
||||||
|
Set<BlockPos> visited = new HashSet<>();
|
||||||
|
|
||||||
|
frontier.add(pipePos);
|
||||||
|
|
||||||
|
// Visit all connected pumps to update their network
|
||||||
|
while (!frontier.isEmpty()) {
|
||||||
|
BlockPos currentPos = frontier.remove(0);
|
||||||
|
if (visited.contains(currentPos))
|
||||||
|
continue;
|
||||||
|
visited.add(currentPos);
|
||||||
|
BlockState currentState = currentPos.equals(pipePos) ? pipeState : world.getBlockState(currentPos);
|
||||||
|
FluidPipeBehaviour pipe = getPipe(world, currentPos);
|
||||||
|
if (pipe == null)
|
||||||
|
continue;
|
||||||
|
for (Direction direction : getPipeConnections(currentState, pipe)) {
|
||||||
|
BlockPos target = currentPos.offset(direction);
|
||||||
|
if (!world.isAreaLoaded(target, 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TileEntity tileEntity = world.getTileEntity(target);
|
||||||
|
BlockState targetState = world.getBlockState(target);
|
||||||
|
if (tileEntity instanceof PumpTileEntity) {
|
||||||
|
if (!AllBlocks.MECHANICAL_PUMP.has(targetState) || targetState.get(PumpBlock.FACING)
|
||||||
|
.getAxis() != direction.getAxis())
|
||||||
|
continue;
|
||||||
|
PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
||||||
|
pump.updatePipesOnSide(direction.getOpposite());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (visited.contains(target))
|
||||||
|
continue;
|
||||||
|
FluidPipeBehaviour targetPipe = getPipe(world, target);
|
||||||
|
if (targetPipe == null)
|
||||||
|
continue;
|
||||||
|
if (targetPipe.isConnectedTo(targetState, direction.getOpposite()))
|
||||||
|
frontier.add(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Direction> getPipeConnections(BlockState state, FluidPipeBehaviour pipe) {
|
||||||
|
List<Direction> list = new ArrayList<>();
|
||||||
|
for (Direction d : Iterate.directions)
|
||||||
|
if (pipe.isConnectedTo(state, d))
|
||||||
|
list.add(d);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getPumpRange() {
|
||||||
|
return AllConfigs.SERVER.fluids.mechanicalPumpRange.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OutlineParams showBlockFace(BlockFace face) {
|
||||||
|
MutableObject<OutlineParams> params = new MutableObject<>(new OutlineParams());
|
||||||
|
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> {
|
||||||
|
Vec3d directionVec = new Vec3d(face.getFace()
|
||||||
|
.getDirectionVec());
|
||||||
|
Vec3d scaleVec = directionVec.scale(-.25f * face.getFace()
|
||||||
|
.getAxisDirection()
|
||||||
|
.getOffset());
|
||||||
|
directionVec = directionVec.scale(.5f);
|
||||||
|
params.setValue(CreateClient.outliner.showAABB(face,
|
||||||
|
FluidPropagator.smallCenter.offset(directionVec.add(new Vec3d(face.getPos())))
|
||||||
|
.grow(scaleVec.x, scaleVec.y, scaleVec.z)
|
||||||
|
.grow(1 / 16f)));
|
||||||
|
});
|
||||||
|
return params.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
static AxisAlignedBB smallCenter = new AxisAlignedBB(BlockPos.ZERO).shrink(.25);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.fluid.FluidHelper;
|
||||||
|
import com.simibubi.create.foundation.utility.BlockHelper;
|
||||||
|
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.fluid.Fluid;
|
||||||
|
import net.minecraft.fluid.Fluids;
|
||||||
|
import net.minecraft.fluid.IFluidState;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
|
||||||
|
public class FluidReactions {
|
||||||
|
|
||||||
|
public static void handlePipeFlowCollision(World world, BlockPos pos, FluidStack fluid, FluidStack fluid2) {
|
||||||
|
Fluid f1 = fluid.getFluid();
|
||||||
|
Fluid f2 = fluid2.getFluid();
|
||||||
|
BlockHelper.destroyBlock(world, pos, 1);
|
||||||
|
if (f1 == Fluids.WATER && f2 == Fluids.LAVA || f2 == Fluids.WATER && f1 == Fluids.LAVA)
|
||||||
|
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handlePipeSpillCollision(World world, BlockPos pos, Fluid pipeFluid, IFluidState worldFluid) {
|
||||||
|
Fluid pf = FluidHelper.convertToStill(pipeFluid);
|
||||||
|
Fluid wf = worldFluid.getFluid();
|
||||||
|
if (pf == Fluids.WATER && wf == Fluids.LAVA)
|
||||||
|
world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState());
|
||||||
|
if (pf == Fluids.WATER && wf == Fluids.FLOWING_LAVA)
|
||||||
|
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
|
||||||
|
else if (pf == Fluids.LAVA && wf == Fluids.WATER)
|
||||||
|
world.setBlockState(pos, Blocks.STONE.getDefaultState());
|
||||||
|
else if (pf == Fluids.LAVA && wf == Fluids.FLOWING_WATER)
|
||||||
|
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -182,7 +182,7 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE<FluidTankT
|
||||||
return ActionResultType.SUCCESS;
|
return ActionResultType.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
controllerTE.sendData();
|
controllerTE.sendDataImmediately();
|
||||||
controllerTE.markDirty();
|
controllerTE.markDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,6 +276,7 @@ public class FluidTankConnectivityHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
te.fluidCapability.invalidate();
|
||||||
if (tryReconnect)
|
if (tryReconnect)
|
||||||
formTanks(world, cache == null ? new TankSearchCache() : cache, frontier);
|
formTanks(world, cache == null ? new TankSearchCache() : cache, frontier);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,10 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
protected int width;
|
protected int width;
|
||||||
protected int height;
|
protected int height;
|
||||||
|
|
||||||
|
private static final int SYNC_RATE = 8;
|
||||||
|
protected int syncCooldown;
|
||||||
|
protected boolean queuedSync;
|
||||||
|
|
||||||
// For rendering purposes only
|
// For rendering purposes only
|
||||||
InterpolatedChasingValue fluidLevel;
|
InterpolatedChasingValue fluidLevel;
|
||||||
|
|
||||||
|
@ -60,6 +64,7 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
window = true;
|
window = true;
|
||||||
height = 1;
|
height = 1;
|
||||||
width = 1;
|
width = 1;
|
||||||
|
refreshCapability();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateConnectivity() {
|
protected void updateConnectivity() {
|
||||||
|
@ -74,6 +79,11 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
if (syncCooldown > 0) {
|
||||||
|
syncCooldown--;
|
||||||
|
if (syncCooldown == 0 && queuedSync)
|
||||||
|
sendData();
|
||||||
|
}
|
||||||
if (updateConnectivity)
|
if (updateConnectivity)
|
||||||
updateConnectivity();
|
updateConnectivity();
|
||||||
if (fluidLevel != null)
|
if (fluidLevel != null)
|
||||||
|
@ -96,7 +106,7 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
|
|
||||||
FluidAttributes attributes = newFluidStack.getFluid()
|
FluidAttributes attributes = newFluidStack.getFluid()
|
||||||
.getAttributes();
|
.getAttributes();
|
||||||
int luminosity = attributes.getLuminosity(newFluidStack) / 2;
|
int luminosity = (int) (attributes.getLuminosity(newFluidStack) / 1.2f);
|
||||||
boolean reversed = attributes.isLighterThanAir();
|
boolean reversed = attributes.isLighterThanAir();
|
||||||
int maxY = (int) ((getFillState() * height) + 1);
|
int maxY = (int) ((getFillState() * height) + 1);
|
||||||
|
|
||||||
|
@ -116,6 +126,11 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!world.isRemote) {
|
||||||
|
markDirty();
|
||||||
|
sendData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setLuminosity(int luminosity) {
|
protected void setLuminosity(int luminosity) {
|
||||||
|
@ -162,6 +177,7 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
getWorld().setBlockState(pos, state, 22);
|
getWorld().setBlockState(pos, state, 22);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshCapability();
|
||||||
markDirty();
|
markDirty();
|
||||||
sendData();
|
sendData();
|
||||||
}
|
}
|
||||||
|
@ -173,6 +189,23 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
te.setWindows(!te.window);
|
te.setWindows(!te.window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendDataImmediately() {
|
||||||
|
syncCooldown = 0;
|
||||||
|
queuedSync = false;
|
||||||
|
sendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendData() {
|
||||||
|
if (syncCooldown > 0) {
|
||||||
|
queuedSync = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.sendData();
|
||||||
|
queuedSync = false;
|
||||||
|
syncCooldown = SYNC_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
public void setWindows(boolean window) {
|
public void setWindows(boolean window) {
|
||||||
this.window = window;
|
this.window = window;
|
||||||
for (int yOffset = 0; yOffset < height; yOffset++) {
|
for (int yOffset = 0; yOffset < height; yOffset++) {
|
||||||
|
@ -213,10 +246,18 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
if (controller.equals(this.controller))
|
if (controller.equals(this.controller))
|
||||||
return;
|
return;
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
|
refreshCapability();
|
||||||
markDirty();
|
markDirty();
|
||||||
sendData();
|
sendData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void refreshCapability() {
|
||||||
|
LazyOptional<IFluidHandler> oldCap = fluidCapability;
|
||||||
|
fluidCapability = LazyOptional.of(() -> isController() ? tankInventory
|
||||||
|
: getControllerTE() != null ? getControllerTE().tankInventory : new FluidTank(0));
|
||||||
|
oldCap.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
public BlockPos getController() {
|
public BlockPos getController() {
|
||||||
return isController() ? pos : controller;
|
return isController() ? pos : controller;
|
||||||
}
|
}
|
||||||
|
@ -236,38 +277,37 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
super.read(tag);
|
super.read(compound, clientPacket);
|
||||||
updateConnectivity = tag.contains("Uninitialized");
|
|
||||||
luminosity = tag.getInt("Luminosity");
|
|
||||||
controller = null;
|
|
||||||
|
|
||||||
if (tag.contains("Controller"))
|
|
||||||
controller = NBTUtil.readBlockPos(tag.getCompound("Controller"));
|
|
||||||
|
|
||||||
if (isController()) {
|
|
||||||
window = tag.getBoolean("Window");
|
|
||||||
width = tag.getInt("Size");
|
|
||||||
height = tag.getInt("Height");
|
|
||||||
tankInventory.setCapacity(getTotalTankSize() * getCapacityMultiplier());
|
|
||||||
tankInventory.readFromNBT(tag.getCompound("TankContent"));
|
|
||||||
if (tankInventory.getSpace() < 0)
|
|
||||||
tankInventory.drain(-tankInventory.getSpace(), FluidAction.EXECUTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag.contains("ForceFluidLevel") || fluidLevel == null)
|
|
||||||
fluidLevel = new InterpolatedChasingValue().start(getFillState())
|
|
||||||
.withSpeed(1 / 2f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
|
||||||
BlockPos controllerBefore = controller;
|
BlockPos controllerBefore = controller;
|
||||||
int prevSize = width;
|
int prevSize = width;
|
||||||
int prevHeight = height;
|
int prevHeight = height;
|
||||||
int prevLum = luminosity;
|
int prevLum = luminosity;
|
||||||
|
|
||||||
super.readClientUpdate(tag);
|
updateConnectivity = compound.contains("Uninitialized");
|
||||||
|
luminosity = compound.getInt("Luminosity");
|
||||||
|
controller = null;
|
||||||
|
|
||||||
|
if (compound.contains("Controller"))
|
||||||
|
controller = NBTUtil.readBlockPos(compound.getCompound("Controller"));
|
||||||
|
|
||||||
|
if (isController()) {
|
||||||
|
window = compound.getBoolean("Window");
|
||||||
|
width = compound.getInt("Size");
|
||||||
|
height = compound.getInt("Height");
|
||||||
|
tankInventory.setCapacity(getTotalTankSize() * getCapacityMultiplier());
|
||||||
|
tankInventory.readFromNBT(compound.getCompound("TankContent"));
|
||||||
|
if (tankInventory.getSpace() < 0)
|
||||||
|
tankInventory.drain(-tankInventory.getSpace(), FluidAction.EXECUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compound.contains("ForceFluidLevel") || fluidLevel == null)
|
||||||
|
fluidLevel = new InterpolatedChasingValue().start(getFillState())
|
||||||
|
.withSpeed(1 / 2f);
|
||||||
|
|
||||||
|
if (!clientPacket)
|
||||||
|
return;
|
||||||
|
|
||||||
boolean changeOfController =
|
boolean changeOfController =
|
||||||
controllerBefore == null ? controller != null : !controllerBefore.equals(controller);
|
controllerBefore == null ? controller != null : !controllerBefore.equals(controller);
|
||||||
|
@ -279,15 +319,17 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
if (isController()) {
|
if (isController()) {
|
||||||
float fillState = getFillState();
|
float fillState = getFillState();
|
||||||
if (tag.contains("ForceFluidLevel") || fluidLevel == null)
|
if (compound.contains("ForceFluidLevel") || fluidLevel == null)
|
||||||
fluidLevel = new InterpolatedChasingValue().start(fillState)
|
fluidLevel = new InterpolatedChasingValue().start(fillState);
|
||||||
.withSpeed(1 / 2f);
|
|
||||||
fluidLevel.target(fillState);
|
fluidLevel.target(fillState);
|
||||||
}
|
}
|
||||||
if (luminosity != prevLum && hasWorld())
|
if (luminosity != prevLum && hasWorld())
|
||||||
world.getChunkProvider()
|
world.getChunkProvider()
|
||||||
.getLightManager()
|
.getLightManager()
|
||||||
.checkBlock(pos);
|
.checkBlock(pos);
|
||||||
|
|
||||||
|
if (compound.contains("LazySync"))
|
||||||
|
fluidLevel.withSpeed(compound.contains("LazySync") ? 1 / 8f : 1 / 2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected float getFillState() {
|
protected float getFillState() {
|
||||||
|
@ -295,44 +337,42 @@ public class FluidTankTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT tag) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
if (updateConnectivity)
|
if (updateConnectivity)
|
||||||
tag.putBoolean("Uninitialized", true);
|
compound.putBoolean("Uninitialized", true);
|
||||||
if (!isController())
|
if (!isController())
|
||||||
tag.put("Controller", NBTUtil.writeBlockPos(controller));
|
compound.put("Controller", NBTUtil.writeBlockPos(controller));
|
||||||
if (isController()) {
|
if (isController()) {
|
||||||
tag.putBoolean("Window", window);
|
compound.putBoolean("Window", window);
|
||||||
tag.put("TankContent", tankInventory.writeToNBT(new CompoundNBT()));
|
compound.put("TankContent", tankInventory.writeToNBT(new CompoundNBT()));
|
||||||
tag.putInt("Size", width);
|
compound.putInt("Size", width);
|
||||||
tag.putInt("Height", height);
|
compound.putInt("Height", height);
|
||||||
}
|
|
||||||
tag.putInt("Luminosity", luminosity);
|
|
||||||
return super.write(tag);
|
|
||||||
}
|
}
|
||||||
|
compound.putInt("Luminosity", luminosity);
|
||||||
|
super.write(compound, clientPacket);
|
||||||
|
|
||||||
@Override
|
if (!clientPacket)
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
return;
|
||||||
if (forceFluidLevelUpdate)
|
if (forceFluidLevelUpdate)
|
||||||
compound.putBoolean("ForceFluidLevel", true);
|
compound.putBoolean("ForceFluidLevel", true);
|
||||||
|
if (queuedSync)
|
||||||
|
compound.putBoolean("LazySync", true);
|
||||||
forceFluidLevelUpdate = false;
|
forceFluidLevelUpdate = false;
|
||||||
return super.writeToClient(compound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||||
if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
|
if (!fluidCapability.isPresent())
|
||||||
FluidTankTileEntity controller = getControllerTE();
|
refreshCapability();
|
||||||
if (controller != null)
|
if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
|
||||||
return controller.fluidCapability.cast();
|
return fluidCapability.cast();
|
||||||
}
|
|
||||||
return super.getCapability(cap, side);
|
return super.getCapability(cap, side);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove() {
|
public void remove() {
|
||||||
super.remove();
|
super.remove();
|
||||||
fluidCapability.invalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fluids.capability.templates.FluidTank;
|
||||||
|
|
||||||
|
public class InterPumpFluidHandler extends FluidTank {
|
||||||
|
|
||||||
|
InterPumpEndpoint endpoint;
|
||||||
|
|
||||||
|
public InterPumpFluidHandler(InterPumpEndpoint endpoint) {
|
||||||
|
super(Integer.MAX_VALUE);
|
||||||
|
this.endpoint = endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int fill(FluidStack resource, FluidAction action) {
|
||||||
|
if (resource.isEmpty())
|
||||||
|
return 0;
|
||||||
|
int maxInput = Math.min(resource.getAmount(), Math.max(getTransferCapacity() - getFluidAmount(), 0));
|
||||||
|
FluidStack toInsert = resource.copy();
|
||||||
|
toInsert.setAmount(maxInput);
|
||||||
|
FluidPropagator.showBlockFace(endpoint.location).colored(0x77d196).lineWidth(1/4f);
|
||||||
|
return super.fill(toInsert, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||||
|
return super.drain(maxDrain, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidStack provide() {
|
||||||
|
FluidStack heldFluid = getFluid();
|
||||||
|
if (heldFluid.isEmpty())
|
||||||
|
return heldFluid;
|
||||||
|
FluidStack copy = heldFluid.copy();
|
||||||
|
copy.setAmount(1);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getTransferCapacity() {
|
||||||
|
return Math.min(endpoint.getTransferSpeed(true), endpoint.getTransferSpeed(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.FlowingFluidBlock;
|
||||||
|
import net.minecraft.fluid.Fluid;
|
||||||
|
import net.minecraft.fluid.Fluids;
|
||||||
|
import net.minecraft.fluid.IFluidState;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
|
import net.minecraftforge.fluids.capability.templates.FluidTank;
|
||||||
|
|
||||||
|
public class OpenEndedPipe {
|
||||||
|
|
||||||
|
World world;
|
||||||
|
|
||||||
|
private OpenEndFluidHandler fluidHandler;
|
||||||
|
private BlockPos outputPos;
|
||||||
|
private boolean wasPulling;
|
||||||
|
private boolean stale;
|
||||||
|
|
||||||
|
public OpenEndedPipe(BlockFace face) {
|
||||||
|
fluidHandler = new OpenEndFluidHandler();
|
||||||
|
outputPos = face.getConnectedPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick(World world, boolean pulling) {
|
||||||
|
this.world = world;
|
||||||
|
if (!world.isAreaLoaded(outputPos, 0))
|
||||||
|
return;
|
||||||
|
if (pulling != wasPulling) {
|
||||||
|
if (pulling)
|
||||||
|
fluidHandler.clear();
|
||||||
|
wasPulling = pulling;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockState state = world.getBlockState(outputPos);
|
||||||
|
IFluidState fluidState = state.getFluidState();
|
||||||
|
boolean waterlog = state.has(BlockStateProperties.WATERLOGGED);
|
||||||
|
|
||||||
|
if (!waterlog && !state.getMaterial()
|
||||||
|
.isReplaceable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO different pipe end types
|
||||||
|
if (pulling) {
|
||||||
|
if (fluidState.isEmpty() || !fluidState.isSource())
|
||||||
|
return;
|
||||||
|
if (!fluidHandler.tryCollectFluid(fluidState.getFluid()))
|
||||||
|
return;
|
||||||
|
if (waterlog) {
|
||||||
|
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, false), 3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
world.setBlockState(outputPos, fluidState.getBlockState()
|
||||||
|
.with(FlowingFluidBlock.LEVEL, 14), 3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fluid providedFluid = fluidHandler.tryProvidingFluid();
|
||||||
|
if (providedFluid == null)
|
||||||
|
return;
|
||||||
|
if (!fluidState.isEmpty() && fluidState.getFluid() != providedFluid) {
|
||||||
|
FluidReactions.handlePipeSpillCollision(world, outputPos, providedFluid, fluidState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fluidState.isSource())
|
||||||
|
return;
|
||||||
|
if (waterlog) {
|
||||||
|
if (providedFluid.getFluid() != Fluids.WATER)
|
||||||
|
return;
|
||||||
|
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, true), 3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
world.setBlockState(outputPos, providedFluid.getDefaultState()
|
||||||
|
.getBlockState(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LazyOptional<IFluidHandler> getCapability() {
|
||||||
|
return LazyOptional.of(() -> fluidHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundNBT writeToNBT(CompoundNBT compound) {
|
||||||
|
fluidHandler.writeToNBT(compound);
|
||||||
|
compound.putBoolean("Pulling", wasPulling);
|
||||||
|
return compound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readNBT(CompoundNBT compound) {
|
||||||
|
fluidHandler.readFromNBT(compound);
|
||||||
|
wasPulling = compound.getBoolean("Pulling");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markStale() {
|
||||||
|
stale = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unmarkStale() {
|
||||||
|
stale = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStale() {
|
||||||
|
return stale;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class OpenEndFluidHandler extends FluidTank {
|
||||||
|
|
||||||
|
public OpenEndFluidHandler() {
|
||||||
|
super(1500);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int fill(FluidStack resource, FluidAction action) {
|
||||||
|
// Never allow being filled when a source is attached
|
||||||
|
if (world == null)
|
||||||
|
return 0;
|
||||||
|
if (!world.isAreaLoaded(outputPos, 0))
|
||||||
|
return 0;
|
||||||
|
BlockState state = world.getBlockState(outputPos);
|
||||||
|
IFluidState fluidState = state.getFluidState();
|
||||||
|
if (!fluidState.isEmpty() && fluidState.getFluid() != resource.getFluid()) {
|
||||||
|
FluidReactions.handlePipeSpillCollision(world, outputPos, resource.getFluid(), fluidState);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (fluidState.isSource())
|
||||||
|
return 0;
|
||||||
|
if (!(state.has(BlockStateProperties.WATERLOGGED) && resource.getFluid() == Fluids.WATER)
|
||||||
|
&& !state.getMaterial()
|
||||||
|
.isReplaceable())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Never allow being filled above 1000
|
||||||
|
FluidStack insertable = resource.copy();
|
||||||
|
insertable.setAmount(Math.min(insertable.getAmount(), Math.max(1000 - getFluidAmount(), 0)));
|
||||||
|
return super.fill(insertable, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean tryCollectFluid(Fluid fluid) {
|
||||||
|
for (boolean simulate : Iterate.trueAndFalse)
|
||||||
|
if (super.fill(new FluidStack(fluid, 1000),
|
||||||
|
simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE) != 1000)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Fluid tryProvidingFluid() {
|
||||||
|
Fluid fluid = getFluid().getFluid();
|
||||||
|
for (boolean simulate : Iterate.trueAndFalse)
|
||||||
|
if (drain(1000, simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE).getAmount() != 1000)
|
||||||
|
return null;
|
||||||
|
return fluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
setFluid(FluidStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,14 +1,23 @@
|
||||||
package com.simibubi.create.content.contraptions.fluids;
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||||
|
|
||||||
import com.simibubi.create.AllShapes;
|
import com.simibubi.create.AllShapes;
|
||||||
import com.simibubi.create.AllTileEntities;
|
import com.simibubi.create.AllTileEntities;
|
||||||
import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock;
|
import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock;
|
||||||
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.IWaterLoggable;
|
import net.minecraft.block.IWaterLoggable;
|
||||||
import net.minecraft.fluid.Fluids;
|
import net.minecraft.fluid.Fluids;
|
||||||
import net.minecraft.fluid.IFluidState;
|
import net.minecraft.fluid.IFluidState;
|
||||||
import net.minecraft.item.BlockItemUseContext;
|
import net.minecraft.item.BlockItemUseContext;
|
||||||
|
import net.minecraft.item.ItemUseContext;
|
||||||
|
import net.minecraft.network.DebugPacketSender;
|
||||||
import net.minecraft.state.StateContainer.Builder;
|
import net.minecraft.state.StateContainer.Builder;
|
||||||
import net.minecraft.state.properties.BlockStateProperties;
|
import net.minecraft.state.properties.BlockStateProperties;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
@ -20,6 +29,8 @@ import net.minecraft.util.math.shapes.VoxelShape;
|
||||||
import net.minecraft.world.IBlockReader;
|
import net.minecraft.world.IBlockReader;
|
||||||
import net.minecraft.world.IWorld;
|
import net.minecraft.world.IWorld;
|
||||||
import net.minecraft.world.IWorldReader;
|
import net.minecraft.world.IWorldReader;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
|
||||||
public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable {
|
public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable {
|
||||||
|
|
||||||
|
@ -44,6 +55,40 @@ public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable
|
||||||
.getOpposite());
|
.getOpposite());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState updateAfterWrenched(BlockState newState, ItemUseContext context) {
|
||||||
|
BlockState state = super.updateAfterWrenched(newState, context);
|
||||||
|
World world = context.getWorld();
|
||||||
|
BlockPos pos = context.getPos();
|
||||||
|
if (world.isRemote)
|
||||||
|
return state;
|
||||||
|
TileEntity tileEntity = world.getTileEntity(pos);
|
||||||
|
if (!(tileEntity instanceof PumpTileEntity))
|
||||||
|
return state;
|
||||||
|
PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
||||||
|
if (pump.networks == null)
|
||||||
|
return state;
|
||||||
|
|
||||||
|
FluidNetwork apn1 = pump.networks.get(true);
|
||||||
|
FluidNetwork apn2 = pump.networks.get(false);
|
||||||
|
|
||||||
|
// Collect pipes that can be skipped
|
||||||
|
apn1.clearFlows(world, true);
|
||||||
|
apn2.clearFlows(world, true);
|
||||||
|
|
||||||
|
// Swap skipsets as the networks change sides
|
||||||
|
Map<BlockFace, FluidStack> skippedConnections = apn1.previousFlow;
|
||||||
|
apn1.previousFlow = apn2.previousFlow;
|
||||||
|
apn2.previousFlow = skippedConnections;
|
||||||
|
|
||||||
|
// Init networks next tick
|
||||||
|
pump.networksToUpdate.forEach(MutableBoolean::setTrue);
|
||||||
|
pump.networks.swap();
|
||||||
|
pump.reversed = !pump.reversed;
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Axis getRotationAxis(BlockState state) {
|
public Axis getRotationAxis(BlockState state) {
|
||||||
return state.get(FACING)
|
return state.get(FACING)
|
||||||
|
@ -61,9 +106,32 @@ public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void neighborChanged(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos neighborPos,
|
||||||
|
boolean isMoving) {
|
||||||
|
DebugPacketSender.func_218806_a(world, pos);
|
||||||
|
if (world.isRemote)
|
||||||
|
return;
|
||||||
|
if (otherBlock instanceof FluidPipeBlock)
|
||||||
|
return;
|
||||||
|
TileEntity tileEntity = world.getTileEntity(pos);
|
||||||
|
if (!(tileEntity instanceof PumpTileEntity))
|
||||||
|
return;
|
||||||
|
PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
||||||
|
Direction facing = state.get(FACING);
|
||||||
|
for (boolean front : Iterate.trueAndFalse) {
|
||||||
|
Direction side = front ? facing : facing.getOpposite();
|
||||||
|
if (!pos.offset(side)
|
||||||
|
.equals(neighborPos))
|
||||||
|
continue;
|
||||||
|
pump.updatePipesOnSide(side);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IFluidState getFluidState(BlockState state) {
|
public IFluidState getFluidState(BlockState state) {
|
||||||
return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : Fluids.EMPTY.getDefaultState();
|
return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false)
|
||||||
|
: Fluids.EMPTY.getDefaultState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,15 +144,22 @@ public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable
|
||||||
public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState,
|
public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState,
|
||||||
IWorld world, BlockPos pos, BlockPos neighbourPos) {
|
IWorld world, BlockPos pos, BlockPos neighbourPos) {
|
||||||
if (state.get(BlockStateProperties.WATERLOGGED)) {
|
if (state.get(BlockStateProperties.WATERLOGGED)) {
|
||||||
world.getPendingFluidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
|
world.getPendingFluidTicks()
|
||||||
|
.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
||||||
IFluidState ifluidstate = context.getWorld().getFluidState(context.getPos());
|
IFluidState ifluidstate = context.getWorld()
|
||||||
return super.getStateForPlacement(context).with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
|
.getFluidState(context.getPos());
|
||||||
|
return super.getStateForPlacement(context).with(BlockStateProperties.WATERLOGGED,
|
||||||
|
Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPump(BlockState state) {
|
||||||
|
return state.getBlock() instanceof PumpBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class PumpRenderer extends KineticTileEntityRenderer {
|
||||||
PumpTileEntity pump = (PumpTileEntity) te;
|
PumpTileEntity pump = (PumpTileEntity) te;
|
||||||
Vec3d rotationOffset = new Vec3d(.5, 14 / 16f, .5);
|
Vec3d rotationOffset = new Vec3d(.5, 14 / 16f, .5);
|
||||||
BlockState blockState = te.getBlockState();
|
BlockState blockState = te.getBlockState();
|
||||||
float angle = MathHelper.lerp(pump.arrowDirection.get(partialTicks), 0, 90) - 90;
|
float angle = MathHelper.lerp(pump.arrowDirection.getValue(partialTicks), 0, 90) - 90;
|
||||||
for (float yRot : new float[] { 0, 90 }) {
|
for (float yRot : new float[] { 0, 90 }) {
|
||||||
ms.push();
|
ms.push();
|
||||||
SuperByteBuffer arrow = AllBlockPartials.MECHANICAL_PUMP_ARROW.renderOn(blockState);
|
SuperByteBuffer arrow = AllBlockPartials.MECHANICAL_PUMP_ARROW.renderOn(blockState);
|
||||||
|
|
|
@ -1,29 +1,349 @@
|
||||||
package com.simibubi.create.content.contraptions.fluids;
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
import java.util.ArrayList;
|
||||||
import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||||
|
|
||||||
|
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||||
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
import com.simibubi.create.foundation.utility.LerpedFloat;
|
||||||
|
import com.simibubi.create.foundation.utility.LerpedFloat.Chaser;
|
||||||
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.nbt.ListNBT;
|
||||||
import net.minecraft.tileentity.TileEntityType;
|
import net.minecraft.tileentity.TileEntityType;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraftforge.common.util.Constants.NBT;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||||
|
|
||||||
public class PumpTileEntity extends KineticTileEntity {
|
public class PumpTileEntity extends KineticTileEntity {
|
||||||
|
|
||||||
InterpolatedChasingValue arrowDirection;
|
LerpedFloat arrowDirection;
|
||||||
|
Couple<FluidNetwork> networks;
|
||||||
|
Couple<Map<BlockFace, OpenEndedPipe>> openEnds;
|
||||||
|
Couple<MutableBoolean> networksToUpdate;
|
||||||
|
|
||||||
|
boolean reversed;
|
||||||
|
FluidStack providedFluid;
|
||||||
|
|
||||||
public PumpTileEntity(TileEntityType<?> typeIn) {
|
public PumpTileEntity(TileEntityType<?> typeIn) {
|
||||||
super(typeIn);
|
super(typeIn);
|
||||||
arrowDirection = new InterpolatedChasingValue();
|
arrowDirection = LerpedFloat.linear()
|
||||||
arrowDirection.start(1);
|
.startWithValue(1);
|
||||||
|
networksToUpdate = Couple.create(MutableBoolean::new);
|
||||||
|
openEnds = Couple.create(HashMap::new);
|
||||||
|
setProvidedFluid(FluidStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
reversed = getSpeed() < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
if (world.isRemote) {
|
|
||||||
float speed = getSpeed();
|
float speed = getSpeed();
|
||||||
if (speed != 0)
|
|
||||||
arrowDirection.target(Math.signum(speed));
|
if (world.isRemote) {
|
||||||
arrowDirection.tick();
|
if (speed == 0)
|
||||||
|
return;
|
||||||
|
arrowDirection.chase(speed >= 0 ? 1 : -1, .5f, Chaser.EXP);
|
||||||
|
arrowDirection.tickChaser();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockState blockState = getBlockState();
|
||||||
|
if (!(blockState.getBlock() instanceof PumpBlock))
|
||||||
|
return;
|
||||||
|
Direction face = blockState.get(PumpBlock.FACING);
|
||||||
|
MutableBoolean networkUpdated = new MutableBoolean(false);
|
||||||
|
|
||||||
|
if (networks == null) {
|
||||||
|
networks = Couple.create(new FluidNetwork(), new FluidNetwork());
|
||||||
|
networks.forEachWithContext((fn, front) -> {
|
||||||
|
BlockFace blockFace = new BlockFace(pos, front ? face : face.getOpposite());
|
||||||
|
fn.assemble(world, this, blockFace);
|
||||||
|
FluidPropagator.showBlockFace(blockFace)
|
||||||
|
.lineWidth(1 / 8f);
|
||||||
|
});
|
||||||
|
networkUpdated.setTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
networksToUpdate.forEachWithContext((update, front) -> {
|
||||||
|
if (update.isFalse())
|
||||||
|
return;
|
||||||
|
FluidNetwork activePipeNetwork = networks.get(front);
|
||||||
|
if (activePipeNetwork == null)
|
||||||
|
return;
|
||||||
|
BlockFace blockFace = new BlockFace(pos, front ? face : face.getOpposite());
|
||||||
|
activePipeNetwork.reAssemble(world, this, blockFace);
|
||||||
|
FluidPropagator.showBlockFace(blockFace)
|
||||||
|
.lineWidth(1 / 8f);
|
||||||
|
update.setFalse();
|
||||||
|
networkUpdated.setTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (networkUpdated.isTrue())
|
||||||
|
return;
|
||||||
|
|
||||||
|
networks.forEach(fn -> fn.tick(world, this));
|
||||||
|
|
||||||
|
if (speed == 0)
|
||||||
|
return;
|
||||||
|
if (speed < 0 != reversed) {
|
||||||
|
networks.forEachWithContext((fn, current) -> fn.clearFlows(world, true));
|
||||||
|
reversed = speed < 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean pullingSide = isPullingOnSide(true);
|
||||||
|
float flowSpeed = Math.abs(speed) / 256f;
|
||||||
|
|
||||||
|
networks.forEachWithContext((fn, front) -> {
|
||||||
|
boolean pulling = isPullingOnSide(front);
|
||||||
|
fn.tickFlows(world, this, pulling, flowSpeed);
|
||||||
|
openEnds.get(front)
|
||||||
|
.values()
|
||||||
|
.forEach(oep -> oep.tick(world, pulling));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!networks.get(pullingSide)
|
||||||
|
.hasEndpoints()) {
|
||||||
|
setProvidedFluid(FluidStack.EMPTY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (networks.getFirst()
|
||||||
|
.hasEndpoints()
|
||||||
|
&& networks.getSecond()
|
||||||
|
.hasEndpoints()) {
|
||||||
|
performTransfer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
super.remove();
|
||||||
|
if (networks != null)
|
||||||
|
networks.forEachWithContext((fn, current) -> fn.clearFlows(world, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performTransfer() {
|
||||||
|
boolean input = isPullingOnSide(true);
|
||||||
|
Collection<FluidNetworkEndpoint> inputs = networks.get(input)
|
||||||
|
.getEndpoints(true);
|
||||||
|
Collection<FluidNetworkEndpoint> outputs = networks.get(!input)
|
||||||
|
.getEndpoints(false);
|
||||||
|
|
||||||
|
int flowSpeed = getFluidTransferSpeed();
|
||||||
|
FluidStack transfer = FluidStack.EMPTY;
|
||||||
|
for (boolean simulate : Iterate.trueAndFalse) {
|
||||||
|
FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE;
|
||||||
|
|
||||||
|
List<FluidNetworkEndpoint> availableInputs = new ArrayList<>(inputs);
|
||||||
|
while (!availableInputs.isEmpty() && transfer.getAmount() < flowSpeed) {
|
||||||
|
int diff = flowSpeed - transfer.getAmount();
|
||||||
|
int dividedTransfer = diff / availableInputs.size();
|
||||||
|
int remainder = diff % availableInputs.size();
|
||||||
|
|
||||||
|
for (Iterator<FluidNetworkEndpoint> iterator = availableInputs.iterator(); iterator.hasNext();) {
|
||||||
|
int toTransfer = dividedTransfer;
|
||||||
|
if (remainder > 0) {
|
||||||
|
toTransfer++;
|
||||||
|
remainder--;
|
||||||
|
}
|
||||||
|
|
||||||
|
FluidNetworkEndpoint ne = iterator.next();
|
||||||
|
IFluidHandler handler = ne.provideHandler()
|
||||||
|
.orElse(null);
|
||||||
|
if (handler == null) {
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
FluidStack drained = handler.drain(toTransfer, action);
|
||||||
|
if (drained.isEmpty()) {
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (transfer.isFluidEqual(drained) || transfer.isEmpty()) {
|
||||||
|
if (drained.getAmount() < toTransfer)
|
||||||
|
iterator.remove();
|
||||||
|
FluidStack copy = drained.copy();
|
||||||
|
copy.setAmount(drained.getAmount() + transfer.getAmount());
|
||||||
|
transfer = copy;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FluidNetworkEndpoint> availableOutputs = new ArrayList<>(outputs);
|
||||||
|
while (!availableOutputs.isEmpty() && transfer.getAmount() > 0) {
|
||||||
|
int dividedTransfer = transfer.getAmount() / availableOutputs.size();
|
||||||
|
int remainder = transfer.getAmount() % availableOutputs.size();
|
||||||
|
|
||||||
|
for (Iterator<FluidNetworkEndpoint> iterator = availableOutputs.iterator(); iterator.hasNext();) {
|
||||||
|
FluidNetworkEndpoint ne = iterator.next();
|
||||||
|
int toTransfer = dividedTransfer;
|
||||||
|
if (remainder > 0) {
|
||||||
|
toTransfer++;
|
||||||
|
remainder--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transfer.isEmpty())
|
||||||
|
break;
|
||||||
|
IFluidHandler handler = ne.provideHandler()
|
||||||
|
.orElse(null);
|
||||||
|
if (handler == null) {
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FluidStack divided = transfer.copy();
|
||||||
|
divided.setAmount(toTransfer);
|
||||||
|
int fill = handler.fill(divided, action);
|
||||||
|
transfer.setAmount(transfer.getAmount() - fill);
|
||||||
|
if (fill < toTransfer)
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
flowSpeed -= transfer.getAmount();
|
||||||
|
transfer = FluidStack.EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFluidTransferSpeed() {
|
||||||
|
float rotationSpeed = Math.abs(getSpeed());
|
||||||
|
int flowSpeed = (int) (rotationSpeed / 2f);
|
||||||
|
if (rotationSpeed != 0 && flowSpeed == 0)
|
||||||
|
flowSpeed = 1;
|
||||||
|
return flowSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
compound.putBoolean("Reversed", reversed);
|
||||||
|
serializeOpenEnds(compound);
|
||||||
|
super.write(compound, clientPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
reversed = compound.getBoolean("Reversed");
|
||||||
|
deserializeOpenEnds(compound);
|
||||||
|
super.read(compound, clientPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updatePipesOnSide(Direction side) {
|
||||||
|
if (!isSideAccessible(side))
|
||||||
|
return;
|
||||||
|
updatePipeNetwork(isFront(side));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isFront(Direction side) {
|
||||||
|
if (networks == null)
|
||||||
|
return false;
|
||||||
|
BlockState blockState = getBlockState();
|
||||||
|
if (!(blockState.getBlock() instanceof PumpBlock))
|
||||||
|
return false;
|
||||||
|
Direction front = blockState.get(PumpBlock.FACING);
|
||||||
|
boolean isFront = side == front;
|
||||||
|
return isFront;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updatePipeNetwork(boolean front) {
|
||||||
|
if (networks != null)
|
||||||
|
networks.get(front)
|
||||||
|
.clearFlows(world, true);
|
||||||
|
networksToUpdate.get(front)
|
||||||
|
.setTrue();
|
||||||
|
if (getSpeed() == 0 || (isPullingOnSide(front)) && networks != null)
|
||||||
|
setProvidedFluid(FluidStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSideAccessible(Direction side) {
|
||||||
|
BlockState blockState = getBlockState();
|
||||||
|
if (!(blockState.getBlock() instanceof PumpBlock))
|
||||||
|
return false;
|
||||||
|
return blockState.get(PumpBlock.FACING)
|
||||||
|
.getAxis() == side.getAxis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPullingOnSide(boolean front) {
|
||||||
|
return front == reversed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<BlockFace, OpenEndedPipe> getOpenEnds(Direction side) {
|
||||||
|
return openEnds.get(isFront(side));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void serializeOpenEnds(CompoundNBT compound) {
|
||||||
|
compound.put("OpenEnds", openEnds.serializeEach(m -> {
|
||||||
|
CompoundNBT compoundNBT = new CompoundNBT();
|
||||||
|
ListNBT entries = new ListNBT();
|
||||||
|
m.entrySet()
|
||||||
|
.forEach(e -> {
|
||||||
|
CompoundNBT innerCompound = new CompoundNBT();
|
||||||
|
innerCompound.put("Pos", e.getKey()
|
||||||
|
.serializeNBT());
|
||||||
|
e.getValue()
|
||||||
|
.writeToNBT(innerCompound);
|
||||||
|
entries.add(innerCompound);
|
||||||
|
});
|
||||||
|
compoundNBT.put("Entries", entries);
|
||||||
|
return compoundNBT;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deserializeOpenEnds(CompoundNBT compound) {
|
||||||
|
openEnds = Couple.deserializeEach(compound.getList("OpenEnds", NBT.TAG_COMPOUND), c -> {
|
||||||
|
Map<BlockFace, OpenEndedPipe> map = new HashMap<>();
|
||||||
|
NBTHelper.iterateCompoundList(c.getList("Entries", NBT.TAG_COMPOUND), innerCompound -> {
|
||||||
|
BlockFace key = BlockFace.fromNBT(innerCompound.getCompound("Pos"));
|
||||||
|
OpenEndedPipe value = new OpenEndedPipe(key);
|
||||||
|
value.readNBT(innerCompound);
|
||||||
|
map.put(key, value);
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
|
||||||
|
compound.put("OpenEnds", openEnds.serializeEach(m -> {
|
||||||
|
CompoundNBT compoundNBT = new CompoundNBT();
|
||||||
|
ListNBT entries = new ListNBT();
|
||||||
|
m.entrySet()
|
||||||
|
.forEach(e -> {
|
||||||
|
CompoundNBT innerCompound = new CompoundNBT();
|
||||||
|
innerCompound.put("Pos", e.getKey()
|
||||||
|
.serializeNBT());
|
||||||
|
e.getValue()
|
||||||
|
.writeToNBT(innerCompound);
|
||||||
|
entries.add(innerCompound);
|
||||||
|
});
|
||||||
|
compoundNBT.put("Entries", entries);
|
||||||
|
return compoundNBT;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProvidedFluid(FluidStack providedFluid) {
|
||||||
|
this.providedFluid = providedFluid;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,8 +118,8 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
inputItemInventory.deserializeNBT(compound.getCompound("InputItems"));
|
inputItemInventory.deserializeNBT(compound.getCompound("InputItems"));
|
||||||
outputItemInventory.deserializeNBT(compound.getCompound("OutputItems"));
|
outputItemInventory.deserializeNBT(compound.getCompound("OutputItems"));
|
||||||
if (compound.contains("fluids"))
|
if (compound.contains("fluids"))
|
||||||
|
@ -128,15 +128,14 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
compound.put("InputItems", inputItemInventory.serializeNBT());
|
compound.put("InputItems", inputItemInventory.serializeNBT());
|
||||||
compound.put("OutputItems", outputItemInventory.serializeNBT());
|
compound.put("OutputItems", outputItemInventory.serializeNBT());
|
||||||
fluidInventory.ifPresent(combinedFuidHandler -> {
|
fluidInventory.ifPresent(combinedFuidHandler -> {
|
||||||
ListNBT nbt = combinedFuidHandler.getListNBT();
|
ListNBT nbt = combinedFuidHandler.getListNBT();
|
||||||
compound.put("fluids", nbt);
|
compound.put("fluids", nbt);
|
||||||
});
|
});
|
||||||
return compound;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onEmptied() {
|
public void onEmptied() {
|
||||||
|
|
|
@ -155,17 +155,17 @@ public class BlazeBurnerTileEntity extends SmartTileEntity {
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putInt("fuelLevel", activeFuel.ordinal());
|
compound.putInt("fuelLevel", activeFuel.ordinal());
|
||||||
compound.putInt("burnTimeRemaining", remainingBurnTime);
|
compound.putInt("burnTimeRemaining", remainingBurnTime);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
activeFuel = FuelType.values()[compound.getInt("fuelLevel")];
|
activeFuel = FuelType.values()[compound.getInt("fuelLevel")];
|
||||||
remainingBurnTime = compound.getInt("burnTimeRemaining");
|
remainingBurnTime = compound.getInt("burnTimeRemaining");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -103,21 +103,21 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putInt("InstructionIndex", currentInstruction);
|
compound.putInt("InstructionIndex", currentInstruction);
|
||||||
compound.putInt("InstructionDuration", currentInstructionDuration);
|
compound.putInt("InstructionDuration", currentInstructionDuration);
|
||||||
compound.putInt("Timer", timer);
|
compound.putInt("Timer", timer);
|
||||||
compound.put("Instructions", Instruction.serializeAll(instructions));
|
compound.put("Instructions", Instruction.serializeAll(instructions));
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
currentInstruction = compound.getInt("InstructionIndex");
|
currentInstruction = compound.getInt("InstructionIndex");
|
||||||
currentInstructionDuration = compound.getInt("InstructionDuration");
|
currentInstructionDuration = compound.getInt("InstructionDuration");
|
||||||
timer = compound.getInt("Timer");
|
timer = compound.getInt("Timer");
|
||||||
instructions = Instruction.deserializeAll(compound.getList("Instructions", NBT.TAG_COMPOUND));
|
instructions = Instruction.deserializeAll(compound.getList("Instructions", NBT.TAG_COMPOUND));
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -79,8 +79,7 @@ public class BeltTileEntity extends KineticTileEntity {
|
||||||
@Override
|
@Override
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||||
super.addBehaviours(behaviours);
|
super.addBehaviours(behaviours);
|
||||||
behaviours.add(new DirectBeltInputBehaviour(this)
|
behaviours.add(new DirectBeltInputBehaviour(this).setInsertionHandler(this::tryInsertingFromSide));
|
||||||
.setInsertionHandler(this::tryInsertingFromSide));
|
|
||||||
behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems)
|
behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems)
|
||||||
.withStackPlacement(this::getWorldPositionOf));
|
.withStackPlacement(this::getWorldPositionOf));
|
||||||
}
|
}
|
||||||
|
@ -175,7 +174,7 @@ public class BeltTileEntity extends KineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
if (controller != null)
|
if (controller != null)
|
||||||
compound.put("Controller", NBTUtil.writeBlockPos(controller));
|
compound.put("Controller", NBTUtil.writeBlockPos(controller));
|
||||||
compound.putBoolean("IsController", isController());
|
compound.putBoolean("IsController", isController());
|
||||||
|
@ -186,23 +185,12 @@ public class BeltTileEntity extends KineticTileEntity {
|
||||||
|
|
||||||
if (isController())
|
if (isController())
|
||||||
compound.put("Inventory", getInventory().write());
|
compound.put("Inventory", getInventory().write());
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
CasingType casingBefore = casing;
|
super.read(compound, clientPacket);
|
||||||
super.readClientUpdate(tag);
|
|
||||||
if (casingBefore != casing) {
|
|
||||||
requestModelDataUpdate();
|
|
||||||
if (hasWorld())
|
|
||||||
world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void read(CompoundNBT compound) {
|
|
||||||
super.read(compound);
|
|
||||||
|
|
||||||
if (compound.getBoolean("IsController"))
|
if (compound.getBoolean("IsController"))
|
||||||
controller = pos;
|
controller = pos;
|
||||||
|
@ -219,7 +207,16 @@ public class BeltTileEntity extends KineticTileEntity {
|
||||||
if (isController())
|
if (isController())
|
||||||
getInventory().read(compound.getCompound("Inventory"));
|
getInventory().read(compound.getCompound("Inventory"));
|
||||||
|
|
||||||
|
CasingType casingBefore = casing;
|
||||||
casing = NBTHelper.readEnum(compound, "Casing", CasingType.class);
|
casing = NBTHelper.readEnum(compound, "Casing", CasingType.class);
|
||||||
|
|
||||||
|
if (!clientPacket)
|
||||||
|
return;
|
||||||
|
if (casingBefore == casing)
|
||||||
|
return;
|
||||||
|
requestModelDataUpdate();
|
||||||
|
if (hasWorld())
|
||||||
|
world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -406,7 +403,8 @@ public class BeltTileEntity extends KineticTileEntity {
|
||||||
if (teAbove instanceof BrassTunnelTileEntity) {
|
if (teAbove instanceof BrassTunnelTileEntity) {
|
||||||
BrassTunnelTileEntity tunnelTE = (BrassTunnelTileEntity) teAbove;
|
BrassTunnelTileEntity tunnelTE = (BrassTunnelTileEntity) teAbove;
|
||||||
if (tunnelTE.hasDistributionBehaviour()) {
|
if (tunnelTE.hasDistributionBehaviour()) {
|
||||||
if (!tunnelTE.getStackToDistribute().isEmpty())
|
if (!tunnelTE.getStackToDistribute()
|
||||||
|
.isEmpty())
|
||||||
return inserted;
|
return inserted;
|
||||||
if (!tunnelTE.testFlapFilter(side.getOpposite(), inserted))
|
if (!tunnelTE.testFlapFilter(side.getOpposite(), inserted))
|
||||||
return inserted;
|
return inserted;
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package com.simibubi.create.content.contraptions.relays.encased;
|
package com.simibubi.create.content.contraptions.relays.encased;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock;
|
import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock;
|
||||||
|
|
||||||
import mcp.MethodsReturnNonnullByDefault;
|
import mcp.MethodsReturnNonnullByDefault;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
@ -11,8 +14,6 @@ import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.IWorldReader;
|
import net.minecraft.world.IWorldReader;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@MethodsReturnNonnullByDefault
|
@MethodsReturnNonnullByDefault
|
||||||
public abstract class AbstractEncasedShaftBlock extends RotatedPillarKineticBlock {
|
public abstract class AbstractEncasedShaftBlock extends RotatedPillarKineticBlock {
|
||||||
public AbstractEncasedShaftBlock(Properties properties) {
|
public AbstractEncasedShaftBlock(Properties properties) {
|
||||||
|
@ -30,7 +31,6 @@ public abstract class AbstractEncasedShaftBlock extends RotatedPillarKineticBloc
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public PushReaction getPushReaction(@Nullable BlockState state) {
|
public PushReaction getPushReaction(@Nullable BlockState state) {
|
||||||
return PushReaction.PUSH_ONLY;
|
return PushReaction.PUSH_ONLY;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,15 @@ public class AdjustablePulleyTileEntity extends KineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putInt("Signal", signal);
|
compound.putInt("Signal", signal);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
signal = compound.getInt("Signal");
|
signal = compound.getInt("Signal");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getModifier() {
|
public float getModifier() {
|
||||||
|
|
|
@ -15,10 +15,8 @@ import net.minecraft.state.BooleanProperty;
|
||||||
import net.minecraft.state.StateContainer.Builder;
|
import net.minecraft.state.StateContainer.Builder;
|
||||||
import net.minecraft.state.properties.BlockStateProperties;
|
import net.minecraft.state.properties.BlockStateProperties;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.Direction;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.IBlockReader;
|
import net.minecraft.world.IBlockReader;
|
||||||
import net.minecraft.world.IWorldReader;
|
|
||||||
import net.minecraft.world.TickPriority;
|
import net.minecraft.world.TickPriority;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.server.ServerWorld;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
|
|
|
@ -21,17 +21,17 @@ public class GaugeTileEntity extends KineticTileEntity implements IHaveGoggleInf
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putFloat("Value", dialTarget);
|
compound.putFloat("Value", dialTarget);
|
||||||
compound.putInt("Color", color);
|
compound.putInt("Color", color);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
dialTarget = compound.getFloat("Value");
|
dialTarget = compound.getFloat("Value");
|
||||||
color = compound.getInt("Color");
|
color = compound.getInt("Color");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -73,15 +73,15 @@ public class BeltObserverTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putInt("TurnOff", turnOffTicks);
|
compound.putInt("TurnOff", turnOffTicks);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
turnOffTicks = compound.getInt("TurnOff");
|
turnOffTicks = compound.getInt("TurnOff");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,16 +52,32 @@ public class BeltTunnelTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
ListNBT flapsNBT = new ListNBT();
|
ListNBT flapsNBT = new ListNBT();
|
||||||
for (Direction direction : flaps.keySet())
|
for (Direction direction : flaps.keySet())
|
||||||
flapsNBT.add(IntNBT.of(direction.getIndex()));
|
flapsNBT.add(IntNBT.of(direction.getIndex()));
|
||||||
compound.put("Flaps", flapsNBT);
|
compound.put("Flaps", flapsNBT);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
|
|
||||||
|
if (!clientPacket)
|
||||||
|
return;
|
||||||
|
|
||||||
|
flapsNBT = new ListNBT();
|
||||||
|
if (!flapsToSend.isEmpty()) {
|
||||||
|
for (Pair<Direction, Boolean> pair : flapsToSend) {
|
||||||
|
CompoundNBT flap = new CompoundNBT();
|
||||||
|
flap.putInt("Flap", pair.getKey()
|
||||||
|
.getIndex());
|
||||||
|
flap.putBoolean("FlapInward", pair.getValue());
|
||||||
|
flapsNBT.add(flap);
|
||||||
|
}
|
||||||
|
compound.put("TriggerFlaps", flapsNBT);
|
||||||
|
flapsToSend.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
Set<Direction> newFlaps = new HashSet<>(6);
|
Set<Direction> newFlaps = new HashSet<>(6);
|
||||||
ListNBT flapsNBT = compound.getList("Flaps", NBT.TAG_INT);
|
ListNBT flapsNBT = compound.getList("Flaps", NBT.TAG_INT);
|
||||||
for (INBT inbt : flapsNBT)
|
for (INBT inbt : flapsNBT)
|
||||||
|
@ -76,39 +92,19 @@ public class BeltTunnelTileEntity extends SmartTileEntity {
|
||||||
.target(0)
|
.target(0)
|
||||||
.withSpeed(.05f));
|
.withSpeed(.05f));
|
||||||
|
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (!clientPacket)
|
||||||
public CompoundNBT writeToClient(CompoundNBT tag) {
|
return;
|
||||||
CompoundNBT writeToClient = super.writeToClient(tag);
|
if (!compound.contains("TriggerFlaps"))
|
||||||
if (!flapsToSend.isEmpty()) {
|
return;
|
||||||
ListNBT flapsNBT = new ListNBT();
|
flapsNBT = compound.getList("TriggerFlaps", NBT.TAG_COMPOUND);
|
||||||
for (Pair<Direction, Boolean> pair : flapsToSend) {
|
|
||||||
CompoundNBT flap = new CompoundNBT();
|
|
||||||
flap.putInt("Flap", pair.getKey()
|
|
||||||
.getIndex());
|
|
||||||
flap.putBoolean("FlapInward", pair.getValue());
|
|
||||||
flapsNBT.add(flap);
|
|
||||||
}
|
|
||||||
writeToClient.put("TriggerFlaps", flapsNBT);
|
|
||||||
flapsToSend.clear();
|
|
||||||
}
|
|
||||||
return writeToClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
|
||||||
super.readClientUpdate(tag);
|
|
||||||
if (tag.contains("TriggerFlaps")) {
|
|
||||||
ListNBT flapsNBT = tag.getList("TriggerFlaps", NBT.TAG_COMPOUND);
|
|
||||||
for (INBT inbt : flapsNBT) {
|
for (INBT inbt : flapsNBT) {
|
||||||
CompoundNBT flap = (CompoundNBT) inbt;
|
CompoundNBT flap = (CompoundNBT) inbt;
|
||||||
Direction side = Direction.byIndex(flap.getInt("Flap"));
|
Direction side = Direction.byIndex(flap.getInt("Flap"));
|
||||||
flap(side, flap.getBoolean("FlapInward"));
|
flap(side, flap.getBoolean("FlapInward"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void updateTunnelConnections() {
|
public void updateTunnelConnections() {
|
||||||
flaps.clear();
|
flaps.clear();
|
||||||
|
|
|
@ -328,7 +328,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putBoolean("ConnectedLeft", connectedLeft);
|
compound.putBoolean("ConnectedLeft", connectedLeft);
|
||||||
compound.putBoolean("ConnectedRight", connectedRight);
|
compound.putBoolean("ConnectedRight", connectedRight);
|
||||||
|
|
||||||
|
@ -344,14 +344,16 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
|
||||||
return nbt;
|
return nbt;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
boolean wasConnectedLeft = connectedLeft;
|
||||||
|
boolean wasConnectedRight = connectedRight;
|
||||||
|
|
||||||
connectedLeft = compound.getBoolean("ConnectedLeft");
|
connectedLeft = compound.getBoolean("ConnectedLeft");
|
||||||
connectedRight = compound.getBoolean("ConnectedRight");
|
connectedRight = compound.getBoolean("ConnectedRight");
|
||||||
|
|
||||||
stackToDistribute = ItemStack.read(compound.getCompound("StackToDistribute"));
|
stackToDistribute = ItemStack.read(compound.getCompound("StackToDistribute"));
|
||||||
distributionProgress = compound.getFloat("DistributionProgress");
|
distributionProgress = compound.getFloat("DistributionProgress");
|
||||||
distributionDistanceLeft = compound.getInt("DistanceLeft");
|
distributionDistanceLeft = compound.getInt("DistanceLeft");
|
||||||
|
@ -362,14 +364,10 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity {
|
||||||
return Pair.of(pos, face);
|
return Pair.of(pos, face);
|
||||||
});
|
});
|
||||||
|
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (!clientPacket)
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
return;
|
||||||
boolean wasConnectedLeft = connectedLeft;
|
|
||||||
boolean wasConnectedRight = connectedRight;
|
|
||||||
super.readClientUpdate(tag);
|
|
||||||
if (wasConnectedLeft != connectedLeft || wasConnectedRight != connectedRight) {
|
if (wasConnectedLeft != connectedLeft || wasConnectedRight != connectedRight) {
|
||||||
requestModelDataUpdate();
|
requestModelDataUpdate();
|
||||||
if (hasWorld())
|
if (hasWorld())
|
||||||
|
|
|
@ -277,22 +277,22 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.put("Item", item.serializeNBT());
|
compound.put("Item", item.serializeNBT());
|
||||||
compound.putFloat("ItemPosition", itemPosition.value);
|
compound.putFloat("ItemPosition", itemPosition.value);
|
||||||
compound.putFloat("Pull", pull);
|
compound.putFloat("Pull", pull);
|
||||||
compound.putFloat("Push", push);
|
compound.putFloat("Push", push);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
ItemStack previousItem = item;
|
ItemStack previousItem = item;
|
||||||
item = ItemStack.read(compound.getCompound("Item"));
|
item = ItemStack.read(compound.getCompound("Item"));
|
||||||
itemPosition.lastValue = itemPosition.value = compound.getFloat("ItemPosition");
|
itemPosition.lastValue = itemPosition.value = compound.getFloat("ItemPosition");
|
||||||
pull = compound.getFloat("Pull");
|
pull = compound.getFloat("Pull");
|
||||||
push = compound.getFloat("Push");
|
push = compound.getFloat("Push");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
|
|
||||||
if (hasWorld() && world.isRemote && !previousItem.equals(item, false) && !item.isEmpty()) {
|
if (hasWorld() && world.isRemote && !previousItem.equals(item, false) && !item.isEmpty()) {
|
||||||
if (world.rand.nextInt(3) != 0)
|
if (world.rand.nextInt(3) != 0)
|
||||||
|
|
|
@ -93,20 +93,20 @@ public class DepotTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
if (heldItem != null)
|
if (heldItem != null)
|
||||||
compound.put("HeldItem", heldItem.serializeNBT());
|
compound.put("HeldItem", heldItem.serializeNBT());
|
||||||
compound.put("OutputBuffer", processingOutputBuffer.serializeNBT());
|
compound.put("OutputBuffer", processingOutputBuffer.serializeNBT());
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
heldItem = null;
|
heldItem = null;
|
||||||
if (compound.contains("HeldItem"))
|
if (compound.contains("HeldItem"))
|
||||||
heldItem = TransportedItemStack.read(compound.getCompound("HeldItem"));
|
heldItem = TransportedItemStack.read(compound.getCompound("HeldItem"));
|
||||||
processingOutputBuffer.deserializeNBT(compound.getCompound("OutputBuffer"));
|
processingOutputBuffer.deserializeNBT(compound.getCompound("OutputBuffer"));
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -43,17 +43,17 @@ public class AdjustableRepeaterTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
state = compound.getInt("State");
|
state = compound.getInt("State");
|
||||||
charging = compound.getBoolean("Charging");
|
charging = compound.getBoolean("Charging");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putInt("State", state);
|
compound.putInt("State", state);
|
||||||
compound.putBoolean("Charging", charging);
|
compound.putBoolean("Charging", charging);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int step(StepContext context) {
|
private int step(StepContext context) {
|
||||||
|
|
|
@ -220,21 +220,21 @@ public class FunnelTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
protected void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
if (sendFlap != 0) {
|
super.write(compound, clientPacket);
|
||||||
|
if (clientPacket && sendFlap != 0) {
|
||||||
compound.putInt("Flap", sendFlap);
|
compound.putInt("Flap", sendFlap);
|
||||||
sendFlap = 0;
|
sendFlap = 0;
|
||||||
}
|
}
|
||||||
return super.writeToClient(compound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
if (tag.contains("Flap")) {
|
super.read(compound, clientPacket);
|
||||||
int direction = tag.getInt("Flap");
|
if (clientPacket && compound.contains("Flap")) {
|
||||||
|
int direction = compound.getInt("Flap");
|
||||||
flap.set(direction);
|
flap.set(direction);
|
||||||
}
|
}
|
||||||
super.readClientUpdate(tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -142,18 +142,18 @@ public class AdjustableCrateTileEntity extends CrateTileEntity implements INamed
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putBoolean("Main", true);
|
compound.putBoolean("Main", true);
|
||||||
compound.putInt("AllowedAmount", allowedAmount);
|
compound.putInt("AllowedAmount", allowedAmount);
|
||||||
compound.put("Inventory", inventory.serializeNBT());
|
compound.put("Inventory", inventory.serializeNBT());
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
allowedAmount = compound.getInt("AllowedAmount");
|
allowedAmount = compound.getInt("AllowedAmount");
|
||||||
inventory.deserializeNBT(compound.getCompound("Inventory"));
|
inventory.deserializeNBT(compound.getCompound("Inventory"));
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -272,8 +272,8 @@ public class ArmTileEntity extends KineticTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
|
|
||||||
ListNBT pointsNBT = new ListNBT();
|
ListNBT pointsNBT = new ListNBT();
|
||||||
inputs.stream()
|
inputs.stream()
|
||||||
|
@ -288,31 +288,23 @@ public class ArmTileEntity extends KineticTileEntity {
|
||||||
compound.put("HeldItem", heldItem.serializeNBT());
|
compound.put("HeldItem", heldItem.serializeNBT());
|
||||||
compound.putInt("TargetPointIndex", chasedPointIndex);
|
compound.putInt("TargetPointIndex", chasedPointIndex);
|
||||||
compound.putFloat("MovementProgress", chasedPointProgress);
|
compound.putFloat("MovementProgress", chasedPointProgress);
|
||||||
return compound;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
super.writeToClient(compound);
|
int previousIndex = chasedPointIndex;
|
||||||
return compound;
|
Phase previousPhase = phase;
|
||||||
}
|
ListNBT interactionPointTagBefore = interactionPointTag;
|
||||||
|
|
||||||
@Override
|
super.read(compound, clientPacket);
|
||||||
public void read(CompoundNBT compound) {
|
|
||||||
super.read(compound);
|
|
||||||
heldItem = ItemStack.read(compound.getCompound("HeldItem"));
|
heldItem = ItemStack.read(compound.getCompound("HeldItem"));
|
||||||
phase = NBTHelper.readEnum(compound, "Phase", Phase.class);
|
phase = NBTHelper.readEnum(compound, "Phase", Phase.class);
|
||||||
chasedPointIndex = compound.getInt("TargetPointIndex");
|
chasedPointIndex = compound.getInt("TargetPointIndex");
|
||||||
chasedPointProgress = compound.getFloat("MovementProgress");
|
chasedPointProgress = compound.getFloat("MovementProgress");
|
||||||
interactionPointTag = compound.getList("InteractionPoints", NBT.TAG_COMPOUND);
|
interactionPointTag = compound.getList("InteractionPoints", NBT.TAG_COMPOUND);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (!clientPacket)
|
||||||
public void readClientUpdate(CompoundNBT tag) {
|
return;
|
||||||
int previousIndex = chasedPointIndex;
|
|
||||||
Phase previousPhase = phase;
|
|
||||||
ListNBT interactionPointTagBefore = interactionPointTag;
|
|
||||||
super.readClientUpdate(tag);
|
|
||||||
|
|
||||||
boolean ceiling = isOnCeiling();
|
boolean ceiling = isOnCeiling();
|
||||||
if (interactionPointTagBefore == null || interactionPointTagBefore.size() != interactionPointTag.size())
|
if (interactionPointTagBefore == null || interactionPointTagBefore.size() != interactionPointTag.size())
|
||||||
|
|
|
@ -23,18 +23,18 @@ public class AnalogLeverTileEntity extends SmartTileEntity implements IHaveGoggl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putInt("State", state);
|
compound.putInt("State", state);
|
||||||
compound.putInt("ChangeTimer", lastChange);
|
compound.putInt("ChangeTimer", lastChange);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
state = compound.getInt("State");
|
state = compound.getInt("State");
|
||||||
lastChange = compound.getInt("ChangeTimer");
|
lastChange = compound.getInt("ChangeTimer");
|
||||||
clientState.target(state);
|
clientState.target(state);
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -64,18 +64,18 @@ public class RedstoneLinkTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putBoolean("Transmitter", transmitter);
|
compound.putBoolean("Transmitter", transmitter);
|
||||||
compound.putInt("Receive", getReceivedSignal());
|
compound.putInt("Receive", getReceivedSignal());
|
||||||
compound.putBoolean("ReceivedChanged", receivedSignalChanged);
|
compound.putBoolean("ReceivedChanged", receivedSignalChanged);
|
||||||
compound.putInt("Transmit", transmittedSignal);
|
compound.putInt("Transmit", transmittedSignal);
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
transmitter = compound.getBoolean("Transmitter");
|
transmitter = compound.getBoolean("Transmitter");
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
|
|
||||||
receivedSignal = compound.getInt("Receive");
|
receivedSignal = compound.getInt("Receive");
|
||||||
receivedSignalChanged = compound.getBoolean("ReceivedChanged");
|
receivedSignalChanged = compound.getBoolean("ReceivedChanged");
|
||||||
|
|
|
@ -36,25 +36,23 @@ public class StockpileSwitchTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
|
||||||
onWhenAbove = compound.getFloat("OnAbove");
|
onWhenAbove = compound.getFloat("OnAbove");
|
||||||
offWhenBelow = compound.getFloat("OffBelow");
|
offWhenBelow = compound.getFloat("OffBelow");
|
||||||
currentLevel = compound.getFloat("Current");
|
currentLevel = compound.getFloat("Current");
|
||||||
powered = compound.getBoolean("Powered");
|
powered = compound.getBoolean("Powered");
|
||||||
|
|
||||||
super.read(compound);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
|
||||||
compound.putFloat("OnAbove", onWhenAbove);
|
compound.putFloat("OnAbove", onWhenAbove);
|
||||||
compound.putFloat("OffBelow", offWhenBelow);
|
compound.putFloat("OffBelow", offWhenBelow);
|
||||||
compound.putFloat("Current", currentLevel);
|
compound.putFloat("Current", currentLevel);
|
||||||
compound.putBoolean("Powered", powered);
|
compound.putBoolean("Powered", powered);
|
||||||
|
|
||||||
return super.write(compound);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getLevel() {
|
public float getLevel() {
|
||||||
|
|
|
@ -6,7 +6,6 @@ import static net.minecraft.util.text.TextFormatting.GRAY;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
|
||||||
import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket.Option;
|
import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket.Option;
|
||||||
import com.simibubi.create.foundation.gui.AbstractSimiContainerScreen;
|
import com.simibubi.create.foundation.gui.AbstractSimiContainerScreen;
|
||||||
import com.simibubi.create.foundation.gui.AllGuiTextures;
|
import com.simibubi.create.foundation.gui.AllGuiTextures;
|
||||||
|
@ -20,7 +19,6 @@ import com.simibubi.create.foundation.item.TooltipHelper;
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
|
|
||||||
import net.minecraft.client.gui.widget.Widget;
|
import net.minecraft.client.gui.widget.Widget;
|
||||||
import net.minecraft.client.renderer.RenderHelper;
|
|
||||||
import net.minecraft.client.resources.I18n;
|
import net.minecraft.client.resources.I18n;
|
||||||
import net.minecraft.entity.player.PlayerInventory;
|
import net.minecraft.entity.player.PlayerInventory;
|
||||||
import net.minecraft.util.text.ITextComponent;
|
import net.minecraft.util.text.ITextComponent;
|
||||||
|
|
|
@ -7,9 +7,9 @@ import com.simibubi.create.AllBlocks;
|
||||||
import com.simibubi.create.AllItems;
|
import com.simibubi.create.AllItems;
|
||||||
import com.simibubi.create.AllSoundEvents;
|
import com.simibubi.create.AllSoundEvents;
|
||||||
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock;
|
import com.simibubi.create.content.contraptions.relays.belt.BeltBlock;
|
||||||
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
|
|
||||||
import com.simibubi.create.content.contraptions.relays.belt.BeltPart;
|
import com.simibubi.create.content.contraptions.relays.belt.BeltPart;
|
||||||
import com.simibubi.create.content.contraptions.relays.belt.BeltSlope;
|
import com.simibubi.create.content.contraptions.relays.belt.BeltSlope;
|
||||||
|
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock;
|
import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock;
|
||||||
import com.simibubi.create.content.schematics.ItemRequirement;
|
import com.simibubi.create.content.schematics.ItemRequirement;
|
||||||
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
|
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
|
||||||
|
@ -162,19 +162,13 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
if (!clientPacket) {
|
||||||
inventory.deserializeNBT(compound.getCompound("Inventory"));
|
inventory.deserializeNBT(compound.getCompound("Inventory"));
|
||||||
|
|
||||||
if (compound.contains("CurrentPos"))
|
if (compound.contains("CurrentPos"))
|
||||||
currentPos = NBTUtil.readBlockPos(compound.getCompound("CurrentPos"));
|
currentPos = NBTUtil.readBlockPos(compound.getCompound("CurrentPos"));
|
||||||
|
|
||||||
readClientUpdate(compound);
|
|
||||||
super.read(compound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readClientUpdate(CompoundNBT compound) {
|
|
||||||
|
|
||||||
// Gui information
|
// Gui information
|
||||||
statusMsg = compound.getString("Status");
|
statusMsg = compound.getString("Status");
|
||||||
schematicProgress = compound.getFloat("Progress");
|
schematicProgress = compound.getFloat("Progress");
|
||||||
|
@ -201,6 +195,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
||||||
if (compound.contains("FlyingBlocks"))
|
if (compound.contains("FlyingBlocks"))
|
||||||
readFlyingBlocks(compound);
|
readFlyingBlocks(compound);
|
||||||
|
|
||||||
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void readFlyingBlocks(CompoundNBT compound) {
|
protected void readFlyingBlocks(CompoundNBT compound) {
|
||||||
|
@ -239,22 +234,16 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
if (!clientPacket) {
|
||||||
compound.put("Inventory", inventory.serializeNBT());
|
compound.put("Inventory", inventory.serializeNBT());
|
||||||
|
|
||||||
if (state == State.RUNNING) {
|
if (state == State.RUNNING) {
|
||||||
compound.putBoolean("Running", true);
|
compound.putBoolean("Running", true);
|
||||||
if (currentPos != null)
|
if (currentPos != null)
|
||||||
compound.put("CurrentPos", NBTUtil.writeBlockPos(currentPos));
|
compound.put("CurrentPos", NBTUtil.writeBlockPos(currentPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
writeToClient(compound);
|
|
||||||
return super.write(compound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
|
||||||
|
|
||||||
// Gui information
|
// Gui information
|
||||||
compound.putFloat("Progress", schematicProgress);
|
compound.putFloat("Progress", schematicProgress);
|
||||||
compound.putFloat("PaperProgress", bookPrintingProgress);
|
compound.putFloat("PaperProgress", bookPrintingProgress);
|
||||||
|
@ -283,7 +272,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
||||||
tagBlocks.add(b.serializeNBT());
|
tagBlocks.add(b.serializeNBT());
|
||||||
compound.put("FlyingBlocks", tagBlocks);
|
compound.put("FlyingBlocks", tagBlocks);
|
||||||
|
|
||||||
return compound;
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,6 +4,7 @@ public class CFluids extends ConfigBase {
|
||||||
|
|
||||||
public ConfigInt fluidTankCapacity = i(8, 1, "fluidTankCapacity", Comments.buckets, Comments.fluidTankCapacity);
|
public ConfigInt fluidTankCapacity = i(8, 1, "fluidTankCapacity", Comments.buckets, Comments.fluidTankCapacity);
|
||||||
public ConfigInt fluidTankMaxHeight = i(32, 1, "fluidTankMaxHeight", Comments.blocks, Comments.fluidTankMaxHeight);
|
public ConfigInt fluidTankMaxHeight = i(32, 1, "fluidTankMaxHeight", Comments.blocks, Comments.fluidTankMaxHeight);
|
||||||
|
public ConfigInt mechanicalPumpRange = i(16, 1, "mechanicalPumpRange", Comments.blocks, Comments.mechanicalPumpRange);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -15,6 +16,7 @@ public class CFluids extends ConfigBase {
|
||||||
static String buckets = "[in Buckets]";
|
static String buckets = "[in Buckets]";
|
||||||
static String fluidTankCapacity = "The amount of liquid a tank can hold per block.";
|
static String fluidTankCapacity = "The amount of liquid a tank can hold per block.";
|
||||||
static String fluidTankMaxHeight = "The maximum height a fluid tank can reach.";
|
static String fluidTankMaxHeight = "The maximum height a fluid tank can reach.";
|
||||||
|
static String mechanicalPumpRange = "The maximum distance a mechanical pump can push or pull liquids on either side.";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,10 @@ package com.simibubi.create.foundation.fluid;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import net.minecraft.fluid.Fluid;
|
||||||
|
import net.minecraft.fluid.Fluids;
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fluids.ForgeFlowingFluid;
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
|
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
|
||||||
|
@ -13,6 +16,34 @@ public class FluidHelper {
|
||||||
ITEM_TO_TANK, TANK_TO_ITEM;
|
ITEM_TO_TANK, TANK_TO_ITEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isWater(Fluid fluid) {
|
||||||
|
return convertToStill(fluid) == Fluids.WATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLava(Fluid fluid) {
|
||||||
|
return convertToStill(fluid) == Fluids.LAVA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Fluid convertToFlowing(Fluid fluid) {
|
||||||
|
if (fluid == Fluids.WATER)
|
||||||
|
return Fluids.FLOWING_WATER;
|
||||||
|
if (fluid == Fluids.LAVA)
|
||||||
|
return Fluids.FLOWING_LAVA;
|
||||||
|
if (fluid instanceof ForgeFlowingFluid)
|
||||||
|
return ((ForgeFlowingFluid) fluid).getFlowingFluid();
|
||||||
|
return fluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Fluid convertToStill(Fluid fluid) {
|
||||||
|
if (fluid == Fluids.FLOWING_WATER)
|
||||||
|
return Fluids.WATER;
|
||||||
|
if (fluid == Fluids.FLOWING_LAVA)
|
||||||
|
return Fluids.LAVA;
|
||||||
|
if (fluid instanceof ForgeFlowingFluid)
|
||||||
|
return ((ForgeFlowingFluid) fluid).getStillFluid();
|
||||||
|
return fluid;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static FluidExchange exchange(IFluidHandler fluidTank, IFluidHandlerItem fluidItem, FluidExchange preferred,
|
public static FluidExchange exchange(IFluidHandler fluidTank, IFluidHandlerItem fluidItem, FluidExchange preferred,
|
||||||
int maxAmount) {
|
int maxAmount) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.simibubi.create.foundation.fluid;
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack.Entry;
|
import com.mojang.blaze3d.matrix.MatrixStack.Entry;
|
||||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||||
|
import com.simibubi.create.foundation.utility.ColorHelper;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
import com.simibubi.create.foundation.utility.MatrixStacker;
|
import com.simibubi.create.foundation.utility.MatrixStacker;
|
||||||
|
|
||||||
|
@ -62,8 +63,9 @@ public class FluidRenderer {
|
||||||
.translateBack(center);
|
.translateBack(center);
|
||||||
|
|
||||||
boolean X = side.getAxis() == Axis.X;
|
boolean X = side.getAxis() == Axis.X;
|
||||||
|
int darkColor = ColorHelper.mixColors(color, 0xff000011, 1/4f);
|
||||||
renderTiledHorizontalFace(X ? xMax : zMax, side, X ? zMin : xMin, yMin, X ? zMax : xMax, yMax, builder,
|
renderTiledHorizontalFace(X ? xMax : zMax, side, X ? zMin : xMin, yMin, X ? zMax : xMax, yMax, builder,
|
||||||
ms, light, color, fluidTexture);
|
ms, light, darkColor, fluidTexture);
|
||||||
|
|
||||||
ms.pop();
|
ms.pop();
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
package com.simibubi.create.foundation.tileEntity;
|
|
||||||
|
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
|
||||||
import net.minecraft.tileentity.TileEntityType;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
|
|
||||||
public abstract class PosBoundSmartTileEntity extends SmartTileEntity {
|
|
||||||
|
|
||||||
private boolean newPositionVisited;
|
|
||||||
|
|
||||||
public PosBoundSmartTileEntity(TileEntityType<?> tileEntityTypeIn) {
|
|
||||||
super(tileEntityTypeIn);
|
|
||||||
newPositionVisited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
if (!world.isRemote && newPositionVisited) {
|
|
||||||
newPositionVisited = false;
|
|
||||||
initInNewPosition();
|
|
||||||
}
|
|
||||||
super.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void read(CompoundNBT compound) {
|
|
||||||
long positionInTag = new BlockPos(compound.getInt("x"), compound.getInt("y"), compound.getInt("z")).toLong();
|
|
||||||
long positionKey = compound.getLong("BoundPosition");
|
|
||||||
|
|
||||||
newPositionVisited = false;
|
|
||||||
if (!hasWorld() || !world.isRemote) {
|
|
||||||
if (positionInTag != positionKey) {
|
|
||||||
removePositionDependentData(compound);
|
|
||||||
newPositionVisited = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.read(compound);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Server-only. When this TE realizes, that it's reading its tag in a different
|
|
||||||
* position, it should remove all position dependent information here.
|
|
||||||
*
|
|
||||||
* @param nbt
|
|
||||||
*/
|
|
||||||
protected void removePositionDependentData(CompoundNBT nbt) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Server-only. When a TE has been created or moved, it will call this before the
|
|
||||||
* regular init.
|
|
||||||
*/
|
|
||||||
protected void initInNewPosition() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -38,8 +38,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
|
||||||
* Gets called just before reading tile data for behaviours. Register anything
|
* Gets called just before reading tile data for behaviours. Register anything
|
||||||
* here that depends on your custom te data.
|
* here that depends on your custom te data.
|
||||||
*/
|
*/
|
||||||
public void addBehavioursDeferred(List<TileEntityBehaviour> behaviours) {
|
public void addBehavioursDeferred(List<TileEntityBehaviour> behaviours) {}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
|
@ -53,44 +52,61 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
|
||||||
lazyTick();
|
lazyTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
behaviours.values().forEach(TileEntityBehaviour::tick);
|
behaviours.values()
|
||||||
|
.forEach(TileEntityBehaviour::tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
behaviours.values().forEach(TileEntityBehaviour::initialize);
|
behaviours.values()
|
||||||
|
.forEach(TileEntityBehaviour::initialize);
|
||||||
lazyTick();
|
lazyTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateClient(CompoundNBT compound) {
|
@Override
|
||||||
behaviours.values().forEach(tb -> tb.updateClient(compound));
|
public final CompoundNBT write(CompoundNBT compound) {
|
||||||
|
write(compound, false);
|
||||||
|
return compound;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT write(CompoundNBT compound) {
|
public final CompoundNBT writeToClient(CompoundNBT compound) {
|
||||||
behaviours.values().forEach(tb -> tb.writeNBT(compound));
|
write(compound, true);
|
||||||
return super.write(compound);
|
return compound;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
public final void readClientUpdate(CompoundNBT tag) {
|
||||||
behaviours.values().forEach(tb -> tb.writeToClient(compound));
|
read(tag, true);
|
||||||
return super.writeToClient(compound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(CompoundNBT compound) {
|
public final void read(CompoundNBT tag) {
|
||||||
|
read(tag, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook only these in future subclasses of STE
|
||||||
|
*/
|
||||||
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
if (firstNbtRead) {
|
if (firstNbtRead) {
|
||||||
firstNbtRead = false;
|
firstNbtRead = false;
|
||||||
ArrayList<TileEntityBehaviour> list = new ArrayList<>();
|
ArrayList<TileEntityBehaviour> list = new ArrayList<>();
|
||||||
addBehavioursDeferred(list);
|
addBehavioursDeferred(list);
|
||||||
list.forEach(b -> behaviours.put(b.getType(), b));
|
list.forEach(b -> behaviours.put(b.getType(), b));
|
||||||
}
|
}
|
||||||
|
|
||||||
super.read(compound);
|
super.read(compound);
|
||||||
forEachBehaviour(tb -> tb.readNBT(compound));
|
behaviours.values()
|
||||||
|
.forEach(tb -> tb.read(compound, clientPacket));
|
||||||
|
}
|
||||||
|
|
||||||
if (world != null && world.isRemote)
|
|
||||||
updateClient(compound);
|
/**
|
||||||
|
* Hook only these in future subclasses of STE
|
||||||
|
*/
|
||||||
|
protected void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
|
super.write(compound);
|
||||||
|
behaviours.values()
|
||||||
|
.forEach(tb -> tb.write(compound, clientPacket));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,7 +125,8 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void forEachBehaviour(Consumer<TileEntityBehaviour> action) {
|
protected void forEachBehaviour(Consumer<TileEntityBehaviour> action) {
|
||||||
behaviours.values().forEach(tb -> {
|
behaviours.values()
|
||||||
|
.forEach(tb -> {
|
||||||
if (!tb.isPaused())
|
if (!tb.isPaused())
|
||||||
action.accept(tb);
|
action.accept(tb);
|
||||||
});
|
});
|
||||||
|
|
|
@ -37,15 +37,11 @@ public abstract class TileEntityBehaviour {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readNBT(CompoundNBT nbt) {
|
public void read(CompoundNBT nbt, boolean clientPacket) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateClient(CompoundNBT nbt) {
|
public void write(CompoundNBT nbt, boolean clientPacket) {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeNBT(CompoundNBT nbt) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,8 +107,4 @@ public abstract class TileEntityBehaviour {
|
||||||
return ste.getBehaviour(type);
|
return ste.getBehaviour(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
|
||||||
return compound;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,30 +52,26 @@ public class FilteringBehaviour extends TileEntityBehaviour {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeNBT(CompoundNBT nbt) {
|
public void write(CompoundNBT nbt, boolean clientPacket) {
|
||||||
nbt.put("Filter", getFilter().serializeNBT());
|
nbt.put("Filter", getFilter().serializeNBT());
|
||||||
nbt.putInt("FilterAmount", count);
|
nbt.putInt("FilterAmount", count);
|
||||||
super.writeNBT(nbt);
|
|
||||||
|
if (clientPacket && forceClientState) {
|
||||||
|
nbt.putBoolean("ForceScrollable", true);
|
||||||
|
forceClientState = false;
|
||||||
|
}
|
||||||
|
super.write(nbt, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readNBT(CompoundNBT nbt) {
|
public void read(CompoundNBT nbt, boolean clientPacket) {
|
||||||
filter = ItemStack.read(nbt.getCompound("Filter"));
|
filter = ItemStack.read(nbt.getCompound("Filter"));
|
||||||
count = nbt.getInt("FilterAmount");
|
count = nbt.getInt("FilterAmount");
|
||||||
if (nbt.contains("ForceScrollable")) {
|
if (nbt.contains("ForceScrollable")) {
|
||||||
scrollableValue = count;
|
scrollableValue = count;
|
||||||
ticksUntilScrollPacket = -1;
|
ticksUntilScrollPacket = -1;
|
||||||
}
|
}
|
||||||
super.readNBT(nbt);
|
super.read(nbt, clientPacket);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
|
||||||
if (forceClientState) {
|
|
||||||
compound.putBoolean("ForceScrollable", true);
|
|
||||||
forceClientState = false;
|
|
||||||
}
|
|
||||||
return super.writeToClient(compound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -59,40 +59,27 @@ public class SidedFilteringBehaviour extends FilteringBehaviour {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeNBT(CompoundNBT nbt) {
|
public void write(CompoundNBT nbt, boolean clientPacket) {
|
||||||
nbt.put("Filters", NBTHelper.writeCompoundList(sidedFilters.entrySet(), entry -> {
|
nbt.put("Filters", NBTHelper.writeCompoundList(sidedFilters.entrySet(), entry -> {
|
||||||
CompoundNBT compound = new CompoundNBT();
|
CompoundNBT compound = new CompoundNBT();
|
||||||
compound.putInt("Side", entry.getKey()
|
compound.putInt("Side", entry.getKey()
|
||||||
.getIndex());
|
.getIndex());
|
||||||
entry.getValue()
|
entry.getValue()
|
||||||
.writeNBT(compound);
|
.write(compound, clientPacket);
|
||||||
return compound;
|
return compound;
|
||||||
}));
|
}));
|
||||||
super.writeNBT(nbt);
|
super.write(nbt, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readNBT(CompoundNBT nbt) {
|
public void read(CompoundNBT nbt, boolean clientPacket) {
|
||||||
NBTHelper.iterateCompoundList(nbt.getList("Filters", NBT.TAG_COMPOUND), compound -> {
|
NBTHelper.iterateCompoundList(nbt.getList("Filters", NBT.TAG_COMPOUND), compound -> {
|
||||||
Direction face = Direction.byIndex(compound.getInt("Side"));
|
Direction face = Direction.byIndex(compound.getInt("Side"));
|
||||||
if (sidedFilters.containsKey(face))
|
if (sidedFilters.containsKey(face))
|
||||||
sidedFilters.get(face)
|
sidedFilters.get(face)
|
||||||
.readNBT(compound);
|
.read(compound, clientPacket);
|
||||||
});
|
});
|
||||||
super.readNBT(nbt);
|
super.read(nbt, clientPacket);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompoundNBT writeToClient(CompoundNBT nbt) {
|
|
||||||
nbt.put("Filters", NBTHelper.writeCompoundList(sidedFilters.entrySet(), entry -> {
|
|
||||||
CompoundNBT compound = new CompoundNBT();
|
|
||||||
compound.putInt("Side", entry.getKey()
|
|
||||||
.getIndex());
|
|
||||||
entry.getValue()
|
|
||||||
.writeToClient(compound);
|
|
||||||
return compound;
|
|
||||||
}));
|
|
||||||
return super.writeToClient(nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,15 +33,15 @@ public class SingleTargetAutoExtractingBehaviour extends AutoExtractingBehaviour
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeNBT(CompoundNBT nbt) {
|
public void write(CompoundNBT nbt, boolean clientPacket) {
|
||||||
nbt.putBoolean("Advantage", advantageOnNextSync);
|
nbt.putBoolean("Advantage", advantageOnNextSync);
|
||||||
super.writeNBT(nbt);
|
super.write(nbt, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readNBT(CompoundNBT nbt) {
|
public void read(CompoundNBT nbt, boolean clientPacket) {
|
||||||
advantageOnNextSync = nbt.getBoolean("Advantage");
|
advantageOnNextSync = nbt.getBoolean("Advantage");
|
||||||
super.readNBT(nbt);
|
super.read(nbt, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -116,26 +116,26 @@ public class LinkBehaviour extends TileEntityBehaviour {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeNBT(CompoundNBT compound) {
|
public void write(CompoundNBT nbt, boolean clientPacket) {
|
||||||
super.writeNBT(compound);
|
super.write(nbt, clientPacket);
|
||||||
compound.put("FrequencyFirst", frequencyFirst.getStack()
|
nbt.put("FrequencyFirst", frequencyFirst.getStack()
|
||||||
.write(new CompoundNBT()));
|
.write(new CompoundNBT()));
|
||||||
compound.put("FrequencyLast", frequencyLast.getStack()
|
nbt.put("FrequencyLast", frequencyLast.getStack()
|
||||||
.write(new CompoundNBT()));
|
.write(new CompoundNBT()));
|
||||||
compound.putLong("LastKnownPosition", tileEntity.getPos()
|
nbt.putLong("LastKnownPosition", tileEntity.getPos()
|
||||||
.toLong());
|
.toLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readNBT(CompoundNBT compound) {
|
public void read(CompoundNBT nbt, boolean clientPacket) {
|
||||||
long positionInTag = tileEntity.getPos()
|
long positionInTag = tileEntity.getPos()
|
||||||
.toLong();
|
.toLong();
|
||||||
long positionKey = compound.getLong("LastKnownPosition");
|
long positionKey = nbt.getLong("LastKnownPosition");
|
||||||
newPosition = positionInTag != positionKey;
|
newPosition = positionInTag != positionKey;
|
||||||
|
|
||||||
super.readNBT(compound);
|
super.read(nbt, clientPacket);
|
||||||
frequencyFirst = new Frequency(ItemStack.read(compound.getCompound("FrequencyFirst")));
|
frequencyFirst = new Frequency(ItemStack.read(nbt.getCompound("FrequencyFirst")));
|
||||||
frequencyLast = new Frequency(ItemStack.read(compound.getCompound("FrequencyLast")));
|
frequencyLast = new Frequency(ItemStack.read(nbt.getCompound("FrequencyLast")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFrequency(boolean first, ItemStack stack) {
|
public void setFrequency(boolean first, ItemStack stack) {
|
||||||
|
|
|
@ -51,28 +51,23 @@ public class ScrollValueBehaviour extends TileEntityBehaviour {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeNBT(CompoundNBT nbt) {
|
public void write(CompoundNBT nbt, boolean clientPacket) {
|
||||||
nbt.putInt("ScrollValue", value);
|
nbt.putInt("ScrollValue", value);
|
||||||
super.writeNBT(nbt);
|
if (clientPacket && forceClientState) {
|
||||||
|
nbt.putBoolean("ForceScrollable", true);
|
||||||
|
forceClientState = false;
|
||||||
|
}
|
||||||
|
super.write(nbt, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readNBT(CompoundNBT nbt) {
|
public void read(CompoundNBT nbt, boolean clientPacket) {
|
||||||
value = nbt.getInt("ScrollValue");
|
value = nbt.getInt("ScrollValue");
|
||||||
if (nbt.contains("ForceScrollable")) {
|
if (nbt.contains("ForceScrollable")) {
|
||||||
ticksUntilScrollPacket = -1;
|
ticksUntilScrollPacket = -1;
|
||||||
scrollableValue = value;
|
scrollableValue = value;
|
||||||
}
|
}
|
||||||
super.readNBT(nbt);
|
super.read(nbt, clientPacket);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompoundNBT writeToClient(CompoundNBT compound) {
|
|
||||||
if (forceClientState) {
|
|
||||||
compound.putBoolean("ForceScrollable", true);
|
|
||||||
forceClientState = false;
|
|
||||||
}
|
|
||||||
return super.writeToClient(compound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,15 +21,15 @@ public class DeferralBehaviour extends TileEntityBehaviour {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeNBT(CompoundNBT nbt) {
|
public void write(CompoundNBT nbt, boolean clientPacket) {
|
||||||
nbt.putBoolean("NeedsUpdate", needsUpdate);
|
nbt.putBoolean("NeedsUpdate", needsUpdate);
|
||||||
super.writeNBT(nbt);
|
super.write(nbt, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readNBT(CompoundNBT nbt) {
|
public void read(CompoundNBT nbt, boolean clientPacket) {
|
||||||
needsUpdate = nbt.getBoolean("NeedsUpdate");
|
needsUpdate = nbt.getBoolean("NeedsUpdate");
|
||||||
super.readNBT(nbt);
|
super.read(nbt, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,21 +1,10 @@
|
||||||
package com.simibubi.create.foundation.utility;
|
package com.simibubi.create.foundation.utility;
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.Vector3f;
|
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.Direction.Axis;
|
import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
|
|
||||||
public class AngleHelper {
|
public class AngleHelper {
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static void applyRotation(Direction direction, MatrixStack ms) {
|
|
||||||
ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(AngleHelper.horizontalAngle(direction)));
|
|
||||||
ms.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(AngleHelper.verticalAngle(direction)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float horizontalAngle(Direction facing) {
|
public static float horizontalAngle(Direction facing) {
|
||||||
float angle = facing.getHorizontalAngle();
|
float angle = facing.getHorizontalAngle();
|
||||||
if (facing.getAxis() == Axis.X)
|
if (facing.getAxis() == Axis.X)
|
||||||
|
@ -39,8 +28,8 @@ public class AngleHelper {
|
||||||
return (float) (angle * 180 / Math.PI);
|
return (float) (angle * 180 / Math.PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float angleLerp(float pct, float current, float target) {
|
public static float angleLerp(double pct, double current, double target) {
|
||||||
return current + getShortestAngleDiff(current, target) * pct;
|
return (float) (current + getShortestAngleDiff(current, target) * pct);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float getShortestAngleDiff(double current, double target) {
|
public static float getShortestAngleDiff(double current, double target) {
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.simibubi.create.foundation.utility;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.nbt.NBTUtil;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
|
public class BlockFace extends Pair<BlockPos, Direction> {
|
||||||
|
|
||||||
|
public BlockFace(BlockPos first, Direction second) {
|
||||||
|
super(first, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEquivalent(BlockFace other) {
|
||||||
|
if (equals(other))
|
||||||
|
return true;
|
||||||
|
return getConnectedPos().equals(other.getPos()) && getPos().equals(other.getConnectedPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockPos getPos() {
|
||||||
|
return getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Direction getFace() {
|
||||||
|
return getSecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Direction getOppositeFace() {
|
||||||
|
return getSecond().getOpposite();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFace getOpposite() {
|
||||||
|
return new BlockFace(getConnectedPos(), getOppositeFace());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockPos getConnectedPos() {
|
||||||
|
return getPos().offset(getFace());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundNBT serializeNBT() {
|
||||||
|
CompoundNBT compoundNBT = new CompoundNBT();
|
||||||
|
compoundNBT.put("Pos", NBTUtil.writeBlockPos(getPos()));
|
||||||
|
NBTHelper.writeEnum(compoundNBT, "Face", getFace());
|
||||||
|
return compoundNBT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockFace fromNBT(CompoundNBT compound) {
|
||||||
|
return new BlockFace(NBTUtil.readBlockPos(compound.getCompound("Pos")),
|
||||||
|
NBTHelper.readEnum(compound, "Face", Direction.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,10 +1,17 @@
|
||||||
package com.simibubi.create.foundation.utility;
|
package com.simibubi.create.foundation.utility;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.nbt.ListNBT;
|
||||||
|
|
||||||
public class Couple<T> extends Pair<T, T> {
|
public class Couple<T> extends Pair<T, T> {
|
||||||
|
|
||||||
private static Couple<Boolean> TRUE_AND_FALSE = Couple.create(true, false);
|
private static Couple<Boolean> TRUE_AND_FALSE = Couple.create(true, false);
|
||||||
|
@ -17,6 +24,10 @@ public class Couple<T> extends Pair<T, T> {
|
||||||
return new Couple<>(first, second);
|
return new Couple<>(first, second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> Couple<T> create(Supplier<T> factory) {
|
||||||
|
return new Couple<>(factory.get(), factory.get());
|
||||||
|
}
|
||||||
|
|
||||||
public T get(boolean first) {
|
public T get(boolean first) {
|
||||||
return first ? getFirst() : getSecond();
|
return first ? getFirst() : getSecond();
|
||||||
}
|
}
|
||||||
|
@ -69,4 +80,13 @@ public class Couple<T> extends Pair<T, T> {
|
||||||
return Couple.create(second, first);
|
return Couple.create(second, first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ListNBT serializeEach(Function<T, CompoundNBT> serializer) {
|
||||||
|
return NBTHelper.writeCompoundList(ImmutableList.of(first, second), serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <S> Couple<S> deserializeEach(ListNBT list, Function<CompoundNBT, S> deserializer) {
|
||||||
|
List<S> readCompoundList = NBTHelper.readCompoundList(list, deserializer);
|
||||||
|
return new Couple<>(readCompoundList.get(0), readCompoundList.get(1));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
package com.simibubi.create.foundation.utility;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
// Can replace all Interpolated value classes
|
||||||
|
// InterpolatedChasingValue, InterpolatedValue, InterpolatedChasingAngle, InterpolatedAngle
|
||||||
|
public class LerpedFloat {
|
||||||
|
|
||||||
|
Interpolater interpolater;
|
||||||
|
float previousValue;
|
||||||
|
float value;
|
||||||
|
|
||||||
|
Chaser chaseFunction;
|
||||||
|
float chaseTarget;
|
||||||
|
float chaseSpeed;
|
||||||
|
|
||||||
|
boolean forcedSync;
|
||||||
|
|
||||||
|
public LerpedFloat(Interpolater interpolater) {
|
||||||
|
this.interpolater = interpolater;
|
||||||
|
startWithValue(0);
|
||||||
|
forcedSync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LerpedFloat linear() {
|
||||||
|
return new LerpedFloat((p, c, t) -> (float) MathHelper.lerp(p, c, t));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LerpedFloat angular() {
|
||||||
|
return new LerpedFloat(AngleHelper::angleLerp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LerpedFloat startWithValue(double value) {
|
||||||
|
float f = (float) value;
|
||||||
|
this.previousValue = f;
|
||||||
|
this.chaseTarget = f;
|
||||||
|
this.value = f;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LerpedFloat chase(double value, double speed, Chaser chaseFunction) {
|
||||||
|
this.chaseTarget = (float) value;
|
||||||
|
this.chaseSpeed = (float) speed;
|
||||||
|
this.chaseFunction = chaseFunction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean updateChaseSpeed(double speed) {
|
||||||
|
float prevSpeed = this.chaseSpeed;
|
||||||
|
this.chaseSpeed = (float) speed;
|
||||||
|
return !MathHelper.epsilonEquals(prevSpeed, speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tickChaser() {
|
||||||
|
previousValue = value;
|
||||||
|
if (chaseFunction == null)
|
||||||
|
return;
|
||||||
|
if (MathHelper.epsilonEquals((double) value, chaseTarget)) {
|
||||||
|
value = chaseTarget;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
value = chaseFunction.chase(value, chaseSpeed, chaseTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(double value) {
|
||||||
|
this.previousValue = this.value;
|
||||||
|
this.value = (float) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getValue() {
|
||||||
|
return getValue(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getValue(float partialTicks) {
|
||||||
|
return MathHelper.lerp(partialTicks, previousValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getChaseTarget() {
|
||||||
|
return chaseTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forceNextSync() {
|
||||||
|
forcedSync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundNBT writeNBT() {
|
||||||
|
CompoundNBT compoundNBT = new CompoundNBT();
|
||||||
|
compoundNBT.putFloat("Speed", chaseSpeed);
|
||||||
|
compoundNBT.putFloat("Target", chaseTarget);
|
||||||
|
compoundNBT.putFloat("Value", value);
|
||||||
|
if (forcedSync)
|
||||||
|
compoundNBT.putBoolean("Force", true);
|
||||||
|
forcedSync = false;
|
||||||
|
return compoundNBT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readNBT(CompoundNBT compoundNBT, boolean clientPacket) {
|
||||||
|
if (!clientPacket || compoundNBT.contains("Force"))
|
||||||
|
startWithValue(compoundNBT.getFloat("Value"));
|
||||||
|
readChaser(compoundNBT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readChaser(CompoundNBT compoundNBT) {
|
||||||
|
chaseSpeed = compoundNBT.getFloat("Speed");
|
||||||
|
chaseTarget = compoundNBT.getFloat("Target");
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Interpolater {
|
||||||
|
float interpolate(double progress, double current, double target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Chaser {
|
||||||
|
|
||||||
|
public static final Chaser IDLE = (c, s, t) -> (float) c;
|
||||||
|
public static final Chaser EXP = exp(Double.MAX_VALUE);
|
||||||
|
public static final Chaser LINEAR = (c, s, t) -> (float) (c + MathHelper.clamp(t - c, -s, s));
|
||||||
|
|
||||||
|
public static Chaser exp(double maxEffectiveSpeed) {
|
||||||
|
return (c, s, t) -> (float) (c + MathHelper.clamp((t - c) * s, -maxEffectiveSpeed, maxEffectiveSpeed));
|
||||||
|
}
|
||||||
|
|
||||||
|
float chase(double current, double speed, double target);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -68,11 +68,15 @@ public class VecHelper {
|
||||||
vec.z + (r.nextFloat() - .5f) * 2 * radius);
|
vec.z + (r.nextFloat() - .5f) * 2 * radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vec3d planeByNormal(Vec3d vec) {
|
public static Vec3d axisAlingedPlaneOf(Vec3d vec) {
|
||||||
vec = vec.normalize();
|
vec = vec.normalize();
|
||||||
return new Vec3d(1, 1, 1).subtract(Math.abs(vec.x), Math.abs(vec.y), Math.abs(vec.z));
|
return new Vec3d(1, 1, 1).subtract(Math.abs(vec.x), Math.abs(vec.y), Math.abs(vec.z));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vec3d axisAlingedPlaneOf(Direction face) {
|
||||||
|
return axisAlingedPlaneOf(new Vec3d(face.getDirectionVec()));
|
||||||
|
}
|
||||||
|
|
||||||
public static ListNBT writeNBT(Vec3d vec) {
|
public static ListNBT writeNBT(Vec3d vec) {
|
||||||
ListNBT listnbt = new ListNBT();
|
ListNBT listnbt = new ListNBT();
|
||||||
listnbt.add(DoubleNBT.of(vec.x));
|
listnbt.add(DoubleNBT.of(vec.x));
|
||||||
|
@ -114,6 +118,11 @@ public class VecHelper {
|
||||||
.scale(maxLength) : vec;
|
.scale(maxLength) : vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vec3d clampComponentWise(Vec3d vec, float maxLength) {
|
||||||
|
return new Vec3d(MathHelper.clamp(vec.x, -maxLength, maxLength), MathHelper.clamp(vec.y, -maxLength, maxLength),
|
||||||
|
MathHelper.clamp(vec.z, -maxLength, maxLength));
|
||||||
|
}
|
||||||
|
|
||||||
public static Vec3d project(Vec3d vec, Vec3d ontoVec) {
|
public static Vec3d project(Vec3d vec, Vec3d ontoVec) {
|
||||||
if (ontoVec.equals(Vec3d.ZERO))
|
if (ontoVec.equals(Vec3d.ZERO))
|
||||||
return Vec3d.ZERO;
|
return Vec3d.ZERO;
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class BlockClusterOutline extends Outline {
|
||||||
|
|
||||||
Vec3d center = VecHelper.getCenterOf(pos);
|
Vec3d center = VecHelper.getCenterOf(pos);
|
||||||
Vec3d offset = new Vec3d(face.getDirectionVec());
|
Vec3d offset = new Vec3d(face.getDirectionVec());
|
||||||
Vec3d plane = VecHelper.planeByNormal(offset);
|
Vec3d plane = VecHelper.axisAlingedPlaneOf(offset);
|
||||||
Axis axis = face.getAxis();
|
Axis axis = face.getAxis();
|
||||||
|
|
||||||
offset = offset.scale(1 / 2f + 1 / 64d);
|
offset = offset.scale(1 / 2f + 1 / 64d);
|
||||||
|
|
|
@ -61,7 +61,7 @@ public abstract class Outline {
|
||||||
float lineWidth = params.getLineWidth();
|
float lineWidth = params.getLineWidth();
|
||||||
Vec3d extension = diff.normalize()
|
Vec3d extension = diff.normalize()
|
||||||
.scale(lineWidth / 2);
|
.scale(lineWidth / 2);
|
||||||
Vec3d plane = VecHelper.planeByNormal(diff);
|
Vec3d plane = VecHelper.axisAlingedPlaneOf(diff);
|
||||||
Direction face = Direction.getFacingFromVector(diff.x, diff.y, diff.z);
|
Direction face = Direction.getFacingFromVector(diff.x, diff.y, diff.z);
|
||||||
Axis axis = face.getAxis();
|
Axis axis = face.getAxis();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.simibubi.create.foundation.utility.outliner;
|
package com.simibubi.create.foundation.utility.outliner;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -110,7 +111,7 @@ public class Outliner {
|
||||||
// Maintenance
|
// Maintenance
|
||||||
|
|
||||||
public Outliner() {
|
public Outliner() {
|
||||||
outlines = new HashMap<>();
|
outlines = Collections.synchronizedMap(new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tickOutlines() {
|
public void tickOutlines() {
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
"advancement.create.electron_tube": "Beep boop",
|
"advancement.create.electron_tube": "Beep boop",
|
||||||
"advancement.create.electron_tube.desc": "Make some Electron Tubes, useful in crafting less primitive machinery.",
|
"advancement.create.electron_tube.desc": "Make some Electron Tubes, useful in crafting less primitive machinery.",
|
||||||
"advancement.create.mechanical_saw": "Stationary Chopping",
|
"advancement.create.mechanical_saw": "Stationary Chopping",
|
||||||
"advancement.create.mechanical_saw.desc": "Place and power a Mechanical mechanical_saw",
|
"advancement.create.mechanical_saw.desc": "Place and power a Mechanical Saw",
|
||||||
"advancement.create.basin": "Basin Operation",
|
"advancement.create.basin": "Basin Operation",
|
||||||
"advancement.create.basin.desc": "Place a basin and try throwing items into it.",
|
"advancement.create.basin.desc": "Place a basin and try throwing items into it.",
|
||||||
"advancement.create.mixer": "Mixin' it Up",
|
"advancement.create.mixer": "Mixin' it Up",
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"death.attack.create.fan_fire": "%1$s was burned to death by hot air",
|
"death.attack.create.fan_fire": "%1$s was burned to death by hot air",
|
||||||
"death.attack.create.fan_lava": "%1$s was burned to death by lava fan",
|
"death.attack.create.fan_lava": "%1$s was burned to death by lava fan",
|
||||||
"death.attack.create.mechanical_drill": "%1$s was impaled by Mechanical mechanical_drill",
|
"death.attack.create.mechanical_drill": "%1$s was impaled by Mechanical mechanical_drill",
|
||||||
"death.attack.create.mechanical_saw": "%1$s got cut in half by Mechanical mechanical_saw",
|
"death.attack.create.mechanical_saw": "%1$s got cut in half by Mechanical Saw",
|
||||||
"death.attack.create.cuckoo_clock_explosion": "%1$s was blown up by tampered cuckoo clock",
|
"death.attack.create.cuckoo_clock_explosion": "%1$s was blown up by tampered cuckoo clock",
|
||||||
"create.block.deployer.damage_source_name": "a rogue Deployer",
|
"create.block.deployer.damage_source_name": "a rogue Deployer",
|
||||||
"create.block.cart_assembler.invalid": "Place your Cart Assembler on a rail block",
|
"create.block.cart_assembler.invalid": "Place your Cart Assembler on a rail block",
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
"create.recipe.pressing": "Pressing",
|
"create.recipe.pressing": "Pressing",
|
||||||
"create.recipe.mixing": "Mixing",
|
"create.recipe.mixing": "Mixing",
|
||||||
"create.recipe.packing": "Compacting",
|
"create.recipe.packing": "Compacting",
|
||||||
"create.recipe.mechanical_sawing": "mechanical_sawing",
|
"create.recipe.mechanical_sawing": "Sawing",
|
||||||
"create.recipe.mechanical_crafting": "Mechanical Crafting",
|
"create.recipe.mechanical_crafting": "Mechanical Crafting",
|
||||||
"create.recipe.block_cutting": "Block Cutting",
|
"create.recipe.block_cutting": "Block Cutting",
|
||||||
"create.recipe.blockzapper_upgrade": "Handheld Blockzapper",
|
"create.recipe.blockzapper_upgrade": "Handheld Blockzapper",
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
"to": [12, 12, 12],
|
"to": [12, 12, 12],
|
||||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]},
|
"rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]},
|
||||||
"faces": {
|
"faces": {
|
||||||
"north": {"uv": [0, 8, 4, 12], "texture": "#3"},
|
"north": {"uv": [0, 6, 4, 10], "texture": "#3"},
|
||||||
"east": {"uv": [0, 8, 4, 12], "texture": "#3"},
|
"east": {"uv": [0, 6, 4, 10], "texture": "#3"},
|
||||||
"south": {"uv": [0, 8, 4, 12], "texture": "#3"},
|
"south": {"uv": [0, 6, 4, 10], "texture": "#3"},
|
||||||
"west": {"uv": [0, 8, 4, 12], "texture": "#3"}
|
"west": {"uv": [0, 6, 4, 10], "texture": "#3"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -76,20 +76,6 @@
|
||||||
"up": {"uv": [0, 6, 6, 8.5], "rotation": 180, "texture": "#5"},
|
"up": {"uv": [0, 6, 6, 8.5], "rotation": 180, "texture": "#5"},
|
||||||
"down": {"uv": [0, 6, 6, 8.5], "texture": "#5"}
|
"down": {"uv": [0, 6, 6, 8.5], "texture": "#5"}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "GearCaseOuter",
|
|
||||||
"from": [4, 4, 4.5],
|
|
||||||
"to": [12, 12, 11.5],
|
|
||||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 6.5]},
|
|
||||||
"faces": {
|
|
||||||
"north": {"uv": [1, 1, 5, 5], "rotation": 180, "texture": "#5"},
|
|
||||||
"east": {"uv": [6, 4.5, 10, 8], "rotation": 270, "texture": "#5"},
|
|
||||||
"south": {"uv": [1, 1, 5, 5], "texture": "#5"},
|
|
||||||
"west": {"uv": [6, 4.5, 10, 8], "rotation": 90, "texture": "#5"},
|
|
||||||
"up": {"uv": [6, 4.5, 10, 8], "rotation": 180, "texture": "#5"},
|
|
||||||
"down": {"uv": [6, 4.5, 10, 8], "texture": "#5"}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"display": {
|
"display": {
|
||||||
|
@ -130,7 +116,7 @@
|
||||||
{
|
{
|
||||||
"name": "cogwheel",
|
"name": "cogwheel",
|
||||||
"origin": [8, 8, 8],
|
"origin": [8, 8, 8],
|
||||||
"children": [0, 1, 2, 3, 4, 5]
|
"children": [0, 1, 2, 3, 4]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
Binary file not shown.
After Width: | Height: | Size: 148 B |
Loading…
Add table
Reference in a new issue