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)"); } }
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"); }
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)); }); }
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"); }
///<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"); } } } } }
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(); }
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); } }
/* * 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) { } }
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; }
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); }
/// <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); }
/// <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); }
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); }
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(); } }
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"); }
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; } } } }); }
// 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); } }); }
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); } }
/** * 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); }
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); }
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); }
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); } }
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); }