Пример #1
0
        public void MoveToLobby(MiNET.Player player, int hub = 0)
        {
            if (_skyCoreApi.GameType.Equals("hub"))
            {
                if (hub == 0)
                {
                    player.SendMessage("§c§l(!)§r §cYou are already connected to a hub.");
                    return;
                }

                string hubNum = hub.ToString();

                GameController gameController = _skyCoreApi.GameModes["hub"];
                foreach (GameLevel hubLevel in gameController.GameLevels.Values)
                {
                    if (hubLevel.GameId.Replace("hub", "").Equals(hubNum))
                    {
                        hubLevel.AddPlayer((SkyPlayer)player);
                        return;
                    }
                }

                player.SendMessage($"§c§l(!)§r §cHub{hubNum} does not exist.");
                return;
            }

            player.SendMessage("§e§l(!)§r §eMoving to Hub...");

            ExternalGameHandler.AddPlayer((SkyPlayer)player, "hub");
        }
Пример #2
0
        public void OnDisable()
        {
            IsDisabled = true;

            if (!GameType.Equals("hub"))
            {
                foreach (Level level in Server.LevelManager.Levels)
                {
                    foreach (MiNET.Player player in level.Players.Values)
                    {
                        ExternalGameHandler.AddPlayer(player as SkyPlayer, "hub");
                    }
                }

                Thread.Sleep(1000);
            }

            foreach (Level level in Server.LevelManager.Levels)
            {
                foreach (MiNET.Player player in level.Players.Values)
                {
                    player.Disconnect("                      §d§lSkytonia §f§lNetwork§r\n" +
                                      "§7Skytonia is currently rebooting, try joining again soon!");
                }
            }

            RunnableTask.CancelAllTasks();

            PunishCore.Close();
            StatisticsCore.Close();
        }
Пример #3
0
        public void ShowEndGameMenu(SkyPlayer player)
        {
            var simpleForm = new SimpleForm
            {
                Title   = GetGameModalTitle(),
                Content = GetEndOfGameContent(player),
                Buttons = new List <Button>
                {
                    new Button
                    {
                        Text = "§2§lPlay Again\n" +
                               "§r§8(Jump into a new game)",
                        Image = new Image
                        {
                            Type = "url",
                            Url  = "https://static.skytonia.com/dl/replayiconmenu.png"
                        },
                        ExecuteAction = delegate { ExternalGameHandler.AddPlayer(player, GameType); }
                    }
                }
            };

            StateType currentStateType = CurrentState.GetEnumState(this);

            if (currentStateType != StateType.EndGame &&
                currentStateType != StateType.Closing)
            {
                simpleForm.Buttons.Add(
                    new Button
                {
                    Text = "§6§lSpectate Game\n" +
                           "§r§8(Continue watching this game)",
                    Image = new Image
                    {
                        Type = "url",
                        Url  = "https://static.skytonia.com/dl/spectateiconmenu.png"
                    },
                    ExecuteAction = delegate { SetPlayerTeam(player, GetSpectatorTeam()); }
                }
                    );
            }

            simpleForm.Buttons.Add(
                new Button
            {
                Text = "§c§lChange Game\n" +
                       "§r§8(Choose a different game)",
                Image = new Image
                {
                    Type = "url",
                    Url  = "https://static.skytonia.com/dl/comingsooniconmenu.png"
                },
                ExecuteAction = delegate { GameUtil.ShowGameList(player); }
            }
                );

            player.SendForm(simpleForm);
        }
Пример #4
0
        public void UpdateGameState(GameState gameState)
        {
            lock (_tickLock)
            {
                try
                {
                    CurrentState.LeaveState(this);
                }
                catch (Exception e)
                {
                    BugSnagUtil.ReportBug(e, this, CurrentState);
                }

                CurrentState = gameState;

                try
                {
                    CurrentState.EnterState(this);
                }
                catch (Exception e)
                {
                    BugSnagUtil.ReportBug(e, this, CurrentState);

                    //Move all players to a new game.
                    DoForAllPlayers(player =>
                    {
                        try
                        {
                            if (player == null)
                            {
                                return;
                            }

                            ExternalGameHandler.AddPlayer(player, GameType);
                        }
                        catch (Exception e2)
                        {
                            //Ignore
                            BugSnagUtil.ReportBug(e, this, CurrentState);
                        }
                    });

                    if (gameState.GetEnumState(this) != StateType.Closing)
                    {
                        UpdateGameState(new VoidGameState());
                    }
                }
            }
        }
