void Grind(IMySlimBlock Block, float SpeedRatio) { Block.DecreaseMountLevel(SpeedRatio, ToolCargo, useDefaultDeconstructEfficiency: true); Block.MoveItemsFromConstructionStockpile(ToolCargo); Block.DoDamage(0, VRage.Utils.MyStringHash.GetOrCompute("Grind"), true, null, Tool.EntityId); if (Block.FatBlock?.IsFunctional == false && Block.FatBlock?.HasInventory == true) { foreach (var Inventory in Block.FatBlock.GetInventories()) { if (Inventory.CurrentVolume == VRage.MyFixedPoint.Zero) { continue; } foreach (var Item in Inventory.GetItems()) { var Amount = Inventory.ComputeAmountThatFits(Item); ToolCargo.TransferItemFrom(Inventory, (int)Item.ItemId, null, null, Amount, false); } } } if (Block.IsFullyDismounted) { Block.CubeGrid.RazeBlock(Block.Position); } }
void Work(int ticks = 1) { if (!MyAPIGateway.Multiplayer.IsServer) { return; } LineD WeldRay = new LineD(BeamStart, BeamEnd); List <IHitInfo> Hits = new List <IHitInfo>(); List <MyLineSegmentOverlapResult <MyEntity> > Overlaps = new List <MyLineSegmentOverlapResult <MyEntity> >(); MyGamePruningStructure.GetTopmostEntitiesOverlappingRay(ref WeldRay, Overlaps); List <IMyCubeGrid> Grids = new List <IMyCubeGrid>(); List <IMyCharacter> Characters = new List <IMyCharacter>(); List <IMyFloatingObject> Flobjes = new List <IMyFloatingObject>(); Overlaps.Select(x => x.Element as IMyEntity).SortByType(Grids, Characters, Flobjes); ClosestGrid = Grids.OrderBy(Grid => Vector3D.DistanceSquared(Tool.GetPosition(), Grid.GetPosition())).FirstOrDefault(); foreach (IMyCharacter Char in Characters) { Char.DoDamage(GrinderSpeed, MyDamageType.Grind, true, null, Tool.EntityId); } foreach (IMyCubeGrid Grid in Grids) { if (Grid == Tool.CubeGrid) { continue; } try { List <IMySlimBlock> Blocks = Grid.GetBlocksOnRay(WeldRay.From, WeldRay.To); //if (!SessionCore.Debug && Blocks.Count == 0) return; if (IsWelder) { Weld(Blocks, ticks); } if (IsGrinder) { Grind(Blocks, ticks); } } catch (Exception Scrap) { SessionCore.LogError(Grid.DisplayName, Scrap); } } foreach (IMyFloatingObject Flobj in Flobjes) { ToolCargo.PickupItem(Flobj); } }
void Grind(List <IMySlimBlock> Blocks, int ticks = 1) { var Grinder = Tool as IMyShipGrinder; if (Grinder == null) { return; } Blocks = Blocks.Where(x => x.IsGrindable() && x != Grinder.SlimBlock).ToList(); if (Blocks.Count == 0) { return; } if (DistanceMode) { Blocks = Blocks.OrderBy(x => Vector3D.DistanceSquared(x.GetPosition(), Tool.GetPosition())).ToList(); } float SpeedRatio = GrinderSpeed / (DistanceMode ? 1 : Blocks.Count) * ticks; foreach (IMySlimBlock Block in Blocks) { Block.MoveItemsFromConstructionStockpile(ToolCargo); Block.DecreaseMountLevel(SpeedRatio, ToolCargo, useDefaultDeconstructEfficiency: true); if (Block.FatBlock?.IsFunctional == false && Block.FatBlock?.HasInventory == true) { foreach (var Inventory in Block.FatBlock.GetInventories()) { if (Inventory.CurrentVolume == VRage.MyFixedPoint.Zero) { continue; } foreach (var Item in Inventory.GetItems()) { var Amount = Inventory.ComputeAmountThatFits(Item); ToolCargo.TransferItemFrom(Inventory, (int)Item.ItemId, null, null, Amount, false); } } } if (Block.IsFullyDismounted) { Block.CubeGrid.RazeBlock(Block.Position); } if (DistanceMode) { break; } } }
void Grind(List <IMySlimBlock> Blocks, int ticks = 1) { var Grinder = Tool as IMyShipGrinder; if (Grinder == null) { return; } Blocks = Blocks.Where(x => x.IsGrindable() && x != Grinder.SlimBlock).ToList(); if (Blocks.Count == 0) { return; } if (DistanceMode) { Blocks = Blocks.OrderBy(x => Vector3D.DistanceSquared(x.GetPosition(), Tool.GetPosition())).ToList(); } float SpeedRatio = GrinderSpeed / (DistanceMode ? 1 : Blocks.Count) * ticks; foreach (IMySlimBlock Block in Blocks) { MyDamageInformation GrindDamage = new MyDamageInformation(false, SpeedRatio, MyDamageType.Grind, Grinder.EntityId); Block.MoveItemsFromConstructionStockpile(ToolCargo); Block.DecreaseMountLevel(SpeedRatio, ToolCargo, useDefaultDeconstructEfficiency: true); if (Block.IsFullyDismounted) { if (Block.FatBlock?.HasInventory == true) { foreach (var Inventory in Block.FatBlock.GetInventories()) { foreach (var Item in Inventory.GetItems()) { ToolCargo.TransferItemFrom(Inventory, (int)Item.ItemId, null, null, null, false); } } } Block.CubeGrid.RazeBlock(Block.Position); } if (DistanceMode) { break; } } }
void Place(IMySlimBlock Block) { if (!Block.IsProjectable()) { return; } var FirstItem = ((MyCubeBlockDefinition)Block.BlockDefinition).Components[0].Definition.Id; if (MyAPIGateway.Session.CreativeMode || ToolCargo.PullAny(OnboardInventoryOwners, FirstItem.SubtypeName, 1)) { var Projector = ((Block.CubeGrid as MyCubeGrid).Projector as IMyProjector); Projector.Build(Block, 0, Tool.EntityId, false); ToolCargo.RemoveItemsOfType(1, FirstItem); } else { UnbuiltBlocks.Add(Block); SessionCore.DebugWrite($"{Tool.CustomName}.Place()", $"Tool can't pull the component {FirstItem.SubtypeName}!", IsExcessive: false); } }
void Weld(ICollection <IMySlimBlock> Blocks, int ticks = 1) { //UnbuiltBlocks.Clear(); if (Blocks.Count == 0) { return; } float SpeedRatio = (WelderSpeed / Blocks.Count) * ticks * SpeedMultiplier; float BoneFixSpeed = WelderBoneRepairSpeed * ticks; var UniqueBlocks = Blocks.CollapseDuplicates(); HashSet <IMySlimBlock> unbuilt = new HashSet <IMySlimBlock>(); foreach (IMySlimBlock Block in UniqueBlocks.Keys) { float blockRatio = SpeedRatio * UniqueBlocks.GetData(Block); if (Block.CubeGrid.Physics?.Enabled == true) { if (!Weld(Block, blockRatio, BoneFixSpeed)) { unbuilt.Add(Block); } } else { Place(Block); } } if (unbuilt.Count > 0) { Dictionary <string, int> Missing = new Dictionary <string, int>(); unbuilt.ReadMissingComponents(Missing); if (!ToolCargo.PullAny(OnboardInventoryOwners, Missing)) { UnbuiltBlocks.UnionWith(unbuilt); } } }
public override void UpdateBeforeSimulation100() { GridAvailablePower = ToolGrid.GetMaxPowerOutput(); if (!Tool.Enabled) { return; } //if (RunTimesAvailable && MaxRunTime >= 0.25f) // Text.AppendLine($"Performance impact: {(RunTimesAvailable ? Math.Round(AvgRunTime, 4).ToString() : "--")}/{(RunTimesAvailable ? Math.Round(MaxRunTime, 4).ToString() : "--")} ms (avg/max)"); if (UnbuiltBlocks.Count > 0) { Dictionary <string, int> TotalMissingList = new Dictionary <string, int>(); Dictionary <IMySlimBlock, Dictionary <string, int> > MissingPerBlock = new Dictionary <IMySlimBlock, Dictionary <string, int> >(); UnbuiltBlocks.ReadMissingComponents(TotalMissingList, MissingPerBlock); if (!ToolCargo.PullAny(OnboardInventoryOwners, TotalMissingList)) { ComplainMissing(MissingPerBlock); } UnbuiltBlocks.Clear(); } }
void WeldDistanceMode(ICollection <IMySlimBlock> Blocks, int ticks = 1) { //UnbuiltBlocks.Clear(); if (Blocks.Count == 0) { return; } Blocks = Blocks.OrderByDescending(x => Vector3D.DistanceSquared(x.GetPosition(), Tool.GetPosition())).ToList(); float SpeedRatio = WelderSpeed * ticks * SpeedMultiplier; float BoneFixSpeed = WelderBoneRepairSpeed * ticks; foreach (IMySlimBlock Block in Blocks) { if (Block.CubeGrid.Physics?.Enabled == true) { bool welded = Weld(Block, SpeedRatio, BoneFixSpeed); if (!welded) { var missing = Block.ReadMissingComponents(); if (!ToolCargo.PullAny(OnboardInventoryOwners, missing)) { UnbuiltBlocks.Add(Block); } } else { break; } } else { Place(Block); break; } } }
protected override void ProcessFlobjes(HashSet <IMyFloatingObject> Flobjes) { if (Flobjes.Count == 0) { return; } if (!MyAPIGateway.Session.IsServer) { return; } float CargoFillRatio = (float)((double)ToolCargo.CurrentVolume / (double)ToolCargo.MaxVolume); foreach (IMyFloatingObject Flobj in Flobjes) { if (CargoFillRatio < 0.75) { ToolCargo.PickupItem(Flobj); } else { break; } } }
void Work(int ticks = 1) { if (IsDrill) { return; } LineD WeldRay = new LineD(BeamCtlModule.BeamStart, BeamCtlModule.BeamEnd); List <MyLineSegmentOverlapResult <MyEntity> > Overlaps = new List <MyLineSegmentOverlapResult <MyEntity> >(); MyGamePruningStructure.GetTopmostEntitiesOverlappingRay(ref WeldRay, Overlaps); HashSet <IMyCubeGrid> Grids = new HashSet <IMyCubeGrid>(); HashSet <IMyCharacter> Characters = new HashSet <IMyCharacter>(); HashSet <IMyFloatingObject> Flobjes = new HashSet <IMyFloatingObject>(); Overlaps.Select(x => x.Element as IMyEntity).SortByType(Grids, Characters, Flobjes); Grids.Remove(ToolGrid); if (SessionCore.Settings.Debug && Vector3D.Distance(Tool.GetPosition(), MyAPIGateway.Session.LocalHumanPlayer.GetPosition()) <= 200) { string GridNames = ""; foreach (var grid in Grids) { GridNames += $"{grid.DisplayName};"; } DebugNote.Text = $"{Tool.CustomName}: processing {Grids.Count} entities: {GridNames}{(IsWelder ? $" sup.invs: {GridInventoryModule.GetAccessibleInventories(Tool).Count}; unbuilt: {(this as LaserWelder).UnbuiltBlocks.Count}" : "")}"; GridNames = null; } foreach (IMyCubeGrid Grid in Grids) { //if (Grid.EntityId == ToolGrid.EntityId) continue; try { ProcessGrid(Grid, ticks); } catch (Exception Scrap) { SessionCore.LogError(Grid.DisplayName, Scrap); } } if (MyAPIGateway.Session.IsServer) { foreach (IMyCharacter Char in Characters) { if (Char.WorldAABB.Intersects(ref WeldRay)) { Char.DoDamage(VanillaToolConstants.GrinderSpeed * ticks / 2, MyDamageType.Grind, true, null, Tool.EntityId); } } foreach (IMyFloatingObject Flobj in Flobjes) { if (CargoFillRatio < 0.75) { ToolCargo.PickupItem(Flobj); } else { break; } } } }
void Weld(List <IMySlimBlock> Blocks, int ticks = 1) { var Welder = Tool as IMyShipWelder; if (Welder == null) { return; } Blocks = Blocks.Where(x => x.IsWeldable() || x.IsProjectable()).ToList(); if (Blocks.Count == 0) { return; } if (DistanceMode) { Blocks = Blocks.OrderByDescending(x => Vector3D.DistanceSquared(x.GetPosition(), Tool.GetPosition())).ToList(); } float SpeedRatio = WelderSpeed / (DistanceMode ? 1 : Blocks.Count) * ticks; float BoneFixSpeed = WelderBoneRepairSpeed * ticks; var Missing = Blocks.ReadMissingComponents(); bool Pull = Tool.UseConveyorSystem ? ToolCargo.PullAny(OnboardInventoryOwners, Missing) : false; Missing.Clear(); HashSet <IMySlimBlock> UnbuiltBlocks = new HashSet <IMySlimBlock>(); foreach (IMySlimBlock Block in Blocks) { if (Block.CubeGrid.Physics?.Enabled == true) { if (Block.CanContinueBuild(ToolCargo) || Block.HasDeformation) { Block.MoveItemsToConstructionStockpile(ToolCargo); Block.IncreaseMountLevel(SpeedRatio, Welder.OwnerId, ToolCargo, BoneFixSpeed, false); } else { UnbuiltBlocks.Add(Block); } } else { try { var FirstItem = ((MyCubeBlockDefinition)Block.BlockDefinition).Components[0].Definition.Id; if (ToolCargo.PullAny(OnboardInventoryOwners, FirstItem.SubtypeName, 1)) { try { var Projector = ((Block.CubeGrid as MyCubeGrid).Projector as IMyProjector); Projector.Build(Block, 0, Tool.EntityId, false); } catch (Exception Scrap) { SessionCore.LogError(Tool.CustomName + ".WeldProjectorBlock.Build", Scrap); } ToolCargo.RemoveItemsOfType(1, FirstItem); } } catch (Exception Scrap) { SessionCore.LogError(Tool.CustomName + ".WeldProjectorBlockStart", Scrap); } } if (DistanceMode) { break; } } PrintMissing(UnbuiltBlocks); }
void Grind(IMySlimBlock Block, float SpeedRatio, bool Raze = true) { if (Block == null) { return; } try { Stopwatch watch = Stopwatch.StartNew(); Block.DecreaseMountLevel(SpeedRatio, ToolCargo); watch.Stop(); //WriteToLog($"GrindBlocks[{MyKernel.Block.CustomName}]", $"Decreasing mount level took {Math.Round(watch.Elapsed.TotalMilliseconds, 3)}ms", EemRdx.SessionModules.LoggingLevelEnum.ProfilingLog); watch.Restart(); Block.MoveItemsFromConstructionStockpile(ToolCargo); watch.Stop(); //WriteToLog($"GrindBlocks[{MyKernel.Block.CustomName}]", $"Moving items took {Math.Round(watch.Elapsed.TotalMilliseconds, 3)}ms", EemRdx.SessionModules.LoggingLevelEnum.ProfilingLog); watch.Restart(); // This is necessary for compatibility with EEM and other mods which react to damage to their grids Block.DoDamage(0, MyStringHash.GetOrCompute("Grind"), true, null, MyKernel.Block.EntityId); watch.Stop(); //WriteToLog($"GrindBlocks[{MyKernel.Block.CustomName}]", $"Doing damage took {Math.Round(watch.Elapsed.TotalMilliseconds, 3)}ms", EemRdx.SessionModules.LoggingLevelEnum.ProfilingLog); watch.Restart(); if (Block.FatBlock?.IsFunctional == false && Block.FatBlock?.HasInventory == true) { foreach (IMyInventory Inventory in Block.FatBlock.GetInventories()) { if (Inventory.CurrentVolume == VRage.MyFixedPoint.Zero) { continue; } List <MyInventoryItem> Items = new List <MyInventoryItem>(); Inventory.GetItems(Items); foreach (MyInventoryItem Item in Items) { VRage.MyFixedPoint Amount = (VRage.MyFixedPoint)Math.Min((float)(Inventory as Sandbox.Game.MyInventory).ComputeAmountThatFits(Item.Type), (float)Item.Amount); if ((float)Amount > 0) { ToolCargo.TransferItemFrom(Inventory, (int)Item.ItemId, null, null, Amount, false); } } } watch.Stop(); //WriteToLog($"GrindBlocks[{MyKernel.Block.CustomName}]", $"Block has an inventory; cleaning took {Math.Round(watch.Elapsed.TotalMilliseconds, 3)}ms", EemRdx.SessionModules.LoggingLevelEnum.ProfilingLog); watch.Reset(); } if (Raze && Block.IsFullyDismounted) { watch.Restart(); Block.CubeGrid.RazeBlock(Block.Position); watch.Stop(); //WriteToLog($"GrindBlocks[{MyKernel.Block.CustomName}]", $"Razing the block took {Math.Round(watch.Elapsed.TotalMilliseconds, 3)}ms", EemRdx.SessionModules.LoggingLevelEnum.ProfilingLog); } } catch (Exception Scrap) { LogError($"GrindBlocks[{MyKernel.Block.CustomName}]", $"Grinding of the block {Extensions.GeneralExtensions.GetTypeName(Block)} failed", Scrap); } }
IEnumerator <bool> WeldAndPlaceBlocks(ICollection <IMySlimBlock> RealBlocks, ICollection <IMySlimBlock> ProjectedBlocks) { if (RealBlocks == null || ProjectedBlocks == null) { yield return(false); } if (RealBlocks.Count == 0 && ProjectedBlocks.Count == 0) { yield return(false); } if (MyKernel.TermControls.ToolMode == false) { yield return(false); } if (!SafeZonesHelper.IsActionAllowed(MyKernel.Block.GetPosition(), MySafeZoneAction.Welding | MySafeZoneAction.Building, MyKernel.Block.EntityId)) { yield return(false); } bool ShouldContinue = RealBlocks.Count > 0 || ProjectedBlocks.Count > 0; //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Entry Point: real blocks: {RealBlocks.Count}, projected blocks: {ProjectedBlocks.Count}, should continue: {ShouldContinue}"); if (!ShouldContinue) { yield return(false); } if (MyKernel.TermControls.DistanceMode && RealBlocks.Count > 0) { IMySlimBlock FarthestBlock = RealBlocks.OrderBy(x => Vector3D.DistanceSquared(x.CubeGrid.GridIntegerToWorld(x.Position), MyKernel.Block.GetPosition())).Last(); RealBlocks.Clear(); RealBlocks.Add(FarthestBlock); //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Selected block for distance mode"); } float SpeedRatio = NominalWorkingFrequency * MyKernel.TermControls.SpeedMultiplier * WeldGrindSpeedMultiplier * (VanillaToolConstants.WelderSpeed / RealBlocks.Count); float BoneFixSpeed = VanillaToolConstants.WelderBoneRepairSpeed * NominalWorkingFrequency; IMyProjector Projector = null; if (ProjectedBlocks.Count > 0) { Projector = ((ProjectedBlocks.First().CubeGrid as MyCubeGrid).Projector as IMyProjector); } //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Checked for projectors"); if (!MyAPIGateway.Session.CreativeMode) { Dictionary <string, int> RequiredComponentNames = new Dictionary <string, int>(); { Action worker = () => { foreach (IMySlimBlock Block in RealBlocks) { Block.GetMissingComponents(RequiredComponentNames); } }; bool completed = false; Action callback = () => completed = true; MyAPIGateway.Parallel.StartBackground(worker, callback); while (!completed) { yield return(true); } } //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Got missing components"); foreach (IMySlimBlock Block in ProjectedBlocks) { var FirstItem = ((MyCubeBlockDefinition)Block.BlockDefinition).Components[0].Definition.Id; if (RequiredComponentNames.ContainsKey(FirstItem.SubtypeName)) { RequiredComponentNames[FirstItem.SubtypeName] += 1; } else { RequiredComponentNames.Add(FirstItem.SubtypeName, 1); } } //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Got missing components for projected blocks"); Dictionary <MyItemType, float> RequiredComponents = new Dictionary <MyItemType, float>(); var list = RequiredComponentNames.ToList(); foreach (KeyValuePair <string, int> kvp in list) { //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Trying to generate itemtype..."); //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"for {kvp.Key}"); MyItemType itemtype = new MyItemType("MyObjectBuilder_Component", kvp.Key); //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Generated item value"); //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"(item: {itemtype.SubtypeId}, amount: {kvp.Value})"); RequiredComponents.Add(itemtype, kvp.Value); } //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Reassembled missing dictionary"); List <IMyTerminalBlock> InventoryOwners = new List <IMyTerminalBlock>(MyKernel.Inventory.InventoryOwners); InventoryOwners.Add(MyKernel.Tool); InventoryModule.CalculateMissingItems(RequiredComponents, MyKernel.Inventory.GetAggregateItemsFor(InventoryOwners)); //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Calculated aggregate missing components"); if (MyKernel.Tool.UseConveyorSystem) { Dictionary <MyItemType, float> _RqComponents = new Dictionary <MyItemType, float>(RequiredComponents); foreach (var RequiredComponent in RequiredComponents) { float pulledAmount = MyKernel.Inventory.TryTransferTo(ToolCargo, RequiredComponent.Key, RequiredComponent.Value, InventoryOwners); _RqComponents[RequiredComponent.Key] -= pulledAmount; } RequiredComponents = _RqComponents; //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Pulled missing components"); } MyKernel.ResponderModule.UpdateMissing(RequiredComponents); yield return(true); int weldedBlocks = 0; List <IMySlimBlock> UnweldedBlocks = new List <IMySlimBlock>(); foreach (IMySlimBlock Block in RealBlocks) { if (Block.CanContinueBuild(ToolCargo) || Block.HasDeformation) { if (MyKernel.Session.Settings.AllowAsyncWelding) { if (CanWeldInAsyncMode(Block)) { MyAPIGateway.Parallel.StartBackground(() => Weld(Block, SpeedRatio, BoneFixSpeed)); } else { Weld(Block, SpeedRatio, BoneFixSpeed); } } else { Weld(Block, SpeedRatio, BoneFixSpeed); } weldedBlocks++; if (!MyKernel.Session.Settings.AllowAsyncWelding && weldedBlocks != RealBlocks.Count - 1) { yield return(true); } } else { UnweldedBlocks.Add(Block); } } //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Welded real blocks"); if (weldedBlocks > 0) { yield return(true); } int placedBlocks = 0; List <IMySlimBlock> NonplacedBlocksByLimit = new List <IMySlimBlock>(); List <IMySlimBlock> NonplacedBlocksByResources = new List <IMySlimBlock>(); List <IMySlimBlock> PlaceableProjectedBlocks = new List <IMySlimBlock>(); foreach (IMySlimBlock Block in ProjectedBlocks) { MyCubeBlockDefinition blockDef = Block.BlockDefinition as MyCubeBlockDefinition; if (MyKernel.Tool.IsWithinWorldLimits(Projector, blockDef.BlockPairName, blockDef.PCU)) { var FirstItem = blockDef.Components[0].Definition.Id; if (ToolCargo.GetItemAmount(FirstItem) >= 1) { PlaceableProjectedBlocks.Add(Block); } else { NonplacedBlocksByResources.Add(Block); } } else { NonplacedBlocksByLimit.Add(Block); } } foreach (IMySlimBlock Block in PlaceableProjectedBlocks) { var FirstItem = ((MyCubeBlockDefinition)Block.BlockDefinition).Components[0].Definition.Id; Projector.Build(Block, MyKernel.Tool.OwnerId, MyKernel.Tool.EntityId, false); ToolCargo.RemoveItemsOfType(1, FirstItem); placedBlocks++; if (placedBlocks != ProjectedBlocks.Count - 1) { yield return(true); } } if (UnweldedBlocks.Count > 0) { StringBuilder UnweldedReport = new StringBuilder(); UnweldedReport.AppendLine($"Failed to weld {UnweldedBlocks.Count} blocks:"); List <IGrouping <MyObjectBuilderType, IMySlimBlock> > unweldedByType = UnweldedBlocks.GroupBy(x => x.BlockDefinition.Id.TypeId).ToList(); foreach (IGrouping <MyObjectBuilderType, IMySlimBlock> grouping in unweldedByType) { UnweldedReport.AppendLine($"{grouping.Key.ToString().Replace("MyObjectBuilder_", "")} ({grouping.Count()})"); } if (NonplacedBlocksByLimit.Count > 0 || NonplacedBlocksByResources.Count > 0) { UnweldedReport.AppendLine(); } MyKernel.ResponderModule.UpdateStatusReport(UnweldedReport, append: true); } if (NonplacedBlocksByLimit.Count > 0) { StringBuilder NonplacedReport = new StringBuilder(); NonplacedReport.AppendLine($"Failed to place {UnweldedBlocks.Count} blocks,"); NonplacedReport.AppendLine($"reached the PCU/block limit:"); List <IGrouping <MyObjectBuilderType, IMySlimBlock> > unplacedByType = UnweldedBlocks.GroupBy(x => x.BlockDefinition.Id.TypeId).ToList(); foreach (IGrouping <MyObjectBuilderType, IMySlimBlock> grouping in unplacedByType) { NonplacedReport.AppendLine($"{grouping.Key.ToString().Replace("MyObjectBuilder_", "")} ({grouping.Count()})"); } MyKernel.ResponderModule.UpdateStatusReport(NonplacedReport, append: true); } if (NonplacedBlocksByResources.Count > 0) { StringBuilder NonplacedReport = new StringBuilder(); NonplacedReport.AppendLine($"Failed to place {UnweldedBlocks.Count} blocks,"); NonplacedReport.AppendLine($"out of resources:"); List <IGrouping <MyObjectBuilderType, IMySlimBlock> > unplacedByType = UnweldedBlocks.GroupBy(x => x.BlockDefinition.Id.TypeId).ToList(); foreach (IGrouping <MyObjectBuilderType, IMySlimBlock> grouping in unplacedByType) { NonplacedReport.AppendLine($"{grouping.Key.ToString().Replace("MyObjectBuilder_", "")} ({grouping.Count()})"); } MyKernel.ResponderModule.UpdateStatusReport(NonplacedReport, append: true); } //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Placed projected blocks"); } else if (MyAPIGateway.Session.CreativeMode) { foreach (IMySlimBlock Block in RealBlocks) { if (MyKernel.Session.Settings.AllowAsyncWelding) { if (CanWeldInAsyncMode(Block)) { MyAPIGateway.Parallel.StartBackground(() => Weld(Block, SpeedRatio, BoneFixSpeed)); } else { Weld(Block, SpeedRatio, BoneFixSpeed); } } else { Weld(Block, SpeedRatio, BoneFixSpeed); } } foreach (IMySlimBlock Block in ProjectedBlocks) { Projector.Build(Block, MyKernel.Tool.OwnerId, MyKernel.Tool.EntityId, false); } } //MyKernel.SessionBase.Log.DebugLog.WriteToLog($"WeldAndPlaceBlocks", $"Exit Point"); yield return(false); }
protected override IEnumerator <bool> ProcessVoxels(HashSet <IMyVoxelBase> Voxels) { if (!MyKernel.Session.Settings.EnableDrilling) { yield return(false); } if (Voxels.Count == 0) { yield return(false); } if (MyKernel.TermControls.ToolMode == true) { yield return(false); } if (!SafeZonesHelper.IsActionAllowed(MyKernel.Block.GetPosition(), MySafeZoneAction.Drilling, MyKernel.Block.EntityId)) { yield return(false); } //WriteToLog("ProcessVoxels", $"Processing {Voxels.Count} voxels"); Stopwatch stopwatch = Stopwatch.StartNew(); LineD WorkingRay = new LineD(MyKernel.BeamDrawer.BeamStart, MyKernel.BeamDrawer.BeamEnd); foreach (MyVoxelBase Voxel in Voxels.OfType <MyVoxelBase>()) { if (!SafeZonesHelper.IsActionAllowed((Voxel as IMyEntity).WorldAABB, MySafeZoneAction.Drilling, MyKernel.Block.EntityId)) { continue; } if (Voxel.GetOrePriority() == -1) { continue; // Idk why, but the same early exit is found in MyShipDrill } Vector3D?VoxelHit = Voxel.GetClosestPointOnRay(WorkingRay, step: 0.99f); if (VoxelHit.HasValue) { MyKernel.ResponderModule.UpdateStatusReport($"\r\nFound a voxel", true); lock (BlockedVoxels) { if (!BlockedVoxels.ContainsKey(Voxel.EntityId)) { BlockedVoxels.Add(Voxel.EntityId, new List <Vector3I>()); } } Vector3D hitpos = VoxelHit.Value; //MyVoxelMaterialDefinition Material = Voxel.GetMaterialAt(ref hitpos); Vector3D CutoutSphereCenter = hitpos + (-WorkingRay.Direction * DrillingOffsetM); //stopwatch.Stop(); //WriteToLog("ProcessVoxels", $"Hit: {Math.Round(Vector3D.Distance(WorkingRay.From, hitpos), 2)}m, cutout: {Math.Round(Vector3D.Distance(WorkingRay.From, CutoutSphereCenter), 2)} m away, Material: {(Material != null ? Material.MaterialTypeName : "null")}"); //stopwatch.Start(); BoundingSphereD Cutout = new BoundingSphereD(CutoutSphereCenter, CutoutRadius); //List<Vector3I> VoxelPoints = Voxel.GetVoxelPointsInSphere(Cutout); Vector3I refCorner; Vector3I refMaxCorner; MyStorageData cutoutVoxels = Voxel.GetVoxelCacheInSphere(Cutout, out refCorner, out refMaxCorner); //WriteToLog("ProcessVoxels", $"Cutout cache Min is {Math.Round(Vector3D.Distance(hitpos, Voxel.PositionLeftBottomCorner + refCorner), 2)}m away"); //WriteToLog("ProcessVoxels", $"Cutout cache Max is {Math.Round(Vector3D.Distance(hitpos, Voxel.PositionLeftBottomCorner + refCorner + cutoutVoxels.Size3D), 2)}m away"); Dictionary <MyVoxelMaterialDefinition, float> Materials = new Dictionary <MyVoxelMaterialDefinition, float>(); int nullMaterials = 0; int totalPoints = 0; Stopwatch enumeratorWatch = new Stopwatch(); using (MyStorageData.MortonEnumerator VoxelLoop = new MyStorageData.MortonEnumerator(cutoutVoxels, MyStorageDataTypeEnum.Content | MyStorageDataTypeEnum.Material)) { MyKernel.ResponderModule.UpdateStatusReport($"Entered enumerator", true); enumeratorWatch.Start(); Dictionary <byte, float> RawMaterials = new Dictionary <byte, float>(); Vector3I VoxelInSphereCenter; Vector3 CoordsSystemOutValue; //MyVoxelCoordSystems.WorldPositionToLocalPosition(Cutout.Center, Voxel.PositionComp.WorldMatrix, Voxel.PositionComp.WorldMatrixInvScaled, Voxel.SizeInMetresHalf, out CoordsSystemOutValue); //VoxelInSphereCenter = new Vector3I(CoordsSystemOutValue / 1f) + Voxel.StorageMin; Vector3D sphereCenter = Cutout.Center; MyVoxelCoordSystems.WorldPositionToLocalPosition(Voxel.PositionLeftBottomCorner, ref sphereCenter, out CoordsSystemOutValue); VoxelInSphereCenter = new Vector3I(CoordsSystemOutValue / 1f) + Voxel.StorageMin; Vector3D ReconstructedPosition = Voxel.PositionLeftBottomCorner + VoxelInSphereCenter; //WriteToLog("ProcessVoxels", $"VoxelInSphereCenter is {Math.Round(Vector3D.Distance(hitpos, ReconstructedPosition), 2)}m away from hitpos"); double CutoutRadiusSquared = Cutout.Radius * Cutout.Radius; int processedPoints = 0; int skippedPoints = 0; int linearIndex = -1; for (bool move = true; move != false;) { enumeratorWatch.Start(); try { move = VoxelLoop.MoveNext(); } catch { move = false; MyKernel.ResponderModule.UpdateStatusReport("Keen enumerator died", true); } if (move) { linearIndex++; Vector3I voxelPoint; cutoutVoxels.ComputePosition(linearIndex, out voxelPoint); voxelPoint += refCorner; BoundingBoxD voxelBox = new BoundingBoxD(Voxel.PositionLeftBottomCorner + voxelPoint, Voxel.PositionLeftBottomCorner + voxelPoint + 1); var PointContainment = Cutout.Contains(voxelBox); bool Contacts = PointContainment.HasFlag(ContainmentType.Contains) || PointContainment.HasFlag(ContainmentType.Intersects); if (Contacts || Vector3D.DistanceSquared(ReconstructedPosition, Voxel.PositionLeftBottomCorner + voxelPoint) <= CutoutRadiusSquared) { bool pointBlocked = true; lock (BlockedVoxels) { pointBlocked = BlockedVoxels[Voxel.EntityId].Contains(voxelPoint); if (!pointBlocked) { BlockedVoxels[Voxel.EntityId].Add(voxelPoint); } } if (!pointBlocked) { byte ContentFillLevel = cutoutVoxels.Content(linearIndex); byte MaterialId = cutoutVoxels.Material(linearIndex); float MaterialFillRatio = ContentFillLevel / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT; if (!RawMaterials.ContainsKey(MaterialId)) { RawMaterials.Add(MaterialId, MaterialFillRatio); } else { RawMaterials[MaterialId] += MaterialFillRatio; } processedPoints++; } else { skippedPoints++; } } else { skippedPoints++; } int voxelIterationLimit = MyKernel.Session.Settings.SpeedMultiplierAcceleratesDrilling ? VoxelIterationLimit * MyKernel.TermControls.SpeedMultiplier : VoxelIterationLimit; if (processedPoints > 0 && processedPoints % voxelIterationLimit == 0) { //MyKernel.ResponderModule.UpdateStatusReport($"Cutting out {Math.Round(Cutout.Radius * 2, 1)}m sphere:\r\n{linearIndex} voxels processed", append: true); enumeratorWatch.Stop(); yield return(true); } } totalPoints = linearIndex; } MyKernel.ResponderModule.UpdateStatusReport($"Total processed points: {totalPoints} ({processedPoints}/{skippedPoints})", true); enumeratorWatch.Stop(); MyKernel.ResponderModule.UpdateStatusReport($"EnumeratorWatch: {Math.Round(enumeratorWatch.Elapsed.TotalMilliseconds, 3)}ms", true); //WriteToLog("ProcessVoxels", $"Found {processedPoints} valid voxel points out of {totalPoints}", EemRdx.SessionModules.LoggingLevelEnum.DebugLog, true, 2000); foreach (KeyValuePair <byte, float> kvp in RawMaterials) { MyVoxelMaterialDefinition material = MyDefinitionManager.Static.GetVoxelMaterialDefinition(kvp.Key); if (material != null) { Materials.Add(material, kvp.Value * DrillingYield); } else { nullMaterials++; continue; } } } MyKernel.ResponderModule.UpdateStatusReport($"Quitted enumerator", true); //WriteToLog("ProcessVoxels", $"Found {VoxelPoints.Count} valid voxel points", EemRdx.SessionModules.LoggingLevelEnum.DebugLog, true, 2000); //WriteToLog("ProcessVoxels", $"Found {Materials.Count} valid materials{(nullMaterials > 0 ? $" and {nullMaterials} null materials" : "")}", EemRdx.SessionModules.LoggingLevelEnum.DebugLog, true, 2000); //foreach (var kvp in Materials) //{ // WriteToLog("ProcessVoxels", $"Material: {kvp.Key.MaterialTypeName} (mined ore: {(kvp.Key.MinedOre != null ? kvp.Key.MinedOre : "null")}), amount: {kvp.Value}"); //} MyKernel.ResponderModule.UpdateStatusReport($"Calculating materials", true); Dictionary <MyObjectBuilder_Ore, float> MaterialsToAdd = new Dictionary <MyObjectBuilder_Ore, float>(); int nullMinedOres = 0; foreach (KeyValuePair <MyVoxelMaterialDefinition, float> kvp in Materials) { MyVoxelMaterialDefinition material = kvp.Key; if (string.IsNullOrWhiteSpace(material.MinedOre)) { nullMinedOres++; continue; } try { if (MyKernel.TermControls.DumpStone && material.MinedOre == "Stone") { continue; } MyObjectBuilder_Ore oreBuilder = MyObjectBuilderSerializer.CreateNewObject <MyObjectBuilder_Ore>(material.MinedOre); oreBuilder.MaterialTypeName = new MyStringHash?(material.Id.SubtypeId); MyPhysicalItemDefinition oreDef = MyDefinitionManager.Static.GetPhysicalItemDefinition(oreBuilder); float MinedAmountInKg = (kvp.Value / 1000 / oreDef.Volume) * oreDef.Mass * kvp.Key.MinedOreRatio * 32; stopwatch.Stop(); //WriteToLog("ProcessVoxels", $"Found material {material.MaterialTypeName}, {Math.Round(kvp.Value)} points, mined amount would be {Math.Round(MinedAmountInKg)} kg"); stopwatch.Start(); MaterialsToAdd.Add(oreBuilder, MinedAmountInKg); } catch (Exception Scrap) { LogError("ProcessVoxels().dict_Materials.Iterate", $"Unknown error occurred on material {material.MinedOre}", Scrap); } } Stopwatch cutoutWatch = Stopwatch.StartNew(); //Voxel.Storage.WriteRange(cutoutVoxels, MyStorageDataTypeFlags.ContentAndMaterial, refCorner - 1, refMaxCorner + 1); Voxel.RootVoxel.PerformCutOutSphereFast(Cutout.Center, (float)Cutout.Radius, true); cutoutWatch.Stop(); //WriteToLog("ProcessVoxels", $"Sphere was cut in {cutoutWatch.ElapsedTicks} ticks, which is {Math.Round(cutoutWatch.Elapsed.TotalMilliseconds, 4)} ms"); foreach (var kvp in MaterialsToAdd) { MyDefinitionId OreId = kvp.Key.GetId(); MyItemType oreItemType = new MyItemType(OreId.TypeId, OreId.SubtypeId); float amountToAdd = kvp.Value; while (amountToAdd > 0.1f) { while (((float)ToolCargo.CurrentVolume / (float)ToolCargo.MaxVolume) > 0.9f) { yield return(true); } MyInventoryItem oreItem = new MyInventoryItem(oreItemType, 0, (VRage.MyFixedPoint)amountToAdd); float FittingAmount = (float)(ToolCargo as Sandbox.Game.MyInventory).ComputeAmountThatFits(OreId); if (FittingAmount > amountToAdd) { FittingAmount = amountToAdd; } ToolCargo.AddItems((VRage.MyFixedPoint)FittingAmount, kvp.Key); amountToAdd -= FittingAmount; //MyKernel.ResponderModule.UpdateStatusReport($"Adding {Math.Round(FittingAmount)}u of {OreId.SubtypeId}, {amountToAdd} remains", append: false); } } } else { MyKernel.ResponderModule.UpdateStatusReport($"No voxel found", true); } } stopwatch.Stop(); double ElapsedMs = stopwatch.Elapsed.TotalMilliseconds; //WriteToLog("ProcessVoxels", $"Voxels processed, elapsed time: {stopwatch.ElapsedTicks} ticks, which is {Math.Round(ElapsedMs, 3)} ms"); MyKernel.ResponderModule.UpdateStatusReport($"Cycle finished", true); yield return(false); }
void Place(ICollection <IMySlimBlock> _Blocks) { try { if (_Blocks.Count == 0) { return; } HashSet <IMySlimBlock> Blocks = new HashSet <IMySlimBlock>(_Blocks); HashSet <IMySlimBlock> unbuilt = new HashSet <IMySlimBlock>(); var Projector = ((Blocks.First().CubeGrid as MyCubeGrid).Projector as IMyProjector); if (MyAPIGateway.Session.CreativeMode) { foreach (IMySlimBlock Block in Blocks) { Projector.Build(Block, Tool.OwnerId, Tool.EntityId, false); } return; } Dictionary <string, int> ToPull = new Dictionary <string, int>(); if (Welder.UseConveyorSystem) { foreach (IMySlimBlock Block in Blocks) { var FirstItem = ((MyCubeBlockDefinition)Block.BlockDefinition).Components[0].Definition.Id; if (!ToPull.ContainsKey(FirstItem.SubtypeName)) { ToPull.Add(FirstItem.SubtypeName, 1); } else { ToPull[FirstItem.SubtypeName] += 1; } } lock (GridInventoryModule.InventoryLock) { GridInventoryModule.PullIn(Welder, Reduce(ToPull), "Component"); } } foreach (IMySlimBlock Block in Blocks) { var FirstItem = ((MyCubeBlockDefinition)Block.BlockDefinition).Components[0].Definition.Id; if (ToolCargo.GetItemAmount(FirstItem) >= 1) { Projector.Build(Block, Tool.OwnerId, Tool.EntityId, false); ToolCargo.RemoveItemsOfType(1, FirstItem); } else { unbuilt.Add(Block); } } SessionCore.DebugAsync(Tool.CustomName, $"Place failed for {unbuilt.Count} blocks: can't pull first component", WriteOnlyIfDebug: true); UnbuiltBlocks.UnionWith(unbuilt); ComplainUnbuilt(); } catch (Exception Scrap) { SessionCore.LogError($"{Tool.CustomName}.Place()", Scrap); } }
void Work(int ticks = 1) { if (!MyAPIGateway.Multiplayer.IsServer) { return; } if (IsDrill) { return; } LineD WeldRay = new LineD(BeamStart, BeamEnd); List <MyLineSegmentOverlapResult <MyEntity> > Overlaps = new List <MyLineSegmentOverlapResult <MyEntity> >(); MyGamePruningStructure.GetTopmostEntitiesOverlappingRay(ref WeldRay, Overlaps); HashSet <IMyCubeGrid> Grids = new HashSet <IMyCubeGrid>(); HashSet <IMyCharacter> Characters = new HashSet <IMyCharacter>(); HashSet <IMyFloatingObject> Flobjes = new HashSet <IMyFloatingObject>(); Overlaps.Select(x => x.Element as IMyEntity).SortByType(Grids, Characters, Flobjes); Grids.Remove(ToolGrid); if (SessionCore.Debug && Vector3D.Distance(BlockPosition, MyAPIGateway.Session.LocalHumanPlayer.GetPosition()) <= 200) { string GridNames = ""; foreach (var grid in Grids) { GridNames += $"{grid.DisplayName};"; } DebugNote.Text = $"{Tool.CustomName}: processing {Grids.Count} entities: {GridNames}"; GridNames = null; } foreach (IMyCubeGrid Grid in Grids) { //if (Grid.EntityId == ToolGrid.EntityId) continue; try { ProcessGrid(Grid, ticks); } catch (Exception Scrap) { SessionCore.LogError(Grid.DisplayName, Scrap); } } foreach (IMyCharacter Char in Characters) { if (Char.WorldAABB.Intersects(ref WeldRay)) { Char.DoDamage(GrinderSpeed * ticks / 2, MyDamageType.Grind, true, null, Tool.EntityId); } } foreach (IMyFloatingObject Flobj in Flobjes) { if ((double)ToolCargo.CurrentVolume / (double)ToolCargo.MaxVolume < 0.75) { ToolCargo.PickupItem(Flobj); } } /*if (Tool is IMyShipDrill) * { * List<MyLineSegmentOverlapResult<MyVoxelBase>> VoxelOverlaps = new List<MyLineSegmentOverlapResult<MyVoxelBase>>(); * MyGamePruningStructure.GetVoxelMapsOverlappingRay(ref WeldRay, VoxelOverlaps); * MyVoxelBase Voxel = VoxelOverlaps.OrderBy(x => Vector3D.DistanceSquared(BlockPosition, x.Element.PositionComp.GetPosition())).First().Element; * ProcessVoxel(Voxel, ticks); * }*/ }