public static void DeleteSmart(this IMyCubeGrid Grid) { if (!MyAPIGateway.Session.IsServer) { return; } List <IMyCubeGrid> Subgrids = Grid.GetAllSubgrids(); foreach (IMyCubeGrid Subgrid in Subgrids) { Subgrid.Close(); } Grid.Close(); }
/// Closes this grid and all its subgrids (may include things docked on connectors!) public static void CloseAll(this IMyCubeGrid grid) { var slimBlocks = new List <IMySlimBlock>(); grid.GetBlocks(slimBlocks, b => b.FatBlock is IMyMotorBase); foreach (var slim in slimBlocks) { var fat = slim.FatBlock as IMyMotorBase; var subGrid = fat.TopGrid; if (subGrid != null) { subGrid.Close(); } } grid.Close(); }
public override bool HandleCommand(ulong userId, string[] words) { if (!PluginSettings.Instance.DockingEnabled) { return(false); } if (words.Length < 1) { Communication.SendPrivateInformation(userId, GetHelp()); return(true); } if (m_docking) { Communication.SendPrivateInformation(userId, "Server is busy"); return(true); } m_docking = true; try { string pylonName = string.Join(" ", words); /* * int timeLeft; * if (Entity.CheckCoolDown(pylonName, out timeLeft)) * { * Communication.Message(String.Format("The docking zone '{0}' is on cooldown. Please wait a {1} seconds before trying to dock/undock again.", pylonName, Math.Max(0, timeLeft))); * return; * } */ if (PlayerMap.Instance.GetPlayerIdsFromSteamId(userId).Count < 1) { Communication.SendPrivateInformation(userId, $"Unable to find player Id: {userId}"); return(true); } long playerId = PlayerMap.Instance.GetPlayerIdsFromSteamId(userId).First(); Dictionary <string, List <IMyCubeBlock> > testList; List <IMyCubeBlock> beaconList; DockingZone.FindByName(pylonName, out testList, out beaconList, playerId); if (beaconList.Count == 4) { // Check ownership foreach (IMyCubeBlock entityBlock in beaconList) { IMyTerminalBlock terminal = (IMyTerminalBlock)entityBlock; if (!terminal.HasPlayerAccess(playerId)) { Communication.SendPrivateInformation(userId, $"You do not have permission to use '{pylonName}'. You must either own all the beacons or they must be shared with faction."); return(true); } } // Check for bounding box intsection of other docking zones int intersectElement = 0; if (Entity.CheckForIntersection(testList, beaconList, out intersectElement)) { Communication.SendPrivateInformation(userId, $"The docking zone '{pylonName}' intersects with docking zone '{testList.ElementAt( intersectElement ).Key}'. Make sure you place your docking zones so they don't overlap."); return(true); } // Check if ship already docked in this zone IMyCubeBlock e = beaconList[0]; IMyCubeGrid parent = (IMyCubeGrid)e.Parent; long[] beaconListIds = beaconList.Select(b => b.EntityId).ToArray(); long ownerId = beaconList.First().OwnerId; List <DockingItem> checkItems = Docking.Instance.Find(d => d.PlayerId == ownerId && d.TargetEntityId == parent.EntityId && d.DockingBeaconIds.Intersect(beaconListIds).Count() == 4); if (checkItems.Count >= PluginSettings.Instance.DockingShipsPerZone) { Communication.SendPrivateInformation(userId, $"Docking zone '{pylonName}' already contains the maximum capacity of ships."); return(true); } // Figure out center of docking area, and other distance information double maxDistance = 99; Vector3D vPos = new Vector3D(0, 0, 0); foreach (IMyCubeBlock b in beaconList) { Vector3D beaconPos = Entity.GetBlockEntityPosition(b); vPos += beaconPos; } vPos = vPos / 4; foreach (IMyCubeBlock b in beaconList) { Vector3D beaconPos = Entity.GetBlockEntityPosition(b); maxDistance = Math.Min(maxDistance, Vector3D.Distance(vPos, beaconPos)); } // Find ship in docking area IMyCubeGrid dockingEntity = null; HashSet <IMyEntity> cubeGrids = new HashSet <IMyEntity>(); Wrapper.GameAction(() => { MyAPIGateway.Entities.GetEntities(cubeGrids, f => f is IMyCubeGrid); }); foreach (IMyCubeGrid gridCheck in cubeGrids) { if (gridCheck.IsStatic || gridCheck == parent) { continue; } double distance = Vector3D.Distance(gridCheck.GetPosition(), vPos); if (distance < maxDistance) { dockingEntity = gridCheck; break; } } // Figure out if the ship fits in docking area, and then save ship if (dockingEntity != null) { // Get bounding box of both the docking zone and docking ship OrientedBoundingBoxD targetBounding = Entity.GetBoundingBox(beaconList); OrientedBoundingBoxD dockingBounding = Entity.GetBoundingBox(dockingEntity); // Make sure the docking zone contains the docking ship. If they intersect or are disjointed, then fail if (!Entity.GreaterThan(dockingBounding.HalfExtent * 2, targetBounding.HalfExtent * 2)) { Communication.SendPrivateInformation(userId, $"The ship '{dockingEntity.DisplayName}' is too large for it's carrier. The ship's bounding box must fit inside the docking zone bounding box!"); return(true); } if (targetBounding.Contains(ref dockingBounding) != ContainmentType.Contains) { Communication.SendPrivateInformation(userId, $"The ship '{dockingEntity.DisplayName}' is not fully inside the docking zone '{pylonName}'. Make sure the ship is fully contained inside the docking zone"); return(true); } // Calculate the mass and ensure the docking ship is less than half the mass of the dock float parentMass = Entity.CalculateMass(parent); float dockingMass = Entity.CalculateMass(dockingEntity); if (dockingMass > parentMass) { Communication.SendPrivateInformation(userId, $"The ship you're trying to dock is too heavy for it's carrier. The ship mass must be less than half the large ship / stations mass! (DM={dockingMass}kg CM={parentMass}kg)"); return(true); } // Check to see if the ship is piloted, if it is, error out. // TODO: Check to see if we can get a real time copy of this entity? List <IMySlimBlock> blocks = new List <IMySlimBlock>(); dockingEntity.GetBlocks(blocks, x => x.FatBlock is MyCockpit); foreach (IMySlimBlock slim in blocks) { //MyObjectBuilder_Cockpit c = (MyObjectBuilder_Cockpit)slim.FatBlock.GetObjectBuilderCubeBlock(); var c = (MyShipController)slim.FatBlock; if (c.Pilot != null) { Communication.SendPrivateInformation(userId, $"Ship in docking zone '{pylonName}' has a pilot! Please exit the ship before trying to dock. (Sometimes this can lag a bit. Wait 10 seconds and try again)"); return(true); } } // Save position and rotation information. Some fun stuff here. // Get our dock rotation as a quaternion Quaternion saveQuat = Quaternion.CreateFromRotationMatrix(parent.WorldMatrix.GetOrientation()); // Transform docked ship's local position by inverse of the the parent (unwinds parent) and save it for when we undock Vector3D savePos = Vector3D.Transform(dockingEntity.GetPosition() - parent.GetPosition(), Quaternion.Inverse(saveQuat)); // Get local rotation of dock ship, and save it for when we undock saveQuat = Quaternion.Inverse(saveQuat) * Quaternion.CreateFromRotationMatrix(dockingEntity.WorldMatrix.GetOrientation()); // Save ship to file and remove FileInfo info = new FileInfo(Path.Combine(Essentials.PluginPath, "Docking", $"docked_{ownerId}_{parent.EntityId}_{dockingEntity.EntityId}.sbc")); if (!Directory.Exists(info.DirectoryName)) { Directory.CreateDirectory(info.DirectoryName); } //CubeGridEntity dockingGrid = new CubeGridEntity((MyObjectBuilder_CubeGrid)dockingEntity.GetObjectBuilder(), dockingEntity); MyObjectBuilder_CubeGrid gridBuilder = CubeGrids.SafeGetObjectBuilder(dockingEntity); if (gridBuilder == null) { Communication.SendPrivateInformation(userId, $"Failed to load entity for export: {dockingEntity.DisplayName}"); return(true); } // Save item DockingItem dockItem = new DockingItem { DockedEntityId = dockingEntity.EntityId, TargetEntityId = parent.EntityId, PlayerId = ownerId, DockingBeaconIds = beaconList.Select(s => s.EntityId).ToArray( ), DockedName = dockingEntity.DisplayName, SavePos = savePos, SaveQuat = saveQuat }; Docking.Instance.Add(dockItem); // Serialize and save ship to file MyObjectBuilderSerializer.SerializeXML(info.FullName, false, gridBuilder); Wrapper.BeginGameAction(() => dockingEntity.Close( )); Communication.SendPrivateInformation(userId, $"Docked ship '{dockItem.DockedName}' in docking zone '{pylonName}'."); Log.Info("Docked ship \"{0}\" in docking zone \"{1}\". Saved to {2}", dockItem.DockedName, pylonName, info.FullName); /* * // Add a cool down * DockingCooldownItem cItem = new DockingCooldownItem(); * cItem.name = pylonName; * cItem.startTime = DateTime.Now; * PluginDocking.CooldownList.Add(cItem); */ } else { Communication.SendPrivateInformation(userId, $"No ships in docking zone '{pylonName}'."); } } else if (beaconList.Count > 4) { Communication.SendPrivateInformation(userId, $"Too many beacons with the name or another zone with the name '{pylonName}'. Place only 4 beacons to create a zone or try a different zone name."); } else { Communication.SendPrivateInformation(userId, string.Format("Can not locate docking zone '{0}'. There must be 4 beacons with the name '{0}' to create a docking zone. Beacons must be fully built!", pylonName)); } return(true); } catch (SecurityException ex) { Log.Error("Can't access docked ship file.", ex); return(false); } catch (UnauthorizedAccessException ex) { Log.Error("Can't access docked ship file.", ex); return(false); } catch (DirectoryNotFoundException ex) { Log.Error("Directory does not exist", ex); return(false); } catch (IOException ex) { Log.Error(ex); return(false); } finally { m_docking = false; } }
public void HandleChatCommand(ulong steamId, string command) { MyPromoteLevel level = MyAPIGateway.Session.GetUserPromoteLevel(steamId); Logging.Instance.WriteLine($"Got chat command from {steamId} : {command}"); if (command.Equals("!join", StringComparison.CurrentCultureIgnoreCase)) { if (!Settings.Instance.Hub) { Communication.SendServerChat(steamId, "Join commands are not valid in battle servers!"); return; } Communication.SendServerChat(steamId, $"There are {Servers.Count} battle servers. Please select the one you want by sending '!join [number]'"); List <int> availableServers = (from server in Servers.Values where server.CanJoin select server.Index + 1).ToList(); if (availableServers.Count < Servers.Count) { Communication.SendServerChat(steamId, $"These servers are ready for matches: {string.Join(", ", availableServers)}"); } else { Communication.SendServerChat(steamId, $"All {Servers.Count} servers are available for new matches!"); } return; } if (command.StartsWith("!join", StringComparison.CurrentCultureIgnoreCase)) { int ind = command.IndexOf(" "); if (ind == -1) { Communication.SendServerChat(steamId, "Couldn't parse your server selection!"); return; } string numtex = command.Substring(ind); ServerItem server; int num; if (!int.TryParse(numtex, out num)) { Communication.SendServerChat(steamId, "Couldn't parse your server selection!"); return; } if (!Servers.TryGetValue(num - 1, out server)) { Communication.SendServerChat(steamId, $"Couldn't find server {num}"); return; } if (!server.CanJoin) { Communication.SendServerChat(steamId, "Sorry, this server is not open to new members. Please try another."); return; } IMyPlayer player = Utilities.GetPlayerBySteamId(steamId); var block = player?.Controller?.ControlledEntity?.Entity as IMyCubeBlock; IMyCubeGrid grid = block?.CubeGrid; if (grid == null) { Communication.SendServerChat(steamId, "Can't find your ship. Make sure you're seated in the ship you want to take with you."); return; } var blocks = new List <IMySlimBlock>(); grid.GetBlocks(blocks); if (blocks.Count > Settings.Instance.MaxBlockCount) { Communication.SendServerChat(steamId, $"Your ship has {blocks.Count} blocks. The limit for this server is {Settings.Instance.MaxBlockCount}"); return; } byte[] payload = Utilities.SerializeAndSign(grid, Utilities.GetPlayerBySteamId(steamId), block.Position); Communication.SegmentAndSend(Communication.MessageType.ClientGridPart, payload, MyAPIGateway.Multiplayer.ServerId, steamId); server.Join(steamId); var timer = new Timer(10000); timer.AutoReset = false; timer.Elapsed += (a, b) => MyAPIGateway.Utilities.InvokeOnGameThread(() => grid.Close()); timer.Start(); return; } if (command.Equals("!hub", StringComparison.CurrentCultureIgnoreCase)) { if (Settings.Instance.Hub) { Communication.SendServerChat(steamId, "You're already in the hub!"); return; } Communication.RedirectClient(steamId, Settings.Instance.HubIP); return; } if (level >= MyPromoteLevel.Moderator) { if (command.StartsWith("!spectate", StringComparison.CurrentCultureIgnoreCase)) { int ind = command.IndexOf(" "); if (ind == -1) { Communication.SendServerChat(steamId, "Couldn't parse your server selection!"); return; } string numtex = command.Substring(ind); ServerItem server; int num; if (!int.TryParse(numtex, out num)) { Communication.SendServerChat(steamId, "Couldn't parse your server selection!"); return; } if (!Servers.TryGetValue(num - 1, out server)) { Communication.SendServerChat(steamId, $"Couldn't find server {num}"); return; } MyAPIGateway.Utilities.DeleteFileInLocalStorage("Ship.bin", typeof(LinkModCore)); Communication.RedirectClient(steamId, server.IP); return; } } if (level >= MyPromoteLevel.Admin) { if (command.Equals("!endjoin", StringComparison.CurrentCultureIgnoreCase)) { _lobbyTimer.Stop(); _lobbyRunning = false; _matchRunning = true; Communication.SendNotification(0, "MATCH START!", MyFontEnum.Green); Logging.Instance.WriteLine("Starting match"); _matchTimer.Start(); return; } if (command.Equals("!endmatch", StringComparison.CurrentCultureIgnoreCase)) { _matchTimer.Stop(); _matchRunning = false; Communication.SendNotification(0, "MATCH OVER!", MyFontEnum.Red, 10000); Logging.Instance.WriteLine("Ending match"); Utilities.ScrubServer(); return; } if (command.Equals("!reload", StringComparison.CurrentCultureIgnoreCase)) { Settings.LoadSettings(); Communication.SendServerChat(steamId, "Okay."); return; } if (command.Equals("!save", StringComparison.CurrentCultureIgnoreCase)) { Settings.SaveSettings(); Communication.SendServerChat(steamId, "Okay."); return; } if (command.StartsWith("!reset", StringComparison.CurrentCultureIgnoreCase)) { int ind = command.IndexOf(" "); if (ind == -1) { foreach (var s in Servers.Values) { s.Reset(); } Communication.SendServerChat(steamId, "Reset all servers"); return; } string numtex = command.Substring(ind); ServerItem server; int num; if (!int.TryParse(numtex, out num)) { Communication.SendServerChat(steamId, "Couldn't parse your server selection!"); return; } if (Servers.TryGetValue(num - 1, out server)) { server.Reset(); Communication.SendServerChat(steamId, $"Reset server {num}"); } } } if (command.Equals("!help", StringComparison.CurrentCultureIgnoreCase)) { if (level >= MyPromoteLevel.Admin) { Communication.SendServerChat(steamId, ADMIN_HELP); } else { if (level >= MyPromoteLevel.Moderator) { Communication.SendServerChat(steamId, MODERATOR_HELP); } else { Communication.SendServerChat(steamId, HELP_TEXT); } } } }
private void DeleteGrid(IMyCubeGrid cubeGrid, string reason) { MyLog.Default.WriteLineAndConsole($"DELETED GRID: {cubeGrid.DisplayName}. Reason: {reason}."); cubeGrid.Delete(); cubeGrid.Close(); }
private void CheckBeforeJump(Vector3D gridpos, ulong steamId, IMyCubeGrid gridtotp) { ServerJumpClass.Instance.SomeLog("CheckBeforeJump() start"); bool HyperDrive = false; bool GateLink = false; string IP = "0.0.0.0:27016"; Communication.SendServerChat(steamId, "CheckBeforeJump start!" + gridpos); List <IMyEntity> allentities = new List <IMyEntity>(); var tmpsphere = new BoundingSphereD(gridpos, 5100); allentities = MyAPIGateway.Entities.GetEntitiesInSphere(ref tmpsphere); Communication.SendServerChat(steamId, "GetTopMostEntitiesInSphere :" + allentities.Count); List <IMyCubeGrid> allentitieslist = allentities.OfType <IMyCubeGrid>().ToList(); Communication.SendServerChat(steamId, ".OfType<IMyCubeGrid>() :" + allentitieslist.Count); if (allentitieslist.Count >= 2) { foreach (IMyCubeGrid grid in allentitieslist) { if (grid?.GridSizeEnum == MyCubeSize.Small || grid.Physics == null || grid.MarkedForClose || grid.Closed) { continue; } // Logging.Instance.WriteLine($"grid.Name = " + grid.Name); Communication.SendServerChat(steamId, "before GetBlocks :"); var blocks = new List <IMySlimBlock>(); var tmpspher2e = new BoundingSphereD(grid.GetPosition(), 1000); blocks = grid.GetBlocksInsideSphere(ref tmpspher2e); Communication.SendServerChat(steamId, " GetBlocks :" + blocks.Count); foreach (IMySlimBlock block in blocks) { try { // Communication.SendServerChat(steamId, " block :" + block.GetObjectBuilderCubeBlock().SubtypeName); if (block.FatBlock == null) { continue; } if (block?.FatBlock?.BlockDefinition.SubtypeId == "HyperDrive" && ((block.FatBlock.GetObjectBuilderCubeBlock() as MyObjectBuilder_JumpDrive).StoredPower >= (block.FatBlock as MyJumpDrive).BlockDefinition.PowerNeededForJump)) { HyperDrive = true; Communication.SendServerChat(steamId, " HyperDrive = true; :"); // Logging.Instance.WriteLine($"found HyperDrive !" + tmp2); } if (block.FatBlock.BlockDefinition.SubtypeId == "JumpGateLink") { GateLink = true; IP = (block.FatBlock as IMyTerminalBlock)?.CustomData.ToString(); Communication.SendServerChat(steamId, " GateLink = true; :"); } if (HyperDrive && GateLink) { // MyAPIGateway.Utilities.InvokeOnGameThread(() => { byte[] payload = Utilities.SerializeAndSign(gridtotp, Utilities.GetPlayerBySteamId(steamId), (Utilities.GetPlayerBySteamId(steamId)?.Controller?.ControlledEntity?.Entity as IMyCubeBlock).Position); Communication.SegmentAndSend(Communication.MessageType.ClientGridPart, payload, MyAPIGateway.Multiplayer.ServerId, steamId); //Communication.SendServerChat(steamId, "redirect to 178.210.32.201:27016!"); Communication.RedirectClient(steamId, IP);//"178.210.32.201:27016" ServerJumpClass.Instance.SomeLog("[Jump] Client: " + Utilities.GetPlayerBySteamId(steamId).DisplayName + " steamId: " + steamId + " Grid: " + grid.DisplayName + " To: " + IP); var timer = new Timer(10000); timer.AutoReset = false; timer.Elapsed += (a, b) => MyAPIGateway.Utilities.InvokeOnGameThread(() => gridtotp.Close()); timer.Start(); //}); return; } } catch { Communication.SendServerChat(steamId, " catch foreach (IMySlimBlock block in blocks) "); } } } Communication.SendServerChat(steamId, "HyperDrive = " + HyperDrive + "GateLink = " + GateLink); return; } else { Communication.SendServerChat(steamId, "allentitieslist.Count >=2!"); } return; }
public void HandleChatCommand(ulong steamId, string command) { MyPromoteLevel level = MyAPIGateway.Session.GetUserPromoteLevel(steamId); ServerJumpClass.Instance.SomeLog($"Got chat command from {steamId} : {command}"); if (command.Equals("!join", StringComparison.CurrentCultureIgnoreCase)) { InitJump(steamId); return; } if (command.StartsWith("!join", StringComparison.CurrentCultureIgnoreCase)) { int ind = command.IndexOf(" "); if (ind == -1) { Communication.SendServerChat(steamId, "Couldn't parse your server selection!"); return; } string numtex = command.Substring(ind); ServerItem server; int num; if (!int.TryParse(numtex, out num)) { Communication.SendServerChat(steamId, "Couldn't parse your server selection!"); return; } if (!Servers.TryGetValue(num - 1, out server)) { Communication.SendServerChat(steamId, $"Couldn't find server {num}"); return; } if (!server.CanJoin) { Communication.SendServerChat(steamId, "Sorry, this server is not open to new members. Please try another."); return; } IMyPlayer player = Utilities.GetPlayerBySteamId(steamId); var block = player?.Controller?.ControlledEntity?.Entity as IMyCubeBlock; IMyCubeGrid grid = block?.CubeGrid; if (grid == null) { Communication.SendServerChat(steamId, "Can't find your ship. Make sure you're seated in the ship you want to take with you."); return; } var blocks = new List <IMySlimBlock>(); grid.GetBlocks(blocks); if (blocks.Count > Settings.MaxBlockCount) { Communication.SendServerChat(steamId, $"Your ship has {blocks.Count} blocks. The limit for this server is {Settings.MaxBlockCount}"); return; } byte[] payload = Utilities.SerializeAndSign(grid, Utilities.GetPlayerBySteamId(steamId), block.Position); Communication.SegmentAndSend(Communication.MessageType.ClientGridPart, payload, MyAPIGateway.Multiplayer.ServerId, steamId); server.Join(steamId); var timer = new Timer(10000); timer.AutoReset = false; timer.Elapsed += (a, b) => MyAPIGateway.Utilities.InvokeOnGameThread(() => grid.Close()); timer.Start(); return; } if (command.Equals("!hub", StringComparison.CurrentCultureIgnoreCase)) { if (Settings.Hub) { Communication.SendServerChat(steamId, "You're already in the hub!"); return; } Communication.RedirectClient(steamId, Settings.HubIP); return; } if (level >= MyPromoteLevel.Moderator) { if (command.StartsWith("!spectate", StringComparison.CurrentCultureIgnoreCase)) { int ind = command.IndexOf(" "); if (ind == -1) { Communication.SendServerChat(steamId, "Couldn't parse your server selection!"); return; } string numtex = command.Substring(ind); ServerItem server; int num; if (!int.TryParse(numtex, out num)) { Communication.SendServerChat(steamId, "Couldn't parse your server selection!"); return; } if (!Servers.TryGetValue(num - 1, out server)) { Communication.SendServerChat(steamId, $"Couldn't find server {num}"); return; } ServerJumpClass.Instance.SomeLog("DeleteFileInLocalStorage"); // MyAPIGateway.Utilities.DeleteFileInLocalStorage("Ship.bin", typeof(ServerJump)); Communication.RedirectClient(steamId, server.IP); return; } } if (level >= MyPromoteLevel.Admin) { if (command.Equals("!reload", StringComparison.CurrentCultureIgnoreCase)) { //Settings.LoadSettings(); Communication.SendServerChat(steamId, "Okay."); return; } if (command.Equals("!save", StringComparison.CurrentCultureIgnoreCase)) { // Settings.SaveSettings(); Communication.SendServerChat(steamId, "Okay."); return; } if (command.StartsWith("!reset", StringComparison.CurrentCultureIgnoreCase)) { int ind = command.IndexOf(" "); if (ind == -1) { foreach (var s in Servers.Values) { s.Reset(); } Communication.SendServerChat(steamId, "Reset all servers"); return; } string numtex = command.Substring(ind); ServerItem server; int num; if (!int.TryParse(numtex, out num)) { Communication.SendServerChat(steamId, "Couldn't parse your server selection!"); return; } if (Servers.TryGetValue(num - 1, out server)) { server.Reset(); Communication.SendServerChat(steamId, $"Reset server {num}"); } } } if (command.Equals("!help", StringComparison.CurrentCultureIgnoreCase)) { if (level >= MyPromoteLevel.Admin) { Communication.SendServerChat(steamId, ADMIN_HELP); } else { if (level >= MyPromoteLevel.Moderator) { Communication.SendServerChat(steamId, MODERATOR_HELP); } else { Communication.SendServerChat(steamId, HELP_TEXT); } } } }
public override void UpdateAfterSimulation100() { try { //if(!MyAPIGateway.Multiplayer.IsServer) // only server-side/SP if (!AiSessionCore.IsServer) { return; } IMyRemoteControl rc = (IMyRemoteControl)Entity; IMyCubeGrid grid = rc.CubeGrid; if (grid.Physics == null || !rc.IsWorking || !Constants.NpcFactions.Contains(rc.GetOwnerFactionTag())) { if (Constants.CleanupDebug) { AiSessionCore.GeneralLog.WriteToLog("CleanEemRc", grid.DisplayName + " (" + grid.EntityId + " @ " + grid.WorldMatrix.Translation + ") is not valid; " + (grid.Physics == null ? "Phys=null" : "Phys OK") + "; " + (rc.IsWorking ? "RC OK" : "RC Not working!") + "; " + (!Constants.NpcFactions.Contains(rc.GetOwnerFactionTag()) ? "Owner faction tag is not in NPC list (" + rc.GetOwnerFactionTag() + ")" : "Owner Faction OK")); } return; } if (!rc.CustomData.Contains(Constants.CleanupRcTag)) { if (Constants.CleanupDebug) { AiSessionCore.GeneralLog.WriteToLog("CleanEemRc", grid.DisplayName + " (" + grid.EntityId + " @ " + grid.WorldMatrix.Translation + ") RC does not contain the " + Constants.CleanupRcTag + "tag!"); } return; } if (Constants.CleanupRcExtraTags.Length > 0) { bool hasExtraTag = Constants.CleanupRcExtraTags.Any(tag => rc.CustomData.Contains(tag)); if (!hasExtraTag) { if (Constants.CleanupDebug) { AiSessionCore.GeneralLog.WriteToLog("CleanEemRc", grid.DisplayName + " (" + grid.EntityId + " @ " + grid.WorldMatrix.Translation + ") RC does not contain one of the extra tags!"); } return; } } if (Constants.CleanupDebug) { AiSessionCore.GeneralLog.WriteToLog("CleanEemRc", "Checking RC '" + rc.CustomName + "' from grid '" + grid.DisplayName + "' (" + grid.EntityId + ") for any nearby players..."); } int rangeSq = CleanEem.RangeSq; Vector3D gridCenter = grid.WorldAABB.Center; if (rangeSq <= 0) { if (Constants.CleanupDebug) { AiSessionCore.GeneralLog.WriteToLog("CleanEemRc", "- WARNING: Range not assigned yet, ignoring grid for now."); } return; } //check if any player is within range of the ship foreach (IMyPlayer player in CleanEem.Players) { if (Vector3D.DistanceSquared(player.GetPosition(), gridCenter) <= rangeSq) { if (Constants.CleanupDebug) { AiSessionCore.GeneralLog.WriteToLog("CleanEemRc", " - player '" + player.DisplayName + "' is within " + Math.Round(Math.Sqrt(rangeSq), 1) + "m of it, not removing."); } return; } } if (Constants.CleanupDebug) { AiSessionCore.GeneralLog.WriteToLog("CleanEemRc", " - no player is within " + Math.Round(Math.Sqrt(rangeSq), 1) + "m of it, removing..."); } AiSessionCore.GeneralLog.WriteToLog("CleanEemRc", "NPC ship '" + grid.DisplayName + "' (" + grid.EntityId + ") removed."); CleanEem.GetAttachedGrids(grid); // this gets all connected grids and places them in Exploration.grids (it clears it first) foreach (IMyCubeGrid g in CleanEem.Grids) { g.Close(); // this only works server-side AiSessionCore.GeneralLog.WriteToLog("CleanEemRc", " - subgrid '" + g.DisplayName + "' (" + g.EntityId + ") removed."); } grid.Close(); // this only works server-side } catch (Exception e) { AiSessionCore.GeneralLog.WriteToLog("CleanEemRc", $"Exception: {e}"); } }