Пример #5
0
        public override void OnTick(GameLevel gameLevel, int currentTick, out int outTick)
        {
            outTick = currentTick;

            if (TimeRemaining-- >= 0)
            {
                string message;
                if (TimeRemaining == 0)
                {
                    message = "§r§f §r";
                }
                else
                {
                    int timeRemaining = TimeRemaining / 2;
                    message = $"§d§lGame Ended:§r §fNext Game in §7{timeRemaining} §fSecond{(timeRemaining != 1 ? "s" : "")}...";
                }

                gameLevel.DoForAllPlayers(player =>
                {
                    player.BarHandler.AddMajorLine(message, 4, 3);
                });
            }
            else
            {
                List <SkyPlayer> remainingPlayers = gameLevel.GetAllPlayers();
                if (remainingPlayers.Count > 0)
                {
                    foreach (SkyPlayer player in remainingPlayers)
                    {
                        gameLevel.RemovePlayer(player);

                        if (SkyCoreAPI.IsRebootQueued)
                        {
                            player.BarHandler.AddMajorLine(("§d§lGame Ending: §r§fMoving to Network Lobby..."), 20, 7);
                            ExternalGameHandler.AddPlayer(player, "hub");
                        }
                        else
                        {
                            ExternalGameHandler.AddPlayer(player, gameLevel.GameType);
                        }
                    }
                }

                Thread.Sleep(5000);

                gameLevel.UpdateGameState(new VoidGameState());
            }
        }
Пример #6
0
        public override void LeaveState(GameLevel gameLevel)
        {
            gameLevel.DoForAllPlayers(player =>
            {
                player.RemoveAllEffects();

                player.SetHideNameTag(false);
                player.SetNameTagVisibility(true);

                if (SkyCoreAPI.IsRebootQueued)
                {
                    ExternalGameHandler.AddPlayer(player, "hub");
                }
                else
                {
                    ExternalGameHandler.AddPlayer(player, gameLevel.GameType);
                }
            });
        }
Пример #7
0
        public void CommandJoin(MiNET.Player player, string gameName)
        {
            try
            {
                switch (gameName.ToLower())
                {
                case "murder":
                {
                    ExternalGameHandler.AddPlayer((SkyPlayer)player, "murder");
                    break;
                }

                case "build-battle":
                {
                    ExternalGameHandler.AddPlayer((SkyPlayer)player, "build-battle");
                    break;
                }

                case "hub":
                {
                    ExternalGameHandler.AddPlayer((SkyPlayer)player, "hub");
                    break;
                }

                default:
                {
                    player.SendMessage($"§c§l(!)§r §cCould not find game '{gameName}'.");
                    return;
                }
                }

                player.SendMessage($"§e§l(!)§r §eJoining Game {gameName}...");
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                player.SendMessage($"§c§l(!)§r §cUnable to Join Game '{gameName}'.");
            }
        }
