private void TryPullFrom(BlockFacing inputFace) { BlockPos InputPosition = Pos.AddCopy(inputFace); if (Api.World.BlockAccessor.GetBlockEntity(InputPosition) is BlockEntityContainer beContainer) { //do not both push and pull across the same chute-chute connection if (beContainer.Block is BlockChute chute) { string[] pushFaces = chute.Attributes["pushFaces"].AsArray <string>(null); if (pushFaces?.Contains(inputFace.Opposite.Code) == true) { return; } } ItemSlot sourceSlot = beContainer.Inventory.GetAutoPullFromSlot(inputFace.Opposite); ItemSlot targetSlot = sourceSlot == null ? null : inventory.GetBestSuitedSlot(sourceSlot).slot; BlockEntityItemFlow beFlow = beContainer as BlockEntityItemFlow; if (sourceSlot != null && targetSlot != null && (beFlow == null || targetSlot.Empty)) { ItemStackMoveOperation op = new ItemStackMoveOperation(Api.World, EnumMouseButton.Left, 0, EnumMergePriority.DirectMerge, (int)itemFlowAccum); int horTravelled = sourceSlot.Itemstack.Attributes.GetInt("chuteQHTravelled"); if (horTravelled < 2) { int qmoved = sourceSlot.TryPutInto(targetSlot, ref op); if (qmoved > 0) { if (beFlow != null) { targetSlot.Itemstack.Attributes.SetInt("chuteQHTravelled", inputFace.IsHorizontal ? (horTravelled + 1): 0); targetSlot.Itemstack.Attributes.SetInt("chuteDir", inputFace.Opposite.Index); } else { targetSlot.Itemstack.Attributes.RemoveAttribute("chuteQHTravelled"); targetSlot.Itemstack.Attributes.RemoveAttribute("chuteDir"); } sourceSlot.MarkDirty(); targetSlot.MarkDirty(); MarkDirty(false); beFlow?.MarkDirty(); } if (qmoved > 0 && Api.World.Rand.NextDouble() < 0.2) { Api.World.PlaySoundAt(hopperTumble, Pos.X + 0.5, Pos.Y + 0.5, Pos.Z + 0.5, null, true, 8, 0.5f); itemFlowAccum -= qmoved; } } } } }
private bool TryPushInto(BlockFacing outputFace) { BlockPos OutputPosition = Pos.AddCopy(outputFace); if (Api.World.BlockAccessor.GetBlockEntity(OutputPosition) is BlockEntityContainer beContainer) { ItemSlot sourceSlot = inventory.FirstOrDefault(slot => !slot.Empty); if ((sourceSlot?.Itemstack?.StackSize ?? 0) == 0) { return(false); //seems FirstOrDefault() method can sometimes give a slot with stacksize == 0, weird } int horTravelled = sourceSlot.Itemstack.Attributes.GetInt("chuteQHTravelled"); int chuteDir = sourceSlot.Itemstack.Attributes.GetInt("chuteDir"); sourceSlot.Itemstack.Attributes.RemoveAttribute("chuteQHTravelled"); sourceSlot.Itemstack.Attributes.RemoveAttribute("chuteDir"); if (horTravelled >= 2) { return(false); //chutes can't move items more than 1 block horizontally without a drop } ItemSlot targetSlot = beContainer.Inventory.GetAutoPushIntoSlot(outputFace.Opposite, sourceSlot); BlockEntityItemFlow beFlow = beContainer as BlockEntityItemFlow; if (targetSlot != null && (beFlow == null || targetSlot.Empty)) { int quantity = (int)itemFlowAccum; ItemStackMoveOperation op = new ItemStackMoveOperation(Api.World, EnumMouseButton.Left, 0, EnumMergePriority.DirectMerge, quantity); int qmoved = sourceSlot.TryPutInto(targetSlot, ref op); if (qmoved > 0) { if (Api.World.Rand.NextDouble() < 0.2) { Api.World.PlaySoundAt(hopperTumble, Pos.X + 0.5, Pos.Y + 0.5, Pos.Z + 0.5, null, true, 8, 0.5f); } if (beFlow != null) { targetSlot.Itemstack.Attributes.SetInt("chuteQHTravelled", outputFace.IsHorizontal ? (horTravelled + 1) : 0); targetSlot.Itemstack.Attributes.SetInt("chuteDir", outputFace.Index); } else { targetSlot.Itemstack.Attributes.RemoveAttribute("chuteQHTravelled"); targetSlot.Itemstack.Attributes.RemoveAttribute("chuteDir"); } sourceSlot.MarkDirty(); targetSlot.MarkDirty(); MarkDirty(false); beFlow?.MarkDirty(false); itemFlowAccum -= qmoved; return(true); } else { //If the push failed, re-apply original chuteDir so that the itemStack still has it for next push attempt sourceSlot.Itemstack.Attributes.SetInt("chuteDir", chuteDir); } } } return(false); }