예제 #1
0
        public void Process()
        {
            lock (m_items)
            {
                if (!m_items.Any())
                {
                    return;
                }

                for (int r = m_items.Count() - 1; r >= 0; r--)
                {
                    TimedEntityCleanupItem item = m_items[r];

                    if (DateTime.Now - item.addedTime > TimeSpan.FromSeconds(item.secondsAfterAdding))
                    {
                        try
                        {
                            IMyEntity entity = null;
                            Wrapper.GameAction(() =>
                            {
                                MyAPIGateway.Entities.TryGetEntityById(item.entityId, out entity);
                            });

                            if (entity != null)
                            {
                                MyObjectBuilder_CubeGrid gridBuilder = CubeGrids.SafeGetObjectBuilder((IMyCubeGrid)entity);
                                if (gridBuilder == null)
                                {
                                    continue;
                                }

                                CubeGridEntity entityToDispose = new CubeGridEntity((MyObjectBuilder_CubeGrid)entity.GetObjectBuilder(), entity);
                                entityToDispose.Dispose();
                            }
                            else
                            {
                                Logging.WriteLineAndConsole("Entity is null");
                            }
                        }
                        catch (Exception ex)
                        {
                            Logging.WriteLineAndConsole(string.Format("Dispose Error: {0}", ex.ToString()));
                        }

                        m_items.RemoveAt(r);
                    }
                }
            }
        }
