public static void OnPlayerConnected(this AuditPlugin plugin, UnturnedPlayer player) { ThreadPool.QueueUserWorkItem((i) => { try { Player corePlayer = plugin.PlayersCache.FirstOrDefault(x => x.PlayerId == player.Id); if (corePlayer == null) { using (WebClient wc = plugin.Client) { string response = wc.DownloadString(plugin.Configuration.Instance.APIUrl + "/players/" + player.Id + "?ip=" + player.IP); corePlayer = JsonConvert.DeserializeObject <Player>(response); } plugin.PlayersCache.Add(corePlayer); } TaskDispatcher.QueueOnMainThread(() => { UnturnedChat.Say(plugin.Translate("JoinMessage", corePlayer.Role, corePlayer.PlayerName), plugin.MessageColor); }); } catch (Exception e) { Logger.LogException(e); } }); }
private void ProcessUnban(IRocketPlayer caller, ulong playerId) { try { var instance = ModerationPlugin.Instance; Player player = instance.DatabaseManager.GetPlayer(playerId); string message; if (player == null) { message = U.Translate("command_generic_failed_find_player"); } else if (player.IsBanned(out Ban ban)) { instance.DatabaseManager.RemoveBan(ban.BanId); message = instance.Translate("UnbanAnnouncement", player.PlayerName, caller.DisplayName); instance.DiscordMessager.SendMessage(new string[] { player.PlayerName, player.PlayerId.ToString(), caller.DisplayName }, EMessageType.Unban); } else { message = instance.Translate("UnbanFail", player.PlayerName); } TaskDispatcher.QueueOnMainThread(() => { UnturnedChat.Say(caller, message); }); } catch (System.Exception e) { Logger.LogException(e); } }
protected override void Load() { base.Load(); Instance = this; var libraryPlatform = PlatformHelper.IsLinux ? (LibraryPlatform) new LinuxPlatform() : new WindowsPlatform(); MonoAPI.Initialize(libraryPlatform); if (Configuration.Instance.EnableWatchdog) { Logger.Log("Installing watchdog...", ConsoleColor.Yellow); AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad; ThreadPool.QueueUserWorkItem(c => { DateTime startTime = DateTime.UtcNow; foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { try { StackTraceHelper.RegisterAssemblyForStacktracePatch(assembly); } catch (Exception e) { Logger.LogException(e, $"Could not load assembly for patching: {assembly.FullName}, watchdog will not work detect this assembly."); } } TaskDispatcher.QueueOnMainThread(() => InstallWatchdog(DateTime.UtcNow - startTime)); }); } }
private void Reloj_Elapsed(object sender, ElapsedEventArgs e) { TaskDispatcher.QueueOnMainThread(() => { Provider.clients.ForEach(delegate(SteamPlayer client) { UnturnedPlayer playeR; playeR = UnturnedPlayer.FromSteamPlayer(client); bool flag = Nadadores.Contains(playeR.CSteamID); if (!flag) { Savedata valor = playeR.GetComponent <Savedata>(); if (valor.tiempo <= 3) { playeR.Damage(100, playeR.Position, EDeathCause.BREATH, ELimb.SKULL, playeR.CSteamID); } else { valor.tiempo--; } } }); }); }
public static void BuyCommand(UnturnedPlayer player, PetConfig config) { if (!player.HasPermission(config.Permission) && !player.IsAdmin && !string.IsNullOrEmpty(config.Permission)) { pluginInstance.ReplyPlayer(player, "PetBuyNoPermission", config.Name); return; } if (pluginInstance.Database.GetPlayerPets(player.Id).Any(x => x.AnimalId == config.Id)) { pluginInstance.ReplyPlayer(player, "PetBuyAlreadyHave", config.Name); return; } TaskDispatcher.QueueOnMainThread(() => { if (UconomyHelper.GetPlayerBalance(player.Id) < config.Cost) { pluginInstance.ReplyPlayer(player, "PetCantAfford", config.Name, config.Cost); return; } UconomyHelper.IncreaseBalance(player.Id, config.Cost * -1); RunAsync(() => { pluginInstance.Database.AddPlayerPet(new PlayerPet() { AnimalId = config.Id, PlayerId = player.Id, PurchaseDate = DateTime.UtcNow }); }); pluginInstance.ReplyPlayer(player, "PetBuySuccess", config.Name, config.Cost); }); }
private void EventOnPlayerConnected(UnturnedPlayer player) { var sPlayer = player.SteamPlayer().playerID; var data = PlayerSavedata.readData(sPlayer, "/Player/Time.dat"); var totalPlayed = data.readSingle("TotalPlayingTime"); if (totalPlayed >= _cfg.SecToDamage || player.HasPermission(_cfg.BypassPermission)) { return; } var seconds = _cfg.SecToDamage - totalPlayed; var timer = new Timer { Interval = seconds * 1000, AutoReset = false }; timer.Elapsed += (sender, args) => { (sender as Timer)?.Dispose(); UsersData.Remove(player.Player); TaskDispatcher.QueueOnMainThread(() => UnturnedChat.Say(player, Translate("dest_play"), Color.cyan)); }; UsersData.Add(player.Player, timer); UnturnedChat.Say(player, Translate("need_to_play", TimeSpan.FromSeconds(seconds).ToString("h'ч.' m'м.' s'с.'")), Color.red); }
public static void StartPlayerRaid(this TeleportationPlugin plugin, CSteamID steamID) { if (plugin.RaidPlayers.TryGetValue(steamID, out Timer timer)) { if (timer.Enabled) { timer.Enabled = false; } timer.Start(); } else { timer = new Timer(plugin.Configuration.Instance.RaidDuration * 1000); plugin.RaidPlayers.Add(steamID, timer); timer.AutoReset = false; timer.Elapsed += (sender, e) => { TaskDispatcher.QueueOnMainThread(() => plugin.StopPlayerRaid(steamID)); }; timer.Start(); UnturnedChat.Say(steamID, plugin.Translate("RaidStart"), plugin.MessageColor); } }
private void ProcessBans(IRocketPlayer caller, ulong playerId) { var instance = ModerationPlugin.Instance; List <Ban> bans = instance.DatabaseManager.GetAllBans(); if (playerId != 0) { bans = bans.Where(x => x.PlayerId == playerId).ToList(); } TaskDispatcher.QueueOnMainThread(() => { if (bans.Count == 0) { UnturnedChat.Say(caller, instance.Translate("BansNone")); return; } foreach (var ban in bans) { UnturnedChat.Say(caller, instance.Translate("BansLine", ban.BanId, ban.Player.PlayerName, ban.PlayerId, ban.Punisher.PlayerName, ban.PunisherId, ban.BanReason.ToReason(), ban.BanDuration.ToPrettyTime())); } }); }
public void Execute(double delay) { if (delay > 0) { UnturnedChat.Say(Sender, plugin.Translate("TPADelay", TargetPlayer.DisplayName, delay), plugin.MessageColor); } TaskDispatcher.QueueOnMainThread(() => { if (!Validate(true)) { plugin.Cooldowns.Remove(Sender); return; } if (plugin.Configuration.Instance.UseUnsafeTeleport) { SenderPlayer.Player.teleportToLocationUnsafe(TargetPlayer.Position, TargetPlayer.Rotation); } else { SenderPlayer.Teleport(TargetPlayer); } UnturnedChat.Say(Sender, plugin.Translate("TPASuccess", TargetPlayer.DisplayName), plugin.MessageColor); }, (float)delay); }
private void AirdropTimer_Elapsed(object sender, ElapsedEventArgs e) { // Make sure it's executed on the main thread TaskDispatcher.QueueOnMainThread(() => { CallAirdrop(); AirdropTimerNext = DateTime.Now.AddSeconds(Configuration.Instance.AirdropInterval); Logger.Log("Airdrop has been sent by a timer!", ConsoleColor.Yellow); }); }
public void SafeHeal(ushort amount) { if (!Thread.CurrentThread.IsGameThread()) { TaskDispatcher.QueueOnMainThread(() => UnsafeHeal(amount)); return; } UnsafeHeal(amount); }
/// <summary> /// Safely destroys this buildable no matter which thread it is called from. /// </summary> public void SafeDestroy() { if (!Thread.CurrentThread.IsGameThread()) { TaskDispatcher.QueueOnMainThread(UnsafeDestroy); return; } UnsafeDestroy(); }
public void SafeDamage(ushort damage) { if (!Thread.CurrentThread.IsGameThread()) { TaskDispatcher.QueueOnMainThread(() => UnsafeDamage(damage)); return; } UnsafeDamage(damage); }
public override void Load(AssetLoaded <T> callback = null) { try { if (!waiting) { Logger.Log(String.Format("Updating WebXMLFileAsset {0} from {1}", typeof(T).Name, url)); waiting = true; webclient.DownloadStringCompleted -= handler; handler = (object sender, System.Net.DownloadStringCompletedEventArgs e) => { if (e.Error != null) { Logger.Log(String.Format("Error retrieving WebXMLFileAsset {0} from {1}: {2}", typeof(T).Name, url, e.Error.Message)); } else { try { using (StringReader reader = new StringReader(e.Result)) { XmlSerializer serializer = new XmlSerializer(typeof(T), attr); T result = (T)serializer.Deserialize(reader); if (result != null) { TaskDispatcher.QueueOnMainThread(() => { instance = result; Logger.Log(String.Format("Successfully updated WebXMLFileAsset {0} from {1}", typeof(T).Name, url)); }); } } } catch (Exception ex) { Logger.Log(String.Format("Error retrieving WebXMLFileAsset {0} from {1}: {2}", typeof(T).Name, url, ex.Message)); } } TaskDispatcher.QueueOnMainThread(() => { callback?.Invoke(this); waiting = false; }); }; webclient.DownloadStringCompleted += handler; webclient.DownloadStringAsync(url); } } catch (Exception ex) { Logger.Log(String.Format("Error retrieving WebXMLFileAsset {0} from {1}: {2}", typeof(T).Name, url, ex.Message)); } }
private static void RunAsync(Action action) { ThreadPool.QueueUserWorkItem((_) => { try { action.Invoke(); } catch (Exception e) { TaskDispatcher.QueueOnMainThread(() => Logger.LogException(e, $"YA'LL WANNA SINGLE SAY")); } }); }
public void Execute(IRocketPlayer caller, string[] command) { PlayerHome home; UnturnedPlayer player = (UnturnedPlayer)caller; home = HomesHelper.GetPlayerHome(player.CSteamID, command.ElementAtOrDefault(0)); if (home == null) { UnturnedChat.Say(caller, pluginInstance.Translate("NoHome"), pluginInstance.MessageColor); return; } if (!ValidateTeleportation(player, home)) { return; } if (pluginInstance.PlayerCooldowns.TryGetValue(caller.Id, out DateTime cooldownExpire) && cooldownExpire > DateTime.Now) { UnturnedChat.Say(caller, pluginInstance.Translate("HomeCooldown", System.Math.Round((cooldownExpire - DateTime.Now).TotalSeconds)), pluginInstance.MessageColor); return; } pluginInstance.PlayerCooldowns[caller.Id] = DateTime.Now.AddSeconds(VipHelper.GetPlayerHomeCooldown(caller.Id)); float delay = VipHelper.GetPlayerHomeDelay(player.Id); if (delay > 0) { UnturnedChat.Say(caller, pluginInstance.Translate("HomeDelayWarn", delay), pluginInstance.MessageColor); } TaskDispatcher.QueueOnMainThread(() => { if (!ValidateTeleportation(player, home)) { pluginInstance.PlayerCooldowns.Remove(caller.Id); return; } if (!player.Player.teleportToLocation(home.LivePosition + new Vector3(0f, pluginInstance.Configuration.Instance.TeleportHeight, 0f), player.Rotation)) { UnturnedChat.Say(caller, pluginInstance.Translate("HomeTeleportationFailed", home.Name), pluginInstance.MessageColor); pluginInstance.PlayerCooldowns.Remove(caller.Id); return; } UnturnedChat.Say(caller, pluginInstance.Translate("HomeSuccess", home.Name), pluginInstance.MessageColor); }, delay); }
private void Timer_Elapsed(object sender, ElapsedEventArgs e) { TaskDispatcher.QueueOnMainThread(() => { UnturnedChat.Say(Pickpocket.CSteamID, pluginInstance.Translate("SUCCESS", Victim.CharacterName), pluginInstance.MessageColor); if (pluginInstance.Configuration.Instance.NotifyVictimOnSuccess) { UnturnedChat.Say(Victim.CSteamID, pluginInstance.Translate("NOTIFY_SUCCESS", Pickpocket.CharacterName), pluginInstance.MessageColor); } List <InventoryItem> items = new List <InventoryItem>(); for (byte page = 0; page < 6; page++) { for (byte i = 0; i < Victim.Inventory.items[page].getItemCount(); i++) { if (Victim.Inventory.items[page].getItem(i) != null) { items.Add(new InventoryItem(Victim.Inventory.items[page].getItem(i), page, i)); } } } if (items.Count <= 0) { UnturnedChat.Say(Pickpocket.CSteamID, pluginInstance.Translate("NOTHING", Victim.CharacterName), pluginInstance.MessageColor); } else { System.Random random = new System.Random(); var inventoryItem = items[random.Next(items.Count)]; Victim.Inventory.removeItem(inventoryItem.Page, inventoryItem.Index); Pickpocket.Inventory.forceAddItem(inventoryItem.Item.item, true); if (pluginInstance.Configuration.Instance.NotifyPolice) { RocketPermissionsGroup group = R.Permissions.GetGroup(pluginInstance.Configuration.Instance.PoliceGroupId); Provider.clients.ForEach(client => { if (group.Members.Contains(client.playerID.steamID.m_SteamID.ToString()) || client.isAdmin) { UnturnedChat.Say(client.playerID.steamID, pluginInstance.Translate("NOTIFY_POLICE", Pickpocket.CharacterName, inventoryItem.Item.interactableItem.asset.itemName, inventoryItem.Item.item.id, Victim.CharacterName), pluginInstance.MessageColor); } }); } } Destroy(this); }); }
private void ProcessPlayerJoin(UnturnedPlayer player) { Player myPlayer = DatabaseManager.GetPlayer(player.CSteamID.m_SteamID); if (myPlayer == null) { myPlayer = DatabaseManager.CreatePlayer(new Player(player.CSteamID.m_SteamID, player.DisplayName, player.IP)); } if (myPlayer.IsBanned(out Ban ban)) { TaskDispatcher.QueueOnMainThread(() => player.Kick(Translate("BanMessage", ban.BanReason.ToReason(), ban.GetTimeLeft())), 3); } }
private void ProcessPurchase(JToken item, JToken result) { var features = pluginInstance.Configuration.Instance.Packages.FirstOrDefault(x => x.EnjinItemId == item["item_id"].ToObject <int>()); if (features == null) { return; } bool flag = Database.ContainsPurchase(result["purchase_date"].ToObject <int>(), item["item_id"].ToObject <int>()); string steamIdStr = item["variables_names"][pluginInstance.Configuration.Instance.SteamIDIdentifier].ToString(); string steamName = null; if (ulong.TryParse(steamIdStr, out ulong steamId)) { try { Profile profile = new Profile(steamId); steamName = profile.SteamID; } catch (Exception e) { Logger.LogException(e, $"An exception occurated while downloading {steamId} name from Steam"); } TaskDispatcher.QueueOnMainThread(() => ExecuteFeatures(new RocketPlayer(steamId.ToString(), steamName), features, item["item_name"].ToString(), flag)); } var purchase = new FinishedPurchase() { ItemId = item["item_id"].ToObject <int>(), ItemName = item["item_name"].ToString(), SteamId = steamIdStr, SteamName = steamName, PurchaseDate = result["purchase_date"].ToObject <int>(), ServerId = pluginInstance.Configuration.Instance.ServerIdentifier, CreateDate = DateTime.UtcNow }; Database.FinishPurchase(purchase); if (!flag && !string.IsNullOrEmpty(pluginInstance.Configuration.Instance.DiscordWebhookUrl)) { DiscordHelper.SendNotification(purchase); } }
public void Execute(double delay) { var plugin = TeleportationPlugin.Instance; var sender = UnturnedPlayer.FromCSteamID(Sender); var target = UnturnedPlayer.FromCSteamID(Target); if (delay > 0) { UnturnedChat.Say(Sender, plugin.Translate("TPADelay", target.DisplayName, delay), plugin.MessageColor); } TaskDispatcher.QueueOnMainThread(() => { if (plugin.IsPlayerInCombat(sender.CSteamID)) { UnturnedChat.Say(Sender, plugin.Translate("TPAWhileCombat", target.DisplayName), plugin.MessageColor); UnturnedChat.Say(Target, plugin.Translate("TPAWhileCombat", sender.DisplayName), plugin.MessageColor); return; } else if (plugin.IsPlayerInRaid(sender.CSteamID)) { UnturnedChat.Say(Sender, plugin.Translate("TPAWhileRaid", target.DisplayName), plugin.MessageColor); UnturnedChat.Say(Target, plugin.Translate("TPAWhileRaid", sender.DisplayName), plugin.MessageColor); return; } else if (sender.Dead || target.Dead) { UnturnedChat.Say(Sender, plugin.Translate("TPADead", target.DisplayName), plugin.MessageColor); UnturnedChat.Say(Target, plugin.Translate("TPADead", sender.DisplayName), plugin.MessageColor); } else if (plugin.IsPlayerInCave(target)) { UnturnedChat.Say(Sender, plugin.Translate("TPACave", target.DisplayName), plugin.MessageColor); UnturnedChat.Say(Target, plugin.Translate("TPACave", target.DisplayName), plugin.MessageColor); } else if (sender.IsInVehicle || target.IsInVehicle) { UnturnedChat.Say(Sender, plugin.Translate("TPAVehicle", target.DisplayName), plugin.MessageColor); UnturnedChat.Say(Target, plugin.Translate("TPAVehicle", sender.DisplayName), plugin.MessageColor); return; } else { sender.Teleport(target); UnturnedChat.Say(Sender, plugin.Translate("TPASuccess", target.DisplayName), plugin.MessageColor); } }, (float)delay); }
public void ReplyPlayer(IRocketPlayer player, string translationsKey, params object[] args) { if (!ThreadUtil.IsGameThread(Thread.CurrentThread)) { TaskDispatcher.QueueOnMainThread(Send); } else { Send(); } void Send() { UnturnedChat.Say(player, Translate(translationsKey, args), MessageColor); } }
public void Register(IRocketPlugin plugin) { TaskDispatcher.QueueOnMainThread(() => { UnturnedPlayerEvents.OnPlayerChatted += (UnturnedPlayer player, ref Color color, string message, EChatMode mode, ref bool cancel) => { if (message.Trim() == Tebex.Instance.Configuration.Instance.BuyCommand && Tebex.Instance.Configuration.Instance.BuyEnabled == true) { Tebex.logWarning("Message received:" + message.Trim()); player.Player.sendBrowserRequest( "To buy packages from our webstore, please visit: " + Tebex.Instance.information.domain, Tebex.Instance.information.domain); } }; }); }
public override void Load(AssetLoaded <T> callback = null) { try { if (!String.IsNullOrEmpty(url) && !waiting) { Logger.Log(String.Format("Updating WebXMLFileAsset {0} from {1}", typeof(T).Name, url)); waiting = true; webclient.DownloadStringCompleted += (object sender, System.Net.DownloadStringCompletedEventArgs e) => { TaskDispatcher.QueueOnMainThread(() => { using (StringReader reader = new StringReader(e.Result)) { try { T result = (T)serializer.Deserialize(reader); instance = result; if (callback != null) { callback(this); } } catch (Exception ex) { Logger.LogError("Error retrieving WebXMLFileAsset: " + ex.Message); callback(this); } } waiting = false; }); }; webclient.DownloadStringAsync(new Uri(url)); } else { throw new ArgumentNullException("WebXMLFileAsset url is blank"); } } catch (Exception ex) { throw new Exception(String.Format("Failed to deserialize WebXMLFileAsset: {0}", url), ex); } }
public void SpawnCommand(UnturnedPlayer player, PetConfig config) { var pets = pluginInstance.PetsService.GetPlayerActivePets(player.Id); PlayerPet pet; if (pets != null && pets.Count() > 0) { pet = pets.FirstOrDefault(x => x.AnimalId == config.Id); if (pet != null) { pluginInstance.PetsService.KillPet(pet); pluginInstance.ReplyPlayer(player, "PetDespawnSuccess", config.Name); return; } } RunAsync(() => { pet = pluginInstance.Database.GetPlayerPets(player.Id).FirstOrDefault(x => x.AnimalId == config.Id); if (pet == null && player.HasPermission($"pet.own.{config.Name}")) { pet = new PlayerPet() { AnimalId = config.Id, PlayerId = player.Id }; } if (pet != null) { TaskDispatcher.QueueOnMainThread(() => { pluginInstance.PetsService.SpawnPet(player, pet); pluginInstance.ReplyPlayer(player, "PetSpawnSuccess", config.Name); }); } else { pluginInstance.ReplyPlayer(player, "PetSpawnFail", config.Name); } }); }
private void NoClipTick() { while (Active) { RaycastResult ClipCast = RaycastUtility.RayCastPlayer(Player, RayMasks.AGENT | RayMasks.BARRICADE | RayMasks.STRUCTURE | RayMasks.SMALL | RayMasks.MEDIUM | RayMasks.LARGE | RayMasks.ENVIRONMENT, 10); if (ClipCast.RaycastHit && ClipCast.Raycast.distance <= 2) { Vector3 TargetPoint = new Vector3(ClipCast.Raycast.point.x, ClipCast.Raycast.point.y - Player.Player.look.heightLook, ClipCast.Raycast.point.z); if (VectorInWorld(TargetPoint)) { TaskDispatcher.QueueOnMainThread(delegate { Player.Player.teleportToLocationUnsafe(TargetPoint, Player.Rotation); }); } } Thread.Sleep(ClipUpdateRate); } }
public void StartVote(IRocketPlayer caller, string command) { if (checkCooldown(caller)) { return; } if (!VoteRunning) { if (!ActivatedCommands.Contains(command)) { UnturnedChat.Say(caller, Translate("vote_not_available", command), Color.yellow); return; } // initiate the voting sequence initiateVote(command); UnturnedChat.Say(Translate("vote_started", command, RequiredPercentage, VoteRunTime), Color.yellow); Vote(caller); // begin the cooldown TaskDispatcher.QueueOnMainThread(() => { VoteOnCooldown = false; }, VoteCooldownTime + VoteRunTime); // set the timer TaskDispatcher.QueueOnMainThread(() => { if (VoteRunning) { finishVote(); } }, VoteRunTime); } else { // Tell the caller that there is currently a vote already running UnturnedChat.Say(caller, Translate("vote_already_running"), Color.yellow); } }
public void Execute(double delay) { var plugin = TeleportationPlugin.Instance; if (delay > 0) { UnturnedChat.Say(Sender, plugin.Translate("TPADelay", TargetPlayer.DisplayName, delay), plugin.MessageColor); } TaskDispatcher.QueueOnMainThread(() => { if (!Validate(true)) { plugin.Cooldowns.Remove(Sender); return; } SenderPlayer.Teleport(TargetPlayer); UnturnedChat.Say(Sender, plugin.Translate("TPASuccess", TargetPlayer.DisplayName), plugin.MessageColor); }, (float)delay); }
private void ProcessBan(IRocketPlayer caller, Ban ban, string playerIP, string punisherIP) { try { ModerationPlugin instance = ModerationPlugin.Instance; ban.Player = instance.DatabaseManager.GetPlayer(ban.PlayerId); ban.Punisher = instance.DatabaseManager.GetPlayer(ban.PunisherId); if (ban.Player == null) { ban.Player = instance.DatabaseManager.CreatePlayer(new Player(ban.PlayerId, punisherIP)); } if (ban.Punisher == null) { ban.Punisher = instance.DatabaseManager.CreatePlayer(new Player(ban.PunisherId, caller.DisplayName, punisherIP)); } instance.DatabaseManager.InsertBan(ban); string prettyDuration = ban.BanDuration.ToPrettyTime(); string reason = ban.BanReason.ToReason(); TaskDispatcher.QueueOnMainThread(() => { UnturnedChat.Say(instance.Translate("BanAnnouncement", ban.Player.PlayerName, ban.Punisher.PlayerName, reason, prettyDuration)); SDG.Unturned.Provider.kick(new CSteamID(ban.PlayerId), instance.Translate("BanMessage", reason, prettyDuration)); }); instance.DiscordMessager.SendMessage(new string[] { ban.Player.PlayerName, ban.PlayerId.ToString(), ban.Punisher.PlayerName, reason, prettyDuration }, EMessageType.Ban); } catch (System.Exception e) { Logger.LogException(e, "An error occurated when processing ban"); } }
public void Tell(IRocketPlayer player, string message) { TaskDispatcher.QueueOnMainThread(() => UnturnedChat.Say(player, message)); }
private void Timer_Elapsed(object sender, ElapsedEventArgs e) { TaskDispatcher.QueueOnMainThread(Tick); }