Пример #8
0
        public override void InitializePlayer()
        {
            if (_hasJoined)
            {
                return;
            }

            try
            {
                if (CertificateData.ExtraData.Xuid == null)
                {
                    Disconnect("§cAn §2§lXBOX§r §caccount required to login to §dSkytonia §eNetwork");
                    return;
                }

                if (Whitelist.IsEnabled() && !Whitelist.OnWhitelist(Username))
                {
                    Disconnect(Whitelist.GetWhitelistMessage());
                    return;
                }

                StatisticsCore.AddPlayer(CertificateData.ExtraData.Xuid, Username);

                //Sync retrieve any active punishments
                PlayerPunishments playerPunishments = PunishCore.GetPunishmentsFor(CertificateData.ExtraData.Xuid);
                Punishment        activePunishment  = playerPunishments.GetActive(PunishmentType.Ban);
                if (activePunishment != null)
                {
                    Disconnect("§cYou are currently banned from the §dSkytonia §eNetwork\n" +
                               $"§c({PunishmentMessages.GetNeatExpiryForPunishment(activePunishment)})\n" +
                               $"§cReason: {activePunishment.PunishReason}");
                    return;
                }

                BarHandler = new BarHandler(this);

                SetPlayerGroup(PlayerGroup.Player);

                _hasJoined = true;

                RunnableTask.RunTask(() =>
                {
                    new DatabaseAction().Query(
                        "SELECT `group_name` FROM player_groups WHERE `player_xuid`=@id",
                        (command) =>
                    {
                        command.Parameters.AddWithValue("@id", CertificateData.ExtraData.Xuid);
                    },
                        (reader) =>
                    {
                        PlayerGroup.ValueOf(reader.GetString(0), out var playerGroup);

                        if (playerGroup == null)
                        {
                            //Simply set, then update perms in the post-delegate
                            playerGroup = PlayerGroup.Player;
                        }

                        PlayerGroup = playerGroup;
                    },
                        new Action(delegate
                    {
                        //Update permission levels
                        SetPlayerGroup(PlayerGroup);

                        _isRankLoaded = true;
                        //SkyUtil.log($"Initialized as {PlayerGroup.GroupName}({CommandPermission})");

                        SetGameMode(GameMode.Adventure);

                        if (SkyCoreApi.GameType.Equals("hub") && PlayerGroup.IsAtLeast(PlayerGroup.Mvp))
                        {
                            SetAllowFly(true);
                        }

                        foreach (Action action in _postLoginActions)
                        {
                            action.Invoke();
                        }
                        _postLoginActions.Clear();

                        if (Username.Equals("OhBlihv") || Username.Equals("Erazeo"))
                        {
                            if (PlayerGroup != PlayerGroup.Admin)
                            {
                                SetPlayerGroup(PlayerGroup.Admin);
                                //SkyUtil.log($"Overriding {Username}'s group to Admin");
                            }
                        }

                        RunnableTask.RunTaskLater(() =>
                        {
                            SendTitle("§f", TitleType.Clear);
                            SendTitle("§f", TitleType.AnimationTimes, 6, 6, 20 * 10);
                            SendTitle("§f", TitleType.ActionBar, 6, 6, 20 * 10);
                            SendTitle("§f", TitleType.Title, 6, 6, 20 * 10);
                            SendTitle("§f", TitleType.SubTitle, 6, 6, 20 * 10);
                        }, 500);

                        //Traditional Loading

                        IsSpawned = true;

                        //Should already be in a 'GameLevel'.
                        //Check and force-spawn them in if they're missing.
                        if (Level is GameLevel level && !level.PlayerTeamDict.ContainsKey(Username))
                        {
                            level.AddPlayer(this);
                        }

                        GameInfo targetedGame = ExternalGameHandler.GetGameForIncomingPlayer(Username);
                        if (targetedGame != null && (!(Level is GameLevel) || !((GameLevel)Level).GameId.Equals(targetedGame.GameId)))
                        {
                            SkyCoreApi.GameModes[SkyCoreApi.GameType].InstantQueuePlayer(this, targetedGame);
                        }

                        //Search this players pending groups
                        new DatabaseAction().Query(
                            "SELECT `group_name` FROM player_pending_groups WHERE `player_name`=@name",
                            (command) => { command.Parameters.AddWithValue("@name", Username); },
                            (reader) =>
                        {
                            PlayerGroup.ValueOf(reader.GetString(0), out var playerGroup);

                            if (playerGroup == null)
                            {
                                return;
                            }

                            SetPlayerGroup(playerGroup);

                            new DatabaseAction().Execute(
                                "DELETE FROM player_pending_groups WHERE `player_name`=@name",
                                (command) => { command.Parameters.AddWithValue("@name", Username); },
                                null);

                            new DatabaseAction().Execute(
                                "INSERT INTO `player_groups`\n" +
                                "  (`player_xuid`, `group_name`)\n" +
                                "VALUES\n" +
                                "  (@xuid, @group)\n" +
                                "ON DUPLICATE KEY UPDATE\n" +
                                "  `player_xuid`    = VALUES(`player_xuid`),\n" +
                                "  `group_name`     = VALUES(`group_name`);",
                                (command) =>
                            {
                                command.Parameters.AddWithValue("@xuid", CertificateData.ExtraData.Xuid);
                                command.Parameters.AddWithValue("@group", PlayerGroup.GroupName);
                            },
                                null
                                );
                        },
                            null);
                    })
                        );
                });

                //Initialize once we've loaded the group etc.
                base.InitializePlayer();
            }
Пример #9
0
        public override void OnTick(GameLevel gameLevel, int currentTick, out int outTick)
        {
            outTick = currentTick;

            CurrentTick = currentTick;

            //Execute every 5 seconds (10 ticks)
            if (currentTick % 10 == 0)
            {
                List <MiNET.Player> playersToRemove = null,
                                    nonAfkPlayers   = null;

                foreach (KeyValuePair <MiNET.Player, AfkPlayer> entry in _afkCheckPlayers)
                {
                    PlayerLocation currentLocation = entry.Key.KnownPosition,
                                                                spawnLocation = entry.Key.SpawnPosition;

                    if (
                        Math.Abs(currentLocation.X - spawnLocation.X) < 2 &&
                        Math.Abs(currentLocation.Y - spawnLocation.Y) < 2 &&
                        Math.Abs(currentLocation.Z - spawnLocation.Z) < 2
                        )
                    {
                        entry.Value.afkTime++;

                        //>6 = >30 seconds AFK
                        if (entry.Value.afkTime > 6)
                        {
                            if (playersToRemove == null)
                            {
                                playersToRemove = new List <MiNET.Player>();
                            }

                            playersToRemove.Add(entry.Key);
                        }
                    }
                    else
                    {
                        if (nonAfkPlayers == null)
                        {
                            nonAfkPlayers = new List <MiNET.Player>();
                        }
                        nonAfkPlayers.Add(entry.Key);
                    }
                }

                if (nonAfkPlayers != null && nonAfkPlayers.Count > 0)
                {
                    foreach (MiNET.Player player in nonAfkPlayers)
                    {
                        _afkCheckPlayers.Remove(player);
                    }
                }

                if (playersToRemove != null && playersToRemove.Count > 0)
                {
                    foreach (MiNET.Player player in playersToRemove)
                    {
                        if (player != null)
                        {
                            ExternalGameHandler.AddPlayer(player as SkyPlayer, "hub");

                            player.DespawnEntity();
                        }

                        gameLevel.RemovePlayer(player);
                        _afkCheckPlayers.Remove(player);
                    }
                }
            }
        }
Пример #10
0
        public void Configure(MiNetServer server)
        {
            Server = server;

            SkyUtil.log("Hooking into MiNET.");

            Instance = this;
            SkyUtil.log("SkyCore Initializing...");

            //Initialize Bugsnag Exception Reporting
            BugSnagUtil.Init();

            SkyUtil.log($"Dev Mode: ({Config.GetProperty("dev-server", "false")})");
            try
            {
                if (Config.GetProperty("dev-server", "false").Equals("true"))
                {
                    IsDevelopmentServer = true;
                    SkyUtil.log("Initializing Server In Development Mode");

                    //Forcefully Enable Whitelist
                    Whitelist.LoadWhitelist();

                    if (!Whitelist.WhitelistContent.Enabled)
                    {
                        SkyUtil.log("Enforcing Whitelist");
                        Whitelist.WhitelistContent.Enabled = true;
                        Whitelist.SaveWhitelist();
                    }
                }
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e);
            }

            ServerPath = Environment.CurrentDirectory;
            SkyUtil.log($"Registered Server Path at '{ServerPath}'");

            CurrentIp = new WebClient().DownloadString("http://icanhazip.com").Replace("\n", "") + ":" + Config.GetProperty("port", "19132");
            SkyUtil.log($"Registered current IP as {CurrentIp}");

            ExternalGameHandler.CurrentHostAddress = CurrentIp;

            BlockFactory.CustomBlockFactory = new SkyBlockFactory();
            server.LevelManager             = new SkyLevelManager(this);

            //Create Games once the LevelManager has been initialized to avoid launching without any levels

            ExternalGameHandler.Init(server);             //Start listening for game servers

            string serverGame = Config.GetProperty("game-type", "none");

            SkyUtil.log($"Setting up Custom Game {serverGame}...");
            GameType = serverGame;
            try
            {
                Type   gameControllerType = null;
                string gameName           = null;

                switch (serverGame)
                {
                case "murder":
                {
                    gameName           = "Murder Mystery";
                    gameControllerType = typeof(MurderGameController);
                    break;
                }

                case "build-battle":
                {
                    gameName           = "Build Battle";
                    gameControllerType = typeof(BuildBattleGameController);
                    break;
                }

                case "none":
                {
                    gameName = "Pure Hub";

                    //none -> hub
                    GameType = "hub";

                    gameControllerType = typeof(HubController);

                    break;
                }
                }

                if (gameControllerType == null)
                {
                    SkyUtil.log("No Game Loaded.");
                    return;
                }

                SkyUtil.log($"Initializing Game {gameName}...");
                _initializeCustomGame(Activator.CreateInstance(gameControllerType, this) as GameController);
                Thread.Sleep(1000);                 //Pause the main thread for a second to ensure the levels are setup and avoid any CME
                SkyUtil.log($"Finished Initializing {gameName}");

                //Register all remaining games
                bool spawnNPC = gameName.Equals("Pure Hub");

                ExternalGameHandler.RegisterGameIntent("murder", spawnNPC);
                ExternalGameHandler.RegisterGameIntent("build-battle", spawnNPC);
                ExternalGameHandler.RegisterGameIntent("block-hunt", spawnNPC);
                ExternalGameHandler.RegisterGameIntent("bed-wars", spawnNPC);
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e);
                //TODO: Prevent players joining
            }

            //

            Permissions          = new SkyPermissions(this);
            server.PlayerFactory = new SkyPlayerFactory {
                SkyCoreApi = this
            };

            SkyUtil.log("Finished Hooks.");
        }
