private bool BuildTarget(BlockTarget target, ShipyardItem item, IMyCubeBlock tool) { IMyProjector projector = target.Projector; IMySlimBlock block = target.Block; if (projector == null || block == null) { return(false); } if (projector.CanBuild(block, false) != BuildCheckResult.OK) { return(false); } if (MyAPIGateway.Session.CreativeMode) { projector.Build(block, 0, tool.EntityId, false); return(projector.CanBuild(block, true) != BuildCheckResult.OK); } //try to remove the first component from inventory string name = ((MyCubeBlockDefinition)block.BlockDefinition).Components[0].Definition.Id.SubtypeName; if (_tmpInventory.PullAny(item.ConnectedCargo, name, 2)) { _tmpInventory.Clear(); projector.Build(block, 0, tool.EntityId, false); return(projector.CanBuild(block, true) != BuildCheckResult.OK); } return(false); }
private void Start() { blockTarget = this.gameObject.GetComponent <BlockTarget>(); blockGenerator = this.gameObject.GetComponent <BlockGenerator>(); blockSlider = this.gameObject.GetComponent <BlockSlider>(); resetCheck = blockGenerator.GenerateBlockSet(true); itemDoCount = itemSuCount = totalHit = totalMiss = 0; SoundManager.Instance.PlayBGM(SoundManager.Instance.bgm_Play); }
void OnDoMoveComplete() { if (m_raycastHit.transform == null) //Nếu khối đã vỡ { FlyInDirection(m_directFly); //bay tiếp theo hướng cũ } else { if (m_raycastHit.transform.tag == "Wall Bottom") //Nếu đã chạm xuống sàn { FinishFly(); } else { if (m_raycastHit.transform.tag == "Block Target") { BlockTarget blockTarget = m_raycastHit.transform.GetComponent <BlockTarget>(); blockTarget.TakeDamage(m_damage); } FlyInDirection(Vector3.Reflect(m_directFly, m_raycastHit.normal)); } } }
private bool StepWeld(ShipyardItem shipyardItem) { var targetsToRemove = new HashSet <BlockTarget>(); var targetsToRedraw = new HashSet <BlockTarget>(); //we need to multiply this by MyShipWelder.WELDER_AMOUNT_PER_SECOND / 2, which also evaluates to 1 float weldAmount = MyAPIGateway.Session.WelderSpeedMultiplier * shipyardItem.Settings.WeldMultiplier; float boneAmount = weldAmount * .1f; if (shipyardItem.TargetBlocks.Count == 0) { var sortBlock = Profiler.Start(FullName, nameof(StepWeld), "Sort Targets"); shipyardItem.TargetBlocks.Clear(); shipyardItem.ProxDict.Clear(); //precalculate all the BlockTarget for our target grids to speed things up var gridTargets = new Dictionary <long, List <BlockTarget> >(); foreach (IMyCubeGrid targetGrid in shipyardItem.YardGrids) { if (targetGrid.Closed || targetGrid.MarkedForClose) { continue; } var tmpBlocks = new List <IMySlimBlock>(); targetGrid.GetBlocks(tmpBlocks); gridTargets.Add(targetGrid.EntityId, new List <BlockTarget>(tmpBlocks.Count)); foreach (IMySlimBlock block in tmpBlocks.ToArray()) { if (block == null || (block.CubeGrid.Physics != null && block.IsFullIntegrity && !block.HasDeformation)) { continue; } var target = new BlockTarget(block, shipyardItem); shipyardItem.TargetBlocks.Add(target); gridTargets[targetGrid.EntityId].Add(target); } //Shouldn't be needed as this is handled by the projector logic in BlockTarget //var proj = targetGrid.Projector(); //if (proj != null && !shipyardItem.YardGrids.Contains(proj.CubeGrid)) //{ // proj.CubeGrid.GetBlocks(tmpBlocks); // gridTargets.Add(proj.CubeGrid.EntityId, new List<BlockTarget>()); // foreach (var block in tmpBlocks.ToArray()) // { // if (block == null || (targetGrid.Physics != null && block.IsFullIntegrity && !block.HasDeformation)) // continue; // var pos = block.GetPosition(); // if (!shipyardItem.ShipyardBox.Contains(ref pos)) // continue; // var target = new BlockTarget(block, shipyardItem); // shipyardItem.TargetBlocks.Add(target); // gridTargets[block.CubeGrid.EntityId].Add(target); // } //} } int count = 0; foreach (KeyValuePair <long, List <BlockTarget> > entry in gridTargets) { count += entry.Value.Count; } foreach (IMyCubeBlock tool in shipyardItem.Tools) { shipyardItem.ProxDict.Add(tool.EntityId, new List <BlockTarget>()); //first sort grids by distance to tool shipyardItem.YardGrids.Sort((a, b) => Vector3D.DistanceSquared(a.Center(), tool.GetPosition()).CompareTo( Vector3D.DistanceSquared(b.Center(), tool.GetPosition()))); foreach (IMyCubeGrid grid in shipyardItem.YardGrids) { //then sort blocks by distance to grid center List <BlockTarget> list = gridTargets[grid.EntityId]; switch (shipyardItem.Settings.BuildPattern) { case BuildPatternEnum.FromProjector: list.Sort((a, b) => a.ProjectorDist.CompareTo(b.ProjectorDist)); break; case BuildPatternEnum.FromCenter: list.Sort((a, b) => a.CenterDist.CompareTo(b.CenterDist)); break; case BuildPatternEnum.FromCorners: list.Sort((a, b) => a.ToolDist[tool.EntityId].CompareTo(b.ToolDist[tool.EntityId])); break; default: throw new Exception("Invalid BuildPatternEnum"); } shipyardItem.ProxDict[tool.EntityId].AddRange(list); } } sortBlock.End(); } //nothing to do if (shipyardItem.TargetBlocks.Count == 0) { Logging.Instance.WriteDebug("TargetBlocks 0"); return(false); } //assign blocks to our welders foreach (IMyCubeBlock welder in shipyardItem.Tools) { for (int i = 0; i < shipyardItem.Settings.BeamCount; i++) { if (shipyardItem.BlocksToProcess[welder.EntityId][i] != null) { continue; } var toRemove = new List <BlockTarget>(); BlockTarget nextTarget = null; foreach (BlockTarget target in shipyardItem.ProxDict[welder.EntityId]) { bool found = false; //each block can only have one laser assigned foreach (KeyValuePair <long, BlockTarget[]> entry in shipyardItem.BlocksToProcess) { if (entry.Value.Contains(target)) { found = true; break; } } if (found) { toRemove.Add(target); continue; } if (target.Projector != null) { BuildCheckResult res = target.Projector.CanBuild(target.Block, false); if (res == BuildCheckResult.AlreadyBuilt) { target.UpdateAfterBuild(); } else if (res != BuildCheckResult.OK) { continue; } else { bool success = false; Utilities.InvokeBlocking(() => success = BuildTarget(target, shipyardItem, welder)); Logging.Instance.WriteDebug(success.ToString()); if (!success) { //toRemove.Add(target); continue; } target.UpdateAfterBuild(); } } if (target.CubeGrid.Physics != null && target.Block.IsFullIntegrity && !target.Block.HasDeformation) { toRemove.Add(target); continue; } nextTarget = target; break; } if (nextTarget != null) { targetsToRedraw.Add(nextTarget); shipyardItem.BlocksToProcess[welder.EntityId][i] = nextTarget; } foreach (BlockTarget removeTarget in toRemove) { shipyardItem.ProxDict[welder.EntityId].Remove(removeTarget); shipyardItem.TargetBlocks.Remove(removeTarget); } } } //update lasers foreach (KeyValuePair <long, BlockTarget[]> entry in shipyardItem.BlocksToProcess) { for (int i = 0; i < entry.Value.Length; i++) { BlockTarget targetBlock = entry.Value[i]; if (targetBlock == null || _stalledTargets.Contains(targetBlock)) { continue; } if (targetsToRedraw.Contains(targetBlock)) { var toolLine = new Communication.ToolLineStruct { ToolId = entry.Key, GridId = targetBlock.CubeGrid.EntityId, BlockPos = targetBlock.GridPosition, PackedColor = Color.DarkCyan.PackedValue, Pulse = false, EmitterIndex = (byte)i }; Communication.SendLine(toolLine, shipyardItem.ShipyardBox.Center); } } } if (shipyardItem.BlocksToProcess.All(e => e.Value.All(t => t == null))) { Logging.Instance.WriteDebug("Null thing?"); return(false); } shipyardItem.UpdatePowerUse(); targetsToRedraw.Clear(); Utilities.InvokeBlocking(() => { foreach (IMyCubeBlock welder in shipyardItem.Tools) { var tool = (IMyCollector)welder; MyInventory welderInventory = ((MyEntity)tool).GetInventory(); int i = 0; foreach (BlockTarget target in shipyardItem.BlocksToProcess[tool.EntityId]) { if (target == null) { continue; } if (target.CubeGrid.Physics == null || target.CubeGrid.Closed || target.CubeGrid.MarkedForClose) { targetsToRemove.Add(target); continue; } if (!MyAPIGateway.Session.CreativeMode) { /* * Welding laser "efficiency" is a float between 0-1 where: * 0.0 => 0% of component stock used for construction (100% loss) * 1.0 => 100% of component stock used for construction (0% loss) * * Efficiency decay/distance formula is the same as above for grinder */ double efficiency = 1 - (target.ToolDist[tool.EntityId] / 200000); if (!shipyardItem.StaticYard) { efficiency /= 2; } if (efficiency < 0.1) { efficiency = 0.1; } //Logging.Instance.WriteDebug(String.Format("Welder[{0}]block[{1}] distance=[{2:F2}m] efficiency=[{3:F5}]", tool.DisplayNameText, i, Math.Sqrt(target.ToolDist[tool.EntityId]), efficiency)); /* * We have to factor in our efficiency ratio before transferring to the block "construction stockpile", * but that math isn't nearly as easy as it was with the grinder. * * For each missing component type, we know how many items are "missing" from the construction model, M * * The simplest approach would be to pull M items from the conveyor system (if enabled), then move * (M*efficiency) items to the "construction stockpile" and vaporize the other (M*(1-efficiency)) items. * However, this approach would leave the construction stockpile incomplete and require several iterations * before M items have actually been copied. * * A better solution is to pull enough "extra" items from the conveyors that the welder has enough to * move M items to the construction stockpile even after losses due to distance inefficiency * * For example, if the target block is missing M=9 items and we are running at 0.9 (90%) efficiency, * ideally that means we should pull 10 units, vaporize 1, and still have 9 for construction. However, * if the conveyor system was only able to supply us with 2 components, we should not continue to blindly * vaporize 1 unit. * * Instead, we have to consult the post-conveyor-pull welder inventory to determine if it has at least * the required number of components. If it does, we vaporize M*(1-efficiency). Otherwise we only * vaporize current_count*(1-efficiency) and transfer the rest to the construction stockpile */ var missingComponents = new Dictionary <string, int>(); target.Block.GetMissingComponents(missingComponents); var wasteComponents = new Dictionary <string, int>(); foreach (KeyValuePair <string, int> entry in missingComponents) { var componentId = new MyDefinitionId(typeof(MyObjectBuilder_Component), entry.Key); int missing = entry.Value; MyFixedPoint totalRequired = (MyFixedPoint)(missing / efficiency); MyFixedPoint currentStock = welderInventory.GetItemAmount(componentId); //Logging.Instance.WriteDebug(String.Format("Welder[{0}]block[{1}] Component[{2}] missing[{3:F3}] inefficiency requires[{4:F3}] in_stock[{5:F3}]", tool.DisplayNameText, i, entry.Key, missing, totalRequired, currentStock)); if (currentStock < totalRequired && tool.UseConveyorSystem) { // Welder doesn't have totalRequired, so try to pull the difference from conveyors welderInventory.PullAny(shipyardItem.ConnectedCargo, entry.Key, (int)Math.Ceiling((double)(totalRequired - currentStock))); currentStock = welderInventory.GetItemAmount(componentId); //Logging.Instance.WriteDebug(String.Format("Welder[{0}]block[{1}] Component[{2}] - after conveyor pull - in_stock[{3:F3}]", tool.DisplayNameText, i, entry.Key, currentStock)); } // Now compute the number of components to delete // MoveItemsToConstructionPile() below won't move anything if we have less than 1 unit, // so don't bother "losing" anything due to ineffeciency if (currentStock >= 1) { // The lesser of (missing, currentStock), times (1 minus) our efficiency fraction MyFixedPoint toDelete = MyFixedPoint.Min(MyFixedPoint.Floor(currentStock), missing) * (MyFixedPoint)(1 - efficiency); //Logging.Instance.WriteDebug(String.Format("Welder[{0}]block[{1}] Component[{2}] amount lost due to distance [{3:F3}]", tool.DisplayNameText, i, entry.Key, toDelete)); welderInventory.RemoveItemsOfType((int)toDelete, componentId); } } target.Block.MoveItemsToConstructionStockpile(welderInventory); missingComponents.Clear(); target.Block.GetMissingComponents(missingComponents); if (missingComponents.Any() && !target.Block.HasDeformation) { if (_stalledTargets.Add(target)) { targetsToRedraw.Add(target); } } else { if (_stalledTargets.Remove(target)) { targetsToRedraw.Add(target); } } target.Block.IncreaseMountLevel(weldAmount, 0, welderInventory, boneAmount, true); if (target.Block.IsFullIntegrity && !target.Block.HasDeformation) { targetsToRemove.Add(target); } } i++; } } }); shipyardItem.MissingComponentsDict.Clear(); foreach (KeyValuePair <long, BlockTarget[]> entry in shipyardItem.BlocksToProcess) { for (int i = 0; i < entry.Value.Length; i++) { BlockTarget target = entry.Value[i]; if (target == null) { continue; } if (targetsToRemove.Contains(target)) { Communication.ClearLine(entry.Key, i); _stalledTargets.Remove(target); shipyardItem.TargetBlocks.Remove(target); entry.Value[i] = null; continue; } if (_stalledTargets.Contains(target)) { var blockComponents = new Dictionary <string, int>(); target.Block.GetMissingComponents(blockComponents); foreach (KeyValuePair <string, int> component in blockComponents) { if (shipyardItem.MissingComponentsDict.ContainsKey(component.Key)) { shipyardItem.MissingComponentsDict[component.Key] += component.Value; } else { shipyardItem.MissingComponentsDict.Add(component.Key, component.Value); } } var toolLine = new Communication.ToolLineStruct { ToolId = entry.Key, GridId = target.CubeGrid.EntityId, BlockPos = target.GridPosition, PackedColor = Color.Purple.PackedValue, Pulse = true, EmitterIndex = (byte)i }; if (targetsToRedraw.Contains(target)) { Communication.ClearLine(entry.Key, i); Communication.SendLine(toolLine, shipyardItem.ShipyardBox.Center); } continue; } } } return(true); }
private void StepGrind(ShipyardItem shipyardItem) { var targetsToRedraw = new HashSet <BlockTarget>(); //we need to multiply this by MyShipGrinderConstants.GRINDER_AMOUNT_PER_SECOND / 2... which evaluates to 1 float grindAmount = MyAPIGateway.Session.GrinderSpeedMultiplier * shipyardItem.Settings.GrindMultiplier; if (shipyardItem.TargetBlocks.Count == 0) { var targetblock = Profiler.Start(FullName, nameof(StepGrind), "Populate target blocks"); var blocks = new List <IMySlimBlock>(); Logging.Instance.WriteLine(shipyardItem.YardGrids.Count.ToString()); foreach (IMyCubeGrid yardGrid in shipyardItem.YardGrids.Where(g => g.Physics != null)) //don't process projections { var tmpBlocks = new List <IMySlimBlock>(); yardGrid.GetBlocks(tmpBlocks); blocks.AddRange(tmpBlocks); } foreach (IMySlimBlock tmpBlock in blocks) { shipyardItem.TargetBlocks.Add(new BlockTarget(tmpBlock, shipyardItem)); } targetblock.End(); } List <BlockTarget> allBlocks = shipyardItem.TargetBlocks.ToList(); if (allBlocks.Count == 0) { return; } if (!shipyardItem.ProxDict.Any()) { //sort blocks by distance to each tool foreach (IMyCubeBlock tool in shipyardItem.Tools) { var targetSortBlock = Profiler.Start(FullName, nameof(StepGrind), "Sort Targets"); List <BlockTarget> sortTargets = allBlocks.ToList(); sortTargets.Sort((a, b) => a.ToolDist[tool.EntityId].CompareTo(b.ToolDist[tool.EntityId])); shipyardItem.ProxDict[tool.EntityId] = sortTargets; targetSortBlock.End(); } } var targetFindBlock = Profiler.Start(FullName, nameof(StepGrind), "Find Targets"); foreach (IMyCubeBlock tool in shipyardItem.Tools) { if (tool.Closed || tool.MarkedForClose) { //this is bad shipyardItem.Disable(); return; } BlockTarget[] blockArray = shipyardItem.BlocksToProcess[tool.EntityId]; //find the next target for each grinder, if it needs one for (int i = 0; i < shipyardItem.Settings.BeamCount; i++) { var toRemove = new HashSet <BlockTarget>(); if (blockArray[i] != null) { continue; } BlockTarget nextTarget = null; for (int b = 0; b < shipyardItem.ProxDict[tool.EntityId].Count; b++) { nextTarget = shipyardItem.ProxDict[tool.EntityId][b]; if (nextTarget.CubeGrid.Closed || nextTarget.CubeGrid.MarkedForClose) { continue; } //one grinder per block, please bool found = false; foreach (KeyValuePair <long, BlockTarget[]> entry in shipyardItem.BlocksToProcess) { foreach (BlockTarget target in entry.Value) { if (target == null) { continue; } if (target == nextTarget) { found = true; break; } } } if (found) { toRemove.Add(nextTarget); continue; } targetsToRedraw.Add(nextTarget); break; } foreach (BlockTarget removeTarget in toRemove) { shipyardItem.ProxDict[tool.EntityId].Remove(removeTarget); shipyardItem.TargetBlocks.Remove(removeTarget); } //we found a block to pair with our grinder, add it to the dictionary and carry on with destruction if (nextTarget != null) { shipyardItem.BlocksToProcess[tool.EntityId][i] = nextTarget; } } } targetFindBlock.End(); shipyardItem.UpdatePowerUse(); var grindActionBlock = Profiler.Start(FullName, nameof(StepGrind), "Grind action"); var removeTargets = new List <BlockTarget>(); //do the grinding Utilities.InvokeBlocking(() => { foreach (IMyCubeBlock tool in shipyardItem.Tools) { for (int b = 0; b < shipyardItem.BlocksToProcess[tool.EntityId].Length; b++) { BlockTarget target = shipyardItem.BlocksToProcess[tool.EntityId][b]; if (target == null) { continue; } if (target.CubeGrid.Closed || target.CubeGrid.MarkedForClose) { Logging.Instance.WriteDebug("Error in grind action: Target closed"); removeTargets.Add(target); return; } if (targetsToRedraw.Contains(target)) { var toolLine = new Communication.ToolLineStruct { ToolId = tool.EntityId, GridId = target.CubeGrid.EntityId, BlockPos = target.GridPosition, PackedColor = Color.OrangeRed.PackedValue, Pulse = false, EmitterIndex = (byte)b }; Communication.SendLine(toolLine, shipyardItem.ShipyardBox.Center); } /* * Grinding laser "efficiency" is a float between 0-1 where: * 0.0 => 0% of components recovered * 1.0 => 100% of components recovered * * Efficiency decays exponentially as distance to the target (length of the "laser") increases * 0m => 1.0000 * 10m => 0.9995 * 25m => 0.9969 * 50m => 0.9875 * 100m => 0.9500 * 150m => 0.8875 * 250m => 0.6875 * 400m => 0.2000 * inf => 0.1000 * We impose a minimum efficiency of 0.1 (10%), which happens at distances > ~450m */ double efficiency = 1 - (target.ToolDist[tool.EntityId] / 200000); if (!shipyardItem.StaticYard) { efficiency /= 2; } if (efficiency < 0.1) { efficiency = 0.1; } //Logging.Instance.WriteDebug(String.Format("Grinder[{0}]block[{1}] distance=[{2:F2}m] efficiency=[{3:F5}]", tool.DisplayNameText, b, Math.Sqrt(target.ToolDist[tool.EntityId]), efficiency)); if (!shipyardItem.YardGrids.Contains(target.CubeGrid)) { //we missed this grid or its split at some point, so add it to the list and register the split event shipyardItem.YardGrids.Add(target.CubeGrid); ((MyCubeGrid)target.CubeGrid).OnGridSplit += shipyardItem.OnGridSplit; } MyInventory grinderInventory = ((MyEntity)tool).GetInventory(); if (!target.Block.IsFullyDismounted) { var decreaseBlock = Profiler.Start(FullName, nameof(StepGrind), "DecreaseMountLevel"); target.Block.DecreaseMountLevel(grindAmount, grinderInventory); decreaseBlock.End(); var inventoryBlock = Profiler.Start(FullName, nameof(StepGrind), "Grind Inventory"); // First move everything into _tmpInventory target.Block.MoveItemsFromConstructionStockpile(_tmpInventory); // Then move items into grinder inventory, factoring in our efficiency ratio foreach (MyPhysicalInventoryItem item in _tmpInventory.GetItems()) { //Logging.Instance.WriteDebug(String.Format("Grinder[{0}]block[{1}] Item[{2}] grind_amt[{3:F2}] collect_amt[{4:F2}]", tool.DisplayNameText, b, item.Content.SubtypeName, item.Amount, (double)item.Amount*efficiency)); grinderInventory.Add(item, (int)Math.Round((double)item.Amount * efficiency)); } // Then clear out everything left in _tmpInventory _tmpInventory.Clear(); inventoryBlock.End(); } // This isn't an <else> clause because target.Block may have become FullyDismounted above, // in which case we need to run both code blocks if (target.Block.IsFullyDismounted) { var dismountBlock = Profiler.Start(FullName, nameof(StepGrind), "FullyDismounted"); var tmpItemList = new List <MyPhysicalInventoryItem>(); var blockEntity = target.Block.FatBlock as MyEntity; if (blockEntity != null && blockEntity.HasInventory) { var dismountInventory = Profiler.Start(FullName, nameof(StepGrind), "DismountInventory"); for (int i = 0; i < blockEntity.InventoryCount; ++i) { MyInventory blockInventory = blockEntity.GetInventory(i); if (blockInventory == null) { continue; } if (blockInventory.Empty()) { continue; } tmpItemList.Clear(); tmpItemList.AddRange(blockInventory.GetItems()); foreach (MyPhysicalInventoryItem item in tmpItemList) { //Logging.Instance.WriteDebug(String.Format("Grinder[{0}]block[{1}] Item[{2}] inventory[{3:F2}] collected[{4:F2}]", tool.DisplayNameText, b, item.Content.SubtypeName, item.Amount, (double)item.Amount * efficiency)); blockInventory.Remove(item, item.Amount); grinderInventory.Add(item, (int)Math.Round((double)item.Amount * efficiency)); } } dismountInventory.End(); } target.Block.SpawnConstructionStockpile(); target.CubeGrid.RazeBlock(target.GridPosition); removeTargets.Add(target); shipyardItem.TargetBlocks.Remove(target); dismountBlock.End(); } } } }); foreach (KeyValuePair <long, List <BlockTarget> > entry in shipyardItem.ProxDict) { foreach (BlockTarget removeBlock in removeTargets) { entry.Value.Remove(removeBlock); } } foreach (BlockTarget removeBlock in removeTargets) { shipyardItem.TargetBlocks.Remove(removeBlock); } //shipyardItem.ActiveTargets = 0; //clear lines for any destroyed blocks and update our target count foreach (KeyValuePair <long, BlockTarget[]> entry in shipyardItem.BlocksToProcess) { for (int i = 0; i < entry.Value.Length; i++) { BlockTarget removeBlock = entry.Value[i]; if (removeTargets.Contains(removeBlock)) { Communication.ClearLine(entry.Key, i); entry.Value[i] = null; } //if (!removeTargets.Contains(removeBlock) && removeBlock != null) //{ // shipyardItem.ActiveTargets++; //} } } grindActionBlock.End(); }
public void InitDisplay(BlockTarget t) { curTarget = t; w.text = t.width + ""; h.text = t.height + ""; }