bool IMyShipController.TryGetPlanetElevation(MyPlanetElevation detail, out double elevation) { var blockPosition = this.PositionComp.GetPosition(); if (!MyGravityProviderSystem.IsPositionInNaturalGravity(blockPosition)) { elevation = double.PositiveInfinity; return(false); } var boundingBox = PositionComp.WorldAABB; var nearestPlanet = MyGamePruningStructure.GetClosestPlanet(ref boundingBox); if (nearestPlanet == null) { elevation = double.PositiveInfinity; return(false); } switch (detail) { case MyPlanetElevation.Sealevel: elevation = ((boundingBox.Center - nearestPlanet.PositionComp.GetPosition()).Length() - nearestPlanet.AverageRadius); return(true); case MyPlanetElevation.Surface: var controlledEntityPosition = CubeGrid.Physics.CenterOfMassWorld; Vector3D closestPoint = nearestPlanet.GetClosestSurfacePointGlobal(ref controlledEntityPosition); elevation = Vector3D.Distance(closestPoint, controlledEntityPosition); return(true); default: throw new ArgumentOutOfRangeException("detail", detail, null); } }
/// <summary> /// Calculate propper direction for meteorits. Everytime above horizon. /// </summary> /// <param name="direction"></param> /// <returns></returns> private static Vector3 GetCorrectedDirection(Vector3 direction) { var currDir = direction; if (m_currentTarget == null) { return(currDir); } var tgtPos = m_currentTarget.Value.Center; MyMeteorShower.m_tgtPos = tgtPos; if (!MyGravityProviderSystem.IsPositionInNaturalGravity(tgtPos)) { return(currDir); } var pltTgtDir = -Vector3D.Normalize(MyGravityProviderSystem.CalculateNaturalGravityInPoint(tgtPos)); var tmpVec = Vector3D.Normalize(Vector3D.Cross(pltTgtDir, currDir)); var mirror = Vector3D.Normalize(Vector3D.Cross(tmpVec, pltTgtDir)); MyMeteorShower.m_mirrorDir = mirror; MyMeteorShower.m_pltTgtDir = pltTgtDir; MyMeteorShower.m_normalSun = tmpVec; double horizonRatio = pltTgtDir.Dot(currDir); //below down horizon if (horizonRatio < -HORIZON_ANGLE_FROM_ZENITH_RATIO) { return(Vector3D.Reflect(-currDir, mirror)); } // between below and above horizon (prohi if (horizonRatio < HORIZON_ANGLE_FROM_ZENITH_RATIO) { MatrixD tmpMat = MatrixD.CreateFromAxisAngle(tmpVec, -Math.Asin(HORIZON_ANGLE_FROM_ZENITH_RATIO)); return(Vector3D.Transform(mirror, tmpMat)); } // above 20 Degree above horizon return(currDir); }
bool IMyShipController.TryGetPlanetPosition(out Vector3D position) { var blockPosition = this.PositionComp.GetPosition(); if (!MyGravityProviderSystem.IsPositionInNaturalGravity(blockPosition)) { position = Vector3D.Zero; return(false); } var boundingBox = PositionComp.WorldAABB; var nearestPlanet = MyGamePruningStructure.GetClosestPlanet(ref boundingBox); if (nearestPlanet == null) { position = Vector3D.Zero; return(false); } position = nearestPlanet.PositionComp.GetPosition(); return(true); }
public override void Draw() { base.Draw(); if (MyDebugDrawSettings.DEBUG_DRAW_METEORITS_DIRECTIONS) { Vector3D m_currDir = GetCorrectedDirection(MySector.DirectionToSunNormalized); MyRenderProxy.DebugDrawLine3D(m_tgtPos, m_tgtPos + 10 * MySector.DirectionToSunNormalized, Color.Yellow, Color.Yellow, false); MyRenderProxy.DebugDrawText3D(m_tgtPos + 10 * MySector.DirectionToSunNormalized, "Sun direction (sd)", Color.Yellow, 0.5F, false, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM); MyRenderProxy.DebugDrawLine3D(m_tgtPos, m_tgtPos + 10 * m_currDir, Color.Red, Color.Red, false); MyRenderProxy.DebugDrawText3D(m_tgtPos + 10 * m_currDir, "Current meteorits direction (cd)", Color.Red, 0.5F, false, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP); if (MyGravityProviderSystem.IsPositionInNaturalGravity(m_tgtPos)) { MyRenderProxy.DebugDrawLine3D(m_tgtPos, m_tgtPos + 10 * m_normalSun, Color.Blue, Color.Blue, false); MyRenderProxy.DebugDrawText3D(m_tgtPos + 10 * m_normalSun, "Perpendicular to sd and n0 ", Color.Blue, 0.5F, false, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER); MyRenderProxy.DebugDrawLine3D(m_tgtPos, m_tgtPos + 10 * m_pltTgtDir, Color.Green, Color.Green, false); MyRenderProxy.DebugDrawText3D(m_tgtPos + 10 * m_pltTgtDir, "Dir from center of planet to target (n0)", Color.Green, 0.5F, false, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER); MyRenderProxy.DebugDrawLine3D(m_tgtPos, m_tgtPos + 10 * m_mirrorDir, Color.Purple, Color.Purple, false); MyRenderProxy.DebugDrawText3D(m_tgtPos + 10 * m_mirrorDir, "Horizon in plane n0 and sd (ho)", Color.Purple, 0.5F, false, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER); } } }
private bool SpawnDrone(MyRadioAntenna antenna, long ownerId, Vector3D position, MySpawnGroupDefinition spawnGroup, Vector3?spawnUp = null, Vector3?spawnForward = null) { long antennaEntityId = antenna.EntityId; Vector3D antennaPos = antenna.PositionComp.GetPosition(); Vector3D upVector; var planet = MyGamePruningStructure.GetClosestPlanet(position); if (planet != null) { if (!MyGravityProviderSystem.IsPositionInNaturalGravity(antennaPos)) { MySandboxGame.Log.WriteLine("Couldn't spawn drone; antenna is not in natural gravity but spawn location is."); return(false); } planet.CorrectSpawnLocation(ref position, spawnGroup.SpawnRadius * 2.0); upVector = position - planet.PositionComp.GetPosition(); upVector.Normalize(); } else { var totalGravityInPoint = MyGravityProviderSystem.CalculateTotalGravityInPoint(position); if (totalGravityInPoint != Vector3.Zero) { upVector = -totalGravityInPoint; upVector.Normalize(); } else if (spawnUp != null) { upVector = spawnUp.Value; } else { upVector = MyUtils.GetRandomVector3Normalized(); } } Vector3D direction = MyUtils.GetRandomPerpendicularVector(ref upVector); if (spawnForward != null) { // Align forward to up vector. Vector3 forward = spawnForward.Value; if (Math.Abs(Vector3.Dot(forward, upVector)) >= 0.98f) { forward = Vector3.CalculatePerpendicularVector(upVector); } else { Vector3 right = Vector3.Cross(forward, upVector); right.Normalize(); forward = Vector3.Cross(upVector, right); forward.Normalize(); } direction = forward; } MatrixD originMatrix = MatrixD.CreateWorld(position, direction, upVector); foreach (var shipPrefab in spawnGroup.Prefabs) { Vector3D shipPosition = Vector3D.Transform((Vector3D)shipPrefab.Position, originMatrix); List <MyCubeGrid> tmpGridList = new List <MyCubeGrid>(); Stack <Action> callback = new Stack <Action>(); callback.Push(delegate() { ChangeDroneOwnership(tmpGridList, ownerId, antennaEntityId); }); MyPrefabManager.Static.SpawnPrefab( resultList: tmpGridList, prefabName: shipPrefab.SubtypeId, position: shipPosition, forward: direction, up: upVector, initialLinearVelocity: default(Vector3), beaconName: null, spawningOptions: VRage.Game.ModAPI.SpawningOptions.None, ownerId: ownerId, updateSync: true, callbacks: callback); } return(true); }
private bool SpawnDrone(MyRadioAntenna antenna, long ownerId, Vector3D position, MySpawnGroupDefinition spawnGroup) { long antennaEntityId = antenna.EntityId; Vector3D antennaPos = antenna.PositionComp.GetPosition(); var planet = MyGravityProviderSystem.GetStrongestGravityWell(position); Vector3D upVector; if (planet != null && planet.IsPositionInGravityWell(position)) { if (!MyGravityProviderSystem.IsPositionInNaturalGravity(antennaPos)) { MySandboxGame.Log.WriteLine("Couldn't spawn drone; antenna is not in natural gravity but spawn location is."); return(false); } planet.CorrectSpawnLocation(ref position, spawnGroup.SpawnRadius * 2.0); upVector = -planet.GetWorldGravityNormalized(ref position); } else { upVector = MyUtils.GetRandomVector3Normalized(); } Vector3D direction = MyUtils.GetRandomPerpendicularVector(ref upVector); MatrixD originMatrix = MatrixD.CreateWorld(position, direction, upVector); foreach (var shipPrefab in spawnGroup.Prefabs) { Vector3D shipPosition = Vector3D.Transform((Vector3D)shipPrefab.Position, originMatrix); m_tmpGridList.Clear(); MyPrefabManager.Static.SpawnPrefab( resultList: m_tmpGridList, prefabName: shipPrefab.SubtypeId, position: shipPosition, forward: direction, up: upVector, initialLinearVelocity: default(Vector3), beaconName: null, spawningOptions: VRage.Game.ModAPI.SpawningOptions.None, ownerId: ownerId, updateSync: true); foreach (var grid in m_tmpGridList) { grid.ChangeGridOwnership(ownerId, MyOwnershipShareModeEnum.None); MyRemoteControl firstRemote = null; foreach (var block in grid.CubeBlocks) { if (block.FatBlock == null) { continue; } var pb = block.FatBlock as MyProgrammableBlock; if (pb != null) { pb.SendRecompile(); } var remote = block.FatBlock as MyRemoteControl; if (firstRemote == null) { firstRemote = remote; } } // If there's no remote control on the grid, we have to register it as is RegisterDrone(antennaEntityId, (MyEntity)firstRemote ?? (MyEntity)grid); } m_tmpGridList.Clear(); } return(true); }
public void BuyGrid(int number) { if (!list.items.ContainsKey(number)) { Context.Respond("There is no item in the market for that slot number."); confirmations.Remove(Context.Player.IdentityId); return; } MarketItem item = list.items[number]; if (!File.Exists(AlliancePlugin.path + "//ShipMarket//ForSale//" + item.ItemId + ".json")) { Context.Respond("That grid is no longer available for sale."); confirmations.Remove(Context.Player.IdentityId); return; } if (!File.Exists(AlliancePlugin.path + "//ShipMarket//Grids//" + item.ItemId + ".xml")) { Context.Respond("This grid should be available, but its file for the grid doesnt exist."); confirmations.Remove(Context.Player.IdentityId); return; } if (MyGravityProviderSystem.IsPositionInNaturalGravity(Context.Player.GetPosition())) { Context.Respond("You cannot use this command in natural gravity!"); confirmations.Remove(Context.Player.IdentityId); return; } foreach (DeniedLocation denied in AlliancePlugin.HangarDeniedLocations) { if (Vector3.Distance(Context.Player.GetPosition(), new Vector3(denied.x, denied.y, denied.z)) <= denied.radius) { Context.Respond("Cannot buy here, too close to a denied location."); confirmations.Remove(Context.Player.IdentityId); return; } } if (EconUtils.getBalance(Context.Player.IdentityId) >= item.Price) { if (confirmations.ContainsKey(Context.Player.IdentityId)) { if (confirmations[Context.Player.IdentityId] >= DateTime.Now) { if (GridManager.LoadGrid(AlliancePlugin.path + "//ShipMarket//Grids//" + item.ItemId + ".xml", Context.Player.GetPosition(), false, Context.Player.SteamUserId, item.Name)) { EconUtils.takeMoney(Context.Player.IdentityId, item.Price); long sellerId = MySession.Static.Players.TryGetIdentityId(item.SellerSteamId); EconUtils.addMoney(sellerId, item.Price); if (AlliancePlugin.GridBackupInstalled) { AlliancePlugin.BackupGridMethod(GridManager.GetObjectBuilders(AlliancePlugin.path + "//ShipMarket//Grids//" + item.ItemId + ".xml"), Context.Player.IdentityId); } item.Buyer = Context.Player.SteamUserId; item.soldAt = DateTime.Now; item.Status = ItemStatus.Sold; Context.Respond("The grid should appear near you."); confirmations.Remove(Context.Player.IdentityId); if (!Directory.Exists(AlliancePlugin.path + "//ShipMarket//Sold//" + item.SellerSteamId)) { Directory.CreateDirectory(AlliancePlugin.path + "//ShipMarket//Sold//" + item.SellerSteamId); } list.items.Remove(number); File.Delete(AlliancePlugin.path + "//ShipMarket//ForSale//" + item.ItemId + ".json"); utils.WriteToJsonFile <MarketItem>(AlliancePlugin.path + "//ShipMarket//Sold//" + item.SellerSteamId + "//" + item.ItemId, item); } else { Context.Respond("Failed to load the grid! transaction cancelled."); return; } } else { Context.Respond("Time ran out, start again"); confirmations[Context.Player.IdentityId] = DateTime.Now.AddSeconds(20); } } else { Context.Respond("Run command again within 20 seconds to confirm. Target grid name is " + item.Name + " Sold by " + AlliancePlugin.GetPlayerName(item.SellerSteamId)); confirmations.Add(Context.Player.IdentityId, DateTime.Now.AddSeconds(20)); Context.Respond("It costs " + String.Format("{0:n0}", item.Price) + " SC."); } } else { Context.Respond("You cannot afford that. It costs " + String.Format("{0:n0}", item.Price) + " SC."); } }
public void EndListing(int number) { if (!list.items.ContainsKey(number)) { Context.Respond("There is no item in the market for that slot number."); return; } MarketItem item = list.items[number]; if (!item.SellerSteamId.Equals(Context.Player.SteamUserId)) { Context.Respond("This listing doesnt belong to you."); return; } if (!File.Exists(AlliancePlugin.path + "//ShipMarket//ForSale//" + item.ItemId + ".json")) { Context.Respond("That grid is no longer available for sale."); return; } if (!File.Exists(AlliancePlugin.path + "//ShipMarket//Grids//" + item.ItemId + ".xml")) { Context.Respond("This grid should be available, but its file for the grid doesnt exist."); return; } if (MyGravityProviderSystem.IsPositionInNaturalGravity(Context.Player.GetPosition())) { Context.Respond("You cannot use this command in natural gravity!"); return; } foreach (DeniedLocation denied in AlliancePlugin.HangarDeniedLocations) { if (Vector3.Distance(Context.Player.GetPosition(), new Vector3(denied.x, denied.y, denied.z)) <= denied.radius) { Context.Respond("Cannot buy here, too close to a denied location."); return; } } if (GridManager.LoadGrid(AlliancePlugin.path + "//ShipMarket//Grids//" + item.ItemId + ".xml", Context.Player.GetPosition(), true, Context.Player.SteamUserId, item.Name)) { EconUtils.takeMoney(Context.Player.IdentityId, item.Price); long sellerId = MySession.Static.Players.TryGetIdentityId(item.SellerSteamId); EconUtils.addMoney(sellerId, item.Price); if (AlliancePlugin.GridBackupInstalled) { AlliancePlugin.BackupGridMethod(GridManager.GetObjectBuilders(AlliancePlugin.path + "//ShipMarket//Grids//" + item.ItemId + ".xml"), Context.Player.IdentityId); } item.Buyer = Context.Player.SteamUserId; item.soldAt = DateTime.Now; if (!Directory.Exists(AlliancePlugin.path + "//ShipMarket//Sold//" + item.SellerSteamId)) { Directory.CreateDirectory(AlliancePlugin.path + "//ShipMarket//Sold//" + item.SellerSteamId); } list.items.Remove(number); File.Delete(AlliancePlugin.path + "//ShipMarket//ForSale//" + item.ItemId + ".json"); File.Delete(AlliancePlugin.path + "//ShipMarket//Grids//" + item.ItemId + ".xml"); Context.Respond("Ended the listing, the grid should appear near you."); } else { Context.Respond("Failed to load the grid! transaction cancelled."); return; } }
public void Sell(string price, string name) { if (MyGravityProviderSystem.IsPositionInNaturalGravity(Context.Player.GetPosition())) { Context.Respond("You cannot use this command in natural gravity!"); confirmations.Remove(Context.Player.IdentityId); return; } foreach (DeniedLocation denied in AlliancePlugin.HangarDeniedLocations) { if (Vector3.Distance(Context.Player.GetPosition(), new Vector3(denied.x, denied.y, denied.z)) <= denied.radius) { Context.Respond("Cannot sell here, too close to a denied location."); confirmations.Remove(Context.Player.IdentityId); return; } } Int64 amount; price = price.Replace(",", ""); price = price.Replace(".", ""); price = price.Replace(" ", ""); try { amount = Int64.Parse(price); } catch (Exception) { Context.Respond("Error parsing amount", Color.Red, "Bank Man"); return; } if (amount < 0 || amount == 0) { Context.Respond("Must be a positive amount", Color.Red, "Bank Man"); return; } ConcurrentBag <MyGroups <MyCubeGrid, MyGridMechanicalGroupData> .Group> gridWithSubGrids = GridFinder.FindLookAtGridGroupMechanical(Context.Player.Character); List <MyCubeGrid> grids = new List <MyCubeGrid>(); foreach (var item1 in gridWithSubGrids) { foreach (MyGroups <MyCubeGrid, MyGridMechanicalGroupData> .Node groupNodes in item1.Nodes) { MyCubeGrid grid = groupNodes.NodeData; if (FacUtils.IsOwnerOrFactionOwned(grid, Context.Player.IdentityId, false)) { if (!grids.Contains(grid)) { foreach (MySurvivalKit block in grid.GetFatBlocks().OfType <MySurvivalKit>()) { block.CustomData = "Custom Data was cleared."; } foreach (MyMedicalRoom block in grid.GetFatBlocks().OfType <MyMedicalRoom>()) { block.CustomData = "Custom Data was cleared."; } List <MyProgrammableBlock> removeThese = new List <MyProgrammableBlock>(); foreach (MyProgrammableBlock block in grid.GetFatBlocks().OfType <MyProgrammableBlock>()) { removeThese.Add(block); } foreach (MyProgrammableBlock block in removeThese) { grid.RemoveBlock(block.SlimBlock); } grids.Add(grid); } } } } if (grids.Count == 0) { Context.Respond("Could not find any grids you own. Are you looking directly at it?"); return; } MarketItem item = new MarketItem(); item.Setup(grids, name, amount, Context.Player.SteamUserId); if (list.AddItem(item)) { if (GridManager.SaveGridNoDelete(AlliancePlugin.path + "//ShipMarket//Grids//" + item.ItemId + ".xml", item.ItemId.ToString(), false, false, grids)) { Context.Respond("Added the item to the market!"); utils.WriteToJsonFile <MarketItem>(AlliancePlugin.path + "//ShipMarket//ForSale//" + item.ItemId + ".json", item); foreach (MyCubeGrid grid in grids) { if (grid != null) { grid.Close(); } } } } else { Context.Respond("Failed to add the grid to the market. Try again."); } }
public void transmit() { foreach (MyPlayer p in MySession.Static.Players.GetOnlinePlayers()) { List <IMyGps> playergpsList = MyAPIGateway.Session?.GPS.GetGpsList(p.Identity.IdentityId); if (playergpsList == null) { break; } foreach (IMyGps gps in playergpsList) { if (gps.Description.Contains("Cronch")) { MyAPIGateway.Session?.GPS.RemoveGps(p.Identity.IdentityId, gps); } } } foreach (var group in MyCubeGridGroups.Static.Logical.Groups) { bool NPC = false; foreach (var item in group.Nodes) { MyCubeGrid grid = item.NodeData; // TransmitPlugin.Log.Info(grid.DisplayName); if (((int)grid.Flags & 4) != 0) { //concealed break; } if (grid.IsStatic && !TransmitPlugin.config.broadcastStations) { break; } if (MyGravityProviderSystem.IsPositionInNaturalGravity(grid.PositionComp.GetPosition()) && !TransmitPlugin.config.broadcastInGravity) { break; } //this bit requires a fac utils to get the faction tag, you can remove it if you dont need it foreach (long l in grid.BigOwners) { if (FacUtils.GetFactionTag(l) != null && FacUtils.GetFactionTag(l).Length > 3) { NPC = true; } } if (NPC) { break; } int PCU = 0; PCU = grid.BlocksPCU; Vector3 location = grid.PositionComp.GetPosition(); //get the gps float broadcastRange = 0; MyGpsCollection gpsCollection = (MyGpsCollection)MyAPIGateway.Session?.GPS; broadcastRange = grid.BlocksPCU * TransmitPlugin.config.meterPerPCU; if (PCU < TransmitPlugin.config.minimumPCU) { break; } IMyFaction gridOwner = FacUtils.GetPlayersFaction(FacUtils.GetOwner(grid)); foreach (MyPlayer p in MySession.Static.Players.GetOnlinePlayers()) { List <MyGps> gpsList = new List <MyGps>(); float distance = Vector3.Distance(location, p.GetPosition()); if (distance <= broadcastRange) { MyGps gps; //add a new gps point if player is in range if (gridOwner != null) { if (gridOwner.IsNeutral(p.Identity.IdentityId) || gridOwner.IsFriendly(p.Identity.IdentityId)) { gps = CreateGps(grid, Color.RoyalBlue, 60, broadcastRange); } else { gps = CreateGps(grid, Color.Red, 60, broadcastRange); } } else { gps = CreateGps(grid, Color.Red, 60, broadcastRange); } gpsList.Add(gps); } foreach (MyGps gps in gpsList) { MyGps gpsRef = gps; long entityId = 0L; entityId = gps.EntityId; gpsCollection.SendAddGps(p.Identity.IdentityId, ref gpsRef, entityId, TransmitPlugin.config.soundForGPS); } } } } }
public static void SpawnCargoShip(bool checkGravity) { Init( ); Wrapper.GameAction(() => { if (ExtenderOptions.IsDebugging) { Essentials.Log.Info("Spawn cargo ship"); } // Select a spawn group to spawn MySpawnGroupDefinition spawnGroup = PickRandomSpawnGroup( ); if (spawnGroup == null) { return; } spawnGroup.ReloadPrefabs( ); double spawnDistance = NEUTRAL_SHIP_SPAWN_DISTANCE; Vector3D playerPosition = Vector3D.Zero; bool isWorldLimited = MyEntities.IsWorldLimited( ); int numPlayers = 0; if (isWorldLimited) { spawnDistance = Math.Min(spawnDistance, MyEntities.WorldSafeHalfExtent( ) - spawnGroup.SpawnRadius); } else { // In infinite worlds players can be thousands of kilometers away, so spawn ship around random player // so cargo ships will be spawned around every player at some time var players = MySession.Static.Players.GetOnlinePlayers( ); // In DS there can be no players connected numPlayers = Math.Max(0, players.Count - 1); int randomPlayerPosition = MyUtils.GetRandomInt(0, numPlayers); int i = 0; foreach (var player in players) { if (i == randomPlayerPosition) { if (player.Character != null) { playerPosition = player.GetPosition( ); } break; } i++; } } if (spawnDistance < 0.0f) { if (ExtenderOptions.IsDebugging) { Essentials.Log.Info("Not enough space in the world to spawn such a huge spawn group!"); } return; } double forbiddenRadius = NEUTRAL_SHIP_FORBIDDEN_RADIUS; BoundingBoxD spawnBox; if (isWorldLimited) { spawnBox = new BoundingBoxD(new Vector3D(playerPosition - spawnDistance), new Vector3D(playerPosition + spawnDistance)); } else { // We need to extend bouding box so cargo ships aren't spawned near other players GetSafeBoundingBoxForPlayers(playerPosition, spawnDistance, out spawnBox); // Forbidden radius is sphere around all players in box. // Bounding box is generated from players positions so their distance to center shall be same for all players forbiddenRadius += spawnBox.HalfExtents.Max( ) - NEUTRAL_SHIP_FORBIDDEN_RADIUS; } // Get the direction to the center and deviate it randomly Vector3D?origin = MyUtils.GetRandomBorderPosition(ref spawnBox); origin = MyEntities.FindFreePlace(origin.Value, spawnGroup.SpawnRadius); if (!origin.HasValue) { if (ExtenderOptions.IsDebugging) { Essentials.Log.Info("Couldn't find free place for cargo spawn"); } return; } // Radius in arc units of the forbidden sphere in the center, when viewed from origin float centerArcRadius = (float)Math.Atan(forbiddenRadius / (origin.Value - spawnBox.Center).Length( )); // Generate direction with elevation from centerArcRadius radians to (cAR + N_S_D_S) radians Vector3D direction = -Vector3D.Normalize(origin.Value); float theta = MyUtils.GetRandomFloat(centerArcRadius, centerArcRadius + NEUTRAL_SHIP_DIRECTION_SPREAD); float phi = MyUtils.GetRandomRadian( ); Vector3D cosVec = Vector3D.CalculatePerpendicularVector(direction); Vector3D sinVec = Vector3D.Cross(direction, cosVec); cosVec *= (Math.Sin(theta) * Math.Cos(phi)); sinVec *= (Math.Sin(theta) * Math.Sin(phi)); direction = direction * Math.Cos(theta) + cosVec + sinVec; Vector3D destination = Vector3D.Zero; RayD ray = new RayD(origin.Value, direction); double?intersection = ray.Intersects(spawnBox); Vector3D directionMult; if (!intersection.HasValue || intersection.Value < NEUTRAL_SHIP_MINIMAL_ROUTE_LENGTH) { directionMult = direction * NEUTRAL_SHIP_MINIMAL_ROUTE_LENGTH; } else { directionMult = direction * intersection.Value; } destination = origin.Value + directionMult; Vector3D upVector = Vector3D.CalculatePerpendicularVector(direction); Vector3D rightVector = Vector3D.Cross(direction, upVector); MatrixD originMatrix = MatrixD.CreateWorld(origin.Value, direction, upVector); // CH:TODO: Convex cast to detect collision // Check ships' path to avoid possible collisions. (TODO: But only if it is said in the definitions) m_raycastHits.Clear( ); foreach (var shipPrefab in spawnGroup.Prefabs) { var prefabDef = MyDefinitionManager.Static.GetPrefabDefinition(shipPrefab.SubtypeId); Debug.Assert(prefabDef != null); Vector3D shipPosition = Vector3.Transform(shipPrefab.Position, originMatrix); Vector3D shipDestination = shipPosition + directionMult; float radius = prefabDef == null ? 10.0f : prefabDef.BoundingSphere.Radius; if (checkGravity) { //these point checks could be done in the trajectory intersect, but checking points is faster than ray intersect if (MyGravityProviderSystem.IsPositionInNaturalGravity(shipPosition, spawnGroup.SpawnRadius)) { if (ExtenderOptions.IsDebugging) { Essentials.Log.Info("Failed to spawn cargo ship: Spawn location is in gravity well"); } return; } if (MyGravityProviderSystem.IsPositionInNaturalGravity(shipDestination, spawnGroup.SpawnRadius)) { if (ExtenderOptions.IsDebugging) { Essentials.Log.Info("Failed to spawn cargo ship: Destination is in gravity well"); } } if (MyGravityProviderSystem.DoesTrajectoryIntersectNaturalGravity(shipPosition, shipDestination, spawnGroup.SpawnRadius + 500)) { if (ExtenderOptions.IsDebugging) { Essentials.Log.Info("Failed to spawn cargo ship: Ship path intersects gravity well"); } return; } } MyPhysics.CastRay(shipPosition, shipDestination, m_raycastHits, MyPhysics.CollisionLayers.ObjectDetectionCollisionLayer); if (m_raycastHits.Count > 0) { if (ExtenderOptions.IsDebugging) { Essentials.Log.Info("Failed to spawn cargo ship: Ship path intersects another object"); } return; } for (int i = 0; i < 4; ++i) { Vector3D shiftVector = upVector * m_upVecMultipliers[i] * radius + rightVector * m_rightVecMultipliers[i] * radius; MyPhysics.CastRay(shipPosition + shiftVector, shipDestination + shiftVector, m_raycastHits, MyPhysics.CollisionLayers.ObjectDetectionCollisionLayer); if (m_raycastHits.Count > 0) { if (ExtenderOptions.IsDebugging) { Essentials.Log.Info("Failed to spawn cargo ship: Ship path intersects another object"); } return; } } } long spawnGroupId = MyPirateAntennas.GetPiratesId( ); // The ships were collision-free. Now spawn them foreach (var shipPrefab in spawnGroup.Prefabs) { // Yes, this could have been saved in the previous loop, but compared to (e.g.) raycasts, this does not take too much time to recalculate Vector3D shipPosition = Vector3D.Transform((Vector3D)shipPrefab.Position, originMatrix); Vector3D shipDestination = shipPosition + directionMult; Vector3D up = Vector3D.CalculatePerpendicularVector(-direction); m_tmpGridList.Clear( ); // CH: We don't want a new identity for each ship anymore. We should handle that in a better way... /*if (shipPrefab.ResetOwnership) * { * if (spawnGroupId == 0) * { * //This is not an NPC so that it doesn't show up in assign ownership drop down menu * MyIdentity spawnGroupIdentity = Sync.Players.CreateNewIdentity("Neutral NPC"); * spawnGroupId = spawnGroupIdentity.IdentityId; * } * }*/ // Deploy ship MyPrefabManager.Static.SpawnPrefab( resultList: m_tmpGridList, prefabName: shipPrefab.SubtypeId, position: shipPosition, forward: direction, up: up, initialLinearVelocity: shipPrefab.Speed * direction, beaconName: shipPrefab.BeaconText, spawningOptions: VRage.Game.ModAPI.SpawningOptions.RotateFirstCockpitTowardsDirection | VRage.Game.ModAPI.SpawningOptions.SpawnRandomCargo | VRage.Game.ModAPI.SpawningOptions.DisableDampeners, ownerId: shipPrefab.ResetOwnership ? spawnGroupId : 0, updateSync: true); /* * foreach (var grid in m_tmpGridList) * { * var cockpit = grid.GetFirstBlockOfType<MyCockpit>(); * if (cockpit != null) * { * MySimpleAutopilot ai = new MySimpleAutopilot(shipDestination, (Vector3)direction); * cockpit.AttachAutopilot(ai); * break; * } * } */ m_tmpGridList.Clear( ); } }); }
public static void OnGlobalSpawnEvent(object senderEvent) { // Select a spawn group to spawn MySpawnGroupDefinition spawnGroup = PickRandomSpawnGroup(); if (spawnGroup == null) { return; } spawnGroup.ReloadPrefabs(); ProfilerShort.Begin("Generate position and direction"); double spawnDistance = NEUTRAL_SHIP_SPAWN_DISTANCE; Vector3D playerPosition = Vector3D.Zero; bool isWorldLimited = MyEntities.IsWorldLimited(); int numPlayers = 0; if (isWorldLimited) { spawnDistance = Math.Min(spawnDistance, MyEntities.WorldSafeHalfExtent() - spawnGroup.SpawnRadius); } else { // In infinite worlds players can be thousands of kilometers away, so spawn ship around random player // so cargo ships will be spawned around every player at some time var players = MySession.Static.Players.GetOnlinePlayers(); // In DS there can be no players connected numPlayers = Math.Max(0, players.Count - 1); int randomPlayerPosition = MyUtils.GetRandomInt(0, numPlayers); int i = 0; foreach (var player in players) { if (i == randomPlayerPosition) { if (player.Character != null) { playerPosition = player.GetPosition(); } break; } i++; } } if (spawnDistance < 0.0f) { MySandboxGame.Log.WriteLine("Not enough space in the world to spawn such a huge spawn group!"); return; } double forbiddenRadius = NEUTRAL_SHIP_FORBIDDEN_RADIUS; BoundingBoxD spawnBox; if (isWorldLimited) { spawnBox = new BoundingBoxD(new Vector3D(playerPosition - spawnDistance), new Vector3D(playerPosition + spawnDistance)); } else { // We need to extend bouding box so cargo ships aren't spawned near other players GetSafeBoundingBoxForPlayers(playerPosition, spawnDistance, out spawnBox); // Forbidden radius is sphere around all players in box. // Bounding box is generated from players positions so their distance to center shall be same for all players forbiddenRadius += spawnBox.HalfExtents.Max() - NEUTRAL_SHIP_FORBIDDEN_RADIUS; } // Get the direction to the center and deviate it randomly Vector3D?origin = MyUtils.GetRandomBorderPosition(ref spawnBox); origin = MyEntities.TestPlaceInSpace(origin.Value, spawnGroup.SpawnRadius); if (!origin.HasValue) { if (++m_eventSpawnTry <= EVENT_SPAWN_TRY_MAX) { MySandboxGame.Log.WriteLine("Could not spawn neutral ships - no free place found. Try " + m_eventSpawnTry + " of " + EVENT_SPAWN_TRY_MAX); MyGlobalEvents.RescheduleEvent(senderEvent as MyGlobalEventBase, NEUTRAL_SHIP_RESCHEDULE_TIME); ProfilerShort.End(); return; } else { m_eventSpawnTry = 0; return; } } m_eventSpawnTry = 0; // Radius in arc units of the forbidden sphere in the center, when viewed from origin float centerArcRadius = (float)Math.Atan(forbiddenRadius / (origin.Value - spawnBox.Center).Length()); // Generate direction with elevation from centerArcRadius radians to (cAR + N_S_D_S) radians Vector3D direction = -Vector3D.Normalize(origin.Value); float theta = MyUtils.GetRandomFloat(centerArcRadius, centerArcRadius + NEUTRAL_SHIP_DIRECTION_SPREAD); float phi = MyUtils.GetRandomRadian(); Vector3D cosVec = Vector3D.CalculatePerpendicularVector(direction); Vector3D sinVec = Vector3D.Cross(direction, cosVec); cosVec *= (Math.Sin(theta) * Math.Cos(phi)); sinVec *= (Math.Sin(theta) * Math.Sin(phi)); direction = direction * Math.Cos(theta) + cosVec + sinVec; Vector3D destination = Vector3D.Zero; RayD ray = new RayD(origin.Value, direction); double? intersection = ray.Intersects(spawnBox); Vector3D directionMult; if (!intersection.HasValue || intersection.Value < NEUTRAL_SHIP_MINIMAL_ROUTE_LENGTH) { directionMult = direction * NEUTRAL_SHIP_MINIMAL_ROUTE_LENGTH; } else { directionMult = direction * intersection.Value; } destination = origin.Value + directionMult; Vector3D upVector = Vector3D.CalculatePerpendicularVector(direction); Vector3D rightVector = Vector3D.Cross(direction, upVector); MatrixD originMatrix = MatrixD.CreateWorld(origin.Value, direction, upVector); ProfilerShort.End(); ProfilerShort.Begin("Check free space"); // CH:TODO: Convex cast to detect collision // Check ships' path to avoid possible collisions. (TODO: But only if it is said in the definitions) m_raycastHits.Clear(); foreach (var shipPrefab in spawnGroup.Prefabs) { var prefabDef = MyDefinitionManager.Static.GetPrefabDefinition(shipPrefab.SubtypeId); Debug.Assert(prefabDef != null); Vector3D shipPosition = Vector3.Transform(shipPrefab.Position, originMatrix); Vector3D shipDestination = shipPosition + directionMult; float radius = prefabDef == null ? 10.0f : prefabDef.BoundingSphere.Radius; //these point checks could be done in the trajectory intersect, but checking points is faster than ray intersect if (MyGravityProviderSystem.IsPositionInNaturalGravity(shipPosition, spawnGroup.SpawnRadius)) { if (!MyFinalBuildConstants.IS_OFFICIAL) { MySandboxGame.Log.WriteLine("Could not spawn neutral ships: spawn point is inside gravity well"); } MyGlobalEvents.RescheduleEvent(senderEvent as MyGlobalEventBase, NEUTRAL_SHIP_RESCHEDULE_TIME); ProfilerShort.End(); return; } if (MyGravityProviderSystem.IsPositionInNaturalGravity(shipDestination, spawnGroup.SpawnRadius)) { if (!MyFinalBuildConstants.IS_OFFICIAL) { MySandboxGame.Log.WriteLine("Could not spawn neutral ships: destination point is inside gravity well"); } MyGlobalEvents.RescheduleEvent(senderEvent as MyGlobalEventBase, NEUTRAL_SHIP_RESCHEDULE_TIME); ProfilerShort.End(); return; } if (MyGravityProviderSystem.DoesTrajectoryIntersectNaturalGravity(shipPosition, shipDestination, spawnGroup.SpawnRadius + NEUTRAL_SHIP_SPAWN_OFFSET)) { if (!MyFinalBuildConstants.IS_OFFICIAL) { MySandboxGame.Log.WriteLine("Could not spawn neutral ships: flight path intersects gravity well"); } MyGlobalEvents.RescheduleEvent(senderEvent as MyGlobalEventBase, NEUTRAL_SHIP_RESCHEDULE_TIME); ProfilerShort.End(); return; } MyPhysics.CastRay(shipPosition, shipDestination, m_raycastHits, MyPhysics.CollisionLayers.ObjectDetectionCollisionLayer); if (m_raycastHits.Count > 0) { if (!MyFinalBuildConstants.IS_OFFICIAL) { MySandboxGame.Log.WriteLine("Could not spawn neutral ships due to collision"); } MyGlobalEvents.RescheduleEvent(senderEvent as MyGlobalEventBase, NEUTRAL_SHIP_RESCHEDULE_TIME); ProfilerShort.End(); return; } for (int i = 0; i < 4; ++i) { Vector3D shiftVector = upVector * m_upVecMultipliers[i] * radius + rightVector * m_rightVecMultipliers[i] * radius; MyPhysics.CastRay(shipPosition + shiftVector, shipDestination + shiftVector, m_raycastHits, MyPhysics.CollisionLayers.ObjectDetectionCollisionLayer); if (m_raycastHits.Count > 0) { if (!MyFinalBuildConstants.IS_OFFICIAL) { MySandboxGame.Log.WriteLine("Could not spawn neutral ships due to collision"); } MyGlobalEvents.RescheduleEvent(senderEvent as MyGlobalEventBase, NEUTRAL_SHIP_RESCHEDULE_TIME); ProfilerShort.End(); return; } } } ProfilerShort.End(); ProfilerShort.Begin("Spawn ships"); long spawnGroupId = MyPirateAntennas.GetPiratesId(); // The ships were collision-free. Now spawn them foreach (var shipPrefab in spawnGroup.Prefabs) { ProfilerShort.Begin(shipPrefab.BeaconText); // Yes, this could have been saved in the previous loop, but compared to (e.g.) raycasts, this does not take too much time to recalculate Vector3D shipPosition = Vector3D.Transform((Vector3D)shipPrefab.Position, originMatrix); Vector3D shipDestination = shipPosition + directionMult; Vector3D up = Vector3D.CalculatePerpendicularVector(-direction); List <MyCubeGrid> tmpGridList = new List <MyCubeGrid>(); // CH: We don't want a new identity for each ship anymore. We should handle that in a better way... /*if (shipPrefab.ResetOwnership) * { * if (spawnGroupId == 0) * { * //This is not an NPC so that it doesn't show up in assign ownership drop down menu * MyIdentity spawnGroupIdentity = Sync.Players.CreateNewIdentity("Neutral NPC"); * spawnGroupId = spawnGroupIdentity.IdentityId; * } * }*/ // Deploy ship ProfilerShort.Begin("Spawn cargo ship"); Stack <Action> callbacks = new Stack <Action>(); callbacks.Push(delegate() { InitAutopilot(tmpGridList, shipDestination, direction); foreach (var grid in tmpGridList) { Debug.Assert(grid.Physics.Enabled); grid.ActivatePhysics(); //last chance to activate physics } }); MyPrefabManager.Static.SpawnPrefab( resultList: tmpGridList, prefabName: shipPrefab.SubtypeId, position: shipPosition, forward: direction, up: up, initialLinearVelocity: shipPrefab.Speed * direction, beaconName: shipPrefab.BeaconText, spawningOptions: VRage.Game.ModAPI.SpawningOptions.RotateFirstCockpitTowardsDirection | VRage.Game.ModAPI.SpawningOptions.SpawnRandomCargo | VRage.Game.ModAPI.SpawningOptions.DisableDampeners, ownerId: shipPrefab.ResetOwnership ? spawnGroupId : 0, callbacks: callbacks); ProfilerShort.End(); ProfilerShort.End(); } ProfilerShort.End(); }
private bool SpawnDrone(MyRadioAntenna antenna, long ownerId, Vector3D position, MySpawnGroupDefinition spawnGroup, Vector3?spawnUp = null, Vector3?spawnForward = null) { long antennaEntityId = antenna.EntityId; Vector3D antennaPos = antenna.PositionComp.GetPosition(); Vector3D upVector; var planet = MyGamePruningStructure.GetClosestPlanet(position); if (planet != null) { if (!MyGravityProviderSystem.IsPositionInNaturalGravity(antennaPos)) { MySandboxGame.Log.WriteLine("Couldn't spawn drone; antenna is not in natural gravity but spawn location is."); return(false); } planet.CorrectSpawnLocation(ref position, spawnGroup.SpawnRadius * 2.0); upVector = position - planet.PositionComp.GetPosition(); upVector.Normalize(); } else { var totalGravityInPoint = MyGravityProviderSystem.CalculateTotalGravityInPoint(position); if (totalGravityInPoint != Vector3.Zero) { upVector = -totalGravityInPoint; upVector.Normalize(); } else if (spawnUp != null) { upVector = spawnUp.Value; } else { upVector = MyUtils.GetRandomVector3Normalized(); } } Vector3D direction = MyUtils.GetRandomPerpendicularVector(ref upVector); if (spawnForward != null) { // Align forward to up vector. Vector3 forward = spawnForward.Value; if (Math.Abs(Vector3.Dot(forward, upVector)) >= 0.98f) { forward = Vector3.CalculatePerpendicularVector(upVector); } else { Vector3 right = Vector3.Cross(forward, upVector); right.Normalize(); forward = Vector3.Cross(upVector, right); forward.Normalize(); } direction = forward; } MatrixD originMatrix = MatrixD.CreateWorld(position, direction, upVector); foreach (var shipPrefab in spawnGroup.Prefabs) { Vector3D shipPosition = Vector3D.Transform((Vector3D)shipPrefab.Position, originMatrix); m_tmpGridList.Clear(); MyPrefabManager.Static.SpawnPrefab( resultList: m_tmpGridList, prefabName: shipPrefab.SubtypeId, position: shipPosition, forward: direction, up: upVector, initialLinearVelocity: default(Vector3), beaconName: null, spawningOptions: VRage.Game.ModAPI.SpawningOptions.None, ownerId: ownerId, updateSync: true); foreach (var grid in m_tmpGridList) { grid.ChangeGridOwnership(ownerId, MyOwnershipShareModeEnum.None); MyRemoteControl firstRemote = null; foreach (var block in grid.CubeBlocks) { if (block.FatBlock == null) { continue; } var pb = block.FatBlock as MyProgrammableBlock; if (pb != null) { pb.SendRecompile(); } var remote = block.FatBlock as MyRemoteControl; if (firstRemote == null) { firstRemote = remote; } } // If there's no remote control on the grid, we have to register it as is RegisterDrone(antennaEntityId, (MyEntity)firstRemote ?? (MyEntity)grid); } m_tmpGridList.Clear(); } return(true); }
public void SaveToHangar() { if (!AlliancePlugin.config.HangarEnabled) { Context.Respond("Alliance hangar is not enabled."); return; } if (MySession.Static.IsSaveInProgress) { Context.Respond("World is saving! Try again soon."); return; } if (cooldowns.TryGetValue(Context.Player.IdentityId, out DateTime value)) { if (DateTime.Now <= value) { Context.Respond(GetCooldownMessage(value)); return; } else { cooldowns[Context.Player.IdentityId] = DateTime.Now.AddSeconds(60); } } else { cooldowns.Add(Context.Player.IdentityId, DateTime.Now.AddSeconds(60)); } if (MyGravityProviderSystem.IsPositionInNaturalGravity(Context.Player.GetPosition())) { Context.Respond("You cannot use this command in natural gravity!"); return; } foreach (DeniedLocation denied in AlliancePlugin.HangarDeniedLocations) { if (Vector3.Distance(Context.Player.GetPosition(), new Vector3(denied.x, denied.y, denied.z)) <= denied.radius) { Context.Respond("Cannot hangar here! Too close to a denied location."); return; } } Boolean console = false; if (Context.Player == null) { console = true; } MyFaction fac = MySession.Static.Factions.GetPlayerFaction(Context.Player.IdentityId); if (fac == null) { Context.Respond("You must be in a faction to use alliance features."); return; } Alliance alliance = AlliancePlugin.GetAlliance(fac); if (alliance == null) { Context.Respond("You are not a member of an alliance."); return; } if (AlliancePlugin.HasFailedUpkeep(alliance)) { Context.Respond("Alliance failed to pay upkeep. Upgrades disabled."); return; } if (!alliance.HasAccess(Context.Player.SteamUserId, AccessLevel.HangarSave)) { Context.Respond("Current rank does not have access to hangar save."); return; } if (alliance.hasUnlockedHangar) { HangarData hangar = alliance.LoadHangar(); if (hangar == null) { Context.Respond("Error loading the hangar."); return; } string name = ""; int pcu = 0; if (hangar.getAvailableSlot() > 0) { ConcurrentBag <MyGroups <MyCubeGrid, MyGridPhysicalGroupData> .Group> gridWithSubGrids = GridFinder.FindLookAtGridGroup(Context.Player.Character); List <MyCubeGrid> grids = new List <MyCubeGrid>(); foreach (var item in gridWithSubGrids) { foreach (MyGroups <MyCubeGrid, MyGridPhysicalGroupData> .Node groupNodes in item.Nodes) { MyCubeGrid grid = groupNodes.NodeData; if (grid.Projector != null) { continue; } if (FacUtils.IsOwnerOrFactionOwned(grid, Context.Player.IdentityId, true)) { pcu += grid.BlocksPCU; foreach (MyProjectorBase proj in grid.GetFatBlocks().OfType <MyProjectorBase>()) { proj.Clipboard.Clear(); } grids.Add(grid); if (name == "") { name = grid.DisplayName; name = name.Replace("/", ""); name = name.Replace("-", ""); name = name.Replace("\\", ""); } } else { Context.Respond("The grid you are looking at includes a grid that isnt owned by you or a faction member."); return; } } } if (grids.Count == 0) { Context.Respond("Could not find grid."); return; } if (name == "") { name = "Temporary Name"; } if (pcu >= AlliancePlugin.config.MaxHangarSlotPCU) { Context.Respond("PCU is greater than the configured maximum"); return; } bool result = hangar.SaveGridToHangar(name + "_" + string.Format("{0:yyyy-MM-dd_HH-mm-ss-fff}", DateTime.Now), Context.Player.SteamUserId, alliance, Context.Player.Character.PositionComp.GetPosition(), fac, grids, Context.Player.IdentityId); if (!result) { Context.Respond("Could not save. Are enemies within 15km?"); } else { Context.Respond("Grid saved."); foreach (MyCubeGrid grid in grids) { if (grid != null) { grid.Close(); } } } } else { Context.Respond("Hangar is full, to upgrade use !ah upgrade true."); } } else { Context.Respond("Alliance has not unlocked the hangar to unlock use !ah unlock."); } }