Пример #11
0
        public override void Close()
        {
            try
            {
                GameLevelTick.Dispose();
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e, this);
            }

            try
            {
                GameLevelTickThread.Abort();
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e, this);
            }

            try
            {
                DoForAllPlayers(player =>
                {
                    ExternalGameHandler.AddPlayer(player, "hub");
                });
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e, this);
            }

            try
            {
                if (CurrentState.GetEnumState(this) != StateType.Closing)
                {
                    UpdateGameState(new VoidGameState());
                }
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e, this);
            }

            try
            {
                base.Close();
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e, this);
            }

            try
            {
                Plugin.Server.LevelManager.Levels.Remove(this);
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e, this);
            }
        }
Пример #12
0
        public static void SpawnHubNPC(GameLevel level, string npcName, PlayerLocation spawnLocation, string command)
        {
            NPCSpawnTask spawnTask = (gameLevel) =>
            {
                try
                {
                    if (String.IsNullOrEmpty(npcName))
                    {
                        Console.WriteLine("§c§l(!) §r§cInvalid NPC text. /hologram <text>");
                        return;
                    }

                    npcName = npcName.Replace("_", " ").Replace("&", "§");

                    if (npcName.Equals("\"\""))
                    {
                        npcName = "";
                    }

                    string     gameName = command;
                    onInteract action   = null;
                    if (!String.IsNullOrEmpty(command))
                    {
                        if (command.StartsWith("GID:"))
                        {
                            gameName = command.Split(':')[1];

                            switch (gameName)
                            {
                            case "murder":
                            case "build-battle":
                            {
                                action = player =>
                                {
                                    //Freeze the players movement
                                    player.Freeze(true);
                                    RunnableTask.RunTaskLater(() => ExternalGameHandler.AddPlayer(player, gameName), 200);
                                };
                                break;
                            }
                            }
                        }
                    }

                    if (gameName.Equals(command))
                    {
                        SkyUtil.log($"Unknown game command '{command}'");
                        return;
                    }

                    //Ensure this NPC can be seen
                    PlayerNPC npc;

                    /*if (action != null)
                     * {
                     *      npc = new PlayerNPC("§a(Punch to play)", gameLevel, spawnLocation, action, gameName) { Scale = 1.5 };
                     * }
                     * else
                     * {
                     *      npc = new PlayerNPC("§e(Coming Soon)", gameLevel, spawnLocation, null, gameName) { Scale = 1.5 };
                     * }*/
                    npc = new PlayerNPC("", gameLevel, spawnLocation, action, gameName)
                    {
                        Scale = 1.5
                    };

                    SkyCoreAPI.Instance.AddPendingTask(() =>
                    {
                        npc.KnownPosition = spawnLocation;
                        //npc.Width = 0D;
                        //npc.Height = 1.0D;
                        npc.SpawnEntity();
                    });

                    {
                        PlayerLocation playerCountLocation = (PlayerLocation)spawnLocation.Clone();

                        //Spawn a hologram with player counts
                        PlayerCountHologram hologram = new PlayerCountHologram(npcName, gameLevel, playerCountLocation, gameName);

                        SkyCoreAPI.Instance.AddPendingTask(() => hologram.SpawnEntity());
                    }

                    {
                        PlayerLocation gameNameLocation = (PlayerLocation)spawnLocation.Clone();
                        gameNameLocation.Y += 3.1f;

                        Hologram gameNameHologram = new Hologram(npcName, gameLevel, gameNameLocation);

                        SkyCoreAPI.Instance.AddPendingTask(() => gameNameHologram.SpawnEntity());
                    }

                    Console.WriteLine($"§e§l(!) §r§eSpawned NPC with text '{npcName}§r'");
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
            };

            if (String.IsNullOrWhiteSpace(command))
            {
                SkyUtil.log("Found null command as key. Using npc game name instead.");
                command = npcName;
            }

            GameNPCs.Add(command, spawnTask);

            if (level != null)
            {
                spawnTask.Invoke(level);
            }
        }
Пример #13
0
        public static void TriggerReboot(bool force = false)
        {
            if (Timer != null)
            {
                Timer.Dispose();
                Timer = null;
            }
            else
            {
                SkyUtil.log("Attempted to double-trigger a reboot! Ignoring...");
                return;                 //If Timer == null, there should already be a reboot happening.
            }

            SkyUtil.log("Shutting down using Restart Handler");
            SkyUtil.log("Moving all players to first available hub");

            //Remove this instance from the game pool
            string gameType = SkyCoreAPI.Instance.GameType;

            if (ExternalGameHandler.GameRegistrations.TryGetValue(gameType, out GamePool gamePool))
            {
                List <InstanceInfo> toRemoveInstances = new List <InstanceInfo>();

                foreach (InstanceInfo instanceInfo in gamePool.GetAllInstances())
                {
                    if (instanceInfo.HostAddress.Equals("local"))
                    {
                        toRemoveInstances.Add(instanceInfo);
                    }
                }

                foreach (InstanceInfo toRemoveInstance in toRemoveInstances)
                {
                    gamePool.RemoveInstance(toRemoveInstance);
                }
            }

            //Remove ourselves from the list, and force players to a new hub
            if (gamePool != null && gameType.Equals("hub"))
            {
                if (gamePool.GetAllInstances().Count > 0)
                {
                    foreach (SkyPlayer player in SkyCoreAPI.Instance.GetAllOnlinePlayers())
                    {
                        ExternalGameHandler.AddPlayer(player, "hub");
                    }

                    //Wait for players to leave
                    Thread.Sleep(5000);
                }
                //else - No hub servers to send players to. Forfeit all players.
            }
            else
            {
                SkyCoreAPI.IsRebootQueued = true;

                //Force will ignore this and kick all players immediately
                if (!force && SkyCoreAPI.Instance.GameModes.TryGetValue(gameType, out GameController localGameController) &&
                    !localGameController.GameLevels.IsEmpty)
                {
                    ICollection <GameLevel> gameLevels = localGameController.GameLevels.Values;

                    long expiryForceTime = DateTimeOffset.Now.ToUnixTimeSeconds() + 300;                     //5 minute timeout if the game is still running
                    int  totalPlayers;

                    do
                    {
                        totalPlayers = 0;

                        foreach (GameLevel gameLevel in gameLevels)
                        {
                            if (gameLevel.CurrentState.GetEnumState(gameLevel).IsJoinable())
                            {
                                //We're allowed to kick all players
                                foreach (SkyPlayer player in gameLevel.GetAllPlayers())
                                {
                                    ExternalGameHandler.AddPlayer(player, "hub");
                                }
                            }
                            else
                            {
                                totalPlayers += gameLevel.GetAllPlayers().Count;
                            }
                        }

                        if (totalPlayers > 0)
                        {
                            SkyUtil.log(
                                $"Waiting for {totalPlayers} to finish games before closing this instance {expiryForceTime - DateTimeOffset.Now.ToUnixTimeSeconds()} seconds remaining.");

                            Thread.Sleep(15000);                             //Check every 1 second if the game has finished
                        }
                    } while (totalPlayers > 0 && DateTimeOffset.Now.ToUnixTimeSeconds() < expiryForceTime);
                }
            }

            SkyUtil.log("Shutting down...");

            //Start Actual Shutdown
            MiNetServer server = SkyCoreAPI.Instance.Server;

            try
            {
                if (server.PluginManager.Plugins.Count > 1)
                {
                    foreach (object pluginObject in server.PluginManager.Plugins)
                    {
                        if (pluginObject is IPlugin plugin)
                        {
                            plugin.OnDisable();
                        }
                    }

                    server.PluginManager.Plugins.Clear();
                }
                else
                {
                    SkyCoreAPI.Instance.OnDisable();
                }
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e);
            }

            try
            {
                server.StopServer();
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e);
            }

            Environment.Exit(0);
        }