예제 #1
0
        public override void OnTick(Entity[] entities)
        {
            int      playerCount = -1;
            GamePool gamePool    = null;

            try
            {
                gamePool    = ExternalGameHandler.GameRegistrations[_gameName];
                playerCount = gamePool.GetCurrentPlayers();
            }
            catch (Exception e)
            {
                SkyUtil.log($"Looking for '{_gameName}'");
                SkyUtil.log(ExternalGameHandler.GameRegistrations.Keys.ToArray().ToString());
                Console.WriteLine(e);
            }

            if (gamePool != null && gamePool.Active && playerCount >= 0)
            {
                if (gamePool.GetAllInstances().Count > 0)
                {
                    SetNameTag($"§fPlayers Online:§r §e{playerCount}");
                }
                else
                {
                    SetNameTag("§cUnavailable");
                }
            }
            else
            {
                SetNameTag("§a(Coming Soon)");
            }
        }
예제 #2
0
        public MurderLevel(SkyCoreAPI plugin, string gameId, string levelPath, GameLevelInfo gameLevelInfo) : base(plugin, "murder", gameId, levelPath, gameLevelInfo)
        {
            if (!(gameLevelInfo is MurderLevelInfo))
            {
                throw new Exception($"Could not load MurderLevelInfo for level {LevelName}");
            }

            foreach (PlayerLocation playerSpawnLocation in ((MurderLevelInfo)GameLevelInfo).PlayerSpawnLocations)
            {
                //TODO: Remove - Causes locations to rise above the roof
                //				 Clone if this is still required
                //playerSpawnLocation.Y += 0.1f; //Ensure this spawn is not inside the ground

                //Round to the centre of the block.
                playerSpawnLocation.X = (float)(Math.Floor(playerSpawnLocation.X) + 0.5f);
                playerSpawnLocation.Z = (float)(Math.Floor(playerSpawnLocation.Z) + 0.5f);
            }

            if (((MurderLevelInfo)GameLevelInfo).PlayerSpawnLocations.Count == 0 ||
                ((MurderLevelInfo)GameLevelInfo).GunPartLocations.Count == 0)
            {
                SkyUtil.log($"Player Spawns -> {((MurderLevelInfo)GameLevelInfo).PlayerSpawnLocations.Count}");
                SkyUtil.log($"Gun Part Locations -> {((MurderLevelInfo)GameLevelInfo).GunPartLocations.Count}");

                throw new Exception("Defined spawns below range!");
            }

            //SkyUtil.log($"Initialized Player Spawns with {((MurderLevelInfo) GameLevelInfo).PlayerSpawnLocations.Count} unique locations");
            //SkyUtil.log($"Initialized Gun Part Locations with {((MurderLevelInfo)GameLevelInfo).GunPartLocations.Count} unique locations");
        }
예제 #3
0
        public override void EnterState(GameLevel gameLevel)
        {
            gameLevel.DoForAllPlayers(player =>
            {
                player.RemoveAllEffects();

                player.SetGameMode(GameMode.Adventure);
            });

            GameLevelInfo gameLevelInfo = gameLevel.GameLevelInfo;

            //Spawn Lobby NPC
            if (gameLevelInfo.LobbyNPCLocation == null)
            {
                gameLevelInfo.LobbyNPCLocation = new PlayerLocation(260.5, 15, 251.5);

                File.WriteAllText(GameController.GetGameLevelInfoLocation(gameLevel.GameType, gameLevel.LevelName), JsonConvert.SerializeObject(gameLevel.GameLevelInfo, Formatting.Indented));
                SkyUtil.log($"LobbyNPCLocation Updated with default value for {gameLevel.LevelName}");
            }

            _spawnedEntities = PlayerNPC.SpawnLobbyNPC(gameLevel, gameLevelInfo.GameType, gameLevel.GameLevelInfo.LobbyNPCLocation);

            gameLevel.AddPendingTask(() =>
            {
                //Spawn Lobby Map/Image
                if (gameLevelInfo.LobbyMapLocation.Y < 0)         //Default == -1
                {
                    gameLevelInfo.LobbyMapLocation = new BlockCoordinates(252, 15, 249);

                    File.WriteAllText(GameController.GetGameLevelInfoLocation(gameLevel.GameType, gameLevel.LevelName), JsonConvert.SerializeObject(gameLevel.GameLevelInfo, Formatting.Indented));
                }

                _spawnedEntities.AddRange(MapUtil.SpawnMapImage(@"C:\Users\Administrator\Desktop\dl\map-images\TestImage.png", 7, 4, gameLevel, gameLevelInfo.LobbyMapLocation));
            });
        }
예제 #4
0
        public BuildBattleGameController(SkyCoreAPI plugin) : base(plugin, "build-battle", "Build Battle",
                                                                   new List <string> {
            "build-battle-template"
        })
        {
            string themeFilePath =
                $"{Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)}\\config\\build-battle-themes.json";

            //Generate Example Config
            if (!File.Exists(themeFilePath))
            {
                List <BuildBattleTheme> tempThemeList = new List <BuildBattleTheme>
                {
                    new BuildBattleTheme("Theme #1",
                                         new List <CachedItem> {
                        new CachedItem(1, 1), new CachedItem(5, 0)
                    }),
                    new BuildBattleTheme("Theme #2",
                                         new List <CachedItem> {
                        new CachedItem(1, 1), new CachedItem(5, 0)
                    })
                };

                File.WriteAllText(themeFilePath, JsonConvert.SerializeObject(tempThemeList, Formatting.Indented));
            }

            object jObject = JsonConvert.DeserializeObject(File.ReadAllText(themeFilePath));

            if (jObject is JArray array)
            {
                try
                {
                    _themeList = array.ToObject <List <BuildBattleTheme> >();

                    foreach (BuildBattleTheme theme in _themeList)
                    {
                        //Automatic Bolding
                        if (theme.ThemeName.StartsWith("§"))
                        {
                            theme.ThemeName = theme.ThemeName.Substring(0, 2) + "§l" +
                                              theme.ThemeName.Substring(2, theme.ThemeName.Length - 2);
                        }
                    }
                }
                catch (Exception e)
                {
                    BugSnagUtil.ReportBug(e, this, new AnonMetadatable((metadata) =>
                    {
                        metadata.AddToTab("JSON", "Theme List Content", jObject);
                    }));
                }
            }
            else
            {
                SkyUtil.log($"Unable to load theme list. Parsed Object was of type {(jObject == null ? "null" : $"{jObject.GetType()}")}");
            }

            SkyUtil.log($"Initialized {_themeList.Count} Themes");
        }
