internal Cuboidf[] GetSelectionBoxes(Vec3i forSize, EnumCircuitSelectionType selType, IPlayer forPlayer = null) { if (currentSelectionType == selType && ((forSize?.Equals(currentSelectionSize)).GetValueOrDefault(false) || (forSize == null && currentSelectionSize == null)) && !selectionBoxesDidChanged) { return(selectionBoxesVoxels); } switch (selType) { case EnumCircuitSelectionType.PlaceWire: GenerateSelectionVoxelBoxes(new Vec3i(1, 1, 1), true, true, true, false); break; case EnumCircuitSelectionType.PlaceComponent: GenerateSelectionVoxelBoxes(forSize, false, false, true, true); break; case EnumCircuitSelectionType.PlaceNothing: GenerateSelectionVoxelBoxes(new Vec3i(1, 1, 1), false, true, true, false); break; } currentSelectionSize = forSize; currentSelectionType = selType; selectionBoxesDidChanged = false; return(selectionBoxesVoxels); }
public Stack <BlockPos> FindTree(IWorldAccessor world, BlockPos startPos) { Queue <Vec4i> queue = new Queue <Vec4i>(); HashSet <BlockPos> checkedPositions = new HashSet <BlockPos>(); Stack <BlockPos> foundPositions = new Stack <BlockPos>(); Block block = world.BlockAccessor.GetBlock(startPos); if (block.Code == null) { return(foundPositions); } string treeFellingGroupCode = block.Attributes?["treeFellingGroupCode"].AsString(); int spreadIndex = block.Attributes?["treeFellingGroupSpreadIndex"].AsInt(0) ?? 0; if (block.Attributes?["treeFellingCanChop"].AsBool(true) == false) { return(foundPositions); } EnumTreeFellingBehavior bh = EnumTreeFellingBehavior.Chop; if (block is ICustomTreeFellingBehavior ctfbh) { bh = ctfbh.GetTreeFellingBehavior(startPos, null, spreadIndex); if (bh == EnumTreeFellingBehavior.NoChop) { return(foundPositions); } } // Must start with a log if (spreadIndex < 2) { return(foundPositions); } if (treeFellingGroupCode == null) { return(foundPositions); } queue.Enqueue(new Vec4i(startPos.X, startPos.Y, startPos.Z, spreadIndex)); foundPositions.Push(startPos); checkedPositions.Add(startPos); while (queue.Count > 0) { if (foundPositions.Count > 2500) { break; } Vec4i pos = queue.Dequeue(); block = world.BlockAccessor.GetBlock(pos.X, pos.Y, pos.Z); if (block is ICustomTreeFellingBehavior ctfbhh) { bh = ctfbhh.GetTreeFellingBehavior(startPos, null, spreadIndex); } if (bh == EnumTreeFellingBehavior.NoChop) { continue; } for (int i = 0; i < Vec3i.DirectAndIndirectNeighbours.Length; i++) { Vec3i facing = Vec3i.DirectAndIndirectNeighbours[i]; BlockPos neibPos = new BlockPos(pos.X + facing.X, pos.Y + facing.Y, pos.Z + facing.Z); float hordist = GameMath.Sqrt(neibPos.HorDistanceSqTo(startPos.X, startPos.Z)); float vertdist = (neibPos.Y - startPos.Y); // "only breaks blocks inside an upside down square base pyramid" float f = bh == EnumTreeFellingBehavior.ChopSpreadVertical ? 0.5f : 2; if (hordist - 1 >= f * vertdist) { continue; } if (checkedPositions.Contains(neibPos)) { continue; } block = world.BlockAccessor.GetBlock(neibPos); if (block.Code == null || block.Id == 0) { continue; } string ngcode = block.Attributes?["treeFellingGroupCode"].AsString(); // Only break the same type tree blocks if (ngcode != treeFellingGroupCode) { continue; } // Only spread from "high to low". i.e. spread from log to leaves, but not from leaves to logs int nspreadIndex = block.Attributes?["treeFellingGroupSpreadIndex"].AsInt(0) ?? 0; if (pos.W < nspreadIndex) { continue; } checkedPositions.Add(neibPos); if (bh == EnumTreeFellingBehavior.ChopSpreadVertical && !facing.Equals(0, 1, 0) && nspreadIndex > 0) { continue; } foundPositions.Push(neibPos.Copy()); queue.Enqueue(new Vec4i(neibPos.X, neibPos.Y, neibPos.Z, nspreadIndex)); } } return(foundPositions); }