private void DestroyGrownMushrooms() { mushroomsDiedTotalDays = Api.World.Calendar.TotalDays; foreach (var offset in grownMushroomOffsets) { BlockPos pos = Pos.AddCopy(offset); var block = Api.World.BlockAccessor.GetBlock(pos); if (block.Variant["mushroom"] == mushroomBlock.Variant["mushroom"]) { Api.World.BlockAccessor.SetBlock(0, pos); } } grownMushroomOffsets = new Vec3i[0]; }
public bool nearToClaimedLand() { int rad = (int)Math.Ceiling(BlastRadius); Cuboidi exploArea = new Cuboidi(Pos.AddCopy(-rad, -rad, -rad), Pos.AddCopy(rad, rad, rad)); List <LandClaim> claims = (Api as ICoreServerAPI).WorldManager.SaveGame.LandClaims; for (int i = 0; i < claims.Count; i++) { if (claims[i].Intersects(exploArea)) { return(true); } } return(false); }
private void SelectLeakingLog() { foreach (int i in new int[] { -1, 1 }) { int[] vectorX = { i, 0, 0 }; int[] vectorZ = { 0, 0, i }; foreach (int[] j in new int[][] { vectorX, vectorZ }) { BlockPos blockPos = Pos.AddCopy(j[0], j[1], j[2]); Block leakingBlock = Api.World.BlockAccessor.GetBlock(blockPos); if (CheckLeakingLogBlock(leakingBlock, false)) { LeakingLogBlockPos = blockPos; UpdateTransientProps(blockPos); } } } }
internal void InteractDebug() { if (RootOff.Y != 0) { return; } var rootBe = (Api.World.BlockAccessor.GetBlockEntity(Pos.AddCopy(RootOff)) as BlockEntityFruitTreeBranch)?.GetBehavior <FruitTreeRootBH>(); if (rootBe != null) { foreach (var val in rootBe.propsByType) { val.Value.State = (EnumFruitTreeState)(((int)val.Value.State + 1) % ((int)EnumFruitTreeState.Dead)); } } MarkDirty(true); }
private void MoveItem(float dt) { for (int d = 0; d < 6; d++) { if (inventory.IsEmpty) { break; //don't need to check for output if we don't have anything to output. } if (DirectionalMask[d] && d != 4) //means we're dealing with an output face if this is true. Also no going back up. { } //Checking for Up } // if (DirectionalMask[4]) { //pull. BlockEntity target = Api.World.BlockAccessor.GetBlockEntity(Pos.AddCopy(BlockFacing.UP)); } //checking for UP }
private void OnTick(float dt) { if (Api.Side == EnumAppSide.Server) { remainingBurnDuration -= dt; if (remainingBurnDuration <= 0) { BlockPos fuelPos = Pos.AddCopy(fromFacing.Opposite); Block fuelBlock = Api.World.BlockAccessor.GetBlock(fuelPos); if (canBurn(fuelBlock, fuelPos)) { TrySpreadTo(fuelPos, fromFacing); } Api.World.BlockAccessor.SetBlock(0, Pos); Api.World.BlockAccessor.RemoveBlockEntity(Pos); // Sometimes block entities don't get removed properly o.O Api.World.BlockAccessor.TriggerNeighbourBlockUpdate(Pos); return; } float spreadChance = (TimePassed - 2.5f) / 450f; if (((ICoreServerAPI)Api).Server.Config.AllowFireSpread && spreadChance > Api.World.Rand.NextDouble()) { TrySpreadFire(); } } if (Api.Side == EnumAppSide.Client) { int index = Math.Min(fireBlock.ParticleProperties.Length - 1, Api.World.Rand.Next(fireBlock.ParticleProperties.Length + 1)); AdvancedParticleProperties particles = fireBlock.ParticleProperties[index]; particles.basePos = RandomBlockPos(Api.World.BlockAccessor, Pos.AddCopy(fromFacing.Opposite), neibBlock, fromFacing); particles.Quantity.avg = 0.75f; particles.TerrainCollision = false; Api.World.SpawnParticles(particles); particles.Quantity.avg = 0; } }
void TriggerPileChanged() { if (Api.Side != EnumAppSide.Server) { return; } int maxSteepness = 4; BlockCoalPile belowcoalpile = Api.World.BlockAccessor.GetBlock(Pos.DownCopy()) as BlockCoalPile; int belowwlayers = belowcoalpile == null ? 0 : belowcoalpile.GetLayercount(Api.World, Pos.DownCopy()); foreach (var face in BlockFacing.HORIZONTALS) { BlockPos npos = Pos.AddCopy(face); Block nblock = Api.World.BlockAccessor.GetBlock(npos); BlockCoalPile nblockcoalpile = Api.World.BlockAccessor.GetBlock(npos) as BlockCoalPile; int nblockcoalpilelayers = nblockcoalpile == null ? 0 : nblockcoalpile.GetLayercount(Api.World, npos); // When should it collapse? // When there layers > 3 and nearby is air or replacable // When nearby is coal and herelayers - neiblayers > 3 // When there is coal below us, the neighbour below us is coal, nearby is air or replaceable, and owncoal+belowcoal - neibbelowcoal > 3 int layerdiff = Math.Max(nblock.Replaceable > 6000 ? Math.Max(0, Layers - maxSteepness) : 0, (nblockcoalpile != null ? Layers - nblockcoalpilelayers - maxSteepness : 0)); if (belowwlayers > 0) { BlockCoalPile nbelowblockcoalpile = Api.World.BlockAccessor.GetBlock(npos.DownCopy()) as BlockCoalPile; int nbelowwlayers = nbelowblockcoalpile == null ? 0 : nbelowblockcoalpile.GetLayercount(Api.World, npos.DownCopy()); layerdiff = Math.Max(layerdiff, (nbelowblockcoalpile != null ? Layers + belowwlayers - nbelowwlayers - maxSteepness : 0)); } if (Api.World.Rand.NextDouble() < layerdiff / (float)maxSteepness) { if (TryPartialCollapse(npos.UpCopy(), 2)) { return; } } } }
private void TrySpawnPumpkin(double curTotalHours) { foreach (BlockFacing facing in BlockFacing.HORIZONTALS) { BlockPos candidatePos = Pos.AddCopy(facing); Block block = Api.World.BlockAccessor.GetBlock(candidatePos); if (!CanReplace(block)) { continue; } Block supportBlock = Api.World.BlockAccessor.GetBlock(candidatePos.DownCopy()); if (CanSupportPumpkin(supportBlock)) { Api.World.BlockAccessor.SetBlock(pumpkinBlock.BlockId, candidatePos); pumpkinTotalHoursForNextStage[facing] = curTotalHours + pumpkinHoursToGrow; return; } } }
private void CheckValidToggleAndNotObstructed() { targetAnvil = Api.World.BlockAccessor.GetBlockEntity(anvilPos) as BlockEntityAnvil; obstructed = false; if (renderer != null) { renderer.Obstructed = false; } mptoggle = Api.World.BlockAccessor.GetBlockEntity(togglePos)?.GetBehavior <BEBehaviorMPToggle>(); if (mptoggle?.ValidHammerBase(Pos) == false) { mptoggle = null; obstructed = true; if (renderer != null) { renderer.Obstructed = true; } return; } BlockPos npos = Pos.AddCopy(0, 1, 0); for (int i = 0; i < 3; i++) { Block block = Api.World.BlockAccessor.GetBlock(npos); Cuboidf[] collboxes = block.GetCollisionBoxes(Api.World.BlockAccessor, npos); if (collboxes != null && collboxes.Length > 0) { obstructed = true; if (renderer != null) { renderer.Obstructed = true; } break; } npos.Add(facing.Normali); } }
private bool TestCokable() { var bl = Api.World.BlockAccessor; bool haveDoor = false; foreach (var facing in BlockFacing.HORIZONTALS) { Block block = bl.GetBlock(Pos.AddCopy(facing)); haveDoor |= block is BlockCokeOvenDoor && block.Variant["state"] == "closed"; } int brickCount = 0; bl.WalkBlocks(Pos.AddCopy(-1, -1, -1), Pos.AddCopy(1, 1, 1), (block, pos) => { brickCount += block.Attributes?["cokeOvenViable"].AsBool(true) == true ? 1 : 0; }); return(haveDoor && brickCount >= 9 + 7 + 7 && bl.GetBlock(Pos.UpCopy()).Attributes?["cokeOvenViable"].AsBool(true) == true); }
public override void Initialize(ICoreAPI api) { base.Initialize(api); Shape = Block.Shape; Facing = BlockFacing.FromCode(Block.Variant["side"]); this.transmissionPos = Pos.AddCopy(Facing); manager = Api.ModLoader.GetModSystem <MechanicalPowerMod>(); manager.AddDeviceForRender(this); AxisSign = new int[3] { 0, 0, 0 }; switch (Facing.Index) { case 0: AxisSign[0] = -1; hinge = new Vec3f(0.5f, 0f, 0.375f); break; case 2: AxisSign[0] = 1; hinge = new Vec3f(0.5f, 0f, 0.625f); break; case 1: AxisSign[2] = -1; hinge = new Vec3f(0.625f, 0f, 0.5f); break; default: AxisSign[2] = 1; break; } if (api.World.Side == EnumAppSide.Client) { RegisterGameTickListener(OnClientGameTick, 16); } }
public void InitializeEnergyPoint(ICoreAPI api) { if (api.World.Side == EnumAppSide.Server) { foreach (BlockFacing face in BlockFacing.ALLFACES) { BlockPos pos = Pos.AddCopy(face); BlockEntityEnergyDuct block = api.World.BlockAccessor.GetBlockEntity(pos) as BlockEntityEnergyDuct; if (block != null) { if (core == null) { if (block.core == null) { core = new EnergyDuctCore(MyMiniLib.GetAttributeInt(Block, "transfer", 500)); core.ducts.Add(this); } else { core = block.core; core.ducts.Add(this); } } else { if (core != block.core && block.core != null) { core = core.CombineCores(block.core); } } } } if (core == null) { core = new EnergyDuctCore(MyMiniLib.GetAttributeInt(Block, "transfer", 500)); core.ducts.Add(this); } } }
private bool TestCokable() { var bl = Api.World.BlockAccessor; bool haveDoor = false; foreach (var facing in BlockFacing.HORIZONTALS) { Block block = bl.GetBlock(Pos.AddCopy(facing)); haveDoor |= block is BlockCokeOvenDoor && block.Variant["state"] == "closed"; } int centerCount = 0; int cornerCount = 0; bl.WalkBlocks(Pos.AddCopy(-1, -1, -1), Pos.AddCopy(1, 1, 1), (block, pos) => { int dx = Math.Abs(Pos.X - pos.X); int dz = Math.Abs(Pos.Z - pos.Z); bool corner = dx == 1 && dz == 1; bool viable = block.Attributes?["cokeOvenViable"].AsBool(true) == true; if (viable) { centerCount += !corner ? 1 : 0; cornerCount += corner ? 1 : 0; } }); // bottom: 5 center, 4 corner // mid: 3 center, 1 door, 4 corner // top: 5 center, 4 corner // 13 center, 12 corner. Allow 4 corner blocks to be missing return(haveDoor && centerCount >= 12 && cornerCount >= 8 && bl.GetBlock(Pos.UpCopy()).Attributes?["cokeOvenViable"].AsBool(true) == true); }
private void onServerTick(float dt) { bool isFruiting = grownMushroomOffsets.Length > 0; if (isFruiting && props.DieWhenTempBelow > -99) { var conds = Api.World.BlockAccessor.GetClimateAt(Pos, EnumGetClimateMode.ForSuppliedDate_TemperatureOnly, Api.World.Calendar.TotalDays); if (conds == null) { return; } if (props.DieWhenTempBelow > conds.Temperature) { DestroyGrownMushrooms(); return; } } if (props.DieAfterFruiting && isFruiting && mushroomsGrownTotalDays + fruitingDays < Api.World.Calendar.TotalDays) { DestroyGrownMushrooms(); return; } if (!isFruiting) { lastUpdateTotalDays = Math.Max(lastUpdateTotalDays, Api.World.Calendar.TotalDays - 50); // Don't check more than 50 days into the past while (Api.World.Calendar.TotalDays - lastUpdateTotalDays > 1) { var conds = Api.World.BlockAccessor.GetClimateAt(Pos, EnumGetClimateMode.ForSuppliedDate_TemperatureOnly, lastUpdateTotalDays + 0.5); if (conds == null) { return; } if (conds.Temperature > 5) { mushroomsGrowingDays += Api.World.Calendar.TotalDays - lastUpdateTotalDays; } lastUpdateTotalDays++; } if (mushroomsGrowingDays > growingDays) { growMushrooms(Api.World.BlockAccessor, MyceliumSystem.rndn); mushroomsGrowingDays = 0; } } else { if (Api.World.Calendar.TotalDays - lastUpdateTotalDays > 0.1) { lastUpdateTotalDays = Api.World.Calendar.TotalDays; for (int i = 0; i < grownMushroomOffsets.Length; i++) { var offset = grownMushroomOffsets[i]; var pos = Pos.AddCopy(offset); var chunk = Api.World.BlockAccessor.GetChunkAtBlockPos(pos); if (chunk == null) { return; } if (!Api.World.BlockAccessor.GetBlock(pos).Code.Equals(mushroomBlockCode)) { grownMushroomOffsets = grownMushroomOffsets.RemoveEntry(i); i--; } } } } }
private void onBurnTick(float dt) { if (firepitStage == 6 && !IsBurning) { GetBehavior <BEBehaviorFirepitAmbient>()?.ToggleAmbientSounds(false); firepitStage++; MarkDirty(true); } if (IsBurning) { heatLiquid(dt); } double dh = Api.World.Calendar.TotalHours - lastTickTotalHours; if (dh > 0.1f) { if (IsBurning) { fuelHours -= (float)dh; } lastTickTotalHours = Api.World.Calendar.TotalHours; } var props = DistProps; if (InputStackTemp >= 75 && props != null) { distillationAccum += dt * props.Ratio; if (distillationAccum >= 0.2f) { distillationAccum -= 0.2f; for (int i = 0; i < 4; i++) { BlockEntityCondenser becd = Api.World.BlockAccessor.GetBlockEntity(Pos.AddCopy(BlockFacing.HORIZONTALS[i])) as BlockEntityCondenser; if (becd != null) { props?.DistilledStack.Resolve(Api.World, "distillationprops"); if (becd.ReceiveDistillate(inventory[0], props)) { break; } } } } } }
private void OnScanForEmptySkep(float dt) { if (Api.Side == EnumAppSide.Client) { return; } if (Api.World.Calendar.TotalHours < cooldownUntilTotalHours) { return; } if (scanIteration == 0) { scanQuantityNearbyFlowers = 0; scanQuantityNearbyHives = 0; scanEmptySkeps.Clear(); } // Let's count/collect 3 things in a 20x20x20 cube // 1. All positions of empty skeps // 2. Amount of living beehives (skeps or wild) // 3. Amount of flowers // Default Spread speed: Once every 4 in game days * factor // Don't spread at all if 3 * livinghives + 3 > flowers // factor = Clamped(livinghives / Math.Sqrt(flowers - 3 * livinghives - 3), 1, 1000) // After spreading: 4 extra days cooldown int minX = -8 + 8 * (scanIteration / 2); int minZ = -8 + 8 * (scanIteration % 2); int size = 8; Block emptySkepN = Api.World.GetBlock(new AssetLocation("skep-empty-north")); Block emptySkepE = Api.World.GetBlock(new AssetLocation("skep-empty-east")); Block emptySkepS = Api.World.GetBlock(new AssetLocation("skep-empty-south")); Block emptySkepW = Api.World.GetBlock(new AssetLocation("skep-empty-west")); Block fullSkepN = Api.World.GetBlock(new AssetLocation("skep-populated-north")); Block fullSkepE = Api.World.GetBlock(new AssetLocation("skep-populated-east")); Block fullSkepS = Api.World.GetBlock(new AssetLocation("skep-populated-south")); Block fullSkepW = Api.World.GetBlock(new AssetLocation("skep-populated-west")); Block wildhive1 = Api.World.GetBlock(new AssetLocation("wildbeehive-medium")); Block wildhive2 = Api.World.GetBlock(new AssetLocation("wildbeehive-large")); Api.World.BlockAccessor.WalkBlocks(Pos.AddCopy(minX, -5, minZ), Pos.AddCopy(minX + size - 1, 5, minZ + size - 1), (block, pos) => { if (block.Id == 0) { return; } if (block.Attributes?.IsTrue("beeFeed") == true) { scanQuantityNearbyFlowers++; } if (block == emptySkepN || block == emptySkepE || block == emptySkepS || block == emptySkepW) { scanEmptySkeps.Add(pos.Copy()); } if (block == fullSkepN || block == fullSkepE || block == fullSkepS || block == fullSkepW || block == wildhive1 || block == wildhive2) { scanQuantityNearbyHives++; } }); scanIteration++; if (scanIteration == 4) { scanIteration = 0; OnScanComplete(); } }
public bool Interact(IPlayer byPlayer, bool preferThis) { bool sneaking = byPlayer.WorldData.EntityControls.Sneak; int damagedTiles = 0; int wrongTiles = 0; int incompleteCount = 0; BlockPos posMain = Pos; // set up incompleteCount (etc) for both orientations and pick whichever is more complete if (sneaking) { int ic = 0; int icOpp = int.MaxValue; int dt = 0; int wt = 0; int dtOpp = 0; int wtOpp = 0; ic = ms.InCompleteBlockCount(Api.World, Pos, (haveBlock, wantLoc) => { if (haveBlock.FirstCodePart() == "refractorybricks" && haveBlock.Variant["state"] == "damaged") { dt++; } else { wt++; } } ); if (ic > 0 && blockScs.IsCompleteCoffin(Pos)) { icOpp = msOpp.InCompleteBlockCount(Api.World, Pos.AddCopy(blockScs.Orientation.Opposite), (haveBlock, wantLoc) => { if (haveBlock.FirstCodePart() == "refractorybricks" && haveBlock.Variant["state"] == "damaged") { dtOpp++; } else { wtOpp++; } } ); } // This logic aims to figure out which structure to show - if one is almost complete (3 wrong tiles or less) that one will be shown; preferThis has a preference if both are equally incomplete (newly placed stonecoffin) or if one is not much more complete than the other (allows for building errors of 1-3 tiles before the shown structure flips) if (wtOpp <= 3 && wt < wtOpp || wtOpp > 3 && wt < wtOpp - 3 || preferThis && wt <= wtOpp || preferThis && wt > 3 && wt <= wtOpp + 3) { incompleteCount = ic; damagedTiles = dt; wrongTiles = wt; if (ic > 0) { msHighlighted = ms; } } else { incompleteCount = icOpp; damagedTiles = dtOpp; wrongTiles = wtOpp; msHighlighted = msOpp; posMain = Pos.AddCopy(blockScs.Orientation.Opposite); } } if (sneaking && incompleteCount > 0) { if (wrongTiles > 0 && damagedTiles > 0) { capi?.TriggerIngameError(this, "incomplete", Lang.Get("Structure is not complete, {0} blocks are missing or wrong, {1} tiles are damaged!", wrongTiles, damagedTiles)); } else { if (wrongTiles > 0) { capi?.TriggerIngameError(this, "incomplete", Lang.Get("Structure is not complete, {0} blocks are missing or wrong!", wrongTiles)); } else { if (damagedTiles == 1) { capi?.TriggerIngameError(this, "incomplete", Lang.Get("Structure is not complete, {0} tile is damaged!", damagedTiles)); } else { capi?.TriggerIngameError(this, "incomplete", Lang.Get("Structure is not complete, {0} tiles are damaged!", damagedTiles)); } } } if (Api.Side == EnumAppSide.Client) { msHighlighted.HighlightIncompleteParts(Api.World, byPlayer, posMain); } return(false); } else { if (Api.Side == EnumAppSide.Client) { msHighlighted?.ClearHighlights(Api.World, byPlayer); } } if (!sneaking) { return(false); } if (!blockScs.IsCompleteCoffin(Pos)) { capi?.TriggerIngameError(this, "incomplete", Lang.Get("Cannot fill an incomplete coffin, place the other half first")); return(false); } ItemSlot slot = byPlayer.InventoryManager.ActiveHotbarSlot; if (!slot.Empty) { if (IngotCount / 4 >= CoalLayerCount) { return(AddCoal(slot)); } else { return(AddIngot(slot)); } } return(true); }
private void onServerTick3s(float dt) { BlockPos coalPilePos = Pos.DownCopy(2); BlockPos othercoalPilePos = coalPilePos.AddCopy(blockScs.Orientation.Opposite); bool beforeReceiveHeat = receivesHeat; bool beforeStructureComplete = structureComplete; if (!receivesHeat) { totalHoursLastUpdate = Api.World.Calendar.TotalHours; } BlockEntityCoalPile becp = Api.World.BlockAccessor.GetBlockEntity(coalPilePos) as BlockEntityCoalPile; float leftHeatHoursLeft = (becp != null && becp.IsBurning) ? becp.GetHoursLeft(totalHoursLastUpdate) : 0f; becp = Api.World.BlockAccessor.GetBlockEntity(othercoalPilePos) as BlockEntityCoalPile; float rightHeatHoursLeft = (becp != null && becp.IsBurning) ? becp.GetHoursLeft(totalHoursLastUpdate) : 0f; receivesHeat = leftHeatHoursLeft > 0 && rightHeatHoursLeft > 0; if (processComplete || !IsFull || !hasLid()) { return; } MultiblockStructure msInUse = null; BlockPos posInUse = null; structureComplete = false; if (ms.InCompleteBlockCount(Api.World, Pos) == 0) { msInUse = ms; posInUse = Pos; structureComplete = true; } else if (msOpp.InCompleteBlockCount(Api.World, Pos.AddCopy(blockScs.Orientation.Opposite)) == 0) { msInUse = msOpp; posInUse = Pos.AddCopy(blockScs.Orientation.Opposite); structureComplete = true; } if (beforeReceiveHeat != receivesHeat || beforeStructureComplete != structureComplete) { MarkDirty(); } if (receivesHeat) { if (!structureComplete) { return; } double hoursPassed = Api.World.Calendar.TotalHours - totalHoursLastUpdate; double heatHoursReceived = Math.Max(0, Math.Min(hoursPassed, Math.Min(leftHeatHoursLeft, rightHeatHoursLeft))); progress += heatHoursReceived / 160f; totalHoursLastUpdate = Api.World.Calendar.TotalHours; MarkDirty(); } if (progress >= 1.0) { int stacksize = inv[1].Itemstack.StackSize; JsonItemStack jstack = inv[1].Itemstack.ItemAttributes?["carburizableProps"]["carburizedOutput"].AsObject <JsonItemStack>(null, Block.Code.Domain); if (jstack.Resolve(Api.World, "carburizable output")) { inv[0].Itemstack.StackSize -= 8; inv[1].Itemstack = jstack.ResolvedItemstack.Clone(); inv[1].Itemstack.StackSize = stacksize; } MarkDirty(); msInUse.WalkMatchingBlocks(Api.World, posInUse, (block, pos) => { float resis = block.Attributes?["heatResistance"].AsFloat(1) ?? 1; if (Api.World.Rand.NextDouble() > resis) { Block nowblock = Api.World.GetBlock(block.CodeWithVariant("state", "damaged")); Api.World.BlockAccessor.SetBlock(nowblock.Id, pos); } }); processComplete = true; } }
private void onBurningTickServer(float dt) { facings.Shuffle(Api.World.Rand); foreach (var val in facings) { BlockPos npos = Pos.AddCopy(val); /*var combprops = Api.World.BlockAccessor.GetBlock(npos).CombustibleProps; * if (combprops != null) * { * Api.World.BlockAccessor.SetBlock(Api.World.GetBlock(new AssetLocation("fire")).BlockId, npos); * BlockEntityFire befire = byEntity.World.BlockAccessor.GetBlockEntity(bpos) as BlockEntityFire; * if (befire != null) befire.Init(blockSel.Face, (byEntity as EntityPlayer).PlayerUID); * * continue; * }*/ var becp = Api.World.BlockAccessor.GetBlockEntity(npos) as BlockEntityCoalPile; becp?.TryIgnite(); if (becp != null) { if (Api.World.Rand.NextDouble() < 0.75) { break; } } } cokeConversionRate = inventory[0].Itemstack.ItemAttributes?["cokeConversionRate"].AsFloat(0) ?? 0; if (cokeConversionRate > 0) { if (isCokable = TestCokable()) { if (Api.World.Calendar.TotalHours - burnStartTotalHours > 12) { inventory[0].Itemstack = new ItemStack(Api.World.GetItem(new AssetLocation("coke")), (int)(inventory[0].StackSize * cokeConversionRate)); burning = false; UnregisterGameTickListener(listenerId); MarkDirty(true); } else { MarkDirty(false); } return; } } bool changed = false; while (Api.World.Calendar.TotalHours - burnStartTotalHours > BurnHoursPerLayer) { burnStartTotalHours += BurnHoursPerLayer; inventory[0].TakeOut(2); if (inventory[0].Empty) { Api.World.BlockAccessor.SetBlock(0, Pos); break; } else { changed = true; } } if (changed) { MarkDirty(true); } }
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); }