예제 #5
0
		///<summary>Ensures at least 1 game is available to join. If not, creates one to fill capacity</summary>
		public virtual void CheckCapacity()
		{
			List<GameLevel> availableGames = new List<GameLevel>();
			List<GameLevel> closingGames   = new List<GameLevel>();
			lock (GameLevels)
			{
				foreach (GameLevel gameLevel in GameLevels.Values)
				{
					if (gameLevel.CurrentState.CanAddPlayer(gameLevel))
					{
						availableGames.Add(gameLevel);
					}
					else if (gameLevel.CurrentState.GetEnumState(gameLevel) == StateType.Closing)
					{
						closingGames.Add(gameLevel);
					}
				}
			}

			lock (GameLevels)
			{
				foreach (GameLevel gameLevel in closingGames)
				{
					//SkyUtil.log($"Closing game {gameLevel.GameId}...");
					gameLevel.Close();

					GameLevels.TryRemove(gameLevel.GameId, out _);
				}
			}

			int j = 0;
			while (j++ + availableGames.Count < 2)
			{
				InitializeNewGame(); //Cannot add the new games to the available games list this tick.
			}
			
			//Clean up unnecessary games
			if (availableGames.Count >= 5)
			{
				lock (GameLevels)
				{
					//Start at the most recently created game
					for (int i = availableGames.Count - 1; i >= 0; i--)
					{
						GameLevel gameLevel = availableGames[i];

						gameLevel.Close();

						if (!GameLevels.TryRemove(gameLevel.GameId, out _))
						{
							SkyUtil.log($"Failed to remove game id:{gameLevel.GameId} from GameLevels");
						}
					}
				}
			}
		}
예제 #6
0
	    protected GameController(SkyCoreAPI plugin, string gameName, string neatName, List<string> levelNames)
        {
            Plugin = plugin;
            
            GameName = neatName;
            RawName = gameName;
            
            foreach(var levelName in levelNames)
            {
                string fullLevelPath = $@"C:\Users\Administrator\Desktop\worlds\{gameName}\{levelName}";
	            if (!Directory.Exists(fullLevelPath))
	            {
					SkyUtil.log($"Unable to find world at ({fullLevelPath})");
				}
	            else
	            {
					LevelNames.Add(fullLevelPath);

		            SkyUtil.log($"Added world at ({fullLevelPath})");

					//Pre-load GameLevelInfo
		            GetGameLevelInfo(levelName);

					//Pre-cache the WorldProvider
		            AnvilProviderFactory.GetLevelProvider(plugin.Server.LevelManager, fullLevelPath);
	            }
            }

			if (LevelNames.Count == 0)
			{
				SkyUtil.log($"No Levels configured for {gameName}");
				return;
			}

			RedisGameIdKey = $"next_game_id_{GameName}";

	        ExternalGameHandler.RegisterInternalGame(RawName);

			GameTickThread = new Thread(() =>
	        {
		        Thread.CurrentThread.IsBackground = true;

		        GameTick = new HighPrecisionTimer(50, _CoreGameTick, true);
	        });
	        GameTickThread.Start();
		}
