diff --git a/.gitignore b/.gitignore index c55b5e2..ca2d1c6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -bin -obj -.vs +bin +obj +.vs .vscode \ No newline at end of file diff --git a/Commands/Tpa.cs b/Commands/Tpa.cs index 19d089f..1087c6c 100644 --- a/Commands/Tpa.cs +++ b/Commands/Tpa.cs @@ -1,65 +1,65 @@ -using Rocket.API; -using Rocket.Unturned.Chat; -using Rocket.Unturned.Player; -using SDG.Unturned; - -namespace SimpleTPA.Commands -{ - internal class Tpa : IRocketCommand - { - public AllowedCaller AllowedCaller => AllowedCaller.Player; - - public string Name => "tpa"; - - public string Help => "Teleport to a player"; - - public string Syntax => "/tpa [playerName]"; - - public List Aliases => new(); - - public List Permissions => new(); - - public void Execute(IRocketPlayer caller, string[] command) - { - if (caller is not UnturnedPlayer) - { - UnturnedChat.Say(caller, SimpleTPAPlugin.instance!.Translate("Invalid_Player"), Palette.COLOR_R); - return; - }; - - if (command[0].Length < 1) - { - UnturnedChat.Say(caller, SimpleTPAPlugin.instance!.Translate("Invalid_Arguments"), Palette.COLOR_R); - return; - } - - UnturnedPlayer playerCommanded = (UnturnedPlayer)caller; - UnturnedPlayer playerParameter = UnturnedPlayer.FromName(command[0]); - - switch (command[0].ToLower()) - { - #region abort - case "ab": - SimpleTPAPlugin.instance!.tpaSystem!.TpaAbort(playerCommanded); return; - case "abort": - SimpleTPAPlugin.instance!.tpaSystem!.TpaAbort(playerCommanded); return; - #endregion - #region deny - case "d": - SimpleTPAPlugin.instance!.tpaSystem!.TpaDeny(playerCommanded); return; - case "deny": - SimpleTPAPlugin.instance!.tpaSystem!.TpaDeny(playerCommanded); return; - #endregion - #region accept - case "a": - SimpleTPAPlugin.instance!.tpaSystem!.TpaAccept(playerCommanded); return; - case "accept": - SimpleTPAPlugin.instance!.tpaSystem!.TpaAccept(playerCommanded); return; - #endregion - - default: - SimpleTPAPlugin.instance!.tpaSystem!.TpaRequest(playerCommanded, playerParameter); return; - } - } - } -} +using Rocket.API; +using Rocket.Unturned.Chat; +using Rocket.Unturned.Player; +using SDG.Unturned; + +namespace SimpleTPA.Commands +{ + internal class Tpa : IRocketCommand + { + public AllowedCaller AllowedCaller => AllowedCaller.Player; + + public string Name => "tpa"; + + public string Help => "Teleport to a player"; + + public string Syntax => "/tpa [playerName]"; + + public List Aliases => new(); + + public List Permissions => new(); + + public void Execute(IRocketPlayer caller, string[] command) + { + if (caller is not UnturnedPlayer) + { + UnturnedChat.Say(caller, SimpleTPAPlugin.instance!.Translate("Invalid_Player"), Palette.COLOR_R); + return; + }; + + if (command[0].Length < 1) + { + UnturnedChat.Say(caller, SimpleTPAPlugin.instance!.Translate("Invalid_Arguments"), Palette.COLOR_R); + return; + } + + UnturnedPlayer playerCommanded = (UnturnedPlayer)caller; + UnturnedPlayer playerParameter = UnturnedPlayer.FromName(command[0]); + + switch (command[0].ToLower()) + { + #region abort + case "ab": + SimpleTPAPlugin.instance!.tpaSystem!.TpaAbort(playerCommanded); return; + case "abort": + SimpleTPAPlugin.instance!.tpaSystem!.TpaAbort(playerCommanded); return; + #endregion + #region deny + case "d": + SimpleTPAPlugin.instance!.tpaSystem!.TpaDeny(playerCommanded); return; + case "deny": + SimpleTPAPlugin.instance!.tpaSystem!.TpaDeny(playerCommanded); return; + #endregion + #region accept + case "a": + SimpleTPAPlugin.instance!.tpaSystem!.TpaAccept(playerCommanded); return; + case "accept": + SimpleTPAPlugin.instance!.tpaSystem!.TpaAccept(playerCommanded); return; + #endregion + + default: + SimpleTPAPlugin.instance!.tpaSystem!.TpaRequest(playerCommanded, playerParameter); return; + } + } + } +} diff --git a/README.md b/README.md index 5bd3901..d41c341 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ -# Simple TPA -Add 4 new command to the unturned server -- /tpa playername : request a teleport for the desired player -- /tpa accept : accept the teleport request -- /tpa deny : denied the request received -- /tpa abort : abort accepted request - -### Configurations -- TickrateToExpire: time to a tpa request expire, calculation: Seconds * ServerTickrate -- TickrateToTeleport: time to player teleport to other player -- ServerTickrate: Actual server tickrate from ``Rocket.config``, used to calculate tickrate seconds - -# Building - -*Windows*: The project uses dotnet 4.8, consider installing into your machine, you need visual studio, simple open the solution file open the Build section and hit the build button (ctrl + shift + b) or you can do into powershell the command dotnet build -c Debug if you have installed dotnet 4.8. - -*Linux*: Install dotnet-sdk from your distro package manager, open the root folder of this project and type ``dotnet build -c Debug``. - -FTM License. +# Simple TPA +Add 4 new command to the unturned server +- /tpa playername : request a teleport for the desired player +- /tpa accept : accept the teleport request +- /tpa deny : denied the request received +- /tpa abort : abort accepted request + +### Configurations +- TickrateToExpire: time to a tpa request expire, calculation: Seconds * ServerTickrate +- TickrateToTeleport: time to player teleport to other player +- ServerTickrate: Actual server tickrate from ``Rocket.config``, used to calculate tickrate seconds + +# Building + +*Windows*: The project uses dotnet 4.8, consider installing into your machine, you need visual studio, simple open the solution file open the Build section and hit the build button (ctrl + shift + b) or you can do into powershell the command dotnet build -c Debug if you have installed dotnet 4.8. + +*Linux*: Install dotnet-sdk from your distro package manager, open the root folder of this project and type ``dotnet build -c Debug``. + +FTM License. diff --git a/SimpleTPA.csproj b/SimpleTPA.csproj index 4624461..8a4b7ad 100644 --- a/SimpleTPA.csproj +++ b/SimpleTPA.csproj @@ -1,36 +1,39 @@ - - - - net4.8 - enable - enable - 10 - - - - - ..\SkinRestriction-master\Libs\Assembly-CSharp.dll - - - ..\SkinRestriction-master\Libs\com.rlabrecque.steamworks.net.dll - - - ..\SkinRestriction-master\Libs\Rocket.API.dll - - - ..\SkinRestriction-master\Libs\Rocket.Core.dll - - - ..\SkinRestriction-master\Libs\Rocket.Unturned.dll - - - ..\SkinRestriction-master\Libs\UnityEngine.dll - - - Libs\UnityEngine.CoreModule.dll - UnityEngineCoreModule - - - - - + + + + net4.8 + enable + enable + 10 + + + + + Libs\AntiCombatLogout.dll + + + Libs\Assembly-CSharp.dll + + + Libs\com.rlabrecque.steamworks.net.dll + + + Libs\Rocket.API.dll + + + Libs\Rocket.Core.dll + + + Libs\Rocket.Unturned.dll + + + Libs\UnityEngine.dll + + + Libs\UnityEngine.CoreModule.dll + UnityEngineCoreModule + + + + + diff --git a/SimpleTPA.sln b/SimpleTPA.sln index a07cd45..b803585 100644 --- a/SimpleTPA.sln +++ b/SimpleTPA.sln @@ -1,25 +1,25 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.9.34902.65 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleTPA", "SimpleTPA.csproj", "{54A3C5CA-5C19-42B5-80FC-07B61DC67422}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {54A3C5CA-5C19-42B5-80FC-07B61DC67422}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {54A3C5CA-5C19-42B5-80FC-07B61DC67422}.Debug|Any CPU.Build.0 = Debug|Any CPU - {54A3C5CA-5C19-42B5-80FC-07B61DC67422}.Release|Any CPU.ActiveCfg = Release|Any CPU - {54A3C5CA-5C19-42B5-80FC-07B61DC67422}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {5CC3CA60-EF70-4BC6-94C3-A4D4FE5F2BCA} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34902.65 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleTPA", "SimpleTPA.csproj", "{54A3C5CA-5C19-42B5-80FC-07B61DC67422}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {54A3C5CA-5C19-42B5-80FC-07B61DC67422}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54A3C5CA-5C19-42B5-80FC-07B61DC67422}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54A3C5CA-5C19-42B5-80FC-07B61DC67422}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54A3C5CA-5C19-42B5-80FC-07B61DC67422}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5CC3CA60-EF70-4BC6-94C3-A4D4FE5F2BCA} + EndGlobalSection +EndGlobal diff --git a/SimpleTPAConfiguration.cs b/SimpleTPAConfiguration.cs index 6613765..4e46fd9 100644 --- a/SimpleTPAConfiguration.cs +++ b/SimpleTPAConfiguration.cs @@ -1,15 +1,15 @@ -using Rocket.API; - -namespace SimpleTPA -{ - public class SimpleTPAConfiguration : IRocketPluginConfiguration - { - public uint TickrateToExpire = 900; - public uint TickrateToTeleport = 900; - public uint ServerTickrate = 60; - public void LoadDefaults() - { - - } - } -} +using Rocket.API; + +namespace SimpleTPA +{ + public class SimpleTPAConfiguration : IRocketPluginConfiguration + { + public uint TickrateToExpire = 900; + public uint TickrateToTeleport = 900; + public uint ServerTickrate = 60; + public void LoadDefaults() + { + + } + } +} diff --git a/SimpleTPAPlugin.cs b/SimpleTPAPlugin.cs index da3e6a3..04880a6 100644 --- a/SimpleTPAPlugin.cs +++ b/SimpleTPAPlugin.cs @@ -1,285 +1,287 @@ -extern alias UnityEngineCoreModule; -using Rocket.API.Collections; -using Rocket.Core.Plugins; -using Rocket.Unturned.Chat; -using Rocket.Unturned.Player; -using SDG.Unturned; -using UnityEngine; -using UnityCoreModule = UnityEngineCoreModule.UnityEngine; - -namespace SimpleTPA -{ - public class SimpleTPAPlugin : RocketPlugin - { - public static SimpleTPAPlugin? instance; - public SimpleTPASystem? tpaSystem; - public override void LoadPlugin() - { - base.LoadPlugin(); - tpaSystem = gameObject.AddComponent(); - Rocket.Unturned.Events.UnturnedPlayerEvents.OnPlayerUpdatePosition += tpaSystem.PositionUpdated; - instance = this; - } - public override TranslationList DefaultTranslations => new() - { - {"Invalid_Player", "Cannot use this command because you are invalid"}, - {"Request_Self", "Cannot Tpa to yourself"}, - {"Invalid_Arguments", "Invalid Arguments"}, - {"Request_Aborted_By_Other", "Your Tpa request has been aborted because other player has requested"}, - {"Already_Requested", "You already have a Tpa request"}, - {"Pending_Request_Expired", "Tpa request has been expired"}, - {"Request_Send", "Tpa to {0} has been send"}, - {"Request_Received", "Tpa from {0}, accept using /tpa a"}, - {"Request_Accepted", "Tpa accepted don't move for {0} seconds"}, - {"Accepted_Request", "Tpa accepted"}, - {"No_Request_To_Accept", "No Tpa request to accept"}, - {"No_Request_To_Deny", "No Tpa request to deny"}, - {"No_Request_To_Abort", "No Tpa request to abort"}, - {"Tpa_Aborted_Moving", "Tpa aborted because you moved"}, - {"Tpa_Denied", "Tpa request has been denied"}, - {"Denied_Tpa", "You denied the Tpa from {0}"}, - {"Tpa_Aborted", "Tpa request has been aborted"}, - }; - } - - public class SimpleTPASystem : MonoBehaviour - { - private Dictionary> tpaPlayers = new(); - - public void Update() - { - #region tpa request - List tpaPlayersToRemove = new(); - Dictionary> tpaPlayersNew = new(tpaPlayers); - - // Swipe all pending tpa - foreach (KeyValuePair> playerData in tpaPlayers) - { - #region requisting expiration - // Check requesting status - if (playerData.Value["Status"] is ETPAStatus reqStatus && reqStatus == ETPAStatus.Requesting) - { - // Get default value - Dictionary updatedData = new(playerData.Value); - // Reduce expiration data - updatedData["Time"] = (uint)updatedData["Time"] - 1; - - // Check if is expirated - if ((uint)updatedData["Time"] <= 0) - { - UnturnedChat.Say(playerData.Key, SimpleTPAPlugin.instance!.Translate("Pending_Request_Expired"), Palette.COLOR_Y); - tpaPlayersToRemove.Add(playerData.Key); - } - - // Update data - tpaPlayersNew[playerData.Key] = updatedData; - } - #endregion - #region accepted delay - // Check requesting status - if (playerData.Value["Status"] is ETPAStatus acStatus && acStatus == ETPAStatus.Accepted) - { - // Get default value - Dictionary updatedData = new(playerData.Value); - // Reduce delay data - updatedData["Time"] = (uint)updatedData["Time"] - 1; - - // Check if is finished - if ((uint)updatedData["Time"] <= 0) - { - // Teleport the player - if (updatedData["To"] is UnturnedPlayer playerReceiving) - playerData.Key.Teleport(playerReceiving); - - tpaPlayersToRemove.Add(playerData.Key); - } - - // Update data - tpaPlayersNew[playerData.Key] = updatedData; - } - #endregion - } - - // Remove finished requests outside the iteration - foreach (UnturnedPlayer player in tpaPlayersToRemove) tpaPlayersNew.Remove(player); - - // Finally we update the real tpaPlayers requests - tpaPlayers = tpaPlayersNew; - #endregion - } - - public void TpaRequest(UnturnedPlayer playerGoing, UnturnedPlayer playerReceiving) - { - // Check if player is requesting to self - if (playerGoing == playerReceiving) - { - // Inform him - UnturnedChat.Say(playerGoing, SimpleTPAPlugin.instance!.Translate("Request_Self"), Palette.COLOR_Y); - return; - } - // Check if player already requested - if (tpaPlayers.TryGetValue(playerGoing, out _)) - { - // Inform him - UnturnedChat.Say(playerGoing, SimpleTPAPlugin.instance!.Translate("Already_Requested"), Palette.COLOR_Y); - return; - } - - // Check other requests for this player, if exist we need to remove it - foreach (KeyValuePair> playerData in tpaPlayers) - { - // Check the status requesting - if (playerData.Value["Status"] is ETPAStatus status && status == ETPAStatus.Requesting) - { - // Check if the receiver is the same as the player command - if (playerData.Value["To"] is UnturnedPlayer player && player == playerReceiving) - { - // Remove the old request - tpaPlayers.Remove(playerData.Key); - // Inform the player about their request cancelled - UnturnedChat.Say(playerData.Key, SimpleTPAPlugin.instance!.Translate("Request_Aborted_By_Other"), Palette.COLOR_Y); - break; - } - } - } - - // Add pending request - tpaPlayers.Add(playerGoing, new() - { - {"To", playerReceiving}, - {"Time", SimpleTPAPlugin.instance!.Configuration.Instance.TickrateToExpire }, - {"Status", ETPAStatus.Requesting}, - }); - - // Inform the going player - UnturnedChat.Say(playerGoing, SimpleTPAPlugin.instance.Translate("Request_Send", playerGoing.DisplayName), Palette.COLOR_Y); - - // Inform the receiving player - UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance.Translate("Request_Received", playerGoing.DisplayName), Palette.COLOR_Y); - } - public void TpaAccept(UnturnedPlayer playerReceiving) - { - // Check if player has been requested - foreach (KeyValuePair> playerData in tpaPlayers) - { - // Check the status requesting - if (playerData.Value["Status"] is ETPAStatus status && status == ETPAStatus.Requesting) - { - // Check if player receiving is you - if (playerData.Value["To"] is UnturnedPlayer player && player == playerReceiving) - { - // Get default value - Dictionary updatedData = playerData.Value; - - // Change values - updatedData["Status"] = ETPAStatus.Accepted; - updatedData["Time"] = SimpleTPAPlugin.instance!.Configuration.Instance.TickrateToTeleport; - - // Update data - tpaPlayers[playerData.Key] = updatedData; - - // Inform the receiving player - UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance!.Translate("Accepted_Request"), Palette.COLOR_Y); - - // Inform the going player - UnturnedChat.Say(playerData.Key, SimpleTPAPlugin.instance!.Translate("Request_Accepted", (int)Math.Round((double)SimpleTPAPlugin.instance.Configuration.Instance.TickrateToTeleport / SimpleTPAPlugin.instance.Configuration.Instance.ServerTickrate)), Palette.COLOR_Y); - return; - } - } - } - // If the function goes here is because theres no request for this player, lets inform him - UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance!.Translate("No_Request_To_Accept"), Palette.COLOR_Y); - } - public void TpaDeny(UnturnedPlayer playerReceiving) - { - // Check if player has been requested - foreach (KeyValuePair> playerData in tpaPlayers) - { - // Check the status requesting - if (playerData.Value["Status"] is ETPAStatus status && status == ETPAStatus.Requesting) - { - // Check if player receiving is you - if (playerData.Value["To"] is UnturnedPlayer player && player == playerReceiving) - { - // Inform the receiving player - UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance!.Translate("Denied_Tpa", playerData.Key.DisplayName), Palette.COLOR_Y); - - // Inform the going player - UnturnedChat.Say(playerData.Key, SimpleTPAPlugin.instance!.Translate("Tpa_Denied"), Palette.COLOR_R); - - // Remove it from requests - tpaPlayers.Remove(playerData.Key); - return; - } - } - } - // If the function goes here is because theres no request for this player, lets inform him - UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance!.Translate("No_Request_To_Deny"), Palette.COLOR_Y); - } - public void TpaAbort(UnturnedPlayer playerCalled) - { - foreach (KeyValuePair> playerData in tpaPlayers) - { - // Check the status requesting - if (playerData.Value["Status"] is ETPAStatus status && status == ETPAStatus.Accepted) - { - // Check if player receiving is you - if (playerData.Value["To"] is UnturnedPlayer player && player == playerCalled) - { - // Inform the receiving player - UnturnedChat.Say(playerCalled, SimpleTPAPlugin.instance!.Translate("Tpa_Aborted"), Palette.COLOR_R); - - // Inform the going player - UnturnedChat.Say(playerData.Key, SimpleTPAPlugin.instance!.Translate("Tpa_Aborted"), Palette.COLOR_R); - - // Remove it from requests - tpaPlayers.Remove(playerData.Key); - return; - } - } - // Check if the player going is you - if (playerData.Key == playerCalled) - { - // Check if receiving player is valid - if (playerData.Value["To"] is UnturnedPlayer playerReceiving) - { - // Inform the receiving player - UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance!.Translate("Tpa_Aborted"), Palette.COLOR_R); - } - - // Inform the going player - UnturnedChat.Say(playerCalled, SimpleTPAPlugin.instance!.Translate("Tpa_Aborted"), Palette.COLOR_R); - - // Remove it from requests - tpaPlayers.Remove(playerData.Key); - return; - } - } - // If the function goes here is because theres no request for this player, lets inform him - UnturnedChat.Say(playerCalled, SimpleTPAPlugin.instance!.Translate("No_Request_To_Abort"), Palette.COLOR_Y); - } - - public void PositionUpdated(UnturnedPlayer player, UnityCoreModule.Vector3 _) - { - // Check if player has a tpa request - if (tpaPlayers.TryGetValue(player, out var updatedData)) - { - // Check if request is accepted - if (updatedData["Status"] is ETPAStatus acStatus && acStatus == ETPAStatus.Accepted) - { - // Remove request - tpaPlayers.Remove(player); - // Inform hes moved during request acception - UnturnedChat.Say(player, SimpleTPAPlugin.instance!.Translate("Tpa_Aborted_Moving"), Palette.COLOR_R); - return; - } - } - } - } - - public enum ETPAStatus - { - Requesting = 0, - Accepted = 1, - } -} +extern alias UnityEngineCoreModule; +using Rocket.API.Collections; +using Rocket.Core.Plugins; +using Rocket.Unturned.Chat; +using Rocket.Unturned.Player; +using SDG.Unturned; +using UnityEngine; +using UnityCoreModule = UnityEngineCoreModule.UnityEngine; + +namespace SimpleTPA +{ + public class SimpleTPAPlugin : RocketPlugin + { + public static SimpleTPAPlugin? instance; + public SimpleTPASystem? tpaSystem; + public override void LoadPlugin() + { + base.LoadPlugin(); + tpaSystem = gameObject.AddComponent(); + Rocket.Unturned.Events.UnturnedPlayerEvents.OnPlayerUpdatePosition += tpaSystem.PositionUpdated; + instance = this; + } + public override TranslationList DefaultTranslations => new() + { + {"Invalid_Player", "Cannot use this command because you are invalid"}, + {"Request_Self", "Cannot Tpa to yourself"}, + {"Invalid_Arguments", "Invalid Arguments"}, + {"Request_Aborted_By_Other", "Your Tpa request has been aborted because other player has requested"}, + {"Already_Requested", "You already have a Tpa request"}, + {"Pending_Request_Expired", "Tpa request has been expired"}, + {"Request_Send", "Tpa to {0} has been send"}, + {"Request_Received", "Tpa from {0}, accept using /tpa a"}, + {"Request_Accepted", "Tpa accepted don't move for {0} seconds"}, + {"Accepted_Request", "Tpa accepted"}, + {"No_Request_To_Accept", "No Tpa request to accept"}, + {"No_Request_To_Deny", "No Tpa request to deny"}, + {"No_Request_To_Abort", "No Tpa request to abort"}, + {"Tpa_Aborted_Moving", "Tpa aborted because you moved"}, + {"Tpa_Denied", "Tpa request has been denied"}, + {"Denied_Tpa", "You denied the Tpa from {0}"}, + {"Tpa_Aborted", "Tpa request has been aborted"}, + }; + } + + public class SimpleTPASystem : MonoBehaviour + { + private Dictionary> tpaPlayers = new(); + + public void Update() + { + #region tpa request + List tpaPlayersToRemove = new(); + Dictionary> tpaPlayersNew = new(tpaPlayers); + + // Swipe all pending tpa + foreach (KeyValuePair> playerData in tpaPlayers) + { + #region requisting expiration + // Check requesting status + if (playerData.Value["Status"] is ETPAStatus reqStatus && reqStatus == ETPAStatus.Requesting) + { + // Get default value + Dictionary updatedData = new(playerData.Value); + // Reduce expiration data + updatedData["Time"] = (uint)updatedData["Time"] - 1; + + // Check if is expirated + if ((uint)updatedData["Time"] <= 0) + { + UnturnedChat.Say(playerData.Key, SimpleTPAPlugin.instance!.Translate("Pending_Request_Expired"), Palette.COLOR_Y); + tpaPlayersToRemove.Add(playerData.Key); + } + + // Update data + tpaPlayersNew[playerData.Key] = updatedData; + } + #endregion + #region accepted delay + // Check requesting status + if (playerData.Value["Status"] is ETPAStatus acStatus && acStatus == ETPAStatus.Accepted) + { + // Get default value + Dictionary updatedData = new(playerData.Value); + // Reduce delay data + updatedData["Time"] = (uint)updatedData["Time"] - 1; + + // Check if is finished + if ((uint)updatedData["Time"] <= 0) + { + // Teleport the player + if (updatedData["To"] is UnturnedPlayer playerReceiving) + playerData.Key.Teleport(playerReceiving); + + tpaPlayersToRemove.Add(playerData.Key); + } + + // Update data + tpaPlayersNew[playerData.Key] = updatedData; + } + #endregion + } + + // Remove finished requests outside the iteration + foreach (UnturnedPlayer player in tpaPlayersToRemove) tpaPlayersNew.Remove(player); + + // Finally we update the real tpaPlayers requests + tpaPlayers = tpaPlayersNew; + #endregion + } + + public void TpaRequest(UnturnedPlayer playerGoing, UnturnedPlayer playerReceiving) + { + // Check if player is requesting to self + if (playerGoing.CharacterName == playerReceiving.CharacterName) + { + // Inform him + UnturnedChat.Say(playerGoing, SimpleTPAPlugin.instance!.Translate("Request_Self"), Palette.COLOR_Y); + return; + } + // Check if player already requested + if (tpaPlayers.TryGetValue(playerGoing, out _)) + { + // Inform him + UnturnedChat.Say(playerGoing, SimpleTPAPlugin.instance!.Translate("Already_Requested"), Palette.COLOR_Y); + return; + } + + // Check other requests for this player, if exist we need to remove it + foreach (KeyValuePair> playerData in tpaPlayers) + { + // Check the status requesting + if (playerData.Value["Status"] is ETPAStatus status && status == ETPAStatus.Requesting) + { + // Check if the receiver is the same as the player command + if (playerData.Value["To"] is UnturnedPlayer player && player.Id == playerReceiving.Id) + { + // Remove the old request + tpaPlayers.Remove(playerData.Key); + // Inform the player about their request cancelled + UnturnedChat.Say(playerData.Key, SimpleTPAPlugin.instance!.Translate("Request_Aborted_By_Other"), Palette.COLOR_Y); + break; + } + } + } + + // Add pending request + tpaPlayers.Add(playerGoing, new() + { + {"To", playerReceiving}, + {"Time", SimpleTPAPlugin.instance!.Configuration.Instance.TickrateToExpire }, + {"Status", ETPAStatus.Requesting}, + }); + + // Inform the going player + UnturnedChat.Say(playerGoing, SimpleTPAPlugin.instance.Translate("Request_Send", playerGoing.CharacterName), Palette.COLOR_Y); + + // Inform the receiving player + UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance.Translate("Request_Received", playerGoing.CharacterName), Palette.COLOR_Y); + } + public void TpaAccept(UnturnedPlayer playerReceiving) + { + // Check if player has been requested + foreach (KeyValuePair> playerData in tpaPlayers) + { + // Check the status requesting + if (playerData.Value["Status"] is ETPAStatus status && status == ETPAStatus.Requesting) + { + // Check if player receiving is you + if (playerData.Value["To"] is UnturnedPlayer player && player.Id == playerReceiving.Id) + { + // Get default value + Dictionary updatedData = playerData.Value; + + // Change values + updatedData["Status"] = ETPAStatus.Accepted; + updatedData["Time"] = SimpleTPAPlugin.instance!.Configuration.Instance.TickrateToTeleport; + + // Update data + tpaPlayers[playerData.Key] = updatedData; + + // Inform the receiving player + UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance!.Translate("Accepted_Request"), Palette.COLOR_Y); + + // Inform the going player + UnturnedChat.Say(playerData.Key, SimpleTPAPlugin.instance!.Translate("Request_Accepted", (int)Math.Round((double)SimpleTPAPlugin.instance.Configuration.Instance.TickrateToTeleport / SimpleTPAPlugin.instance.Configuration.Instance.ServerTickrate)), Palette.COLOR_Y); + return; + } + } + } + // If the function goes here is because theres no request for this player, lets inform him + UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance!.Translate("No_Request_To_Accept"), Palette.COLOR_Y); + } + public void TpaDeny(UnturnedPlayer playerReceiving) + { + // Check if player has been requested + foreach (KeyValuePair> playerData in tpaPlayers) + { + // Check the status requesting + if (playerData.Value["Status"] is ETPAStatus status && status == ETPAStatus.Requesting) + { + // Check if player receiving is you + if (playerData.Value["To"] is UnturnedPlayer player && player.Id == playerReceiving.Id) + { + // Inform the receiving player + UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance!.Translate("Denied_Tpa", playerData.Key.CharacterName), Palette.COLOR_Y); + + // Inform the going player + UnturnedChat.Say(playerData.Key, SimpleTPAPlugin.instance!.Translate("Tpa_Denied"), Palette.COLOR_R); + + // Remove it from requests + tpaPlayers.Remove(playerData.Key); + return; + } + } + } + // If the function goes here is because theres no request for this player, lets inform him + UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance!.Translate("No_Request_To_Deny"), Palette.COLOR_Y); + } + public void TpaAbort(UnturnedPlayer playerCalled) + { + foreach (KeyValuePair> playerData in tpaPlayers) + { + // Check the status requesting + if (playerData.Value["Status"] is ETPAStatus status && status == ETPAStatus.Accepted) + { + // Check if player receiving is you + if (playerData.Value["To"] is UnturnedPlayer player && player.Id == playerCalled.Id) + { + // Inform the receiving player + UnturnedChat.Say(playerCalled, SimpleTPAPlugin.instance!.Translate("Tpa_Aborted"), Palette.COLOR_R); + + // Inform the going player + UnturnedChat.Say(playerData.Key, SimpleTPAPlugin.instance!.Translate("Tpa_Aborted"), Palette.COLOR_R); + + // Remove it from requests + tpaPlayers.Remove(playerData.Key); + return; + } + } + // Check if the player going is you + if (playerData.Key.Id == playerCalled.Id) + { + // Check if receiving player is valid + if (playerData.Value["To"] is UnturnedPlayer playerReceiving) + { + // Inform the receiving player + UnturnedChat.Say(playerReceiving, SimpleTPAPlugin.instance!.Translate("Tpa_Aborted"), Palette.COLOR_R); + } + + // Inform the going player + UnturnedChat.Say(playerCalled, SimpleTPAPlugin.instance!.Translate("Tpa_Aborted"), Palette.COLOR_R); + + // Remove it from requests + tpaPlayers.Remove(playerData.Key); + return; + } + } + // If the function goes here is because theres no request for this player, lets inform him + UnturnedChat.Say(playerCalled, SimpleTPAPlugin.instance!.Translate("No_Request_To_Abort"), Palette.COLOR_Y); + } + public void PositionUpdated(UnturnedPlayer player, UnityCoreModule.Vector3 _) + { + // Check if player has a tpa request + if (tpaPlayers.TryGetValue(player, out var updatedData)) + { + // Check if request is accepted + if (updatedData["Status"] is ETPAStatus acStatus && acStatus == ETPAStatus.Accepted) + { + // Remove request + tpaPlayers.Remove(player); + // Inform hes moved during request acception + UnturnedChat.Say(player, SimpleTPAPlugin.instance!.Translate("Tpa_Aborted_Moving"), Palette.COLOR_R); + return; + } + } + } + public void PlayerInCombat(string playerId) { + + } + } + + public enum ETPAStatus + { + Requesting = 0, + Accepted = 1, + } +}