예제 #2
0
        public override bool HandleCommand(ulong userId, string[] words)
        {
            HashSet <IMyEntity> entitiesFound = CubeGrids.ScanCleanup(userId, words);

            foreach (IMyEntity entity in entitiesFound)
            {
                CubeGridEntity removeEntity = new CubeGridEntity((MyObjectBuilder_CubeGrid)entity.GetObjectBuilder(), entity);
                removeEntity.Dispose();

                IMyCubeGrid grid      = (IMyCubeGrid)entity;
                long        ownerId   = 0;
                string      ownerName = "";
                if (grid.BigOwners.Count > 0)
                {
                    ownerId   = grid.BigOwners.First();
                    ownerName = PlayerMap.Instance.GetPlayerItemFromPlayerId(ownerId).Name;
                }

                Log.Info("Cleanup", string.Format("Cleanup Removed Grid - Id: {0} Display: {1} OwnerId: {2} OwnerName: {3}", entity.EntityId, entity.DisplayName, ownerId, ownerName));
            }
            return(true);
        }
        public BaseResult Delete(long entityID)
        {
            try
            {
                BaseObject baseObj = SectorObjectManager.Instance.GetEntry(entityID);
                if (!(baseObj is CubeGridEntity))
                {
                    return(new BaseResult(string.Format("Entity {0} is not a cubeGrid", entityID), true));
                }

                CubeGridEntity cubeGrid = (CubeGridEntity)baseObj;

                string dispName = cubeGrid.Name;
                cubeGrid.Dispose();
                cubeGrid = null;

                return(new BaseResult(string.Format("Ship \"{0}\" ({1}) successfully deleted", dispName, entityID), false));
            }
            catch (Exception e)
            {
                Log.Error(e);
                return(new BaseResult(string.Format("Internal error: {0}. See log for details", e.Message), true));
            }
        }
        // admin deletearea x y z radius
        public override bool HandleCommand(ulong userId, string command)
        {
            string[] words = command.Split(' ');
            if (words.Length > 3)
            {
                return(false);
            }

            if (!words.Any())
            {
                Communication.SendPrivateInformation(userId, GetHelp());
                return(true);
            }

            int days = -1;

            if (!int.TryParse(words[0], out days) || days < 0)
            {
                Communication.SendPrivateInformation(userId, string.Format("Invalid argument.  Days argument must be an integer that is 0 or greater."));
                return(true);
            }

            // Just assume that anything after the days is going to "ignorenologin"
            bool removeNoLoginInformation = true;
            bool removeOwnerless          = true;

            if (words.Count() > 1)
            {
                foreach (string word in words)
                {
                    if (word.ToLower() == "ignorenologin")
                    {
                        removeNoLoginInformation = false;
                    }
                    if (word.ToLower() == "ignoreownerless")
                    {
                        removeOwnerless = false;
                    }
                }
            }

            Communication.SendPrivateInformation(userId, string.Format("Scanning for grids with owners that haven't logged in {0} days.  (Must Have Login Info={1})", days, removeNoLoginInformation));

            HashSet <IMyEntity> entities = new HashSet <IMyEntity>();

            Wrapper.GameAction(() =>
            {
                MyAPIGateway.Entities.GetEntities(entities, x => x is IMyCubeGrid);
            });

            HashSet <IMyEntity> entitiesFound = new HashSet <IMyEntity>();

            foreach (IMyEntity entity in entities)
            {
                if (!(entity is IMyCubeGrid))
                {
                    continue;
                }

                IMyCubeGrid              grid        = (IMyCubeGrid)entity;
                CubeGridEntity           gridEntity  = (CubeGridEntity)GameEntityManager.GetEntity(grid.EntityId);
                MyObjectBuilder_CubeGrid gridBuilder = CubeGrids.SafeGetObjectBuilder(grid);
                if (gridBuilder == null)
                {
                    continue;
                }

                // This entity is protected by whitelist
                if (PluginSettings.Instance.LoginEntityWhitelist.Length > 0 && PluginSettings.Instance.LoginEntityWhitelist.Contains(grid.EntityId.ToString()))
                {
                    continue;
                }

                if (CubeGrids.GetAllOwners(gridBuilder).Count < 1 && removeOwnerless)
                {
                    Communication.SendPrivateInformation(userId, string.Format("Found entity '{0}' ({1}) not owned by anyone.", gridEntity.Name, entity.EntityId));
                    entitiesFound.Add(entity);
                    continue;
                }

                foreach (long player in CubeGrids.GetBigOwners(gridBuilder))
                {
                    // This playerId is protected by whitelist
                    if (PluginSettings.Instance.LoginPlayerIdWhitelist.Length > 0 && PluginSettings.Instance.LoginPlayerIdWhitelist.Contains(player.ToString()))
                    {
                        continue;
                    }

                    MyObjectBuilder_Checkpoint.PlayerItem checkItem = PlayerMap.Instance.GetPlayerItemFromPlayerId(player);
                    if (checkItem.IsDead || checkItem.Name == "")
                    {
                        Communication.SendPrivateInformation(userId, string.Format("Found entity '{0}' ({1}) owned by dead player - ID: {2}", gridEntity.Name, entity.EntityId, player));
                        entitiesFound.Add(entity);
                        continue;
                    }

                    PlayerItem item = Players.Instance.GetPlayerById(player);
                    if (item == null)
                    {
                        if (removeNoLoginInformation)
                        {
                            Communication.SendPrivateInformation(userId, string.Format("Found entity '{0}' ({1}) owned by a player with no login info: {2}", gridEntity.Name, entity.EntityId, checkItem.Name));
                            entitiesFound.Add(entity);
                        }
                    }
                    else if (item.LastLogin < DateTime.Now.AddDays(days * -1))
                    {
                        Communication.SendPrivateInformation(userId, string.Format("Found entity '{0}' ({1}) owned by inactive player: {2}", gridEntity.Name, entity.EntityId, PlayerMap.Instance.GetPlayerItemFromPlayerId(player).Name));
                        entitiesFound.Add(entity);
                    }
                }
            }

            Communication.SendPrivateInformation(userId, string.Format("Found {0} grids owned by inactive users", entitiesFound.Count));

            foreach (IMyEntity entity in entitiesFound)
            {
                if (!(entity is IMyCubeGrid))
                {
                    continue;
                }

                CubeGridEntity gridEntity = new CubeGridEntity((MyObjectBuilder_CubeGrid)entity.GetObjectBuilder(), entity);
                gridEntity.Dispose();
            }

            Communication.SendPrivateInformation(userId, string.Format("Removed {0} grids owned by inactive users", entitiesFound.Count));
            return(true);
        }
        // /admin movefrom x y z x y z radius
        public override bool HandleCommand(ulong userId, string command)
        {
            string[] words = command.Split(' ');
            if (words.Count( ) < 2)
            {
                Communication.SendPrivateInformation(userId, GetHelp());
                return(true);
            }

            string sourceName = words[0];
            float  distance   = 50f;

            // TODO Allow quotes so we can do distance?
            bool parse = false;

            if (words.Count() > 2)
            {
                parse = float.TryParse(words[words.Count() - 1], out distance);
            }

            string targetName;

            if (parse)
            {
                targetName = string.Join(" ", words.Skip(1).Take(words.Count() - 2).ToArray());
            }
            else
            {
                targetName = string.Join(" ", words.Skip(1).ToArray());
            }

            Communication.SendPrivateInformation(userId, string.Format("Moving {0} to within {1}m of {2}.  This may take about 20 seconds.", sourceName, distance, targetName));

            Vector3D        position;
            CharacterEntity charEntity = SectorObjectManager.Instance.GetTypedInternalData <CharacterEntity>().FirstOrDefault(x => x.DisplayName.ToLower() == targetName.ToLower() && x.Health > 0);

            if (charEntity == null)
            {
                CubeGridEntity gridEntity = SectorObjectManager.Instance.GetTypedInternalData <CubeGridEntity>().FirstOrDefault(x => (x.DisplayName.ToLower().Contains(targetName.ToLower()) || x.Name.ToLower().Contains(targetName.ToLower())) && !x.IsDisposed);
                if (gridEntity == null)
                {
                    Communication.SendPrivateInformation(userId, string.Format("Can not find user or grid with the name: {0}", targetName));
                    return(true);
                }
                position = gridEntity.Position;
            }
            else
            {
                position = charEntity.Position;
            }

            Vector3D       startPosition = MathUtility.RandomPositionFromPoint((Vector3)position, distance);
            CubeGridEntity gridToMove    = SectorObjectManager.Instance.GetTypedInternalData <CubeGridEntity>().FirstOrDefault(x => (x.DisplayName.ToLower().Contains(sourceName.ToLower()) || x.Name.ToLower().Contains(sourceName.ToLower())) && !x.IsDisposed);

            if (gridToMove == null)
            {
                Communication.SendPrivateInformation(userId, string.Format("Unable to find: {0}", sourceName));
                return(true);
            }

            IMyEntity entity   = null;
            long      entityId = gridToMove.EntityId;
            MyObjectBuilder_CubeGrid gridBuilder = null;

            Wrapper.GameAction(() =>
            {
                entity      = MyAPIGateway.Entities.GetEntityById(entityId);
                gridBuilder = (MyObjectBuilder_CubeGrid)entity.GetObjectBuilder();
                Logging.WriteLineAndConsole(string.Format("Moving '{0}' from {1} to {2}", gridToMove.DisplayName, gridToMove.Position, startPosition));
                gridToMove.Dispose();
            });

            Thread.Sleep(5000);

            Wrapper.GameAction(() =>
            {
                MyAPIGateway.Entities.RemoveFromClosedEntities(entity);
                Logging.WriteLineAndConsole(string.Format("Removing '{0}' for move", entity.DisplayName));
            });

            Thread.Sleep(10000);

            Wrapper.GameAction(() =>
            {
                gridBuilder.PositionAndOrientation = new MyPositionAndOrientation(startPosition, gridBuilder.PositionAndOrientation.Value.Forward, gridBuilder.PositionAndOrientation.Value.Up);
                Logging.WriteLineAndConsole(string.Format("Adding '{0}' for move", gridBuilder.DisplayName));
                SectorObjectManager.Instance.AddEntity(new CubeGridEntity(gridBuilder));
            });

            Communication.SendPrivateInformation(userId, string.Format("Moved {0} to within {1}m of {2}", sourceName, (int)Math.Round(Vector3D.Distance(startPosition, position)), targetName));
            return(true);
        }
        // admin deletearea x y z radius
        public override bool HandleCommand(ulong userId, string[] words)
        {
            HashSet <IMyEntity> entities          = new HashSet <IMyEntity>();
            HashSet <IMyEntity> entitiesToConfirm = new HashSet <IMyEntity>();
            HashSet <IMyEntity> entitiesConnected = new HashSet <IMyEntity>();
            HashSet <IMyEntity> entitiesFound     = new HashSet <IMyEntity>();

            Wrapper.GameAction(() =>
            {
                MyAPIGateway.Entities.GetEntities(entities, x => x is IMyCubeGrid);
            });

            foreach (IMyEntity entity in entities)
            {
                if (!(entity is IMyCubeGrid))
                {
                    continue;
                }

                IMyCubeGrid grid = (IMyCubeGrid)entity;
                MyObjectBuilder_CubeGrid gridBuilder = CubeGrids.SafeGetObjectBuilder(grid);
                if (gridBuilder == null)
                {
                    continue;
                }

                bool found = false;
                foreach (MyObjectBuilder_CubeBlock block in gridBuilder.CubeBlocks)
                {
                    if (block.TypeId == typeof(MyObjectBuilder_Beacon))
                    {
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    entitiesToConfirm.Add(grid);
                }
            }

            CubeGrids.GetGridsUnconnected(entitiesFound, entitiesToConfirm);

            foreach (IMyEntity entity in entitiesFound)
            {
                CubeGridEntity gridEntity = (CubeGridEntity)GameEntityManager.GetEntity(entity.EntityId);
                if (gridEntity == null)
                {
                    Log.Info("A found entity gridEntity was null!");
                    continue;
                }
                Communication.SendPrivateInformation(userId, string.Format("Found entity '{0}' ({1}) at {2} with no beacon.", gridEntity.Name, entity.EntityId, General.Vector3DToString(entity.GetPosition())));
            }

            for (int r = entitiesFound.Count - 1; r >= 0; r--)
            {
                //MyAPIGateway.Entities.RemoveEntity(entity);
                IMyEntity      entity     = entitiesFound.ElementAt(r);
                CubeGridEntity gridEntity = new CubeGridEntity((MyObjectBuilder_CubeGrid)entity.GetObjectBuilder(), entity);
                gridEntity.Dispose();
            }

            Communication.SendPrivateInformation(userId, string.Format("Removed {0} grids with no beacons", entitiesFound.Count));

            return(true);
        }
예제 #7
0
        // /admin movefrom x y z x y z radius
        public override bool HandleCommand(ulong userId, string[] words)
        {
            if (words.Count() != 7 && words.Count() != 0)
            {
                return(false);
            }

            if (words.Count() != 7)
            {
                Communication.SendPrivateInformation(userId, GetHelp());
                return(true);
            }

            // Test Input
            float test = 0;

            for (int r = 0; r < 7; r++)
            {
                if (!float.TryParse(words[r], out test))
                {
                    Communication.SendPrivateInformation(userId, string.Format("The value at position {0} - '{1}' is invalid.  Please try the command again.", r + 1, words[r]));
                    return(true);
                }
            }

            Vector3D startPosition = new Vector3(float.Parse(words[0]), float.Parse(words[1]), float.Parse(words[2]));
            Vector3D movePosition  = new Vector3(float.Parse(words[3]), float.Parse(words[4]), float.Parse(words[5]));
            Vector3D difference    = startPosition - movePosition;
            float    radius        = float.Parse(words[6]);

            Communication.SendPrivateInformation(userId, string.Format("Moving all grids in a radius of {0} near {1} to {2}", radius, General.Vector3DToString(startPosition), General.Vector3DToString(movePosition)));

            List <MyObjectBuilder_CubeGrid> gridsToMove = new List <MyObjectBuilder_CubeGrid>();
            BoundingSphereD  sphere         = new BoundingSphereD(startPosition, radius);
            List <IMyEntity> entitiesToMove = MyAPIGateway.Entities.GetEntitiesInSphere(ref sphere);

//			Wrapper.GameAction(() =>
//			{
            foreach (IMyEntity entity in entitiesToMove)
            {
                if (!(entity is IMyCubeGrid))
                {
                    continue;
                }

                Communication.SendPrivateInformation(userId, string.Format("Moving '{0}' from {1} to {2}", entity.DisplayName, General.Vector3DToString(entity.GetPosition()), General.Vector3DToString(entity.GetPosition() + difference)));

                gridsToMove.Add((MyObjectBuilder_CubeGrid)entity.GetObjectBuilder());
                //MyAPIGateway.Entities.RemoveEntity(entity);
                CubeGridEntity gridEntity = new CubeGridEntity((MyObjectBuilder_CubeGrid)entity.GetObjectBuilder(), entity);
                gridEntity.Dispose();
            }
//			});

            Log.Info("Entities Removed ... pausing");
            Thread.Sleep(5000);
            Log.Info("Removing entities from closed entities");

            Wrapper.GameAction(() =>
            {
                foreach (IMyEntity entity in entitiesToMove)
                {
                    if (!(entity is IMyCubeGrid))
                    {
                        continue;
                    }

                    Log.Info(string.Format("Removing '{0}' for move", entity.DisplayName));
                    MyAPIGateway.Entities.RemoveFromClosedEntities(entity);
                }
            });

            Thread.Sleep(10000);

            Wrapper.GameAction(() =>
            {
                foreach (MyObjectBuilder_CubeGrid grid in gridsToMove)
                {
                    grid.PositionAndOrientation = new MyPositionAndOrientation(grid.PositionAndOrientation.Value.Position + difference, grid.PositionAndOrientation.Value.Forward, grid.PositionAndOrientation.Value.Up);
                    //Log.Info(string.Format("Adding '{0}' for move", grid.DisplayName));
                    Communication.SendPrivateInformation(userId, string.Format("Adding grid '{0}' back to world.", grid.DisplayName));
                    SectorObjectManager.Instance.AddEntity(new CubeGridEntity(grid));
                    Thread.Sleep(1000);
                }
            });

            Communication.SendPrivateInformation(userId, string.Format("Moved {0} grids", gridsToMove.Count));

            return(true);
        }
예제 #8
0
        public override bool HandleCommand(ulong userId, string[] words)
        {
            if (!PluginSettings.Instance.DockingEnabled)
            {
                return(false);
            }

            if (words.Length < 1)
            {
                Communication.SendPrivateInformation(userId, GetHelp());
                return(true);
            }

            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, string.Format("Unable to find player Id: {0}", 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, string.Format("You do not have permission to use '{0}'.  You must either own all the beacons or they must be shared with faction.", pylonName));
                        return(true);
                    }
                }

                // Check for bounding box intsection of other docking zones
                int intersectElement = 0;
                if (Entity.CheckForIntersection(testList, beaconList, out intersectElement))
                {
                    Communication.SendPrivateInformation(userId, string.Format("The docking zone '{0}' intersects with docking zone '{1}'.  Make sure you place your docking zones so they don't overlap.", pylonName, testList.ElementAt(intersectElement).Key));
                    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, string.Format("Docking zone already '{0}' already contains the maximum capacity of ships.", pylonName));
                    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>();
                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, string.Format("The ship '{0}' is too large for it's carrier.  The ship's bounding box must fit inside the docking zone bounding box!", dockingEntity.Name));
                        return(true);
                    }

                    if (targetBounding.Contains(ref dockingBounding) != ContainmentType.Contains)
                    {
                        Communication.SendPrivateInformation(userId, string.Format("The ship '{0}' is not fully inside the docking zone '{1}'.  Make sure the ship is fully contained inside the docking zone", dockingEntity.Name, pylonName));
                        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, string.Format("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={0}kg CM={1}kg)", dockingMass, parentMass));
                        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 != null && x.FatBlock.BlockDefinition.TypeId == typeof(MyObjectBuilder_Cockpit));
                    foreach (IMySlimBlock slim_cbe in blocks)
                    {
                        MyObjectBuilder_Cockpit c = (MyObjectBuilder_Cockpit)slim_cbe.FatBlock.GetObjectBuilderCubeBlock();
                        if (c.Pilot != null)
                        {
                            Communication.SendPrivateInformation(userId, string.Format("Ship in docking zone '{0}' has a pilot!  Please exit the ship before trying to dock.  (Sometimes this can lag a bit.  Wait 10 seconds and try again)", pylonName));
                            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());

                    // Serialize and save ship to file, then remove it
                    // Save item
                    DockingItem dockItem = new DockingItem();
                    dockItem.DockedEntityId   = dockingEntity.EntityId;
                    dockItem.TargetEntityId   = parent.EntityId;
                    dockItem.PlayerId         = ownerId;
                    dockItem.DockingBeaconIds = beaconList.Select(s => s.EntityId).ToArray();
                    dockItem.DockedName       = dockingEntity.DisplayName;
                    dockItem.SavePos          = savePos;
                    dockItem.SaveQuat         = saveQuat;
                    Docking.Instance.Add(dockItem);

                    // Save ship to file and remove
                    FileInfo       info        = new FileInfo(Essentials.PluginPath + String.Format("\\Docking\\docked_{0}_{1}_{2}.sbc", ownerId, parent.EntityId, dockingEntity.EntityId));
                    CubeGridEntity dockingGrid = new CubeGridEntity((MyObjectBuilder_CubeGrid)dockingEntity.GetObjectBuilder(), dockingEntity);
                    if (!CubeGrids.WaitForLoadingEntity(dockingGrid))
                    {
                        Communication.SendPrivateInformation(userId, string.Format("Failed to load entity for export: {0}", dockingGrid.EntityId));
                        return(true);
                    }

                    dockingGrid.Export(info);
                    dockingGrid.Dispose();

                    Communication.SendPrivateInformation(userId, string.Format("Docked ship '{0}' in docking zone '{1}'.", dockItem.DockedName, pylonName));

                    /*
                     * // Add a cool down
                     * DockingCooldownItem cItem = new DockingCooldownItem();
                     * cItem.name = pylonName;
                     * cItem.startTime = DateTime.Now;
                     * PluginDocking.CooldownList.Add(cItem);
                     */
                }
                else
                {
                    Communication.SendPrivateInformation(userId, string.Format("No ships in docking zone '{0}'.", pylonName));
                }
            }
            else if (beaconList.Count > 4)
            {
                Communication.SendPrivateInformation(userId, string.Format("Too many beacons with the name or another zone with the name '{0}'.  Place only 4 beacons to create a zone or try a different zone name.", pylonName));
            }
            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);
        }