예제 #7
0
        public void RestartTick(Object stateInfo)
        {
            try
            {
                DateTime currentTime = DateTime.Now;

                int secondsBetween = GetSecondDifference(currentTime, RestartTime);

                //Console.WriteLine($"({secondsBetween} Seconds To Reboot).", currentTime, RestartTime);

                switch (secondsBetween)
                {
                case 0:
                    ((AutoResetEvent)stateInfo).Set();                              //Trigger Shutdown of Timer
                    break;

                //Countdowns
                case 60: SkyUtil.log("Rebooting in 60 Seconds");
                    break;

                case 30: SkyUtil.log("Rebooting in 30 Seconds");
                    break;

                case 10: SkyUtil.log("Rebooting in 10 Seconds");
                    break;

                case 5: SkyUtil.log("Rebooting in 5 Seconds");
                    break;

                case 3: SkyUtil.log("Rebooting in 3 Seconds");
                    break;

                case 2: SkyUtil.log("Rebooting in 2 Seconds");
                    break;

                case 1: SkyUtil.log("Rebooting in 1 Seconds");
                    break;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
예제 #8
0
        /*
         * Helper Methods
         */

        public static void SpawnAllHubNPCs(HubLevel gameLevel)
        {
            try
            {
                if (gameLevel == null)
                {
                    SkyUtil.log($"Attempted to spawn NPCs on gameLevel == null");
                    return;
                }
                if (gameLevel.CurrentlySpawnedNPCs == null)
                {
                    SkyUtil.log($"Attempted to spawn NPCs on gameLevel.CurrentlySpawnedNPCs == null");
                    return;
                }

                foreach (KeyValuePair <string, NPCSpawnTask> entry in GameNPCs)
                {
                    if (entry.Key == null || entry.Value == null)
                    {
                        SkyUtil.log(
                            $"NPC Spawn Key {(entry.Key == null ? "is null" : "is not null")} Value {(entry.Value == null ? "is null" : "is not null")}");
                        continue;
                    }

                    SkyUtil.log($"Spawning NPC {entry.Key}");

                    //Only spawn NPCs which have not been spawned yet
                    if (gameLevel.CurrentlySpawnedNPCs.Contains(entry.Key))
                    {
                        continue;
                    }

                    entry.Value.Invoke(gameLevel);
                    gameLevel.CurrentlySpawnedNPCs.Add(entry.Key);
                }

                SkyUtil.log($"Finished spawning {GameNPCs.Count} NPCs");
            }
            catch (Exception e)
            {
            }
        }
예제 #9
0
	    public virtual GameLevel InstantQueuePlayer(SkyPlayer player, bool join = true)
	    {
		    if (player == null)
		    {
			    if (_isFirstLevelRetrieve)
			    {
				    _isFirstLevelRetrieve = false;

				    //Get Next. Should be used for join.
					return GameLevels.Values.GetEnumerator().Current; 
				}
			    
			    SkyUtil.log("Attempted to pass null SkyPlayer to InstantQueuePlayer. Bad Join?");
			    return null;
		    }
		    
			//SkyUtil.log($"Trying to add {player.Username} player to {GameLevels.Count} games");
		    lock (GameLevels)
		    {
			    foreach (GameLevel gameLevel in GetMostViableGames())
			    {
				    if (!gameLevel.CurrentState.CanAddPlayer(gameLevel))
				    {
					    continue;
				    }

				    if (join)
				    {
						//SkyUtil.log($"Adding {player.Username} to game {gameLevel.GameId}-({gameLevel.LevelId}-{gameLevel.LevelName})");
						gameLevel.AddPlayer(player);
					}

				    return gameLevel;
			    }

				//Player shouldn't be here if no games are accessible
			    ExternalGameHandler.AddPlayer(player, "hub");
			}

		    return null;
	    }
예제 #10
0
        public InstanceInfo GetInstance(string instanceKey)
        {
            if (!_gameInstances.TryGetValue(instanceKey, out var instanceInfo))
            {
                string[] messageSplit = instanceKey.Split(':');

                string hostAddress = messageSplit[0];
                if (!ushort.TryParse(messageSplit[1], out ushort hostPort))
                {
                    SkyUtil.log($"Invalid format of port in instancekey {instanceKey}");
                    return(new InstanceInfo());                    //Return empty instance info to keep them happy
                }

                instanceInfo = new InstanceInfo
                {
                    HostAddress = hostAddress,
                    HostPort    = hostPort
                };

                _gameInstances.TryAdd(instanceKey, instanceInfo);
            }

            return(instanceInfo);
        }
예제 #11
0
        /// <summary>
        /// Retrieves the player name for a given xuid,
        /// assuming the xuid->playername is cached.
        /// Otherwise this will call the db sync to retrieve the name
        /// if not cached.
        /// </summary>
        /// <param name="xuid"></param>
        /// <returns>string containing the playername associated with that xuid, otherwise null</returns>
        public static string GetPlayerNameFromXuid(string xuid)
        {
            if (XuidToName.ContainsKey(xuid))
            {
                return(XuidToName[xuid]);
            }

            string currentName = null;

            new DatabaseAction().Query(
                "SELECT `current_name` FROM `player_info` WHERE `player_xuid`=@player_xuid;",
                (command) =>
            {
                command.Parameters.AddWithValue("@player_xuid", xuid);
            },
                (reader) =>
            {
                currentName = reader.GetString(0);
            },
                new Action(delegate
            {
                SkyUtil.log($"Finished query to find names for {xuid}->{currentName}");
            })
                );

            if (currentName != null)
            {
                AddPlayer(xuid, currentName, false);
            }
            else
            {
                SkyUtil.log($"No name found associated with {xuid}");
            }

            return(currentName);
        }
예제 #12
0
        /// <summary>
        /// Retrieves the xuid for a given player,
        /// assuming the playername->xuid is cached.
        /// Otherwise this will call the db sync to retrieve the xuid
        /// if not cached.
        /// </summary>
        /// <param name="currentName"></param>
        /// <returns>string containing the playername associated with that xuid, otherwise null</returns>
        public static string GetXuidForPlayername(string currentName)
        {
            if (NameToXuid.ContainsKey(currentName))
            {
                return(NameToXuid[currentName]);
            }

            string playerXuid = null;

            new DatabaseAction().Query(
                "SELECT `player_xuid` FROM `player_info` WHERE `current_name`=@current_name;",
                (command) =>
            {
                command.Parameters.AddWithValue("@current_name", currentName);
            },
                (reader) =>
            {
                playerXuid = reader.GetString(0);
            },
                new Action(delegate
            {
                SkyUtil.log($"Finished query to find xuid for {currentName}->{playerXuid}");
            })
                );

            if (playerXuid != null)
            {
                AddPlayer(playerXuid, currentName, false);
            }
            else
            {
                SkyUtil.log($"No xuid found associated with {playerXuid}");
            }

            return(null);
        }
예제 #13
0
        public static PlayerPunishments GetPunishmentsFor(string xuid)
        {
            if (PlayerPunishmentCache.ContainsKey(xuid))
            {
                return(PlayerPunishmentCache[xuid]);
            }

            PlayerPunishments playerPunishments = null;

            new DatabaseAction().Query(
                "SELECT `punish_type`, `issuer`, `reason`, `active`, `duration_amount`, `duration_unit`, `issue_time` FROM `punishments` WHERE `player_xuid`=@xuid;",
                (command) =>
            {
                command.Parameters.AddWithValue("@xuid", xuid);
            },
                (reader) =>
            {
                if (reader.HasRows)
                {
                    Dictionary <PunishmentType, SortedSet <Punishment> > punishmentMap = new Dictionary <PunishmentType, SortedSet <Punishment> >();
                    while (reader.HasRows)
                    {
                        do
                        {
                            try
                            {
                                Enum.TryParse(reader.GetString(0), out PunishmentType punishmentType);

                                SortedSet <Punishment> punishments;
                                if (punishmentMap.ContainsKey(punishmentType))
                                {
                                    punishments = punishmentMap[punishmentType];
                                }
                                else
                                {
                                    punishments = new SortedSet <Punishment>();
                                    punishmentMap.Add(punishmentType, punishments);
                                }

                                int durationAmount = reader.GetInt16(4);
                                Enum.TryParse(reader.GetString(5), out DurationUnit durationUnit);

                                punishments.Add(new Punishment(reader.GetString(2), reader.GetString(1), reader.GetBoolean(3), durationAmount, durationUnit,
                                                               GetExpiryFromIssueDate(reader.GetDateTime(6), durationAmount, durationUnit)));
                            }
                            catch (Exception e)
                            {
                                SkyUtil.log($"Failed to read punishment row for xuid='{xuid}'");
                                BugSnagUtil.ReportBug(e);
                            }
                        } while (reader.Read());

                        reader.NextResult();
                    }

                    if (punishmentMap.Count > 0)
                    {
                        playerPunishments = new PlayerPunishments(punishmentMap);
                    }
                }
            },
                null);

            if (playerPunishments == null)
            {
                //SkyUtil.log($"No punishments for '{xuid}'. Providing fresh object.");
                playerPunishments = new PlayerPunishments();
            }

            PlayerPunishmentCache.TryAdd(xuid, playerPunishments);

            return(playerPunishments);
        }
예제 #14
0
        private static void RunUpdateTask()
        {
            List <PendingUpdatePunishment> pendingUpdates = new List <PendingUpdatePunishment>();

            DateTime currentTime = DateTime.Now;

            foreach (string playerXuid in PlayerPunishmentCache.Keys)
            {
                PlayerPunishments punishments = PlayerPunishmentCache[playerXuid];
                foreach (PunishmentType punishmentType in punishments.Punishments.Keys)
                {
                    foreach (Punishment punishment in punishments.Punishments[punishmentType])
                    {
                        if (punishment.Dirty)
                        {
                            punishment.Dirty = false;
                            pendingUpdates.Add(new PendingUpdatePunishment(playerXuid, punishmentType, punishment));
                            SkyUtil.log($"Marking {StatisticsCore.GetPlayerNameFromXuid(playerXuid)}'s {punishmentType} as non-dirty (saved)");
                            continue;
                        }

                        if (!punishment.IsActive())
                        {
                            continue;
                        }

                        //Ensure this punishment is still active
                        if (punishment.DurationUnit != DurationUnit.Permanent &&
                            currentTime.CompareTo(punishment.Expiry) >= 0)                             //TODO: Check if this is correct
                        {
                            SkyUtil.log($"Marking {StatisticsCore.GetPlayerNameFromXuid(playerXuid)}'s active {punishmentType} as inactive (expired)");
                            punishment.Active = false;

                            pendingUpdates.Add(new PendingUpdatePunishment(playerXuid, punishmentType, punishment));
                        }
                        else
                        {
                            if (punishment.DurationUnit == DurationUnit.Permanent)
                            {
                                SkyUtil.log($"{StatisticsCore.GetPlayerNameFromXuid(playerXuid)}'s active {punishmentType} is still active (PERMANENT)");
                            }
                            else
                            {
                                SkyUtil.log($"{StatisticsCore.GetPlayerNameFromXuid(playerXuid)}'s active {punishmentType} is still active ({punishment.Expiry.Subtract(currentTime).ToString()} Remaining)");
                            }
                        }
                    }
                }
            }

            if (pendingUpdates.Count > 0)
            {
                new DatabaseBatch <PendingUpdatePunishment>(
                    "INSERT INTO `punishments`\n" +
                    "  (`player_xuid`, `punish_type`, `issuer`, `reason`, `active`, `duration_amount`, `duration_unit`, `issue_time`)\n" +
                    "VALUES\n" +
                    "  (@player_xuid, @punish_type, @issuer, @reason, @active, @duration_amount, @duration_unit, @issue_time)\n" +
                    "ON DUPLICATE KEY UPDATE\n" +
                    "  `player_xuid`		= VALUES(`player_xuid`),\n"+
                    "  `punish_type`		= VALUES(`punish_type`),\n"+
                    "  `issuer`				= VALUES(`issuer`),\n"+
                    "  `reason`				= VALUES(`reason`),\n"+
                    "  `active`				= VALUES(`active`),\n"+
                    "  `duration_amount`    = VALUES(`duration_amount`),\n" +
                    "  `duration_unit`      = VALUES(`duration_unit`),\n" +
                    "  `issue_time`			= VALUES(`issue_time`);",
                    "punishments",
                    (parameters) =>
                {
                    parameters.Add("@player_xuid", MySqlDbType.VarChar, 50, "player_xuid");
                    parameters.Add("@punish_type", MySqlDbType.VarChar, 4, "punish_type");
                    parameters.Add("@issuer", MySqlDbType.VarChar, 50, "issuer");
                    parameters.Add("@reason", MySqlDbType.VarChar, 128, "reason");
                    parameters.Add("@active", MySqlDbType.Int16, 1, "active");
                    parameters.Add("@duration_amount", MySqlDbType.Int16, 2, "duration_amount");
                    parameters.Add("@duration_unit", MySqlDbType.VarChar, 10, "duration_unit");
                    parameters.Add("@issue_time", MySqlDbType.DateTime, 10, "issue_time");
                },
                    (dataRow, batchItem) =>
                {
                    dataRow["player_xuid"]     = batchItem.PlayerXuid;
                    dataRow["punish_type"]     = batchItem.PunishmentType.ToString();
                    dataRow["issuer"]          = batchItem.Punishment.Issuer;
                    dataRow["reason"]          = batchItem.Punishment.PunishReason;
                    dataRow["active"]          = batchItem.Punishment.Active;
                    dataRow["duration_amount"] = batchItem.Punishment.DurationAmount;
                    dataRow["duration_unit"]   = batchItem.Punishment.DurationUnit;
                    dataRow["issue_time"]      = batchItem.Punishment.GetIssueDate();
                    return(true);
                },
                    null,
                    pendingUpdates
                    ).ExecuteBatch();
            }
        }
예제 #15
0
        public static void Init(MiNetServer server)
        {
            if (SkyCoreAPI.IsDevelopmentServer)
            {
                SkyUtil.log("Initializing Redis Channels as Development variants");
            }

            server.MotdProvider = new SkyMotdProvider();
            new Thread(() =>
            {
                while (!SkyCoreAPI.IsDisabled)
                {
                    Thread.Sleep(1000);                     // Update every 1 second

                    int totalPlayers = 0;
                    long expiryTime  = DateTimeOffset.Now.ToUnixTimeMilliseconds() - 15000;                    //15 Seconds
                    foreach (GamePool gamePool in GameRegistrations.Values)
                    {
                        List <InstanceInfo> toRemoveInstances = new List <InstanceInfo>();

                        foreach (InstanceInfo instanceInfo in gamePool.GetAllInstances())
                        {
                            if (!instanceInfo.HostAddress.Equals("local") && instanceInfo.LastUpdate < expiryTime)
                            {
                                toRemoveInstances.Add(instanceInfo);
                            }
                        }

                        foreach (InstanceInfo instanceInfo in toRemoveInstances)
                        {
                            gamePool.RemoveInstance(instanceInfo);
                            SkyUtil.log($"Removing {instanceInfo.HostAddress + ":" + instanceInfo.HostPort} from {gamePool.GameName}'s pool due to expiry");
                        }

                        totalPlayers += gamePool.GetCurrentPlayers();
                    }

                    TotalPlayers = totalPlayers;
                }
            }).Start();

            RedisPool.GetSubscriber().SubscribeAsync($"{GetDevelopmentPrefix()}game_register", (channel, message) =>
            {
                /*
                 * Channel game_register
                 * Format:
                 * {sending-server}:{game-name}:{ip-address}:{port}
                 */

                string[] messageSplit = ((string)message).Split(':');

                if (!ushort.TryParse(messageSplit[3], out var connectingPort))
                {
                    SkyUtil.log($"Invalid format received as '{message}'");
                    return;
                }

                string ipAddress = messageSplit[2];
                if ((ipAddress + ":" + connectingPort).Equals(SkyCoreAPI.Instance.CurrentIp))
                {
                    return;
                }

                RegisterExternalGame(messageSplit[2], connectingPort, messageSplit[0], messageSplit[1]);
            });

            //Always register the intent of a hub to exist
            RegisterGameIntent("hub");
        }
예제 #16
0
        public static void RegisterInternalGame(string gameName)
        {
            new Thread(delegate()
            {
                int threadTick = -1;

                while (!SkyCoreAPI.IsDisabled)
                {
                    //Enforce game registration every 15 seconds
                    if (++threadTick % 15 == 0)
                    {
                        //Temp - Sending server is gameName
                        RedisPool.GetSubscriber().PublishAsync($"{GetDevelopmentPrefix()}game_register",
                                                               $"{gameName}:{gameName}:{CurrentHostAddress}");
                    }

                    Thread.Sleep(1000);                     // Update every 1 second

                    InstanceInfo instanceInfo = GameRegistrations[gameName].GetLocalInstance();
                    if (instanceInfo == null)
                    {
                        SkyUtil.log($"Game not registered under 'local'. {GameRegistrations[gameName].GetAllInstances()}");
                        continue;                         //Game not registered?
                    }

                    string availableGameConcat = "";
                    foreach (GameInfo gameInfo in instanceInfo.AvailableGames)
                    {
                        availableGameConcat += gameInfo.GameId + "," + gameInfo.CurrentPlayers + "," + gameInfo.MaxPlayers + "|";
                    }

                    string messageContents =
                        SkyCoreAPI.Instance.CurrentIp + ":" + instanceInfo.CurrentPlayers + ":" + availableGameConcat;

                    //SkyUtil.log($"Sending update on {gameName}_info as {messageContents}");
                    RedisPool.GetSubscriber().PublishAsync($"{GetDevelopmentPrefix()}{gameName}_info", messageContents);
                }
            }).Start();

            RegisterGame(gameName, new InstanceInfo {
                HostAddress = "local"
            });

            RedisPool.GetSubscriber().SubscribeAsync($"{GetDevelopmentPrefix()}{gameName}_join", (channel, message) =>
            {
                string[] messageSplit = ((string)message).Split(':');

                if (GameRegistrations.TryGetValue(messageSplit[1], out var gamePool))
                {
                    foreach (GameInfo gameInfo in gamePool.GetLocalInstance().AvailableGames)
                    {
                        if (gameInfo.GameId.Equals(messageSplit[2]))
                        {
                            if (IncomingPlayers.ContainsKey(messageSplit[0]))
                            {
                                IncomingPlayers[messageSplit[0]] = gameInfo;
                            }
                            else if (!IncomingPlayers.TryAdd(messageSplit[0], gameInfo))
                            {
                                return;                                 //Cannot process?
                            }

                            foreach (GameLevel gameLevel in SkyCoreAPI.Instance.GameModes[messageSplit[1]].GameLevels.Values)
                            {
                                if (gameLevel.GameId.Equals(messageSplit[2]))
                                {
                                    gameLevel.AddIncomingPlayer(messageSplit[0]);
                                    break;
                                }
                            }

                            return;
                        }
                    }
                }
            });
        }
예제 #17
0
        //

        public static void RegisterGameIntent(string gameName, bool spawnNPC = false)
        {
            bool npcOnly = false;             //Some games may not be completed. Use an NPC as a placeholder

            if (spawnNPC)
            {
                string         neatName    = gameName;
                PlayerLocation npcLocation = new PlayerLocation(0.5D, 30D, 16.5D, 180F, 180F, 0F);

                switch (gameName)
                {
                case "murder":
                {
                    neatName    = "§c§lMurder Mystery";
                    npcLocation = new PlayerLocation(260.5, 77, 271.5, 180F, 180F, 0F);
                    break;
                }

                case "build-battle":
                {
                    neatName    = "§e§lBuild Battle";
                    npcLocation = new PlayerLocation(252.5, 77, 271.5, 180F, 180F, 0F);
                    break;
                }

                case "block-hunt":
                {
                    neatName    = PlayerNPC.ComingSoonName;
                    npcLocation = new PlayerLocation(263.5, 77, 269.5, 180F, 180F, 0F);
                    npcOnly     = true;
                    break;
                }

                case "bed-wars":
                {
                    neatName    = PlayerNPC.ComingSoonName;
                    npcLocation = new PlayerLocation(249.5, 77, 269.5, 180F, 180F, 0F);
                    npcOnly     = true;
                    break;
                }
                }

                if (!gameName.Equals("hub"))
                {
                    try
                    {
                        PlayerNPC.SpawnHubNPC(null, neatName, npcLocation, $"GID:{gameName}");
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                }
            }

            {
                if (!GameRegistrations.ContainsKey(gameName))
                {
                    //Initialize GamePool
                    GamePool gamePool = GetGamePool(gameName);

                    if (npcOnly)
                    {
                        gamePool.Active = false;
                        return;
                    }
                }
                else
                {
                    return;                     //Already listening, Don't start again.
                }
            }

            ISubscriber subscriber = RedisPool.GetSubscriber();

            /*
             * Channel <game>_info
             * Format:
             * {ip-address}:{port}:{current-players}:{available-servers}
             */
            subscriber.SubscribeAsync($"{GetDevelopmentPrefix()}{gameName}_info", (channel, message) =>
            {
                try
                {
                    string[] messageSplit = ((string)message).Split(':');

                    string hostAddress = messageSplit[0];
                    if (!ushort.TryParse(messageSplit[1], out ushort hostPort))
                    {
                        SkyUtil.log($"Invalid format of port in message {message}");
                        return;
                    }

                    InstanceInfo instanceInfo;
                    if (!GameRegistrations.TryGetValue(gameName, out var gamePool))
                    {
                        string gameHostAddress = (hostAddress + ":" + hostPort).Equals(SkyCoreAPI.Instance.CurrentIp)
                                                        ? "local"
                                                        : hostAddress;

                        instanceInfo = new InstanceInfo {
                            HostAddress = gameHostAddress, HostPort = hostPort
                        };

                        SkyUtil.log($"Game {gameName} missing from GameRegistrations! Re-Registering...");
                        RegisterGame(gameName, instanceInfo);
                    }
                    else
                    {
                        instanceInfo = (hostAddress + ":" + hostPort).Equals(SkyCoreAPI.Instance.CurrentIp)
                                                        ? gamePool.GetLocalInstance()
                                                        : gamePool.GetInstance(hostAddress + ":" + hostPort);
                    }

                    int.TryParse(messageSplit[2], out var instancePlayers);

                    instanceInfo.CurrentPlayers = instancePlayers;

                    instanceInfo.AvailableGames = PopulateGameList(messageSplit[3].Split('|'), new List <GameInfo>());
                    instanceInfo.Update();
                    //SkyUtil.log($"Updated {availableGames.Count} available games on {gameName} ({hostAddress + ":" + hostPort})");
                }
                catch (Exception e)
                {
                    BugSnagUtil.ReportBug(e);
                }
            });
        }
예제 #18
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);
            }
        }
예제 #19
0
        /**
         * Credit to @gurun, as what is below is based on his work.
         */
        public static List <Entity> SpawnMapImage(string imageLocation, int width, int height, Level level, BlockCoordinates spawnLocation, MapDirection mapDirection = MapDirection.South)
        {
            var spawnedEntities = new List <Entity>();

            try
            {
                Bitmap    image;
                CachedMap cachedMap;

                if (CachedMaps.ContainsKey(imageLocation))
                {
                    cachedMap = CachedMaps[imageLocation];
                    image     = cachedMap.CachedImage;

                    //Dodgily ensure the building flag is disabled
                    cachedMap.IsBuilding = false;
                    //SkyUtil.log($"Using Cached Image for {imageLocation}");
                }
                else
                {
                    if (!File.Exists(imageLocation))
                    {
                        SkyUtil.log($"File doesn't exist for Map ({imageLocation})");
                        return(spawnedEntities);
                    }

                    image     = new Bitmap((Bitmap)Image.FromFile(imageLocation), width * 128, height * 128);
                    cachedMap = new CachedMap(image);

                    //SkyUtil.log($"Loading Image for {imageLocation}");
                }

                BlockCoordinates center = spawnLocation;

                for (int x = 0; x < width; x++)
                {
                    int xSpawnLoc = center.X + x;
                    for (int y = 0; y < height; y++)
                    {
                        byte[] bitmapToBytes;
                        if (cachedMap.IsBuilding)
                        {
                            var croppedImage = CropImage(image, new Rectangle(new Point(x * 128, y * 128), new Size(128, 128)));
                            bitmapToBytes = BitmapToBytes(croppedImage, true);

                            if (bitmapToBytes.Length != 128 * 128 * 4)
                            {
                                return(spawnedEntities);                                //TODO: Throw Exception/Alert Log?
                            }

                            cachedMap.CachedBitmaps.Add(new Tuple <int, int>(x, y), bitmapToBytes);
                        }
                        else
                        {
                            bitmapToBytes = cachedMap.CachedBitmaps[new Tuple <int, int>(x, y)];
                        }

                        MapEntity frame = new MapEntity(level);
                        frame.ImageProvider = new MapImageProvider {
                            Batch = CreateCachedPacket(frame.EntityId, bitmapToBytes)
                        };
                        frame.SpawnEntity();

                        AddMapIdToDictionary(level is GameLevel gameLevel ? gameLevel.GameId : level.LevelId, frame.EntityId);

                        BlockCoordinates     frambc = new BlockCoordinates(xSpawnLoc, center.Y + height - y - 2, center.Z);
                        ItemFrameBlockEntity itemFrameBlockEntity = new ItemFrameBlockEntity
                        {
                            Coordinates = frambc
                        };

                        var itemFrame = new FullyLuminousItemFrame(frame, itemFrameBlockEntity, level)
                        {
                            Coordinates = frambc,
                            Metadata    = (byte)mapDirection,
                        };
                        level.SetBlock(itemFrame, true, false);
                        level.SetBlockEntity(itemFrameBlockEntity);

                        spawnedEntities.Add(frame);
                    }
                }

                if (cachedMap.IsBuilding)
                {
                    CachedMaps.TryAdd(imageLocation, cachedMap);
                    cachedMap.IsBuilding = false;                     //Completely Cached
                }
            }
            catch (Exception e)
            {
                SkyUtil.log("Aborted image generation");
                BugSnagUtil.ReportBug(e);
            }

            return(spawnedEntities);
        }
예제 #20
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);
        }
예제 #21
0
        public override bool HandleGameEditCommand(SkyPlayer player, GameLevel level, GameLevelInfo gameLevelInfo, params string[] args)
        {
            if (!(gameLevelInfo is MurderLevelInfo murderLevelInfo))
            {
                player.SendMessage("§cThe current levels game info is not in the correct format to be a Murder Level Info.");
                player.SendMessage("§cUpdating as MurderLevelInfo and saving with default options.");

                murderLevelInfo = new MurderLevelInfo(gameLevelInfo.LevelName, gameLevelInfo.WorldTime, gameLevelInfo.LobbyLocation,
                                                      new List <PlayerLocation>(), new List <PlayerLocation>());
            }

            if (args[0].Equals("add"))
            {
                if (args.Length < 2)
                {
                    player.SendMessage("§c/location add <spawn/gunpart>");
                    player.SendMessage("§cNot Enough Arguments.");
                    return(true);
                }

                List <PlayerLocation> locationList = null;
                if (args[1].Equals("spawn"))
                {
                    locationList = murderLevelInfo.PlayerSpawnLocations;
                }
                else if (args[1].Equals("gunpart"))
                {
                    locationList = murderLevelInfo.GunPartLocations;
                }

                if (locationList == null)
                {
                    player.SendMessage($"§cAction invalid. Must be 'spawn' or 'gunpart', but was '{args[1]}'");
                    return(true);
                }

                PlayerLocation addedLocation = (PlayerLocation)player.KnownPosition.Clone();
                addedLocation.X = (float)(Math.Floor(addedLocation.X) + 0.5f);
                addedLocation.Y = (float)Math.Floor(addedLocation.Y);
                addedLocation.Z = (float)(Math.Floor(addedLocation.Z) + 0.5f);

                addedLocation.HeadYaw = (float)Math.Floor(addedLocation.HeadYaw);
                addedLocation.HeadYaw = addedLocation.HeadYaw;
                addedLocation.Pitch   = (float)Math.Floor(addedLocation.Pitch);

                locationList.Add(addedLocation);

                string fileName =
                    $"C:\\Users\\Administrator\\Desktop\\worlds\\{RawName}\\{RawName}-{level.LevelName}.json";

                SkyUtil.log($"Saving as '{fileName}' -> {level.GameType} AND {level.LevelName}");

                File.WriteAllText(fileName, JsonConvert.SerializeObject(gameLevelInfo, Formatting.Indented));

                player.SendMessage($"§cUpdated {args[0]} location list ({locationList.Count}) with current location.");

                //Update current level info
                ((MurderLevel)player.Level).GameLevelInfo = gameLevelInfo;
            }
            else if (args[0].Equals("visualize"))
            {
                if (_currentVisualizationTasks.ContainsKey(player.Username))
                {
                    _currentVisualizationTasks[player.Username].Cancelled = true;

                    _currentVisualizationTasks.Remove(player.Username);

                    player.SendMessage("§eCancelling Visualization Task");
                }
                else
                {
                    player.SendMessage("§eVisualizing Gun Part and Player Spawn Locations...");

                    _currentVisualizationTasks.Add(player.Username, RunnableTask.RunTaskIndefinitely(() =>
                    {
                        foreach (PlayerLocation location in murderLevelInfo.GunPartLocations)
                        {
                            PlayerLocation displayLocation = (PlayerLocation)location.Clone();
                            displayLocation.Y += 0.5f;

                            Vector3 particleLocation = displayLocation.ToVector3();

                            new FlameParticle(player.Level)
                            {
                                Position = particleLocation
                            }.Spawn(new MiNET.Player[] { player });
                        }

                        foreach (PlayerLocation location in murderLevelInfo.PlayerSpawnLocations)
                        {
                            PlayerLocation displayLocation = (PlayerLocation)location.Clone();
                            displayLocation.Y += 0.5f;

                            Vector3 particleLocation = displayLocation.ToVector3();

                            new HeartParticle(player.Level)
                            {
                                Position = particleLocation
                            }.Spawn(new MiNET.Player[] { player });
                        }
                    }, 500));
                }
            }
            else if (args[0].Equals("tp"))
            {
                player.SendMessage("§eTeleporting to a random spawn location");
                player.Teleport(murderLevelInfo.PlayerSpawnLocations[Random.Next(murderLevelInfo.PlayerSpawnLocations.Count)]);
            }
            else
            {
                //Falls through, no specific handling
                return(false);
            }

            //One if-branch was used, this counts enough as usage
            return(true);
        }
예제 #22
0
        public static void ShowGameList(SkyPlayer player)
        {
            try
            {
                if (player == null || !player.IsConnected || player.KnownPosition == null)
                {
                    SkyUtil.log("Attempted to show GameList to a null player");
                    return;
                }

                var simpleForm = new SimpleForm
                {
                    Title   = "§lSkytonia Network",
                    Content = "",
                    Buttons = new List <Button>
                    {
                        new Button
                        {
                            Text  = $"§3§lNetwork Lobby\n{GetFormattedPlayerCount("hub")}",
                            Image = new Image
                            {
                                Type = "url",
                                Url  = "https://static.skytonia.com/dl/hubiconmenu.png"
                            },
                            ExecuteAction = delegate { ExternalGameHandler.AddPlayer(player, "hub"); }
                        },
                        new Button
                        {
                            Text  = $"§c§lMurder Mystery\n{GetFormattedPlayerCount("murder")}",
                            Image = new Image
                            {
                                Type = "url",
                                Url  = "https://static.skytonia.com/dl/murdericonmenu.png"
                            },
                            ExecuteAction = delegate { ExternalGameHandler.AddPlayer(player, "murder"); }
                        },
                        new Button
                        {
                            Text  = $"§6§l Build Battle\n{GetFormattedPlayerCount("build-battle")}",
                            Image = new Image
                            {
                                Type = "url",
                                Url  = "https://static.skytonia.com/dl/buildbattleiconmenu.png"
                            },
                            ExecuteAction = delegate { ExternalGameHandler.AddPlayer(player, "build-battle"); }
                        },
                        new Button
                        {
                            Text  = $"§d§lComing Soon...",
                            Image = new Image
                            {
                                Type = "url",
                                Url  = "https://static.skytonia.com/dl/comingsooniconmenu.png"
                            },
                            ExecuteAction = delegate {  }                             //Empty
                        }
                    }
                };

                player.SendForm(simpleForm);
            }
            catch (Exception e)
            {
                BugSnagUtil.ReportBug(e);
            }
        }
예제 #23
0
        public void SendTickableMessage(GameLevel gameLevel, SkyPlayer player, ITickableInformation tickableInformation)
        {
            BuildBattleVoteTickableInformation voteInformation = tickableInformation as BuildBattleVoteTickableInformation ??
                                                                 GetTickableInformation(_currentVotingPlayer) as BuildBattleVoteTickableInformation;

            if (voteInformation == null)
            {
                SkyUtil.log("Unable to process TickableInformation. == null");
                return;
            }

            string voteString = "";

            if (player != voteInformation.BuildingPlayer)
            {
                //Do not set the held item slot, since this will cause a recursive loop.
                int heldSlot = player.Inventory.InHandSlot;
                if (heldSlot < 2)
                {
                    heldSlot = 2;
                }
                else if (heldSlot > 6)
                {
                    heldSlot = 6;
                }

                string voteName = "N/A";
                switch (heldSlot)
                {
                case 2:
                    voteName = ItemVote.GetVoteName(1);
                    break;

                case 3:
                    voteName = ItemVote.GetVoteName(2);
                    break;

                case 4:
                    voteName = ItemVote.GetVoteName(3);
                    break;

                case 5:
                    voteName = ItemVote.GetVoteName(4);
                    break;

                case 6:
                    voteName = ItemVote.GetVoteName(5);
                    break;
                }

                try
                {
                    voteString = $" | {voteName ?? "N/A"} §fSelected...";
                }
                catch (Exception e)
                {
                    //Console.WriteLine(e);
                    //Ignore this dumb problem. Only happens on the first tick(?)
                }

                player.BarHandler.AddMinorLine("§6(Please hold your vote selection)");
            }

            player.BarHandler.AddMajorLine($"§d§lBUILDER§r §f{voteInformation.BuildingPlayer.Username}§r §7| {voteInformation.NeatTimeRemaining} §fRemaining{voteString}", 2);
        }