MONaH-Rasta

NTeleportation

Jul 17th, 2020 (edited)
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 284.92 KB | None | 0 0
  1. //#define DEBUG
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Globalization;
  6. using System.Linq;
  7. using Facepunch;
  8. using Newtonsoft.Json;
  9. using Newtonsoft.Json.Converters;
  10. using Newtonsoft.Json.Linq;
  11. using Oxide.Core;
  12. using Oxide.Core.Configuration;
  13. using Oxide.Core.Plugins;
  14. using Oxide.Game.Rust;
  15. using Rust;
  16. using UnityEngine;
  17. using System.Reflection;
  18. using Oxide.Core.Libraries.Covalence;
  19. using Network;
  20.  
  21. namespace Oxide.Plugins
  22. {
  23.     [Info("NTeleportation", "Author Nogrod, Maintainer nivex", "1.3.7")]
  24.     class NTeleportation : RustPlugin
  25.     {
  26.         private bool newSave;
  27.         private string banditPrefab;
  28.         private string outpostPrefab;
  29.         private const bool True = true;
  30.         private const bool False = false;
  31.         private Vector3 Zero = default(Vector3);
  32.         private readonly Vector3 Up = Vector3.up;
  33.         private readonly Vector3 Down = Vector3.down;
  34.         private const string NewLine = "\n";
  35.         private const string ConfigDefaultPermVip = "nteleportation.vip";
  36.         private const string PermHome = "nteleportation.home";
  37.         private const string PermTpR = "nteleportation.tpr";
  38.         private const string PermTpT = "nteleportation.tpt";
  39.         private const string PermDeleteHome = "nteleportation.deletehome";
  40.         private const string PermHomeHomes = "nteleportation.homehomes";
  41.         private const string PermImportHomes = "nteleportation.importhomes";
  42.         private const string PermRadiusHome = "nteleportation.radiushome";
  43.         private const string PermTp = "nteleportation.tp";
  44.         private const string PermTpB = "nteleportation.tpb";
  45.         private const string PermTpConsole = "nteleportation.tpconsole";
  46.         private const string PermTpHome = "nteleportation.tphome";
  47.         private const string PermTpTown = "nteleportation.tptown";
  48.         private const string PermTpOutpost = "nteleportation.tpoutpost";
  49.         private const string PermTpBandit = "nteleportation.tpbandit";
  50.         private const string PermTpN = "nteleportation.tpn";
  51.         private const string PermTpL = "nteleportation.tpl";
  52.         private const string PermTpRemove = "nteleportation.tpremove";
  53.         private const string PermTpSave = "nteleportation.tpsave";
  54.         private const string PermWipeHomes = "nteleportation.wipehomes";
  55.         private const string PermCraftHome = "nteleportation.crafthome";
  56.         private const string PermCraftTown = "nteleportation.crafttown";
  57.         private const string PermCraftOutpost = "nteleportation.craftoutpost";
  58.         private const string PermCraftBandit = "nteleportation.craftbandit";
  59.         private const string PermCraftTpR = "nteleportation.crafttpr";
  60.         private DynamicConfigFile dataConvert;
  61.         private DynamicConfigFile dataDisabled;
  62.         private DynamicConfigFile dataAdmin;
  63.         private DynamicConfigFile dataHome;
  64.         private DynamicConfigFile dataTPR;
  65.         private DynamicConfigFile dataTPT;
  66.         private DynamicConfigFile dataTown;
  67.         private DynamicConfigFile dataOutpost;
  68.         private DynamicConfigFile dataBandit;
  69.         private Dictionary<ulong, AdminData> Admin;
  70.         private Dictionary<ulong, HomeData> Home;
  71.         private Dictionary<ulong, TeleportData> TPR;
  72.         private Dictionary<string, List<string>> TPT;
  73.         private Dictionary<ulong, TeleportData> Town;
  74.         private Dictionary<ulong, TeleportData> Outpost;
  75.         private Dictionary<ulong, TeleportData> Bandit;
  76.         private bool changedAdmin;
  77.         private bool changedHome;
  78.         private bool changedTPR;
  79.         private bool changedTPT;
  80.         private bool changedTown;
  81.         private bool changedOutpost;
  82.         private bool changedBandit;
  83.         private float boundary;
  84.         private readonly int triggerLayer = LayerMask.GetMask("Trigger");
  85.         private readonly int groundLayer = LayerMask.GetMask("Terrain", "World");
  86.         private int buildingLayer { get; set; } = LayerMask.GetMask("Terrain", "World", "Construction", "Deployed");
  87.         private readonly int blockLayer = LayerMask.GetMask("Construction");
  88.         private readonly int deployedLayer = LayerMask.GetMask("Deployed");
  89.         private readonly Dictionary<ulong, TeleportTimer> TeleportTimers = new Dictionary<ulong, TeleportTimer>();
  90.         private readonly Dictionary<ulong, Timer> PendingRequests = new Dictionary<ulong, Timer>();
  91.         private readonly Dictionary<ulong, BasePlayer> PlayersRequests = new Dictionary<ulong, BasePlayer>();
  92.         private readonly Dictionary<int, string> ReverseBlockedItems = new Dictionary<int, string>();
  93.         private readonly Dictionary<ulong, Vector3> teleporting = new Dictionary<ulong, Vector3>();
  94.         private SortedDictionary<string, Vector3> caves = new SortedDictionary<string, Vector3>();
  95.         private SortedDictionary<string, MonInfo> monuments = new SortedDictionary<string, MonInfo>();
  96.         private bool outpostEnabled;
  97.         private string OutpostTPDisabledMessage = "OutpostTPDisabled";
  98.         private bool banditEnabled;
  99.         private string BanditTPDisabledMessage = "BanditTPDisabled";
  100.  
  101.         [PluginReference]
  102.         private Plugin Clans, Economics, ServerRewards, Friends, CompoundTeleport, ZoneManager, NoEscape, Vanish;
  103.  
  104.         class MonInfo
  105.         {
  106.             public Vector3 Position;
  107.             public float Radius;
  108.         }
  109.  
  110.         #region Configuration
  111.  
  112.         private static Configuration config;
  113.  
  114.         public class InterruptSettings
  115.         {
  116.             [JsonProperty(PropertyName = "Above Water")]
  117.             public bool AboveWater { get; set; } = True;
  118.  
  119.             [JsonProperty(PropertyName = "Balloon")]
  120.             public bool Balloon { get; set; } = True;
  121.  
  122.             [JsonProperty(PropertyName = "Cargo Ship")]
  123.             public bool Cargo { get; set; } = True;
  124.  
  125.             [JsonProperty(PropertyName = "Cold")]
  126.             public bool Cold { get; set; } = False;
  127.  
  128.             [JsonProperty(PropertyName = "Excavator")]
  129.             public bool Excavator { get; set; } = False;
  130.  
  131.             [JsonProperty(PropertyName = "Hot")]
  132.             public bool Hot { get; set; } = False;
  133.  
  134.             [JsonProperty(PropertyName = "Hostile")]
  135.             public bool Hostile { get; set; } = False;
  136.  
  137.             [JsonProperty(PropertyName = "Hurt")]
  138.             public bool Hurt { get; set; } = True;
  139.  
  140.             [JsonProperty(PropertyName = "Lift")]
  141.             public bool Lift { get; set; } = True;
  142.  
  143.             [JsonProperty(PropertyName = "Monument")]
  144.             public bool Monument { get; set; } = False;
  145.  
  146.             [JsonProperty(PropertyName = "Mounted")]
  147.             public bool Mounted { get; set; } = True;
  148.  
  149.             [JsonProperty(PropertyName = "Oil Rig")]
  150.             public bool Oilrig { get; set; } = False;
  151.  
  152.             [JsonProperty(PropertyName = "Safe Zone")]
  153.             public bool Safe { get; set; } = True;
  154.  
  155.             [JsonProperty(PropertyName = "Swimming")]
  156.             public bool Swimming { get; set; } = False;
  157.         }
  158.  
  159.         public class PluginSettings
  160.         {
  161.             [JsonProperty(PropertyName = "Interrupt TP")]
  162.             public InterruptSettings Interrupt { get; set; } = new InterruptSettings();
  163.  
  164.             [JsonProperty(PropertyName = "Block Teleport (NoEscape)")]
  165.             public bool BlockNoEscape { get; set; } = False;
  166.  
  167.             [JsonProperty(PropertyName = "Block Teleport (ZoneManager)")]
  168.             public bool BlockZoneFlag { get; set; } = False;
  169.  
  170.             [JsonProperty(PropertyName = "Chat Name")]
  171.             public string ChatName { get; set; } = "<color=red>Teleportation</color>: ";
  172.  
  173.             [JsonProperty(PropertyName = "Chat Steam64ID")]
  174.             public ulong ChatID { get; set; } = 76561199056025689;
  175.  
  176.             [JsonProperty(PropertyName = "Check Boundaries On Teleport X Y Z")]
  177.             public bool CheckBoundaries { get; set; } = True;
  178.  
  179.             [JsonProperty(PropertyName = "Draw Sphere On Set Home")]
  180.             public bool DrawHomeSphere { get; set; } = True;
  181.  
  182.             [JsonProperty(PropertyName = "Homes Enabled")]
  183.             public bool HomesEnabled { get; set; } = True;
  184.  
  185.             [JsonProperty(PropertyName = "TPR Enabled")]
  186.             public bool TPREnabled { get; set; } = True;
  187.  
  188.             [JsonProperty(PropertyName = "Town Enabled")]
  189.             public bool TownEnabled { get; set; } = True;
  190.  
  191.             [JsonProperty(PropertyName = "Outpost Enabled")]
  192.             public bool OutpostEnabled { get; set; } = True;
  193.  
  194.             [JsonProperty(PropertyName = "Bandit Enabled")]
  195.             public bool BanditEnabled { get; set; } = True;
  196.  
  197.             [JsonProperty(PropertyName = "Strict Foundation Check")]
  198.             public bool StrictFoundationCheck { get; set; } = False;
  199.  
  200.             [JsonProperty(PropertyName = "Cave Distance Small")]
  201.             public float CaveDistanceSmall { get; set; } = 50f;
  202.  
  203.             [JsonProperty(PropertyName = "Cave Distance Medium")]
  204.             public float CaveDistanceMedium { get; set; } = 70f;
  205.  
  206.             [JsonProperty(PropertyName = "Cave Distance Large")]
  207.             public float CaveDistanceLarge { get; set; } = 110f;
  208.  
  209.             [JsonProperty(PropertyName = "Default Monument Size")]
  210.             public float DefaultMonumentSize { get; set; } = 50f;
  211.  
  212.             [JsonProperty(PropertyName = "Minimum Temp")]
  213.             public float MinimumTemp { get; set; } = 0f;
  214.  
  215.             [JsonProperty(PropertyName = "Maximum Temp")]
  216.             public float MaximumTemp { get; set; } = 40f;
  217.  
  218.             [JsonProperty(PropertyName = "Blocked Items", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  219.             public Dictionary<string, string> BlockedItems { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
  220.  
  221.             [JsonProperty(PropertyName = "Bypass CMD")]
  222.             public string BypassCMD { get; set; } = "pay";
  223.  
  224.             [JsonProperty(PropertyName = "Use Economics")]
  225.             public bool UseEconomics { get; set; } = False;
  226.  
  227.             [JsonProperty(PropertyName = "Use Server Rewards")]
  228.             public bool UseServerRewards { get; set; } = False;
  229.  
  230.             [JsonProperty(PropertyName = "Wipe On Upgrade Or Change")]
  231.             public bool WipeOnUpgradeOrChange { get; set; } = False;
  232.  
  233.             [JsonProperty(PropertyName = "Auto Generate Outpost Location")]
  234.             public bool AutoGenOutpost { get; set; } = False;
  235.  
  236.             [JsonProperty(PropertyName = "Auto Generate Bandit Location")]
  237.             public bool AutoGenBandit { get; set; } = False;
  238.         }
  239.  
  240.         public class AdminSettings
  241.         {
  242.             [JsonProperty(PropertyName = "Announce Teleport To Target")]
  243.             public bool AnnounceTeleportToTarget { get; set; } = False;
  244.  
  245.             [JsonProperty(PropertyName = "Usable By Admins")]
  246.             public bool UseableByAdmins { get; set; } = True;
  247.  
  248.             [JsonProperty(PropertyName = "Usable By Moderators")]
  249.             public bool UseableByModerators { get; set; } = True;
  250.  
  251.             [JsonProperty(PropertyName = "Location Radius")]
  252.             public int LocationRadius { get; set; } = 25;
  253.  
  254.             [JsonProperty(PropertyName = "Teleport Near Default Distance")]
  255.             public int TeleportNearDefaultDistance { get; set; } = 30;
  256.         }
  257.  
  258.         public class HomesSettings
  259.         {
  260.             [JsonProperty(PropertyName = "Homes Limit")]
  261.             public int HomesLimit { get; set; } = 2;
  262.  
  263.             [JsonProperty(PropertyName = "VIP Homes Limits", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  264.             public Dictionary<string, int> VIPHomesLimits { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  265.  
  266.             [JsonProperty(PropertyName = "Cooldown")]
  267.             public int Cooldown { get; set; } = 600;
  268.  
  269.             [JsonProperty(PropertyName = "Countdown")]
  270.             public int Countdown { get; set; } = 15;
  271.  
  272.             [JsonProperty(PropertyName = "Daily Limit")]
  273.             public int DailyLimit { get; set; } = 5;
  274.  
  275.             [JsonProperty(PropertyName = "VIP Daily Limits", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  276.             public Dictionary<string, int> VIPDailyLimits { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  277.  
  278.             [JsonProperty(PropertyName = "VIP Cooldowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  279.             public Dictionary<string, int> VIPCooldowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  280.  
  281.             [JsonProperty(PropertyName = "VIP Countdowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  282.             public Dictionary<string, int> VIPCountdowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  283.  
  284.             [JsonProperty(PropertyName = "Location Radius")]
  285.             public int LocationRadius { get; set; } = 25;
  286.  
  287.             [JsonProperty(PropertyName = "Force On Top Of Foundation")]
  288.             public bool ForceOnTopOfFoundation { get; set; } = True;
  289.  
  290.             [JsonProperty(PropertyName = "Check Foundation For Owner")]
  291.             public bool CheckFoundationForOwner { get; set; } = True;
  292.  
  293.             [JsonProperty(PropertyName = "Use Friends")]
  294.             public bool UseFriends { get; set; } = True;
  295.  
  296.             [JsonProperty(PropertyName = "Use Clans")]
  297.             public bool UseClans { get; set; } = True;
  298.  
  299.             [JsonProperty(PropertyName = "Use Teams")]
  300.             public bool UseTeams { get; set; } = True;
  301.  
  302.             [JsonProperty(PropertyName = "Usable Out Of Building Blocked")]
  303.             public bool UsableOutOfBuildingBlocked { get; set; } = False;
  304.  
  305.             [JsonProperty(PropertyName = "Usable Into Building Blocked")]
  306.             public bool UsableIntoBuildingBlocked { get; set; } = False;
  307.  
  308.             [JsonProperty(PropertyName = "Allow Cupboard Owner When Building Blocked")]
  309.             public bool CupOwnerAllowOnBuildingBlocked { get; set; } = True;
  310.  
  311.             [JsonProperty(PropertyName = "Allow Iceberg")]
  312.             public bool AllowIceberg { get; set; } = False;
  313.  
  314.             [JsonProperty(PropertyName = "Allow Cave")]
  315.             public bool AllowCave { get; set; } = False;
  316.  
  317.             [JsonProperty(PropertyName = "Allow Crafting")]
  318.             public bool AllowCraft { get; set; } = False;
  319.  
  320.             [JsonProperty(PropertyName = "Allow Above Foundation")]
  321.             public bool AllowAboveFoundation { get; set; } = True;
  322.  
  323.             [JsonProperty(PropertyName = "Check If Home Is Valid On Listhomes")]
  324.             public bool CheckValidOnList { get; set; } = False;
  325.  
  326.             [JsonProperty(PropertyName = "Pay")]
  327.             public int Pay { get; set; } = 0;
  328.  
  329.             [JsonProperty(PropertyName = "Bypass")]
  330.             public int Bypass { get; set; } = 0;
  331.         }
  332.  
  333.         public class TPTSettings
  334.         {
  335.             [JsonProperty(PropertyName = "Use Friends")]
  336.             public bool UseFriends { get; set; }
  337.  
  338.             [JsonProperty(PropertyName = "Use Clans")]
  339.             public bool UseClans { get; set; }
  340.  
  341.             [JsonProperty(PropertyName = "Use Teams")]
  342.             public bool UseTeams { get; set; }
  343.  
  344.             [JsonProperty(PropertyName = "Allow Cave")]
  345.             public bool AllowCave { get; set; }
  346.         }
  347.  
  348.         public class TPRSettings
  349.         {
  350.             [JsonProperty(PropertyName = "Allow Cave")]
  351.             public bool AllowCave { get; set; } = False;
  352.  
  353.             [JsonProperty(PropertyName = "Allow TPB")]
  354.             public bool AllowTPB { get; set; } = True;
  355.  
  356.             [JsonProperty(PropertyName = "Cooldown")]
  357.             public int Cooldown { get; set; } = 600;
  358.  
  359.             [JsonProperty(PropertyName = "Countdown")]
  360.             public int Countdown { get; set; } = 15;
  361.  
  362.             [JsonProperty(PropertyName = "Daily Limit")]
  363.             public int DailyLimit { get; set; } = 5;
  364.  
  365.             [JsonProperty(PropertyName = "VIP Daily Limits", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  366.             public Dictionary<string, int> VIPDailyLimits { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  367.  
  368.             [JsonProperty(PropertyName = "VIP Cooldowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  369.             public Dictionary<string, int> VIPCooldowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  370.  
  371.             [JsonProperty(PropertyName = "VIP Countdowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  372.             public Dictionary<string, int> VIPCountdowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  373.  
  374.             [JsonProperty(PropertyName = "Request Duration")]
  375.             public int RequestDuration { get; set; } = 30;
  376.  
  377.             [JsonProperty(PropertyName = "Block TPA On Ceiling")]
  378.             public bool BlockTPAOnCeiling { get; set; } = True;
  379.  
  380.             [JsonProperty(PropertyName = "Usable Out Of Building Blocked")]
  381.             public bool UsableOutOfBuildingBlocked { get; set; } = False;
  382.  
  383.             [JsonProperty(PropertyName = "Usable Into Building Blocked")]
  384.             public bool UsableIntoBuildingBlocked { get; set; } = False;
  385.  
  386.             [JsonProperty(PropertyName = "Allow Cupboard Owner When Building Blocked")]
  387.             public bool CupOwnerAllowOnBuildingBlocked { get; set; } = True;
  388.  
  389.             [JsonProperty(PropertyName = "Allow Crafting")]
  390.             public bool AllowCraft { get; set; } = False;
  391.  
  392.             [JsonProperty(PropertyName = "Pay")]
  393.             public int Pay { get; set; } = 0;
  394.  
  395.             [JsonProperty(PropertyName = "Bypass")]
  396.             public int Bypass { get; set; } = 0;
  397.         }
  398.  
  399.         public class TownSettings
  400.         {
  401.             [JsonProperty(PropertyName = "Allow Cave")]
  402.             public bool AllowCave { get; set; } = False;
  403.  
  404.             [JsonProperty(PropertyName = "Cooldown")]
  405.             public int Cooldown { get; set; } = 600;
  406.  
  407.             [JsonProperty(PropertyName = "Countdown")]
  408.             public int Countdown { get; set; } = 15;
  409.  
  410.             [JsonProperty(PropertyName = "Daily Limit")]
  411.             public int DailyLimit { get; set; } = 5;
  412.  
  413.             [JsonProperty(PropertyName = "VIP Daily Limits", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  414.             public Dictionary<string, int> VIPDailyLimits { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  415.  
  416.             [JsonProperty(PropertyName = "VIP Cooldowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  417.             public Dictionary<string, int> VIPCooldowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  418.  
  419.             [JsonProperty(PropertyName = "VIP Countdowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  420.             public Dictionary<string, int> VIPCountdowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  421.  
  422.             [JsonProperty(PropertyName = "Location")]
  423.             public Vector3 Location { get; set; } = Vector3.zero;
  424.  
  425.             [JsonProperty(PropertyName = "Usable Out Of Building Blocked")]
  426.             public bool UsableOutOfBuildingBlocked { get; set; } = False;
  427.  
  428.             [JsonProperty(PropertyName = "Allow Crafting")]
  429.             public bool AllowCraft { get; set; } = False;
  430.  
  431.             [JsonProperty(PropertyName = "Pay")]
  432.             public int Pay { get; set; } = 0;
  433.  
  434.             [JsonProperty(PropertyName = "Bypass")]
  435.             public int Bypass { get; set; } = 0;
  436.         }
  437.  
  438.         private class Configuration
  439.         {
  440.             [JsonProperty(PropertyName = "Settings")]
  441.             public PluginSettings Settings = new PluginSettings();
  442.  
  443.             [JsonProperty(PropertyName = "Admin")]
  444.             public AdminSettings Admin = new AdminSettings();
  445.  
  446.             [JsonProperty(PropertyName = "Home")]
  447.             public HomesSettings Home = new HomesSettings();
  448.  
  449.             [JsonProperty(PropertyName = "TPT")]
  450.             public TPTSettings TPT = new TPTSettings();
  451.  
  452.             [JsonProperty(PropertyName = "TPR")]
  453.             public TPRSettings TPR = new TPRSettings();
  454.  
  455.             [JsonProperty(PropertyName = "Town")]
  456.             public TownSettings Town = new TownSettings();
  457.  
  458.             [JsonProperty(PropertyName = "Outpost")]
  459.             public TownSettings Outpost = new TownSettings();
  460.  
  461.             [JsonProperty(PropertyName = "Bandit")]
  462.             public TownSettings Bandit = new TownSettings();
  463.         }
  464.  
  465.         protected override void LoadConfig()
  466.         {
  467.             base.LoadConfig();
  468.  
  469.             try
  470.             {
  471.                 Config.Settings.Converters = new JsonConverter[] { new UnityVector3Converter() };
  472.                 config = Config.ReadObject<Configuration>();
  473.                 if (config == null) throw new Exception();
  474.             }
  475.             catch
  476.             {
  477.                 PrintError("Your configuration file contains an error. Using default configuration values.");
  478.                 LoadDefaultConfig();
  479.             }
  480.  
  481.             SaveConfig();
  482.         }
  483.  
  484.         protected override void SaveConfig() => Config.WriteObject(config);
  485.  
  486.         protected override void LoadDefaultConfig()
  487.         {
  488.             config = new Configuration();
  489.             Puts("Loaded default configuration.");
  490.         }
  491.  
  492.         #endregion
  493.  
  494.         class DisabledData
  495.         {
  496.             [JsonProperty("List of disabled commands")]
  497.             public List<string> DisabledCommands = new List<string>();
  498.  
  499.             public DisabledData() { }
  500.         }
  501.  
  502.         DisabledData DisabledTPT = new DisabledData();
  503.  
  504.         class AdminData
  505.         {
  506.             [JsonProperty("pl")]
  507.             public Vector3 PreviousLocation { get; set; }
  508.  
  509.             [JsonProperty("l")]
  510.             public Dictionary<string, Vector3> Locations { get; set; } = new Dictionary<string, Vector3>(StringComparer.OrdinalIgnoreCase);
  511.         }
  512.  
  513.         class HomeData
  514.         {
  515.             [JsonProperty("l")]
  516.             public Dictionary<string, Vector3> Locations { get; set; } = new Dictionary<string, Vector3>(StringComparer.OrdinalIgnoreCase);
  517.  
  518.             [JsonProperty("t")]
  519.             public TeleportData Teleports { get; set; } = new TeleportData();
  520.         }
  521.  
  522.         class TeleportData
  523.         {
  524.             [JsonProperty("a")]
  525.             public int Amount { get; set; }
  526.  
  527.             [JsonProperty("d")]
  528.             public string Date { get; set; }
  529.  
  530.             [JsonProperty("t")]
  531.             public int Timestamp { get; set; }
  532.         }
  533.  
  534.         class TeleportTimer
  535.         {
  536.             public Timer Timer { get; set; }
  537.             public BasePlayer OriginPlayer { get; set; }
  538.             public BasePlayer TargetPlayer { get; set; }
  539.         }
  540.  
  541.         private enum checkmode
  542.         {
  543.             home, tpr, tpa, town
  544.         };
  545.  
  546.         protected override void LoadDefaultMessages()
  547.         {
  548.             lang.RegisterMessages(new Dictionary<string, string>
  549.             {
  550.                 {"AdminTP", "You teleported to {0}!"},
  551.                 {"AdminTPTarget", "{0} teleported to you!"},
  552.                 {"AdminTPPlayers", "You teleported {0} to {1}!"},
  553.                 {"AdminTPPlayer", "{0} teleported you to {1}!"},
  554.                 {"AdminTPPlayerTarget", "{0} teleported {1} to you!"},
  555.                 {"AdminTPCoordinates", "You teleported to {0}!"},
  556.                 {"AdminTPTargetCoordinates", "You teleported {0} to {1}!"},
  557.                 {"AdminTPOutOfBounds", "You tried to teleport to a set of coordinates outside the map boundaries!"},
  558.                 {"AdminTPBoundaries", "X and Z values need to be between -{0} and {0} while the Y value needs to be between -100 and 2000!"},
  559.                 {"AdminTPLocation", "You teleported to {0}!"},
  560.                 {"AdminTPLocationSave", "You have saved the current location!"},
  561.                 {"AdminTPLocationRemove", "You have removed the location {0}!"},
  562.                 {"AdminLocationList", "The following locations are available:"},
  563.                 {"AdminLocationListEmpty", "You haven't saved any locations!"},
  564.                 {"AdminTPBack", "You've teleported back to your previous location!"},
  565.                 {"AdminTPBackSave", "Your previous location has been saved, use <color=yellow>/tpb</color> to teleport back!"},
  566.                 {"AdminTPTargetCoordinatesTarget", "{0} teleported you to {1}!"},
  567.                 {"AdminTPConsoleTP", "You were teleported to {0}"},
  568.                 {"AdminTPConsoleTPPlayer", "You were teleported to {0}"},
  569.                 {"AdminTPConsoleTPPlayerTarget", "{0} was teleported to you!"},
  570.                 {"HomeTP", "You teleported to your home '{0}'!"},
  571.                 {"HomeAdminTP", "You teleported to {0}'s home '{1}'!"},
  572.                 {"HomeSave", "You have saved the current location as your home!"},
  573.                 {"HomeNoFoundation", "You can only use a home location on a foundation!"},
  574.                 {"HomeFoundationNotOwned", "You can't use home on someone else's house."},
  575.                 {"HomeFoundationUnderneathFoundation", "You can't use home on a foundation that is underneath another foundation."},
  576.                 {"HomeFoundationNotFriendsOwned", "You or a friend need to own the house to use home!"},
  577.                 {"HomeRemovedInvalid", "Your home '{0}' was removed because not on a foundation or not owned!"},
  578.                 {"HighWallCollision", "High Wall Collision!"},
  579.                 {"HomeRemovedInsideBlock", "Your home '{0}' was removed because inside a foundation!"},
  580.                 {"HomeRemove", "You have removed your home {0}!"},
  581.                 {"HomeDelete", "You have removed {0}'s home '{1}'!"},
  582.                 {"HomeList", "The following homes are available:"},
  583.                 {"HomeListEmpty", "You haven't saved any homes!"},
  584.                 {"HomeMaxLocations", "Unable to set your home here, you have reached the maximum of {0} homes!"},
  585.                 {"HomeQuota", "You have set {0} of the maximum {1} homes!"},
  586.                 {"HomeTPStarted", "Teleporting to your home {0} in {1} seconds!"},
  587.                 {"PayToHome", "Standard payment of {0} applies to all home teleports!"},
  588.                 {"PayToTown", "Standard payment of {0} applies to all town teleports!"},
  589.                 {"PayToTPR", "Standard payment of {0} applies to all tprs!"},
  590.                 {"HomeTPCooldown", "Your teleport is currently on cooldown. You'll have to wait {0} for your next teleport."},
  591.                 {"HomeTPCooldownBypass", "Your teleport was currently on cooldown. You chose to bypass that by paying {0} from your balance."},
  592.                 {"HomeTPCooldownBypassF", "Your teleport is currently on cooldown. You do not have sufficient funds - {0} - to bypass."},
  593.                 {"HomeTPCooldownBypassP", "You may choose to pay {0} to bypass this cooldown." },
  594.                 {"HomeTPCooldownBypassP2", "Type <color=yellow>/home NAME {0}</color>." },
  595.                 {"HomeTPLimitReached", "You have reached the daily limit of {0} teleports today!"},
  596.                 {"HomeTPAmount", "You have {0} home teleports left today!"},
  597.                 {"HomesListWiped", "You have wiped all the saved home locations!"},
  598.                 {"HomeTPBuildingBlocked", "You can't set your home if you are not allowed to build in this zone!"},
  599.                 {"HomeTPSwimming", "You can't set your home while swimming!"},
  600.                 {"HomeTPCrafting", "You can't set your home while crafting!"},
  601.                 {"Request", "You've requested a teleport to {0}!"},
  602.                 {"RequestTarget", "{0} requested to be teleported to you! Use '<color=yellow>/tpa</color>' to accept!"},
  603.                 {"PendingRequest", "You already have a request pending, cancel that request or wait until it gets accepted or times out!"},
  604.                 {"PendingRequestTarget", "The player you wish to teleport to already has a pending request, try again later!"},
  605.                 {"NoPendingRequest", "You have no pending teleport request!"},
  606.                 {"AcceptOnRoof", "You can't accept a teleport while you're on a ceiling, get to ground level!"},
  607.                 {"Accept", "{0} has accepted your teleport request! Teleporting in {1} seconds!"},
  608.                 {"AcceptTarget", "You've accepted the teleport request of {0}!"},
  609.                 {"NotAllowed", "You are not allowed to use this command!"},
  610.                 {"Success", "You teleported to {0}!"},
  611.                 {"SuccessTarget", "{0} teleported to you!"},
  612.                 {"Cancelled", "Your teleport request to {0} was cancelled!"},
  613.                 {"CancelledTarget", "{0} teleport request was cancelled!"},
  614.                 {"TPCancelled", "Your teleport was cancelled!"},
  615.                 {"TPCancelledTarget", "{0} cancelled teleport!"},
  616.                 {"TPYouCancelledTarget", "You cancelled {0} teleport!"},
  617.                 {"TimedOut", "{0} did not answer your request in time!"},
  618.                 {"TimedOutTarget", "You did not answer {0}'s teleport request in time!"},
  619.                 {"TargetDisconnected", "{0} has disconnected, your teleport was cancelled!"},
  620.                 {"TPRCooldown", "Your teleport requests are currently on cooldown. You'll have to wait {0} to send your next teleport request."},
  621.                 {"TPRCooldownBypass", "Your teleport request was on cooldown. You chose to bypass that by paying {0} from your balance."},
  622.                 {"TPRCooldownBypassF", "Your teleport is currently on cooldown. You do not have sufficient funds - {0} - to bypass."},
  623.                 {"TPRCooldownBypassP", "You may choose to pay {0} to bypass this cooldown." },
  624.                 {"TPMoney", "{0} deducted from your account!"},
  625.                 {"TPNoMoney", "You do not have {0} in any account!"},
  626.                 {"TPRCooldownBypassP2", "Type <color=yellow>/tpr {0}</color>." },
  627.                 {"TPRCooldownBypassP2a", "Type <color=yellow>/tpr NAME {0}</color>." },
  628.                 {"TPRLimitReached", "You have reached the daily limit of {0} teleport requests today!"},
  629.                 {"TPRAmount", "You have {0} teleport requests left today!"},
  630.                 {"TPRTarget", "Your target is currently not available!"},
  631.                 {"TPDead", "You can't teleport while being dead!"},
  632.                 {"TPWounded", "You can't teleport while wounded!"},
  633.                 {"TPTooCold", "You're too cold to teleport!"},
  634.                 {"TPTooHot", "You're too hot to teleport!"},
  635.                 {"TPHostile", "Can't teleport to outpost or bandit when hostile!"},
  636.                 {"HostileTimer", "Teleport available in {0} minutes."},
  637.                 {"TPMounted", "You can't teleport while seated!"},
  638.                 {"TPBuildingBlocked", "You can't teleport while in a building blocked zone!"},
  639.                 {"TPAboveWater", "You can't teleport while above water!"},
  640.                 {"TPTargetBuildingBlocked", "You can't teleport in a building blocked zone!"},
  641.                 {"TPTargetInsideBlock", "You can't teleport into a foundation!"},
  642.                 {"TPSwimming", "You can't teleport while swimming!"},
  643.                 {"TPCargoShip", "You can't teleport from the cargo ship!"},
  644.                 {"TPOilRig", "You can't teleport from the oil rig!"},
  645.                 {"TPExcavator", "You can't teleport from the excavator!"},
  646.                 {"TPHotAirBalloon", "You can't teleport to or from a hot air balloon!"},
  647.                 {"TPLift", "You can't teleport while in an elevator or bucket lift!"},
  648.                 {"TPBucketLift", "You can't teleport while in a bucket lift!"},
  649.                 {"TPRegLift", "You can't teleport while in an elevator!"},
  650.                 {"TPSafeZone", "You can't teleport from a safezone!"},
  651.                 {"TPFlagZone", "You can't teleport from this zone!"},
  652.                 {"TPNoEscapeBlocked", "You can't teleport while blocked!"},
  653.                 {"TPCrafting", "You can't teleport while crafting!"},
  654.                 {"TPBlockedItem", "You can't teleport while carrying: {0}!"},
  655.                 {"TooCloseToMon", "You can't teleport so close to the {0}!"},
  656.                 {"TooCloseToCave", "You can't teleport so close to a cave!"},
  657.                 {"HomeTooCloseToCave", "You can't set home so close to a cave!"},
  658.                 {"TownTP", "You teleported to town!"},
  659.                 {"TownTPNotSet", "Town is currently not set!"},
  660.                 {"TownTPDisabled", "Town is currently not enabled!"},
  661.                 {"TownTPLocation", "You have set the town location to {0}!"},
  662.                 {"TownTPStarted", "Teleporting to town in {0} seconds!"},
  663.                 {"TownTPCooldown", "Your teleport is currently on cooldown. You'll have to wait {0} for your next teleport."},
  664.                 {"TownTPCooldownBypass", "Your teleport request was on cooldown. You chose to bypass that by paying {0} from your balance."},
  665.                 {"TownTPCooldownBypassF", "Your teleport is currently on cooldown. You do not have sufficient funds - {0} - to bypass."},
  666.                 {"TownTPCooldownBypassP", "You may choose to pay {0} to bypass this cooldown." },
  667.                 {"TownTPCooldownBypassP2", "Type <color=yellow>/town {0}</color>." },
  668.                 {"TownTPLimitReached", "You have reached the daily limit of {0} teleports today!"},
  669.                 {"TownTPAmount", "You have {0} town teleports left today!"},
  670.  
  671.                 {"OutpostTP", "You teleported to the outpost!"},
  672.                 {"OutpostTPNotSet", "Outpost is currently not set!"},
  673.                 {"OutpostTPDisabled", "Outpost is currently not enabled!"},
  674.                 {"OutpostTPDisabledConfig", "Outpost is currently not enabled because it isn't enabled in the config"},
  675.                 {"OutpostTPDisabledNoLocation", "Outpost is currently not enabled, location is not set and auto generation is disabled!"},
  676.                 {"OutpostTPDisabledNoLocationAutoGen", "Outpost is currently not enabled because auto generation failed!"},
  677.                 {"OutpostTPLocation", "You have set the outpost location to {0}!"},
  678.                 {"OutpostTPStarted", "Teleporting to the outpost in {0} seconds!"},
  679.                 {"OutpostTPCooldown", "Your teleport is currently on cooldown. You'll have to wait {0} for your next teleport."},
  680.                 {"OutpostTPCooldownBypass", "Your teleport request was on cooldown. You chose to bypass that by paying {0} from your balance."},
  681.                 {"OutpostTPCooldownBypassF", "Your teleport is currently on cooldown. You do not have sufficient funds - {0} - to bypass."},
  682.                 {"OutpostTPCooldownBypassP", "You may choose to pay {0} to bypass this cooldown." },
  683.                 {"OutpostTPCooldownBypassP2", "Type <color=yellow>/outpost {0}</color>." },
  684.                 {"OutpostTPLimitReached", "You have reached the daily limit of {0} teleports today!"},
  685.                 {"OutpostTPAmount", "You have {0} outpost teleports left today!"},
  686.  
  687.                 {"BanditTP", "You teleported to bandit town!"},
  688.                 {"BanditTPNotSet", "Bandit is currently not set!"},
  689.                 {"BanditTPDisabled", "Bandit is currently not enabled!"},
  690.                 {"BanditTPDisabledConfig", "Bandit is currently not enabled because it isn't enabled in the config!"},
  691.                 {"BanditTPDisabledNoLocation", "Bandit is currently not enabled, location is not set and auto generation is disabled!"},
  692.                 {"BanditTPDisabledNoLocationAutoGen", "Bandit is currently not enabled because auto generation failed!"},
  693.                 {"BanditTPLocation", "You have set the bandit town location to {0}!"},
  694.                 {"BanditTPStarted", "Teleporting to bandit town in {0} seconds!"},
  695.                 {"BanditTPCooldown", "Your teleport is currently on cooldown. You'll have to wait {0} for your next teleport."},
  696.                 {"BanditTPCooldownBypass", "Your teleport request was on cooldown. You chose to bypass that by paying {0} from your balance."},
  697.                 {"BanditTPCooldownBypassF", "Your teleport is currently on cooldown. You do not have sufficient funds - {0} - to bypass."},
  698.                 {"BanditTPCooldownBypassP", "You may choose to pay {0} to bypass this cooldown." },
  699.                 {"BanditTPCooldownBypassP2", "Type <color=yellow>/bandit {0}</color>." },
  700.                 {"BanditTPLimitReached", "You have reached the daily limit of {0} teleports today!"},
  701.                 {"BanditTPAmount", "You have {0} bandit town teleports left today!"},
  702.  
  703.                 {"Interrupted", "Your teleport was interrupted!"},
  704.                 {"InterruptedTarget", "{0}'s teleport was interrupted!"},
  705.                 {"Unlimited", "Unlimited"},
  706.                 {
  707.                     "TPInfoGeneral", string.Join(NewLine, new[]
  708.                     {
  709.                         "Please specify the module you want to view the info of.",
  710.                         "The available modules are: ",
  711.                     })
  712.                 },
  713.                 {
  714.                     "TPHelpGeneral", string.Join(NewLine, new[]
  715.                     {
  716.                         "<color=yellow>/tpinfo</color> - Shows limits and cooldowns.",
  717.                         "Please specify the module you want to view the help of.",
  718.                         "The available modules are: ",
  719.                     })
  720.                 },
  721.                 {
  722.                     "TPHelpadmintp", string.Join(NewLine, new[]
  723.                     {
  724.                         "As an admin you have access to the following commands:",
  725.                         "<color=yellow>/tp \"targetplayer\"</color> - Teleports yourself to the target player.",
  726.                         "<color=yellow>/tp \"player\" \"targetplayer\"</color> - Teleports the player to the target player.",
  727.                         "<color=yellow>/tp x y z</color> - Teleports you to the set of coordinates.",
  728.                         "<color=yellow>/tpl</color> - Shows a list of saved locations.",
  729.                         "<color=yellow>/tpl \"location name\"</color> - Teleports you to a saved location.",
  730.                         "<color=yellow>/tpsave \"location name\"</color> - Saves your current position as the location name.",
  731.                         "<color=yellow>/tpremove \"location name\"</color> - Removes the location from your saved list.",
  732.                         "<color=yellow>/tpb</color> - Teleports you back to the place where you were before teleporting.",
  733.                         "<color=yellow>/home radius \"radius\"</color> - Find all homes in radius.",
  734.                         "<color=yellow>/home delete \"player name|id\" \"home name\"</color> - Remove a home from a player.",
  735.                         "<color=yellow>/home tp \"player name|id\" \"name\"</color> - Teleports you to the home location with the name 'name' from the player.",
  736.                         "<color=yellow>/home homes \"player name|id\"</color> - Shows you a list of all homes from the player."
  737.                     })
  738.                 },
  739.                 {
  740.                     "TPHelphome", string.Join(NewLine, new[]
  741.                     {
  742.                         "With the following commands you can set your home location to teleport back to:",
  743.                         "<color=yellow>/home add \"name\"</color> - Saves your current position as the location name.",
  744.                         "<color=yellow>/home list</color> - Shows you a list of all the locations you have saved.",
  745.                         "<color=yellow>/home remove \"name\"</color> - Removes the location of your saved homes.",
  746.                         "<color=yellow>/home \"name\"</color> - Teleports you to the home location."
  747.                     })
  748.                 },
  749.                 {
  750.                     "TPHelptpr", string.Join(NewLine, new[]
  751.                     {
  752.                         "With these commands you can request to be teleported to a player or accept someone else's request:",
  753.                         "<color=yellow>/tpr \"player name\"</color> - Sends a teleport request to the player.",
  754.                         "<color=yellow>/tpa</color> - Accepts an incoming teleport request.",
  755.                         "<color=yellow>/tpc</color> - Cancel teleport or request."
  756.                     })
  757.                 },
  758.                 {
  759.                     "TPSettingsGeneral", string.Join(NewLine, new[]
  760.                     {
  761.                         "Please specify the module you want to view the settings of. ",
  762.                         "The available modules are:",
  763.                     })
  764.                 },
  765.                 {
  766.                     "TPSettingshome", string.Join(NewLine, new[]
  767.                     {
  768.                         "Home System has the current settings enabled:",
  769.                         "Time between teleports: {0}",
  770.                         "Daily amount of teleports: {1}",
  771.                         "Amount of saved Home locations: {2}"
  772.                     })
  773.                 },
  774.                 {
  775.                     "TPSettingsbandit", string.Join(NewLine, new[]
  776.                     {
  777.                         "Bandit System has the current settings enabled:",
  778.                         "Time between teleports: {0}",
  779.                         "Daily amount of teleports: {1}"
  780.                     })
  781.                 },
  782.                 {
  783.                     "TPSettingsoutpost", string.Join(NewLine, new[]
  784.                     {
  785.                         "Outpost System has the current settings enabled:",
  786.                         "Time between teleports: {0}",
  787.                         "Daily amount of teleports: {1}"
  788.                     })
  789.                 },
  790.                 {
  791.                     "TPSettingstpr", string.Join(NewLine, new[]
  792.                     {
  793.                         "TPR System has the current settings enabled:",
  794.                         "Time between teleports: {0}",
  795.                         "Daily amount of teleports: {1}"
  796.                     })
  797.                 },
  798.                 {
  799.                     "TPSettingstown", string.Join(NewLine, new[]
  800.                     {
  801.                         "Town System has the current settings enabled:",
  802.                         "Time between teleports: {0}",
  803.                         "Daily amount of teleports: {1}"
  804.                     })
  805.                 },
  806.                 {"TPT_True", "enabled"},
  807.                 {"TPT_False", "disabled"},
  808.                 {"TPT_clan", "TPT clan has been {0}."},
  809.                 {"TPT_friend", "TPT friend has been {0}."},
  810.                 {"TPT_team", "TPT team has been {0}."},
  811.                 {"NotValidTPT", "Not valid, player is not"},
  812.                 {"NotValidTPTFriend", " a friend!"},
  813.                 {"NotValidTPTTeam", " on your team!"},
  814.                 {"NotValidTPTClan", " in your clan!"},
  815.                 {"TPTInfo", "`<color=yellow>/tpt clan|team|friend</color>` - toggle allowing/blocking of players trying to TPT to you via one of these options."},
  816.                 {"PlayerNotFound", "The specified player couldn't be found please try again!"},
  817.                 {"MultiplePlayers", "Found multiple players: {0}"},
  818.                 {"CantTeleportToSelf", "You can't teleport to yourself!"},
  819.                 {"CantTeleportPlayerToSelf", "You can't teleport a player to himself!"},
  820.                 {"TeleportPending", "You can't initiate another teleport while you have a teleport pending!"},
  821.                 {"TeleportPendingTarget", "You can't request a teleport to someone who's about to teleport!"},
  822.                 {"LocationExists", "A location with this name already exists at {0}!"},
  823.                 {"LocationExistsNearby", "A location with the name {0} already exists near this position!"},
  824.                 {"LocationNotFound", "Couldn't find a location with that name!"},
  825.                 {"NoPreviousLocationSaved", "No previous location saved!"},
  826.                 {"HomeExists", "You have already saved a home location by this name!"},
  827.                 {"HomeExistsNearby", "A home location with the name {0} already exists near this position!"},
  828.                 {"HomeNotFound", "Couldn't find your home with that name!"},
  829.                 {"InvalidCoordinates", "The coordinates you've entered are invalid!"},
  830.                 {"InvalidHelpModule", "Invalid module supplied!"},
  831.                 {"InvalidCharacter", "You have used an invalid character, please limit yourself to the letters a to z and numbers."},
  832.                 {
  833.                     "SyntaxCommandTP", string.Join(NewLine, new[]
  834.                     {
  835.                         "A Syntax Error Occurred!",
  836.                         "You can only use the <color=yellow>/tp</color> command as follows:",
  837.                         "<color=yellow>/tp \"targetplayer\"</color> - Teleports yourself to the target player.",
  838.                         "<color=yellow>/tp \"player\" \"targetplayer\"</color> - Teleports the player to the target player.",
  839.                         "<color=yellow>/tp x y z</color> - Teleports you to the set of coordinates.",
  840.                         "<color=yellow>/tp \"player\" x y z</color> - Teleports the player to the set of coordinates."
  841.                     })
  842.                 },
  843.                 {
  844.                     "SyntaxCommandTPL", string.Join(NewLine, new[]
  845.                     {
  846.                         "A Syntax Error Occurred!",
  847.                         "You can only use the <color=yellow>/tpl</color> command as follows:",
  848.                         "<color=yellow>/tpl</color> - Shows a list of saved locations.",
  849.                         "<color=yellow>/tpl \"location name\"</color> - Teleports you to a saved location."
  850.                     })
  851.                 },
  852.                 {
  853.                     "SyntaxCommandTPSave", string.Join(NewLine, new[]
  854.                     {
  855.                         "A Syntax Error Occurred!",
  856.                         "You can only use the <color=yellow>/tpsave</color> command as follows:",
  857.                         "<color=yellow>/tpsave \"location name\"</color> - Saves your current position as 'location name'."
  858.                     })
  859.                 },
  860.                 {
  861.                     "SyntaxCommandTPRemove", string.Join(NewLine, new[]
  862.                     {
  863.                         "A Syntax Error Occurred!",
  864.                         "You can only use the <color=yellow>/tpremove</color> command as follows:",
  865.                         "<color=yellow>/tpremove \"location name\"</color> - Removes the location with the name 'location name'."
  866.                     })
  867.                 },
  868.                 {
  869.                     "SyntaxCommandTPN", string.Join(NewLine, new[]
  870.                     {
  871.                         "A Syntax Error Occurred!",
  872.                         "You can only use the <color=yellow>/tpn</color> command as follows:",
  873.                         "<color=yellow>/tpn \"targetplayer\"</color> - Teleports yourself the default distance behind the target player.",
  874.                         "<color=yellow>/tpn \"targetplayer\" \"distance\"</color> - Teleports you the specified distance behind the target player."
  875.                     })
  876.                 },
  877.                 {
  878.                     "SyntaxCommandSetHome", string.Join(NewLine, new[]
  879.                     {
  880.                         "A Syntax Error Occurred!",
  881.                         "You can only use the <color=yellow>/home add</color> command as follows:",
  882.                         "<color=yellow>/home add \"name\"</color> - Saves the current location as your home with the name 'name'."
  883.                     })
  884.                 },
  885.                 {
  886.                     "SyntaxCommandRemoveHome", string.Join(NewLine, new[]
  887.                     {
  888.                         "A Syntax Error Occurred!",
  889.                         "You can only use the <color=yellow>/home remove</color> command as follows:",
  890.                         "<color=yellow>/home remove \"name\"</color> - Removes the home location with the name 'name'."
  891.                     })
  892.                 },
  893.                 {
  894.                     "SyntaxCommandHome", string.Join(NewLine, new[]
  895.                     {
  896.                         "A Syntax Error Occurred!",
  897.                         "You can only use the <color=yellow>/home</color> command as follows:",
  898.                         "<color=yellow>/home \"name\"</color> - Teleports yourself to your home with the name 'name'.",
  899.                         "<color=yellow>/home \"name\" pay</color> - Teleports yourself to your home with the name 'name', avoiding cooldown by paying for it.",
  900.                         "<color=yellow>/home add \"name\"</color> - Saves the current location as your home with the name 'name'.",
  901.                         "<color=yellow>/home list</color> - Shows you a list of all your saved home locations.",
  902.                         "<color=yellow>/home remove \"name\"</color> - Removes the home location with the name 'name'."
  903.                     })
  904.                 },
  905.                 {
  906.                     "SyntaxCommandHomeAdmin", string.Join(NewLine, new[]
  907.                     {
  908.                         "<color=yellow>/home radius \"radius\"</color> - Shows you a list of all homes in radius(10).",
  909.                         "<color=yellow>/home delete \"player name|id\" \"name\"</color> - Removes the home location with the name 'name' from the player.",
  910.                         "<color=yellow>/home tp \"player name|id\" \"name\"</color> - Teleports you to the home location with the name 'name' from the player.",
  911.                         "<color=yellow>/home homes \"player name|id\"</color> - Shows you a list of all homes from the player."
  912.                     })
  913.                 },
  914.                 {
  915.                     "SyntaxCommandTown", string.Join(NewLine, new[]
  916.                     {
  917.                         "A Syntax Error Occurred!",
  918.                         "You can only use the <color=yellow>/town</color> command as follows:",
  919.                         "<color=yellow>/town</color> - Teleports yourself to town.",
  920.                         "<color=yellow>/town pay</color> - Teleports yourself to town, paying the penalty."
  921.                     })
  922.                 },
  923.                 {
  924.                     "SyntaxCommandTownAdmin", string.Join(NewLine, new[]
  925.                     {
  926.                         "<color=yellow>/town set</color> - Saves the current location as town.",
  927.                     })
  928.                 },
  929.                 {
  930.                     "SyntaxCommandOutpost", string.Join(NewLine, new[]
  931.                     {
  932.                         "A Syntax Error Occurred!",
  933.                         "You can only use the <color=yellow>/outpost</color> command as follows:",
  934.                         "<color=yellow>/outpost</color> - Teleports yourself to the Outpost.",
  935.                         "<color=yellow>/outpost pay</color> - Teleports yourself to the Outpost, paying the penalty."
  936.                     })
  937.                 },
  938.                 {
  939.                     "SyntaxCommandOutpostAdmin", string.Join(NewLine, new[]
  940.                     {
  941.                         "<color=yellow>/outpost set</color> - Saves the current location as Outpost.",
  942.                     })
  943.                 },
  944.                 {
  945.                     "SyntaxCommandBandit", string.Join(NewLine, new[]
  946.                     {
  947.                         "A Syntax Error Occurred!",
  948.                         "You can only use the <color=yellow>/bandit</color> command as follows:",
  949.                         "<color=yellow>/bandit</color> - Teleports yourself to the Bandit Town.",
  950.                         "<color=yellow>/bandit pay</color> - Teleports yourself to the Bandit Town, paying the penalty."
  951.                     })
  952.                 },
  953.                 {
  954.                     "SyntaxCommandBanditAdmin", string.Join(NewLine, new[]
  955.                     {
  956.                         "<color=yellow>/bandit set</color> - Saves the current location as Bandit Town.",
  957.                     })
  958.                 },
  959.                 {
  960.                     "SyntaxCommandHomeDelete", string.Join(NewLine, new[]
  961.                     {
  962.                         "A Syntax Error Occurred!",
  963.                         "You can only use the <color=yellow>/home delete</color> command as follows:",
  964.                         "<color=yellow>/home delete \"player name|id\" \"name\"</color> - Removes the home location with the name 'name' from the player."
  965.                     })
  966.                 },
  967.                 {
  968.                     "SyntaxCommandHomeAdminTP", string.Join(NewLine, new[]
  969.                     {
  970.                         "A Syntax Error Occurred!",
  971.                         "You can only use the <color=yellow>/home tp</color> command as follows:",
  972.                         "<color=yellow>/home tp \"player name|id\" \"name\"</color> - Teleports you to the home location with the name 'name' from the player."
  973.                     })
  974.                 },
  975.                 {
  976.                     "SyntaxCommandHomeHomes", string.Join(NewLine, new[]
  977.                     {
  978.                         "A Syntax Error Occurred!",
  979.                         "You can only use the <color=yellow>/home homes</color> command as follows:",
  980.                         "<color=yellow>/home homes \"player name|id\"</color> - Shows you a list of all homes from the player."
  981.                     })
  982.                 },
  983.                 {
  984.                     "SyntaxCommandListHomes", string.Join(NewLine, new[]
  985.                     {
  986.                         "A Syntax Error Occurred!",
  987.                         "You can only use the <color=yellow>/home list</color> command as follows:",
  988.                         "<color=yellow>/home list</color> - Shows you a list of all your saved home locations."
  989.                     })
  990.                 },
  991.                 {
  992.                     "SyntaxCommandTPT", string.Join(NewLine, new[]
  993.                     {
  994.                         "A Syntax Error Occurred!",
  995.                         "You can only use the <color=yellow>/tpt</color> command as follows:",
  996.                         "<color=yellow>/tpt \"player name\"</color> - Teleports you to a team or clan member."
  997.                     })
  998.                 },
  999.                 {
  1000.                     "SyntaxCommandTPR", string.Join(NewLine, new[]
  1001.                     {
  1002.                         "A Syntax Error Occurred!",
  1003.                         "You can only use the <color=yellow>/tpr</color> command as follows:",
  1004.                         "<color=yellow>/tpr \"player name\"</color> - Sends out a teleport request to 'player name'."
  1005.                     })
  1006.                 },
  1007.                 {
  1008.                     "SyntaxCommandTPA", string.Join(NewLine, new[]
  1009.                     {
  1010.                         "A Syntax Error Occurred!",
  1011.                         "You can only use the <color=yellow>/tpa</color> command as follows:",
  1012.                         "<color=yellow>/tpa</color> - Accepts an incoming teleport request."
  1013.                     })
  1014.                 },
  1015.                 {
  1016.                     "SyntaxCommandTPC", string.Join(NewLine, new[]
  1017.                     {
  1018.                         "A Syntax Error Occurred!",
  1019.                         "You can only use the <color=yellow>/tpc</color> command as follows:",
  1020.                         "<color=yellow>/tpc</color> - Cancels an teleport request."
  1021.                     })
  1022.                 },
  1023.                 {
  1024.                     "SyntaxConsoleCommandToPos", string.Join(NewLine, new[]
  1025.                     {
  1026.                         "A Syntax Error Occurred!",
  1027.                         "You can only use the <color=orange>teleport.topos</color> console command as follows:",
  1028.                         " > <color=orange>teleport.topos \"player\" x y z</color>"
  1029.                     })
  1030.                 },
  1031.                 {
  1032.                     "SyntaxConsoleCommandToPlayer", string.Join(NewLine, new[]
  1033.                     {
  1034.                         "A Syntax Error Occurred!",
  1035.                         "You can only use the <color=orange>teleport.toplayer</color> console command as follows:",
  1036.                         " > <color=orange>teleport.toplayer \"player\" \"target player\"</color>"
  1037.                     })
  1038.                 },
  1039.                 {"LogTeleport", "{0} teleported to {1}."},
  1040.                 {"LogTeleportPlayer", "{0} teleported {1} to {2}."},
  1041.                 {"LogTeleportBack", "{0} teleported back to previous location."}
  1042.             }, this);
  1043.  
  1044.             lang.RegisterMessages(new Dictionary<string, string>
  1045.             {
  1046.                 {"AdminTP", "Вы телепортированы к {0}!"},
  1047.                 {"AdminTPTarget", "{0} телепортирован к вам!"},
  1048.                 {"AdminTPPlayers", "Вы телепортировали {0} к {1}!"},
  1049.                 {"AdminTPPlayer", "{0} телепортировал вас к {1}!"},
  1050.                 {"AdminTPPlayerTarget", "{0} телепортировал {1} к вам!"},
  1051.                 {"AdminTPCoordinates", "Вы телепортированы к {0}!"},
  1052.                 {"AdminTPTargetCoordinates", "Вы телепортировали {0} к {1}!"},
  1053.                 {"AdminTPOutOfBounds", "Вы попытались телепортироваться на координаты, вне границ карты!"},
  1054.                 {"AdminTPBoundaries", "Значения X и Z должны быть между -{0} и {0}, а значение Y между -100 и 2000!"},
  1055.                 {"AdminTPLocation", "Вы телепортированы к {0}!"},
  1056.                 {"AdminTPLocationSave", "Вы сохранили текущее местоположение!"},
  1057.                 {"AdminTPLocationRemove", "Вы удалили местоположение {0}!"},
  1058.                 {"AdminLocationList", "Доступны следующие местоположения:"},
  1059.                 {"AdminLocationListEmpty", "Вы не сохранили никаких местоположений!"},
  1060.                 {"AdminTPBack", "Вы телепортированы назад в ваше предыдущее местоположение!"},
  1061.                 {"AdminTPBackSave", "Ваше предыдущее местоположение сохранено, используйте <color=yellow>/tpb</color>, чтобы телепортироваться назад!"},
  1062.                 {"AdminTPTargetCoordinatesTarget", "{0} телепортировал вас к {1}!"},
  1063.                 {"AdminTPConsoleTP", "Вы были телепортированы к {0}"},
  1064.                 {"AdminTPConsoleTPPlayer", "Вы были телепортированы к {0}"},
  1065.                 {"AdminTPConsoleTPPlayerTarget", "{0} был телепортирован к вам!"},
  1066.                 {"HomeTP", "Вы телепортированы в ваш дом '{0}'!"},
  1067.                 {"HomeAdminTP", "Вы телепортированы к дому '{1}' принадлежащему {0}!"},
  1068.                 {"HomeSave", "Вы сохранили текущее местоположение как ваш дом!"},
  1069.                 {"HomeNoFoundation", "Использовать местоположение в качестве дома разрешено только на фундаменте!"},
  1070.                 {"HomeFoundationNotOwned", "Вы не можете использовать команду home в чужом доме."},
  1071.                 {"HomeFoundationUnderneathFoundation", "Вы не можете использовать команду home на фундаменте, который находится под другим фундаментом."},
  1072.                 {"HomeFoundationNotFriendsOwned", "Вы, или ваш друг должны быть владельцем дома, чтобы использовать команду home!"},
  1073.                 {"HomeRemovedInvalid", "Ваш дом '{0}' был удалён потому, что не на фундаменте, или у фундамента новый владелец!"},
  1074.                 {"HighWallCollision", "Столкновение Высоких Стен!"},
  1075.                 {"HomeRemovedInsideBlock", "Ваш дом '{0}' был удалён потому, что внутри фундамента!"},
  1076.                 {"HomeRemove", "Вы удалили свой дом {0}!"},
  1077.                 {"HomeDelete", "Вы удалили дом '{1}' принадлежащий {0}!"},
  1078.                 {"HomeList", "Доступны следующие дома:"},
  1079.                 {"HomeListEmpty", "Вы не сохранили ни одного дома!"},
  1080.                 {"HomeMaxLocations", "Невозможно установить здесь ваш дом, вы достигли лимита в {0} домов!"},
  1081.                 {"HomeQuota", "Вы установили {0} из {1} максимально возможных домов!"},
  1082.                 {"HomeTPStarted", "Телепортация в ваш дом {0} через {1} секунд!"},
  1083.                 {"PayToHome", "Стандартный платеж {0} распространяется на все телепорты домой!"},
  1084.                 {"PayToTown", "Стандартный платеж {0} распространяется на все телепорты в город!"},
  1085.                 {"PayToTPR", "Стандартный платеж {0} распространяется на все tpr'ы!"},
  1086.                 {"HomeTPCooldown", "Ваш телепорт перезаряжается. Вам необходимо подождать {0} до следующей телепортации."},
  1087.                 {"HomeTPCooldownBypass", "Ваш телепорт был на перезарядке. Вы выбрали обойти это оплатив {0} с вашего баланса."},
  1088.                 {"HomeTPCooldownBypassF", "Ваш телепорт перезаряжается. У вас недостаточно средств - {0} - чтобы обойти."},
  1089.                 {"HomeTPCooldownBypassP", "Вы можете выбрать оплатить {0} чтобы обойти эту перезарядку." },
  1090.                 {"HomeTPCooldownBypassP2", "Напишите <color=yellow>/home \"название дома\" {0}</color>." },
  1091.                 {"HomeTPLimitReached", "Вы исчерпали ежедневный лимит {0} телепортаций сегодня!"},
  1092.                 {"HomeTPAmount", "У вас осталось {0} телепортаций домой сегодня!"},
  1093.                 {"HomesListWiped", "Вы очистили все местоположения, сохранённые как дом!"},
  1094.                 {"HomeTPBuildingBlocked", "Вы не можете сохранить местоположение в качестве дома, если у вас нет прав на строительство в этой зоне!"},
  1095.                 {"HomeTPSwimming", "Вы не можете устанавливать местоположение а качестве дома пока плывёте!"},
  1096.                 {"HomeTPCrafting", "Вы не можете устанавливать местоположение а качестве дома в процессе крафта!"},
  1097.                 {"Request", "Вы запросили телепортацию к {0}!"},
  1098.                 {"RequestTarget", "{0} запросил телепортацию к вам! Используйте <color=yellow>/tpa</color>, чтобы принять!"},
  1099.                 {"PendingRequest", "У вас уже есть активный запрос, отмените его, ожидайте подтверждения, либо отмены по таймауту!"},
  1100.                 {"PendingRequestTarget", "У игрока, к которому вы хотите телепортироваться уже есть активный запрос, попробуйте позже!"},
  1101.                 {"NoPendingRequest", "У вас нет активных запросов на телепортацию!"},
  1102.                 {"AcceptOnRoof", "Вы не можете принять запрос на телепортацию стоя на потолке, спуститесь на уровень фундамента!"},
  1103.                 {"Accept", "{0} принял ваш запрос! Телепортация через {1} секунд!"},
  1104.                 {"AcceptTarget", "Вы приняли запрос на телепортацию {0}!"},
  1105.                 {"NotAllowed", "Вам не разрешено использовать эту команду!"},
  1106.                 {"Success", "Вы телепортированы к {0}!"},
  1107.                 {"SuccessTarget", "{0} телепортирован к вам!"},
  1108.                 {"Cancelled", "Ваш запрос на телепортацию к {0} был отменён!"},
  1109.                 {"CancelledTarget", "Запрос на телепортацию {0} был отменён!"},
  1110.                 {"TPCancelled", "Ваша телепортация отменена!"},
  1111.                 {"TPCancelledTarget", "{0} отменил телепортацию!"},
  1112.                 {"TPYouCancelledTarget", "Вы отменили телепортацию {0}!"},
  1113.                 {"TimedOut", "{0} не ответил на ваш запрос во время!"},
  1114.                 {"TimedOutTarget", "Вы не ответили вовремя на запрос телепортации от {0}!"},
  1115.                 {"TargetDisconnected", "{0} отключился, ваша телепортация отменена!"},
  1116.                 {"TPRCooldown", "Ваши запросы на телепортацию в данный момент на перезарядке. Вам необходимо подождать {0} прежде чем отправить следующий запрос."},
  1117.                 {"TPRCooldownBypass", "Ваши запросы на телепортацию были на перезарядке. Вы выбрали обойти это оплатив {0} с вашего баланса."},
  1118.                 {"TPRCooldownBypassF", "Ваши запросы на телепортацию в данный момент на перезарядке. У вас недостаточно средств - {0} - чтобы обойти это."},
  1119.                 {"TPRCooldownBypassP", "Вы можете выбрать оплатить {0} чтобы обойти эту перезарядку." },
  1120.                 {"TPMoney", "{0} списано с вашего аккаунта!"},
  1121.                 {"TPNoMoney", "У вас нет {0} ни на одном аккаунте!"},
  1122.                 {"TPRCooldownBypassP2", "Напишите <color=yellow>/tpr {0}</color>." },
  1123.                 {"TPRCooldownBypassP2a", "Напишите <color=yellow>/tpr \"имя игрока\" {0}</color>." },
  1124.                 {"TPRLimitReached", "Вы исчерпали ежедневный лимит {0} запросов на телепортацию сегодня!"},
  1125.                 {"TPRAmount", "У вас осталось {0} запросов на телепортацию на сегодня!"},
  1126.                 {"TPRTarget", "Ваша цель в данный момент не доступна!"},
  1127.                 {"TPDead", "Вы не можете телепортироваться, пока мертвы!"},
  1128.                 {"TPWounded", "Вы не можете телепортироваться, будучи раненым!"},
  1129.                 {"TPTooCold", "Вам слишком холодно для телепортации!"},
  1130.                 {"TPTooHot", "Вам слишком жарко для телепортации!"},
  1131.                 {"TPHostile", "Невозможно телепортироваться в город NPC или лагерь бандитов пока враждебен!"},
  1132.                 {"HostileTimer", "Телепорт станет доступен через {0} минут."},
  1133.                 {"TPMounted", "Вы не можете телепортироваться, когда сидите!"},
  1134.                 {"TPBuildingBlocked", "Вы не можете телепортироваться, находясь в зоне блокировки строительства!"},
  1135.                 {"TPAboveWater", "Вы не можете телепортироваться находясь над водой!"},
  1136.                 {"TPTargetBuildingBlocked", "Вы не можете телепортироваться в зону, где блокировано строительство!"},
  1137.                 {"TPTargetInsideBlock", "Вы не можете телепортироваться в фундамент!"},
  1138.                 {"TPSwimming", "Вы не можете телепортироваться, пока плывёте!"},
  1139.                 {"TPCargoShip", "Вы не можете телепортироваться с грузового корабля!"},
  1140.                 {"TPOilRig", "Вы не можете телепортироваться с нефтяной вышки!"},
  1141.                 {"TPExcavator", "Вы не можете телепортироваться с экскаватора!"},
  1142.                 {"TPHotAirBalloon", "Вы не можете телепортироваться с или на воздушный шар!"},
  1143.                 {"TPLift", "Вы не можете телепортироваться в лифте или подъемнике!"},
  1144.                 {"TPBucketLift", "Вы не можете телепортироваться в подъемнике!"},
  1145.                 {"TPRegLift", "Вы не можете телепортироваться в лифте!"},
  1146.                 {"TPSafeZone", "Вы не можете телепортироваться из безопасной зоны!"},
  1147.                 {"TPFlagZone", "Вы не можете телепортироваться из этой зоны!"},
  1148.                 {"TPNoEscapeBlocked", "Вы не можете телепортироваться пока активна блокировка!"},
  1149.                 {"TPCrafting", "Вы не можете телепортироваться в процессе крафта!"},
  1150.                 {"TPBlockedItem", "Вы не можете телепортироваться пока несёте: {0}!"},
  1151.                 {"TooCloseToMon", "Вы не можете телепортироваться так близко к {0}!"},
  1152.                 {"TooCloseToCave", "Вы не можете телепортироваться так близко к пещере!"},
  1153.                 {"HomeTooCloseToCave", "Вы не можете сохранить местоположение в качестве дома так близко к пещере!"},
  1154.                 {"TownTP", "Вы телепортрованы в город!"},
  1155.                 {"TownTPNotSet", "Город не задан!"},
  1156.                 {"TownTPDisabled", "Город в данный момент не активирован!"},
  1157.                 {"TownTPLocation", "Вы задали местоположение города {0}!"},
  1158.                 {"TownTPStarted", "Телепортация в город через {0} секунд!"},
  1159.                 {"TownTPCooldown", "Ваш телепорт в данный момент на перезарядке. Вам необходимо подождать {0} до следующей телепортации."},
  1160.                 {"TownTPCooldownBypass", "Ваш запрос на телепортацию был на перезарядке. Вы выбрали обойти это оплатив {0} с вашего баланса."},
  1161.                 {"TownTPCooldownBypassF", "Ваш телепорт в данный момент на перезарядке. У вас недостаточно средств - {0} - чтобы обойти это."},
  1162.                 {"TownTPCooldownBypassP", "Вы можете выбрать оплатить {0} чтобы обойти эту перезарядку." },
  1163.                 {"TownTPCooldownBypassP2", "Напишите <color=yellow>/town {0}</color>." },
  1164.                 {"TownTPLimitReached", "Вы исчерпали ежедневный лимит {0} телепортаций на сегодня!"},
  1165.                 {"TownTPAmount", "У вас осталось {0} телепортаций в город на сегодня!"},
  1166.  
  1167.                 {"OutpostTP", "Вы телепортированы в город NPC!"},
  1168.                 {"OutpostTPNotSet", "Город NPC в данный момент не установлен!"},
  1169.                 {"OutpostTPDisabled", "Город NPC в данный момент не активирован!"},
  1170.                 {"OutpostTPDisabledConfig", "Город NPC не включен в конфиг-файле"},
  1171.                 {"OutpostTPDisabledNoLocation", "Город NPC в данный момент не активирован, местоположение не задано и автоматическое генерирование местоположения отключено!"},
  1172.                 {"OutpostTPDisabledNoLocationAutoGen", "Город NPC отключен потому, что автоматическое генерирование местоположения не удалось!"},
  1173.                 {"OutpostTPLocation", "Вы установили местоположение города NPC {0}!"},
  1174.                 {"OutpostTPStarted", "Телепортация в город NPC через {0} секунд!"},
  1175.                 {"OutpostTPCooldown", "Ваш телепорт в данный момент на перезарядке. Вам необходимо подождать {0} до следующей телепортации."},
  1176.                 {"OutpostTPCooldownBypass", "Ваш запрос на телепортацию был на перезарядке. Вы выбрали обойти это оплатив {0} с вашего баланса."},
  1177.                 {"OutpostTPCooldownBypassF", "Ваш телепорт в данный момент на перезарядке. У вас недостаточно средств - {0} - чтобы обойти это."},
  1178.                 {"OutpostTPCooldownBypassP", "Вы можете выбрать оплатить {0} чтобы обойти эту перезарядку." },
  1179.                 {"OutpostTPCooldownBypassP2", "Напишите <color=yellow>/outpost {0}</color>." },
  1180.                 {"OutpostTPLimitReached", "Вы исчерпали ежедневный лимит {0} телепортаций на сегодня!"},
  1181.                 {"OutpostTPAmount", "У вас осталось {0} телепортаций в город NPC на сегодня!"},
  1182.  
  1183.                 {"BanditTP", "Вы телепортированы в лагерь бандитов!"},
  1184.                 {"BanditTPNotSet", "Лагерь бандитов в данный момент не установлен!"},
  1185.                 {"BanditTPDisabled", "Лагерь бандитов в данный момент не активирован!"},
  1186.                 {"BanditTPDisabledConfig", "Лагерь бандитов не включен в конфиг-файле!"},
  1187.                 {"BanditTPDisabledNoLocation", "Лагерь бандитов в данный момент не активирован, местоположение не задано и автоматическое генерирование местоположения отключено!"},
  1188.                 {"BanditTPDisabledNoLocationAutoGen", "Лагерь бандитов отключен потому, что автоматическое генерирование местоположения не удалось!"},
  1189.                 {"BanditTPLocation", "Вы установили местоположение лагеря бандитов {0}!"},
  1190.                 {"BanditTPStarted", "Телепортация в лагерь бандитов через {0} секунд!"},
  1191.                 {"BanditTPCooldown", "Ваш телепорт в данный момент на перезарядке. Вам необходимо подождать {0} до следующей телепортации."},
  1192.                 {"BanditTPCooldownBypass", "Ваш запрос на телепортацию был на перезарядке. Вы выбрали обойти это оплатив {0} с вашего баланса."},
  1193.                 {"BanditTPCooldownBypassF", "Ваш телепорт в данный момент на перезарядке. У вас недостаточно средств - {0} - чтобы обойти это."},
  1194.                 {"BanditTPCooldownBypassP", "Вы можете выбрать оплатить {0} чтобы обойти эту перезарядку." },
  1195.                 {"BanditTPCooldownBypassP2", "Напишите <color=yellow>/bandit {0}</color>." },
  1196.                 {"BanditTPLimitReached", "Вы исчерпали ежедневный лимит {0} телепортаций на сегодня!"},
  1197.                 {"BanditTPAmount", "У вас осталось {0} телепортаций в лагерь бандитов на сегодня!"},
  1198.  
  1199.                 {"Interrupted", "Ваша телепортация была прервана!"},
  1200.                 {"InterruptedTarget", "Телепортация {0} была прервана!"},
  1201.                 {"Unlimited", "Не ограничено"},
  1202.                 {
  1203.                     "TPInfoGeneral", string.Join(NewLine, new[]
  1204.                     {
  1205.                         "Пожалуйста, укажите модуль, о котором вы хотите просмотреть информацию.",
  1206.                         "Доступные модули: ",
  1207.                     })
  1208.                 },
  1209.                 {
  1210.                     "TPHelpGeneral", string.Join(NewLine, new[]
  1211.                     {
  1212.                         "<color=yellow>/tpinfo</color> - Отображает лимиты и перезарядки.",
  1213.                         "Пожалуйста, укажите модуль, о котором вы хотите просмотреть помощь.",
  1214.                         "Доступные модули: ",
  1215.                     })
  1216.                 },
  1217.                 {
  1218.                     "TPHelpadmintp", string.Join(NewLine, new[]
  1219.                     {
  1220.                         "Как админ, вы имеете доступ к следующим командам:",
  1221.                         "<color=yellow>/tp \"имя игрока\"</color> - Телепортирует вас к указанному игроку.",
  1222.                         "<color=yellow>/tp \"имя игрока\" \"имя игрока 2\"</color> - Телепортирует игрока с именем 'имя игрока' к игроку 'имя игрока 2'.",
  1223.                         "<color=yellow>/tp x y z</color> - Телепортирует вас на указанные координаты.",
  1224.                         "<color=yellow>/tpl</color> - Отображает список сохранённых местоположений.",
  1225.                         "<color=yellow>/tpl \"название местоположения\"</color> - Телепортирует вас в сохранённое местоположение.",
  1226.                         "<color=yellow>/tpsave \"название местоположения\"</color> - Сохраняет ваше текущее местоположение с указанным названием.",
  1227.                         "<color=yellow>/tpremove \"название местоположения\"</color> - Удаляет местоположение из списка сохранённых.",
  1228.                         "<color=yellow>/tpb</color> - Телепортирует вас назад на место, где вы были перед телепортацией.",
  1229.                         "<color=yellow>/home radius \"радиус\"</color> - Найти все дома в радиусе.",
  1230.                         "<color=yellow>/home delete \"имя игрока или ID\" \"название дома\"</color> - Удаляет дом с указанным именем принадлежащий указанному игроку.",
  1231.                         "<color=yellow>/home tp \"имя игрока или ID\" \"название дома\"</color> - Телепортирует вас в дом игрока с указанным названием принадлежащий указанному игроку.",
  1232.                         "<color=yellow>/home homes \"имя игрока или ID\"</color> - Отображает вам список всех домов, принадлежащих указанному игроку."
  1233.                     })
  1234.                 },
  1235.                 {
  1236.                     "TPHelphome", string.Join(NewLine, new[]
  1237.                     {
  1238.                         "Используя следующие команды, вы можете установить местоположение вашего дома, чтобы затем в него телепортироваться:",
  1239.                         "<color=yellow>/home add \"название дома\"</color> - Сохраняет ваше текущее местоположение как ваш дом с указанным названием.",
  1240.                         "<color=yellow>/home list</color> - Отображает список всех местоположений, сохранённых вами как дом.",
  1241.                         "<color=yellow>/home remove \"название дома\"</color> - Удаляет расположение сохранённого дома с указанным названием.",
  1242.                         "<color=yellow>/home \"название дома\"</color> - Телепортирует вас в местоположение дома с указанным названием."
  1243.                     })
  1244.                 },
  1245.                 {
  1246.                     "TPHelptpr", string.Join(NewLine, new[]
  1247.                     {
  1248.                         "Используя эти команды, вы можете отправить запрос на телепортацию к игроку, или принять чей-то запрос:",
  1249.                         "<color=yellow>/tpr \"имя игрока\"</color> - Отправляет запрос на телепортацию игроку с указанным именем.",
  1250.                         "<color=yellow>/tpa</color> - Принять входящий запрос на телепортацию.",
  1251.                         "<color=yellow>/tpc</color> - Отменить запрос на телепортацию."
  1252.                     })
  1253.                 },
  1254.                 {
  1255.                     "TPSettingsGeneral", string.Join(NewLine, new[]
  1256.                     {
  1257.                         "Пожалуйста, укажите модуль, настройки которого вы хотите просмотреть. ",
  1258.                         "Доступные модули:",
  1259.                     })
  1260.                 },
  1261.                 {
  1262.                     "TPSettingshome", string.Join(NewLine, new[]
  1263.                     {
  1264.                         "Система домов в данный момент имеет следующие включённые параметры:",
  1265.                         "Время между телепортами: {0}",
  1266.                         "Ежедневный лимит телепортаций: {1}",
  1267.                         "Количество сохранённых домов: {2}"
  1268.                     })
  1269.                 },
  1270.                 {
  1271.                     "TPSettingsbandit", string.Join(NewLine, new[]
  1272.                     {
  1273.                         "Система лагеря бандитов в данный момент имеет следующие включённые параметры:",
  1274.                         "Время между телепортами: {0}",
  1275.                         "Ежедневный лимит телепортаций: {1}"
  1276.                     })
  1277.                 },
  1278.                 {
  1279.                     "TPSettingsoutpost", string.Join(NewLine, new[]
  1280.                     {
  1281.                         "Система города NPC в данный момент имеет следующие включённые параметры:",
  1282.                         "Время между телепортами: {0}",
  1283.                         "Ежедневный лимит телепортаций: {1}"
  1284.                     })
  1285.                 },
  1286.                 {
  1287.                     "TPSettingstpr", string.Join(NewLine, new[]
  1288.                     {
  1289.                         "Система TPR в данный момент имеет следующие включённые параметры:",
  1290.                         "Время между телепортами: {0}",
  1291.                         "Ежедневный лимит телепортаций: {1}"
  1292.                     })
  1293.                 },
  1294.                 {
  1295.                     "TPSettingstown", string.Join(NewLine, new[]
  1296.                     {
  1297.                         "Система городов в данный момент имеет следующие включённые параметры:",
  1298.                         "Время между телепортами: {0}",
  1299.                         "Ежедневный лимит телепортаций: {1}"
  1300.                     })
  1301.                 },
  1302.                 {"TPT_True", "включено"},
  1303.                 {"TPT_False", "выключено"},
  1304.                 {"TPT_clan", "TPT clan has been {0}."},
  1305.                 {"TPT_friend", "TPT friend has been {0}."},
  1306.                 {"TPT_team", "TPT team has been {0}."},
  1307.                 {"NotValidTPT", "Неверно, игрок не"},
  1308.                 {"NotValidTPTFriend", " друг!"},
  1309.                 {"NotValidTPTTeam", " в вашей команде!"},
  1310.                 {"NotValidTPTClan", " в вашем клане!"},
  1311.                 {"TPTInfo", "`<color=yellow>/tpt clan|team|friend</color>` - чтобы разрешить/запретить игрокам пытающимся TPT к вам через одну из этих опций."},
  1312.                 {"PlayerNotFound", "Указанный игрок не обнаружен, пожалуйста попробуйте ещё раз!"},
  1313.                 {"MultiplePlayers", "Найдено несколько игроков: {0}"},
  1314.                 {"CantTeleportToSelf", "Вы не можете телепортироваться к себе!"},
  1315.                 {"CantTeleportPlayerToSelf", "Вы не можете телепортровать игрока к самому себе!"},
  1316.                 {"TeleportPending", "Вы не можете инициировать телепортацию, пока у вас есть активный запрос!"},
  1317.                 {"TeleportPendingTarget", "Вы не можете отправить запрос к тому, кто в процессе телепортации!"},
  1318.                 {"LocationExists", "Местоположение с таким названием уже существует в {0}!"},
  1319.                 {"LocationExistsNearby", "Местоположение с названием {0} уже существует рядом с текущей позицией!"},
  1320.                 {"LocationNotFound", "Не найдено местоположение с таким названием!"},
  1321.                 {"NoPreviousLocationSaved", "Предыдущее местоположение не сохранено!"},
  1322.                 {"HomeExists", "Вы уже сохранили дом с таким названием!"},
  1323.                 {"HomeExistsNearby", "Дом с названием {0} уже существует рядом с текущей позицией!"},
  1324.                 {"HomeNotFound", "Дом с таким названием не найден!"},
  1325.                 {"InvalidCoordinates", "Вы указали неверные координаты!"},
  1326.                 {"InvalidHelpModule", "Введен неверный модуль!"},
  1327.                 {"InvalidCharacter", "Вы использовали недопустимый символ, пожалуйста, ограничьте себя буквами от a до z и цифрами."},
  1328.                 {
  1329.                     "SyntaxCommandTP", string.Join(NewLine, new[]
  1330.                     {
  1331.                         "Произошла синтаксическая ошибка!",
  1332.                         "Использование команды <color=yellow>/tp</color> возможно только следующим образом:",
  1333.                         "<color=yellow>/tp \"имя игрока\"</color> - Телепортирует вас к указанному игроку.",
  1334.                         "<color=yellow>/tp \"имя игрока\" \"имя игрока 2\"</color> - Телепортирует игрока с именем 'имя игрока' к игроку 'имя игрока 2'.",
  1335.                         "<color=yellow>/tp x y z</color> - Телепортирует вас на указанные координаты.",
  1336.                         "<color=yellow>/tp \"имя игрока\" x y z</color> - Телепортирует игрока с именем 'имя игрока' на указанные координаты."
  1337.                     })
  1338.                 },
  1339.                 {
  1340.                     "SyntaxCommandTPL", string.Join(NewLine, new[]
  1341.                     {
  1342.                         "Произошла синтаксическая ошибка!",
  1343.                         "Использование команды <color=yellow>/tpl</color> возможно только следующим образом:",
  1344.                         "<color=yellow>/tpl</color> - Отображает список сохранённых местоположений.",
  1345.                         "<color=yellow>/tpl \"название местоположения\"</color> - Телепортирует вас в место с указанным названием."
  1346.                     })
  1347.                 },
  1348.                 {
  1349.                     "SyntaxCommandTPSave", string.Join(NewLine, new[]
  1350.                     {
  1351.                         "Произошла синтаксическая ошибка!",
  1352.                         "Использование команды <color=yellow>/tpsave</color> возможно только следующим образом:",
  1353.                         "<color=yellow>/tpsave \"название местоположения\"</color> - Сохраняет ваше текущее местоположение с указанным названием."
  1354.                     })
  1355.                 },
  1356.                 {
  1357.                     "SyntaxCommandTPRemove", string.Join(NewLine, new[]
  1358.                     {
  1359.                         "Произошла синтаксическая ошибка!",
  1360.                         "Использование команды <color=yellow>/tpremove</color> возможно только следующим образом:",
  1361.                         "<color=yellow>/tpremove \"название местоположения\"</color> - Удаляет местоположение с указанным названием."
  1362.                     })
  1363.                 },
  1364.                 {
  1365.                     "SyntaxCommandTPN", string.Join(NewLine, new[]
  1366.                     {
  1367.                         "Произошла синтаксическая ошибка!",
  1368.                         "Использование команды <color=yellow>/tpn</color> возможно только следующим образом:",
  1369.                         "<color=yellow>/tpn \"имя игрока\"</color> - Телепортирует вас на расстояние по умолчанию позади игрока с указанным именем.",
  1370.                         "<color=yellow>/tpn \"имя игрока\" \"расстояние\"</color> - Телепортирует вас на указанное расстояние позади игрока с указанным именем."
  1371.                     })
  1372.                 },
  1373.                 {
  1374.                     "SyntaxCommandSetHome", string.Join(NewLine, new[]
  1375.                     {
  1376.                         "Произошла синтаксическая ошибка!",
  1377.                         "Использование команды <color=yellow>/home add</color> возможно только следующим образом:",
  1378.                         "<color=yellow>/home add \"название\"</color> - Сохраняет ваше текущее местоположение как ваш дом с указанным названием."
  1379.                     })
  1380.                 },
  1381.                 {
  1382.                     "SyntaxCommandRemoveHome", string.Join(NewLine, new[]
  1383.                     {
  1384.                         "Произошла синтаксическая ошибка!",
  1385.                         "Использование команды <color=yellow>/home remove</color> возможно только следующим образом:",
  1386.                         "<color=yellow>/home remove \"название\"</color> - Удаляет местоположение дома с указанным названием."
  1387.                     })
  1388.                 },
  1389.                 {
  1390.                     "SyntaxCommandHome", string.Join(NewLine, new[]
  1391.                     {
  1392.                         "Произошла синтаксическая ошибка!",
  1393.                         "Использование команды <color=yellow>/home</color> возможно только следующим образом:",
  1394.                         "<color=yellow>/home \"название\"</color> - Телепортирует вас в ваш дом с указанным названием.",
  1395.                         "<color=yellow>/home \"название\" pay</color> - Телепортирует вас в ваш дом с указанным названием, избегая перезарядки, заплатив за это.",
  1396.                         "<color=yellow>/home add \"название\"</color> - Сохраняет ваше текущее местоположение как ваш дом с указанным названием.",
  1397.                         "<color=yellow>/home list</color> - Отображает список всех местоположений, сохранённых вами как дом.",
  1398.                         "<color=yellow>/home remove \"название\"</color> - Удаляет местоположение дома с указанным названием."
  1399.                     })
  1400.                 },
  1401.                 {
  1402.                     "SyntaxCommandHomeAdmin", string.Join(NewLine, new[]
  1403.                     {
  1404.                         "<color=yellow>/home radius \"радиус\"</color> - Отображает список всех домов в радиусе(10).",
  1405.                         "<color=yellow>/home delete \"имя игрока или ID\" \"название\"</color> - Удаляет дом с указанным названием, принадлежащий указанному игроку.",
  1406.                         "<color=yellow>/home tp \"имя игрока или ID\" \"название\"</color> - Телепортирует вас в дом с указанным названием, принадлежащий указанному игроку.",
  1407.                         "<color=yellow>/home homes \"имя игрока или ID\"</color> - Отображает вам список всех домов, принадлежащих указанному игроку."
  1408.                     })
  1409.                 },
  1410.                 {
  1411.                     "SyntaxCommandTown", string.Join(NewLine, new[]
  1412.                     {
  1413.                         "Произошла синтаксическая ошибка!",
  1414.                         "Использование команды <color=yellow>/town</color> возможно только следующим образом:",
  1415.                         "<color=yellow>/town</color> - Телепортирует вас в город.",
  1416.                         "<color=yellow>/town pay</color> - Телепортирует вас в город с оплатой штрафа."
  1417.                     })
  1418.                 },
  1419.                 {
  1420.                     "SyntaxCommandTownAdmin", string.Join(NewLine, new[]
  1421.                     {
  1422.                         "<color=yellow>/town set</color> - Сохраняет текущее местоположение как город.",
  1423.                     })
  1424.                 },
  1425.                 {
  1426.                     "SyntaxCommandOutpost", string.Join(NewLine, new[]
  1427.                     {
  1428.                         "Произошла синтаксическая ошибка!",
  1429.                         "Использование команды <color=yellow>/outpost</color> возможно только следующим образом:",
  1430.                         "<color=yellow>/outpost</color> - Телепортирует вас в город NPC.",
  1431.                         "<color=yellow>/outpost pay</color> - Телепортирует вас в город NPC с оплатой штрафа."
  1432.                     })
  1433.                 },
  1434.                 {
  1435.                     "SyntaxCommandOutpostAdmin", string.Join(NewLine, new[]
  1436.                     {
  1437.                         "<color=yellow>/outpost set</color> - Сохраняет текущее местоположение как город NPC.",
  1438.                     })
  1439.                 },
  1440.                 {
  1441.                     "SyntaxCommandBandit", string.Join(NewLine, new[]
  1442.                     {
  1443.                         "Произошла синтаксическая ошибка!",
  1444.                         "Использование команды <color=yellow>/bandit</color> возможно только следующим образом:",
  1445.                         "<color=yellow>/bandit</color> - Телепортирует вас в лагерь бандитов.",
  1446.                         "<color=yellow>/bandit pay</color> - Телепортирует вас в лагерь бандитов с оплатой штрафа."
  1447.                     })
  1448.                 },
  1449.                 {
  1450.                     "SyntaxCommandBanditAdmin", string.Join(NewLine, new[]
  1451.                     {
  1452.                         "<color=yellow>/bandit set</color> - Сохраняет текущее местоположение как лагерь бандитов.",
  1453.                     })
  1454.                 },
  1455.                 {
  1456.                     "SyntaxCommandHomeDelete", string.Join(NewLine, new[]
  1457.                     {
  1458.                         "Произошла синтаксическая ошибка!",
  1459.                         "Использование команды <color=yellow>/home delete</color> возможно только следующим образом:",
  1460.                         "<color=yellow>/home delete \"имя игрока или ID\" \"название\"</color> - Удаляет дом с указанным названием, принадлежащий указанному игроку."
  1461.                     })
  1462.                 },
  1463.                 {
  1464.                     "SyntaxCommandHomeAdminTP", string.Join(NewLine, new[]
  1465.                     {
  1466.                         "Произошла синтаксическая ошибка!",
  1467.                         "Использование команды <color=yellow>/home tp</color> возможно только следующим образом:",
  1468.                         "<color=yellow>/home tp \"имя игрока или ID\" \"название\"</color> - Телепортирует вас в дом игрока с указанным названием, принадлежащий указанному игроку."
  1469.                     })
  1470.                 },
  1471.                 {
  1472.                     "SyntaxCommandHomeHomes", string.Join(NewLine, new[]
  1473.                     {
  1474.                         "Произошла синтаксическая ошибка!",
  1475.                         "Использование команды <color=yellow>/home homes</color> возможно только следующим образом:",
  1476.                         "<color=yellow>/home homes \"имя игрока или ID\"</color> - Отображает вам список всех домов, принадлежащих указанному игроку."
  1477.                     })
  1478.                 },
  1479.                 {
  1480.                     "SyntaxCommandListHomes", string.Join(NewLine, new[]
  1481.                     {
  1482.                         "Произошла синтаксическая ошибка!",
  1483.                         "Использование команды <color=yellow>/home list</color> возможно только следующим образом:",
  1484.                         "<color=yellow>/home list</color> - Отображает список всех местоположений, сохранённых вами как дом."
  1485.                     })
  1486.                 },
  1487.                 {
  1488.                     "SyntaxCommandTPT", string.Join(NewLine, new[]
  1489.                     {
  1490.                         "Произошла синтаксическая ошибка!",
  1491.                         "Использование команды <color=yellow>/tpt</color> возможно только следующим образом:",
  1492.                         "<color=yellow>/tpt \"имя игрока или ID\"</color> - Телепортирует вас к участнику команды, или клана."
  1493.                     })
  1494.                 },
  1495.                 {
  1496.                     "SyntaxCommandTPR", string.Join(NewLine, new[]
  1497.                     {
  1498.                         "Произошла синтаксическая ошибка!",
  1499.                         "Использование команды <color=yellow>/tpr</color> возможно только следующим образом:",
  1500.                         "<color=yellow>/tpr \"имя игрока или ID\"</color> - Отправляет указанному игроку запрос на телепортацию."
  1501.                     })
  1502.                 },
  1503.                 {
  1504.                     "SyntaxCommandTPA", string.Join(NewLine, new[]
  1505.                     {
  1506.                         "Произошла синтаксическая ошибка!",
  1507.                         "Использование команды <color=yellow>/tpa</color> возможно только следующим образом:",
  1508.                         "<color=yellow>/tpa</color> - Принять входящий запрос на телепортацию."
  1509.                     })
  1510.                 },
  1511.                 {
  1512.                     "SyntaxCommandTPC", string.Join(NewLine, new[]
  1513.                     {
  1514.                         "Произошла синтаксическая ошибка!",
  1515.                         "Использование команды <color=yellow>/tpc</color> возможно только следующим образом:",
  1516.                         "<color=yellow>/tpc</color> - Отменить запрос на телепортацию."
  1517.                     })
  1518.                 },
  1519.                 {
  1520.                     "SyntaxConsoleCommandToPos", string.Join(NewLine, new[]
  1521.                     {
  1522.                         "Произошла синтаксическая ошибка!",
  1523.                         "Использование консольной команды <color=orange>teleport.topos</color> возможно только следующим образом:",
  1524.                         " > <color=orange>teleport.topos \"имя игрока\" x y z</color>"
  1525.                     })
  1526.                 },
  1527.                 {
  1528.                     "SyntaxConsoleCommandToPlayer", string.Join(NewLine, new[]
  1529.                     {
  1530.                         "Произошла синтаксическая ошибка!",
  1531.                         "Использование консольной команды <color=orange>teleport.toplayer</color> возможно только следующим образом:",
  1532.                         " > <color=orange>teleport.toplayer \"имя игрока или ID\" \"имя игрока 2|id 2\"</color>"
  1533.                     })
  1534.                 },
  1535.                 {"LogTeleport", "{0} телепортирован к {1}."},
  1536.                 {"LogTeleportPlayer", "{0} телепортировал {1} к {2}."},
  1537.                 {"LogTeleportBack", "{0} телепортрован назад к предыдущему местоположению."}
  1538.             }, this, "ru");
  1539.         }
  1540.  
  1541.         private void Init()
  1542.         {
  1543.             Unsubscribe(nameof(OnEntityTakeDamage));
  1544.             Unsubscribe(nameof(OnPlayerSleepEnded));
  1545.             Unsubscribe(nameof(OnPlayerDisconnected));
  1546.         }
  1547.  
  1548.         private void Loaded()
  1549.         {
  1550.             dataAdmin = GetFile(nameof(NTeleportation) + "Admin");
  1551.             Admin = dataAdmin.ReadObject<Dictionary<ulong, AdminData>>();
  1552.             dataHome = GetFile(nameof(NTeleportation) + "Home");
  1553.             Home = dataHome.ReadObject<Dictionary<ulong, HomeData>>();
  1554.             dataTPT = GetFile(nameof(NTeleportation) + "TPT");
  1555.             TPT = dataTPT.ReadObject<Dictionary<string, List<string>>>();
  1556.             dataTPR = GetFile(nameof(NTeleportation) + "TPR");
  1557.             TPR = dataTPR.ReadObject<Dictionary<ulong, TeleportData>>();
  1558.             dataTown = GetFile(nameof(NTeleportation) + "Town");
  1559.             Town = dataTown.ReadObject<Dictionary<ulong, TeleportData>>();
  1560.             dataOutpost = GetFile(nameof(NTeleportation) + "Outpost");
  1561.             Outpost = dataOutpost.ReadObject<Dictionary<ulong, TeleportData>>();
  1562.             dataBandit = GetFile(nameof(NTeleportation) + "Bandit");
  1563.             Bandit = dataBandit.ReadObject<Dictionary<ulong, TeleportData>>();
  1564.             dataDisabled = GetFile(nameof(NTeleportation) + "DisabledCommands");
  1565.             DisabledTPT = dataDisabled.ReadObject<DisabledData>();
  1566.             permission.RegisterPermission(PermDeleteHome, this);
  1567.             permission.RegisterPermission(PermHome, this);
  1568.             permission.RegisterPermission(PermHomeHomes, this);
  1569.             permission.RegisterPermission(PermImportHomes, this);
  1570.             permission.RegisterPermission(PermRadiusHome, this);
  1571.             permission.RegisterPermission(PermTp, this);
  1572.             permission.RegisterPermission(PermTpB, this);
  1573.             permission.RegisterPermission(PermTpR, this);
  1574.             permission.RegisterPermission(PermTpConsole, this);
  1575.             permission.RegisterPermission(PermTpHome, this);
  1576.             permission.RegisterPermission(PermTpTown, this);
  1577.             permission.RegisterPermission(PermTpT, this);
  1578.             permission.RegisterPermission(PermTpOutpost, this);
  1579.             permission.RegisterPermission(PermTpBandit, this);
  1580.             permission.RegisterPermission(PermTpN, this);
  1581.             permission.RegisterPermission(PermTpL, this);
  1582.             permission.RegisterPermission(PermTpRemove, this);
  1583.             permission.RegisterPermission(PermTpSave, this);
  1584.             permission.RegisterPermission(PermWipeHomes, this);
  1585.             permission.RegisterPermission(PermCraftHome, this);
  1586.             permission.RegisterPermission(PermCraftTown, this);
  1587.             permission.RegisterPermission(PermCraftOutpost, this);
  1588.             permission.RegisterPermission(PermCraftBandit, this);
  1589.             permission.RegisterPermission(PermCraftTpR, this);
  1590.             foreach (var key in config.Home.VIPCooldowns.Keys)
  1591.                 if (!permission.PermissionExists(key, this)) permission.RegisterPermission(key, this);
  1592.             foreach (var key in config.Home.VIPCountdowns.Keys)
  1593.                 if (!permission.PermissionExists(key, this)) permission.RegisterPermission(key, this);
  1594.             foreach (var key in config.Home.VIPDailyLimits.Keys)
  1595.                 if (!permission.PermissionExists(key, this)) permission.RegisterPermission(key, this);
  1596.             foreach (var key in config.Home.VIPHomesLimits.Keys)
  1597.                 if (!permission.PermissionExists(key, this)) permission.RegisterPermission(key, this);
  1598.             foreach (var key in config.TPR.VIPCooldowns.Keys)
  1599.                 if (!permission.PermissionExists(key, this)) permission.RegisterPermission(key, this);
  1600.             foreach (var key in config.TPR.VIPCountdowns.Keys)
  1601.                 if (!permission.PermissionExists(key, this)) permission.RegisterPermission(key, this);
  1602.             foreach (var key in config.TPR.VIPDailyLimits.Keys)
  1603.                 if (!permission.PermissionExists(key, this)) permission.RegisterPermission(key, this);
  1604.             foreach (var key in config.Town.VIPCooldowns.Keys)
  1605.                 if (!permission.PermissionExists(key, this)) permission.RegisterPermission(key, this);
  1606.             foreach (var key in config.Town.VIPCountdowns.Keys)
  1607.                 if (!permission.PermissionExists(key, this)) permission.RegisterPermission(key, this);
  1608.             foreach (var key in config.Town.VIPDailyLimits.Keys)
  1609.                 if (!permission.PermissionExists(key, this)) permission.RegisterPermission(key, this);
  1610.         }
  1611.  
  1612.         private DynamicConfigFile GetFile(string name)
  1613.         {
  1614.             var file = Interface.Oxide.DataFileSystem.GetFile(name);
  1615.             file.Settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
  1616.             file.Settings.Converters = new JsonConverter[] { new UnityVector3Converter(), new CustomComparerDictionaryCreationConverter<string>(StringComparer.OrdinalIgnoreCase) };
  1617.             return file;
  1618.         }
  1619.  
  1620.         private void CheckNewSave()
  1621.         {
  1622.             if (!newSave && BuildingManager.server.buildingDictionary.Count == 0)
  1623.             {
  1624.                 newSave = true;
  1625.             }
  1626.  
  1627.             if (!newSave)
  1628.             {
  1629.                 return;
  1630.             }
  1631.  
  1632.             if (config.Settings.WipeOnUpgradeOrChange)
  1633.             {
  1634.                 Puts("Rust was upgraded or map changed - clearing homes, town, outpost and bandit!");
  1635.                 Home.Clear();
  1636.                 changedHome = True;
  1637.                 config.Town.Location = Zero;
  1638.                 config.Outpost.Location = Zero;
  1639.                 config.Bandit.Location = Zero;
  1640.                 SaveConfig();
  1641.             }
  1642.             else
  1643.             {
  1644.                 Puts("Rust was upgraded or map changed - homes, town, outpost and bandit may be invalid!");
  1645.             }
  1646.         }
  1647.  
  1648.         void OnServerInitialized()
  1649.         {
  1650.             CheckNewSave();
  1651.             banditPrefab = StringPool.Get(2074025910);
  1652.             banditEnabled = config.Settings.BanditEnabled;
  1653.             outpostPrefab = StringPool.Get(1879405026);
  1654.             outpostEnabled = config.Settings.OutpostEnabled;
  1655.  
  1656.             Subscribe(nameof(OnPlayerSleepEnded));
  1657.             Subscribe(nameof(OnPlayerDisconnected));
  1658.  
  1659.             boundary = TerrainMeta.Size.x / 2;
  1660.             CheckPerms(config.Home.VIPHomesLimits);
  1661.             CheckPerms(config.Home.VIPDailyLimits);
  1662.             CheckPerms(config.Home.VIPCooldowns);
  1663.             CheckPerms(config.TPR.VIPDailyLimits);
  1664.             CheckPerms(config.TPR.VIPCooldowns);
  1665.             CheckPerms(config.Town.VIPDailyLimits);
  1666.             CheckPerms(config.Town.VIPCooldowns);
  1667.             CheckPerms(config.Outpost.VIPDailyLimits);
  1668.             CheckPerms(config.Outpost.VIPCooldowns);
  1669.             CheckPerms(config.Bandit.VIPDailyLimits);
  1670.             CheckPerms(config.Bandit.VIPCooldowns);
  1671.  
  1672.             foreach (var item in config.Settings.BlockedItems)
  1673.             {
  1674.                 var definition = ItemManager.FindItemDefinition(item.Key);
  1675.                 if (definition == null)
  1676.                 {
  1677.                     Puts("Blocked item not found: {0}", item.Key);
  1678.                     continue;
  1679.                 }
  1680.                 ReverseBlockedItems[definition.itemid] = item.Value;
  1681.             }
  1682.  
  1683.             if (CompoundTeleport == null)
  1684.             {
  1685.                 if (outpostEnabled) AddCovalenceCommand("outpost", nameof(CommandOutpost));
  1686.                 if (banditEnabled) AddCovalenceCommand("bandit", nameof(CommandBandit));
  1687.             }
  1688.             if (config.Settings.TownEnabled) AddCovalenceCommand("town", nameof(CommandTown));
  1689.             if (config.Settings.TPREnabled) AddCovalenceCommand("tpr", nameof(CommandTeleportRequest));
  1690.             if (config.Settings.HomesEnabled)
  1691.             {
  1692.                 AddCovalenceCommand("home", nameof(CommandHome));
  1693.                 AddCovalenceCommand("sethome", nameof(CommandSetHome));
  1694.                 AddCovalenceCommand("listhomes", nameof(CommandListHomes));
  1695.                 AddCovalenceCommand("removehome", nameof(CommandRemoveHome));
  1696.                 AddCovalenceCommand("radiushome", nameof(CommandHomeRadius));
  1697.                 AddCovalenceCommand("deletehome", nameof(CommandHomeDelete));
  1698.                 AddCovalenceCommand("tphome", nameof(CommandHomeAdminTP));
  1699.                 AddCovalenceCommand("homehomes", nameof(CommandHomeHomes));
  1700.             }
  1701.  
  1702.             AddCovalenceCommand("tnt", nameof(CommandToggle));
  1703.             AddCovalenceCommand("tp", nameof(CommandTeleport));
  1704.             AddCovalenceCommand("tpn", nameof(CommandTeleportNear));
  1705.             AddCovalenceCommand("tpl", nameof(CommandTeleportLocation));
  1706.             AddCovalenceCommand("tpsave", nameof(CommandSaveTeleportLocation));
  1707.             AddCovalenceCommand("tpremove", nameof(CommandRemoveTeleportLocation));
  1708.             AddCovalenceCommand("tpb", nameof(CommandTeleportBack));
  1709.             AddCovalenceCommand("tpt", nameof(CommandTeleportTeam));
  1710.             AddCovalenceCommand("tpa", nameof(CommandTeleportAccept));
  1711.             AddCovalenceCommand("wipehomes", nameof(CommandWipeHomes));
  1712.             AddCovalenceCommand("tphelp", nameof(CommandTeleportHelp));
  1713.             AddCovalenceCommand("tpinfo", nameof(CommandTeleportInfo));
  1714.             AddCovalenceCommand("tpc", nameof(CommandTeleportCancel));
  1715.             AddCovalenceCommand("teleport.toplayer", nameof(CommandTeleportII));
  1716.             AddCovalenceCommand("teleport.topos", nameof(CommandTeleportII));
  1717.             AddCovalenceCommand("teleport.importhomes", nameof(CommandImportHomes));
  1718.             AddCovalenceCommand("spm", nameof(CommandSphereMonuments));
  1719.             FindMonuments();  // 1.2.2 location moved from Loaded() to fix outpost and bandit location not being set after a wipe
  1720.         }
  1721.  
  1722.         List<string> validCommands = new List<string> { "outpost", "bandit", "tp", "home", "sethome", "listhomes", "tpn", "tpl", "tpsave", "tpremove", "tpb", "removehome", "radiushome", "deletehome", "tphome", "homehomes", "tpt", "tpr", "tpa", "wipehomes", "tphelp", "tpinfo", "teleport.toplayer", "teleport.topos", "teleport.importhomes", "town", "spm" };
  1723.  
  1724.         void OnNewSave(string strFilename)
  1725.         {
  1726.             newSave = true;
  1727.         }
  1728.  
  1729.         void OnServerSave()
  1730.         {
  1731.             SaveTeleportsAdmin();
  1732.             SaveTeleportsHome();
  1733.             SaveTeleportsTPR();
  1734.             SaveTeleportsTPT();
  1735.             SaveTeleportsTown();
  1736.             SaveTeleportsOutpost();
  1737.             SaveTeleportsBandit();
  1738.         }
  1739.  
  1740.         void OnServerShutdown() => OnServerSave();
  1741.  
  1742.         void Unload() => OnServerSave();
  1743.  
  1744.         void OnPluginLoaded(Plugin plugin)
  1745.         {
  1746.             if (plugin.Name == "Economics")
  1747.             {
  1748.                 Economics = plugin;
  1749.             }
  1750.             if (plugin.Name == "ServerRewards")
  1751.             {
  1752.                 ServerRewards = plugin;
  1753.             }
  1754.             if (plugin.Name == "Friends")
  1755.             {
  1756.                 Friends = plugin;
  1757.             }
  1758.             if (plugin.Name == "Clans")
  1759.             {
  1760.                 Clans = plugin;
  1761.             }
  1762.             if (plugin.Name == "CompoundTeleport")
  1763.             {
  1764.                 CompoundTeleport = plugin;
  1765.             }
  1766.         }
  1767.  
  1768.         void OnPluginUnloaded(Plugin plugin)
  1769.         {
  1770.             if (plugin.Name == "Economics")
  1771.             {
  1772.                 Economics = null;
  1773.             }
  1774.             if (plugin.Name == "ServerRewards")
  1775.             {
  1776.                 ServerRewards = null;
  1777.             }
  1778.             if (plugin.Name == "Friends")
  1779.             {
  1780.                 Friends = null;
  1781.             }
  1782.             if (plugin.Name == "Clans")
  1783.             {
  1784.                 Clans = null;
  1785.             }
  1786.             if (plugin.Name == "CompoundTeleport")
  1787.             {
  1788.                 CompoundTeleport = null;
  1789.             }
  1790.         }
  1791.  
  1792.         void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo)
  1793.         {
  1794.             var player = entity.ToPlayer();
  1795.             if (player == null || hitInfo == null) return;
  1796.             if (hitInfo.damageTypes.Has(DamageType.Fall) && teleporting.ContainsKey(player.userID))
  1797.             {
  1798.                 hitInfo.damageTypes = new DamageTypeList();
  1799.                 teleporting.Remove(player.userID);
  1800.             }
  1801.             TeleportTimer teleportTimer;
  1802.             if (!TeleportTimers.TryGetValue(player.userID, out teleportTimer)) return;
  1803.             DamageType major = hitInfo.damageTypes.GetMajorityDamageType();
  1804.             if (!config.Settings.Interrupt.Hurt) return;
  1805.             NextTick(() =>
  1806.             {
  1807.                 if (!player) return;
  1808.                 if (!hitInfo.hasDamage || hitInfo.damageTypes.Total() <= 0) return;
  1809.                 // 1.0.84 new checks for cold/heat based on major damage for the player
  1810.                 if (major == DamageType.Cold && config.Settings.Interrupt.Cold)
  1811.                 {
  1812.                     if (player.metabolism.temperature.value <= config.Settings.MinimumTemp)
  1813.                     {
  1814.                         PrintMsgL(teleportTimer.OriginPlayer, "TPTooCold");
  1815.                         if (teleportTimer.TargetPlayer != null)
  1816.                         {
  1817.                             PrintMsgL(teleportTimer.TargetPlayer, "InterruptedTarget", teleportTimer.OriginPlayer?.displayName);
  1818.                         }
  1819.                         teleportTimer.Timer.Destroy();
  1820.                         TeleportTimers.Remove(player.userID);
  1821.                     }
  1822.                 }
  1823.                 else if (major == DamageType.Heat && config.Settings.Interrupt.Hot)
  1824.                 {
  1825.                     if (player.metabolism.temperature.value >= config.Settings.MaximumTemp)
  1826.                     {
  1827.                         PrintMsgL(teleportTimer.OriginPlayer, "TPTooHot");
  1828.                         if (teleportTimer.TargetPlayer != null)
  1829.                         {
  1830.                             PrintMsgL(teleportTimer.TargetPlayer, "InterruptedTarget", teleportTimer.OriginPlayer?.displayName);
  1831.                         }
  1832.                         teleportTimer.Timer.Destroy();
  1833.                         TeleportTimers.Remove(player.userID);
  1834.                     }
  1835.                 }
  1836.                 else
  1837.                 {
  1838.                     PrintMsgL(teleportTimer.OriginPlayer, "Interrupted");
  1839.                     if (teleportTimer.TargetPlayer != null)
  1840.                     {
  1841.                         PrintMsgL(teleportTimer.TargetPlayer, "InterruptedTarget", teleportTimer.OriginPlayer?.displayName);
  1842.                     }
  1843.                     teleportTimer.Timer.Destroy();
  1844.                     TeleportTimers.Remove(player.userID);
  1845.                 }
  1846.             });
  1847.         }
  1848.  
  1849.         void OnPlayerSleepEnded(BasePlayer player)
  1850.         {
  1851.             if (!player || !teleporting.ContainsKey(player.userID)) return;
  1852.             ulong userID = player.userID;
  1853.             timer.Once(3f, () => teleporting.Remove(userID));
  1854.         }
  1855.  
  1856.         void OnPlayerDisconnected(BasePlayer player)
  1857.         {
  1858.             if (!player) return;
  1859.             Timer reqTimer;
  1860.             if (PendingRequests.TryGetValue(player.userID, out reqTimer))
  1861.             {
  1862.                 var originPlayer = PlayersRequests[player.userID];
  1863.                 if (originPlayer)
  1864.                 {
  1865.                     PlayersRequests.Remove(originPlayer.userID);
  1866.                     PrintMsgL(originPlayer, "RequestTargetOff");
  1867.                 }
  1868.                 reqTimer.Destroy();
  1869.                 PendingRequests.Remove(player.userID);
  1870.                 PlayersRequests.Remove(player.userID);
  1871.             }
  1872.             TeleportTimer teleportTimer;
  1873.             if (TeleportTimers.TryGetValue(player.userID, out teleportTimer))
  1874.             {
  1875.                 teleportTimer.Timer.Destroy();
  1876.                 TeleportTimers.Remove(player.userID);
  1877.             }
  1878.             teleporting.Remove(player.userID);
  1879.         }
  1880.  
  1881.         private void SaveTeleportsAdmin()
  1882.         {
  1883.             if (Admin == null || !changedAdmin) return;
  1884.             dataAdmin.WriteObject(Admin);
  1885.             changedAdmin = False;
  1886.         }
  1887.  
  1888.         private void SaveTeleportsHome()
  1889.         {
  1890.             if (Home == null || !changedHome) return;
  1891.             dataHome.WriteObject(Home);
  1892.             changedHome = False;
  1893.         }
  1894.  
  1895.         private void SaveTeleportsTPR()
  1896.         {
  1897.             if (TPR == null || !changedTPR) return;
  1898.             dataTPR.WriteObject(TPR);
  1899.             changedTPR = False;
  1900.         }
  1901.  
  1902.         private void SaveTeleportsTPT()
  1903.         {
  1904.             if (TPT == null || !changedTPT) return;
  1905.             dataTPT.WriteObject(TPT);
  1906.             changedTPT = False;
  1907.         }
  1908.  
  1909.         private void SaveTeleportsTown()
  1910.         {
  1911.             if (Town == null || !changedTown) return;
  1912.             dataTown.WriteObject(Town);
  1913.             changedTown = False;
  1914.         }
  1915.  
  1916.         private void SaveTeleportsOutpost()
  1917.         {
  1918.             if (Outpost == null || !changedOutpost) return;
  1919.             dataOutpost.WriteObject(Outpost);
  1920.             changedOutpost = False;
  1921.         }
  1922.  
  1923.         private void SaveTeleportsBandit()
  1924.         {
  1925.             if (Bandit == null || !changedBandit) return;
  1926.             dataBandit.WriteObject(Bandit);
  1927.             changedBandit = False;
  1928.         }
  1929.  
  1930.         private void SaveLocation(BasePlayer player)
  1931.         {
  1932.             if (!IsAllowed(player, PermTpB)) return;
  1933.             AdminData adminData;
  1934.             if (!Admin.TryGetValue(player.userID, out adminData))
  1935.                 Admin[player.userID] = adminData = new AdminData();
  1936.             adminData.PreviousLocation = player.transform.position;
  1937.             changedAdmin = True;
  1938.             PrintMsgL(player, "AdminTPBackSave");
  1939.         }
  1940.  
  1941.         char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
  1942.         private readonly System.Text.StringBuilder _sb = new System.Text.StringBuilder();
  1943.  
  1944.         string RandomString(int minAmount = 5, int maxAmount = 10)
  1945.         {
  1946.             _sb.Length = 0;
  1947.  
  1948.             for (int i = 0; i <= UnityEngine.Random.Range(minAmount, maxAmount); i++)
  1949.                 _sb.Append(chars[UnityEngine.Random.Range(0, chars.Length)]);
  1950.  
  1951.             return _sb.ToString();
  1952.         }
  1953.  
  1954.         void FindMonuments()
  1955.         {
  1956.             var realWidth = 0f;
  1957.             string name = null;
  1958.             foreach (var monument in UnityEngine.Object.FindObjectsOfType<MonumentInfo>())
  1959.             {
  1960.                 var monPos = monument.transform.position;
  1961.                 name = monument.displayPhrase.english.TrimEnd();
  1962.                 if (string.IsNullOrEmpty(name))
  1963.                 {
  1964.                     if (monument.name.Contains("cave"))
  1965.                     {
  1966.                         name = (monument.name.Contains("cave_small") ? "Small Cave" : monument.name.Contains("cave_medium") ? "Medium Cave" : "Large Cave") + ":" + RandomString();
  1967.                     }
  1968.                     else name = monument.name;
  1969.                 }
  1970.                 realWidth = monument.name == "OilrigAI" ? 100f : monument.name == "OilrigAI2" ? 200f : 0f;
  1971. #if DEBUG
  1972.                 Puts($"Found {name}, extents {monument.Bounds.extents}");
  1973. #endif
  1974.                 if (realWidth > 0f)
  1975.                 {
  1976. #if DEBUG
  1977.                     Puts($"  corrected to {realWidth}");
  1978. #endif
  1979.                 }
  1980.                 if (monument.name.Contains("cave"))
  1981.                 {
  1982. #if DEBUG
  1983.                     Puts("  Adding to cave list");
  1984. #endif
  1985.                     if (caves.ContainsKey(name)) name += RandomString();
  1986.                     caves.Add(name, monPos);
  1987.                 }
  1988.                 else if (monument.name == outpostPrefab)
  1989.                 {
  1990.                     if (config.Outpost.Location != Zero && Vector3.Distance(monument.transform.position, config.Outpost.Location) > 100f)
  1991.                     {
  1992. #if DEBUG
  1993.                         Puts("Invalid Outpost location detected");
  1994. #endif
  1995.                         config.Outpost.Location = Zero;
  1996.                     }
  1997.                     if (config.Settings.AutoGenOutpost && config.Outpost.Location == Zero)
  1998.                     {
  1999. #if DEBUG
  2000.                         Puts("  Adding Outpost target");
  2001. #endif
  2002.                         var ents = new List<BaseEntity>();
  2003.                         Vis.Entities<BaseEntity>(monPos, 50, ents);
  2004.                         foreach (BaseEntity entity in ents)
  2005.                         {
  2006.                             if (entity.prefabID == 3858860623)
  2007.                             {
  2008.                                 config.Outpost.Location = entity.transform.position + entity.transform.forward + new Vector3(0f, 1f, 0f);
  2009.                                 SaveConfig();
  2010.                                 break;
  2011.                             }
  2012.                             else if (entity is Workbench)
  2013.                             {
  2014.                                 config.Outpost.Location = entity.transform.position + entity.transform.forward + new Vector3(0f, 1f, 0f);
  2015.                                 SaveConfig();
  2016.                                 break;
  2017.                             }
  2018.                             else if (entity is BaseChair)
  2019.                             {
  2020.                                 config.Outpost.Location = entity.transform.position + entity.transform.right + new Vector3(0f, 1f, 0f);
  2021.                                 SaveConfig();
  2022.                                 break;
  2023.                             }
  2024.                         }
  2025.  
  2026.                         if (!config.Settings.OutpostEnabled) OutpostTPDisabledMessage = "OutpostTPDisabledConfig";
  2027.                         else if (config.Outpost.Location == Zero) OutpostTPDisabledMessage = "OutpostTPDisabledNoLocationAutoGen";
  2028.                     }
  2029.                 }
  2030.                 else if (monument.name == banditPrefab)
  2031.                 {
  2032.                     if (config.Bandit.Location != Zero && Vector3.Distance(monument.transform.position, config.Bandit.Location) > 100f)
  2033.                     {
  2034. #if DEBUG
  2035.                         Puts("Invalid Bandit location detected");
  2036. #endif
  2037.                         config.Bandit.Location = Zero;
  2038.                     }
  2039.                     if (config.Settings.AutoGenBandit && config.Bandit.Location == Zero)
  2040.                     {
  2041. #if DEBUG
  2042.                         Puts("  Adding BanditTown target");
  2043. #endif
  2044.                         var ents = new List<BaseEntity>();
  2045.                         Vis.Entities<BaseEntity>(monPos, 50, ents);
  2046.                         foreach (BaseEntity entity in ents)
  2047.                         {
  2048.                             if (entity.prefabID == 3858860623)
  2049.                             {
  2050.                                 config.Bandit.Location = entity.transform.position + entity.transform.forward + new Vector3(0f, 1f, 0f);
  2051.                                 SaveConfig();
  2052.                                 break;
  2053.                             }
  2054.                             else if (entity is Workbench)
  2055.                             {
  2056.                                 config.Bandit.Location = entity.transform.position + entity.transform.forward + new Vector3(0f, 1f, 0f);
  2057.                                 SaveConfig();
  2058.                                 break;
  2059.                             }
  2060.                             else if (entity is BaseChair)
  2061.                             {
  2062.                                 config.Bandit.Location = entity.transform.position + entity.transform.right + new Vector3(0f, 1f, 0f);
  2063.                                 SaveConfig();
  2064.                                 break;
  2065.                             }
  2066.                         }
  2067.                     }
  2068.  
  2069.                     if (!config.Settings.BanditEnabled) BanditTPDisabledMessage = "BanditTPDisabledConfig";
  2070.                     else if (config.Bandit.Location == Zero) BanditTPDisabledMessage = "BanditTPDisabledNoLocationAutoGen";
  2071.                 }
  2072.                 else
  2073.                 {
  2074.                     if (monuments.ContainsKey(name)) name += ":" + RandomString(5, 5);
  2075.                     if (monument.name.Contains("power_sub")) name = monument.name.Substring(monument.name.LastIndexOf("/") + 1).Replace(".prefab", "") + ":" + RandomString(5, 5);
  2076.                     float radius = GetMonumentFloat(name);
  2077.                     monuments[name] = new MonInfo() { Position = monPos, Radius = radius };
  2078. #if DEBUG
  2079.                     Puts($"Adding Monument: {name}, pos: {monPos}, size: {radius}");
  2080. #endif
  2081.                 }
  2082.             }
  2083.  
  2084.             if (config.Outpost.Location == Zero)
  2085.             {
  2086.                 if (!config.Settings.AutoGenOutpost) OutpostTPDisabledMessage = "OutpostTPDisabledNoLocation";
  2087.                 outpostEnabled = False;
  2088.             }
  2089.  
  2090.             if (config.Bandit.Location == Zero)
  2091.             {
  2092.                 if (!config.Settings.AutoGenBandit) BanditTPDisabledMessage = "BanditTPDisabledNoLocation";
  2093.                 banditEnabled = False;
  2094.             }
  2095.         }
  2096.  
  2097.         private void CommandToggle(IPlayer p, string command, string[] args)
  2098.         {
  2099.             if (!p.IsAdmin) return;
  2100.  
  2101.             if (args.Length == 0)
  2102.             {
  2103.                 p.Reply("tnt commandname");
  2104.                 return;
  2105.             }
  2106.  
  2107.             string arg = args[0].ToLower();
  2108.  
  2109.             if (!validCommands.Contains(arg))
  2110.             {
  2111.                 p.Reply("Invalid command name: {0}", null, string.Join(", ", validCommands.ToList()));
  2112.                 return;
  2113.             }
  2114.  
  2115.             if (arg == command.ToLower()) return;
  2116.  
  2117.             if (!DisabledTPT.DisabledCommands.Contains(arg))
  2118.                 DisabledTPT.DisabledCommands.Add(arg);
  2119.             else DisabledTPT.DisabledCommands.Remove(arg);
  2120.  
  2121.             dataDisabled.WriteObject(DisabledTPT);
  2122.             p.Reply("{0} {1}", null, DisabledTPT.DisabledCommands.Contains(arg) ? "Disabled:" : "Enabled:", arg);
  2123.         }
  2124.  
  2125.         private void CommandTeleport(IPlayer p, string command, string[] args)
  2126.         {
  2127.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2128.             var player = p.Object as BasePlayer;
  2129.             if (!player || !IsAllowedMsg(player, PermTp) || !player.IsConnected || player.IsSleeping()) return;
  2130.             BasePlayer target;
  2131.             float x, y, z;
  2132.             switch (args.Length)
  2133.             {
  2134.                 case 1:
  2135.                     target = FindPlayersSingle(args[0], player);
  2136.                     if (target == null) return;
  2137.                     if (target == player)
  2138.                     {
  2139. #if DEBUG
  2140.                         Puts("Debug mode - allowing self teleport.");
  2141. #else
  2142.                 PrintMsgL(player, "CantTeleportToSelf");
  2143.                 return;
  2144. #endif
  2145.                     }
  2146.                     Teleport(player, target);
  2147.                     PrintMsgL(player, "AdminTP", target.displayName);
  2148.                     Puts(_("LogTeleport", null, player.displayName, target.displayName));
  2149.                     if (config.Admin.AnnounceTeleportToTarget)
  2150.                         PrintMsgL(target, "AdminTPTarget", player.displayName);
  2151.                     break;
  2152.                 case 2:
  2153.                     var origin = FindPlayersSingle(args[0], player);
  2154.                     if (origin == null) return;
  2155.                     target = FindPlayersSingle(args[1], player);
  2156.                     if (target == null) return;
  2157.                     if (target == origin)
  2158.                     {
  2159.                         PrintMsgL(player, "CantTeleportPlayerToSelf");
  2160.                         return;
  2161.                     }
  2162.                     Teleport(origin, target);
  2163.                     PrintMsgL(player, "AdminTPPlayers", origin.displayName, target.displayName);
  2164.                     PrintMsgL(origin, "AdminTPPlayer", player.displayName, target.displayName);
  2165.                     if (config.Admin.AnnounceTeleportToTarget)
  2166.                         PrintMsgL(target, "AdminTPPlayerTarget", player.displayName, origin.displayName);
  2167.                     Puts(_("LogTeleportPlayer", null, player.displayName, origin.displayName, target.displayName));
  2168.                     break;
  2169.                 case 3:
  2170.                     if (!float.TryParse(args[0], out x) || !float.TryParse(args[1], out y) || !float.TryParse(args[2], out z))
  2171.                     {
  2172.                         PrintMsgL(player, "InvalidCoordinates");
  2173.                         return;
  2174.                     }
  2175.                     if (config.Settings.CheckBoundaries && !CheckBoundaries(x, y, z)) // added this option because I HATE boundaries
  2176.                     {
  2177.                         PrintMsgL(player, "AdminTPOutOfBounds");
  2178.                         PrintMsgL(player, "AdminTPBoundaries", boundary);
  2179.                         return;
  2180.                     }
  2181.                     Teleport(player, x, y, z);
  2182.                     PrintMsgL(player, "AdminTPCoordinates", player.transform.position);
  2183.                     Puts(_("LogTeleport", null, player.displayName, player.transform.position));
  2184.                     break;
  2185.                 case 4:
  2186.                     target = FindPlayersSingle(args[0], player);
  2187.                     if (target == null) return;
  2188.                     if (!float.TryParse(args[1], out x) || !float.TryParse(args[2], out y) || !float.TryParse(args[3], out z))
  2189.                     {
  2190.                         PrintMsgL(player, "InvalidCoordinates");
  2191.                         return;
  2192.                     }
  2193.                     if (!CheckBoundaries(x, y, z))
  2194.                     {
  2195.                         PrintMsgL(player, "AdminTPOutOfBounds");
  2196.                         PrintMsgL(player, "AdminTPBoundaries", boundary);
  2197.                         return;
  2198.                     }
  2199.                     Teleport(target, x, y, z);
  2200.                     if (player == target)
  2201.                     {
  2202.                         PrintMsgL(player, "AdminTPCoordinates", player.transform.position);
  2203.                         Puts(_("LogTeleport", null, player.displayName, player.transform.position));
  2204.                     }
  2205.                     else
  2206.                     {
  2207.                         PrintMsgL(player, "AdminTPTargetCoordinates", target.displayName, player.transform.position);
  2208.                         if (config.Admin.AnnounceTeleportToTarget)
  2209.                             PrintMsgL(target, "AdminTPTargetCoordinatesTarget", player.displayName, player.transform.position);
  2210.                         Puts(_("LogTeleportPlayer", null, player.displayName, target.displayName, player.transform.position));
  2211.                     }
  2212.                     break;
  2213.                 default:
  2214.                     PrintMsgL(player, "SyntaxCommandTP");
  2215.                     break;
  2216.             }
  2217.         }
  2218.  
  2219.         private void CommandTeleportNear(IPlayer p, string command, string[] args)
  2220.         {
  2221.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2222.             var player = p.Object as BasePlayer;
  2223.             if (!player || !IsAllowedMsg(player, PermTpN) || !player.IsConnected || player.IsSleeping()) return;
  2224.             switch (args.Length)
  2225.             {
  2226.                 case 1:
  2227.                 case 2:
  2228.                     var target = FindPlayersSingle(args[0], player);
  2229.                     if (target == null) return;
  2230.                     if (target == player)
  2231.                     {
  2232. #if DEBUG
  2233.                         Puts("Debug mode - allowing self teleport.");
  2234. #else
  2235.                         PrintMsgL(player, "CantTeleportToSelf");
  2236.                         return;
  2237. #endif
  2238.                     }
  2239.                     int distance = config.Admin.TeleportNearDefaultDistance;
  2240.                     if (args.Length == 2 && !int.TryParse(args[1], out distance))
  2241.                         distance = config.Admin.TeleportNearDefaultDistance;
  2242.                     float x = UnityEngine.Random.Range(-distance, distance);
  2243.                     var z = (float)System.Math.Sqrt(System.Math.Pow(distance, 2) - System.Math.Pow(x, 2));
  2244.                     var destination = target.transform.position;
  2245.                     destination.x = destination.x - x;
  2246.                     destination.z = destination.z - z;
  2247.                     Teleport(player, GetGroundBuilding(destination));
  2248.                     PrintMsgL(player, "AdminTP", target.displayName);
  2249.                     Puts(_("LogTeleport", null, player.displayName, target.displayName));
  2250.                     if (config.Admin.AnnounceTeleportToTarget)
  2251.                         PrintMsgL(target, "AdminTPTarget", player.displayName);
  2252.                     break;
  2253.                 default:
  2254.                     PrintMsgL(player, "SyntaxCommandTPN");
  2255.                     break;
  2256.             }
  2257.         }
  2258.  
  2259.         private void CommandTeleportLocation(IPlayer p, string command, string[] args)
  2260.         {
  2261.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2262.             var player = p.Object as BasePlayer;
  2263.             if (!player || !IsAllowedMsg(player, PermTpL) || !player.IsConnected || player.IsSleeping()) return;
  2264.             AdminData adminData;
  2265.             if (!Admin.TryGetValue(player.userID, out adminData) || adminData.Locations.Count <= 0)
  2266.             {
  2267.                 PrintMsgL(player, "AdminLocationListEmpty");
  2268.                 return;
  2269.             }
  2270.             switch (args.Length)
  2271.             {
  2272.                 case 0:
  2273.                     PrintMsgL(player, "AdminLocationList");
  2274.                     foreach (var location in adminData.Locations)
  2275.                         PrintMsgL(player, $"{location.Key} {location.Value}");
  2276.                     break;
  2277.                 case 1:
  2278.                     Vector3 loc;
  2279.                     if (!adminData.Locations.TryGetValue(args[0], out loc))
  2280.                     {
  2281.                         PrintMsgL(player, "LocationNotFound");
  2282.                         return;
  2283.                     }
  2284.                     Teleport(player, loc);
  2285.                     PrintMsgL(player, "AdminTPLocation", args[0]);
  2286.                     break;
  2287.                 default:
  2288.                     PrintMsgL(player, "SyntaxCommandTPL");
  2289.                     break;
  2290.             }
  2291.         }
  2292.  
  2293.         private void CommandSaveTeleportLocation(IPlayer p, string command, string[] args)
  2294.         {
  2295.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2296.             var player = p.Object as BasePlayer;
  2297.             if (!player || !IsAllowedMsg(player, PermTpSave) || !player.IsConnected || player.IsSleeping()) return;
  2298.             if (args.Length != 1)
  2299.             {
  2300.                 PrintMsgL(player, "SyntaxCommandTPSave");
  2301.                 return;
  2302.             }
  2303.             AdminData adminData;
  2304.             if (!Admin.TryGetValue(player.userID, out adminData))
  2305.                 Admin[player.userID] = adminData = new AdminData();
  2306.             Vector3 location;
  2307.             if (adminData.Locations.TryGetValue(args[0], out location))
  2308.             {
  2309.                 PrintMsgL(player, "LocationExists", location);
  2310.                 return;
  2311.             }
  2312.             var positionCoordinates = player.transform.position;
  2313.             foreach (var loc in adminData.Locations)
  2314.             {
  2315.                 if ((positionCoordinates - loc.Value).magnitude < config.Admin.LocationRadius)
  2316.                 {
  2317.                     PrintMsgL(player, "LocationExistsNearby", loc.Key);
  2318.                     return;
  2319.                 }
  2320.             }
  2321.             adminData.Locations[args[0]] = positionCoordinates;
  2322.             PrintMsgL(player, "AdminTPLocationSave");
  2323.             changedAdmin = True;
  2324.         }
  2325.  
  2326.         private void CommandRemoveTeleportLocation(IPlayer p, string command, string[] args)
  2327.         {
  2328.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2329.             var player = p.Object as BasePlayer;
  2330.             if (!player || !IsAllowedMsg(player, PermTpRemove) || !player.IsConnected || player.IsSleeping()) return;
  2331.             if (args.Length != 1)
  2332.             {
  2333.                 PrintMsgL(player, "SyntaxCommandTPRemove");
  2334.                 return;
  2335.             }
  2336.             AdminData adminData;
  2337.             if (!Admin.TryGetValue(player.userID, out adminData) || adminData.Locations.Count <= 0)
  2338.             {
  2339.                 PrintMsgL(player, "AdminLocationListEmpty");
  2340.                 return;
  2341.             }
  2342.             if (adminData.Locations.Remove(args[0]))
  2343.             {
  2344.                 PrintMsgL(player, "AdminTPLocationRemove", args[0]);
  2345.                 changedAdmin = True;
  2346.                 return;
  2347.             }
  2348.             PrintMsgL(player, "LocationNotFound");
  2349.         }
  2350.  
  2351.         private void CommandTeleportBack(IPlayer p, string command, string[] args)
  2352.         {
  2353.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2354.             var player = p.Object as BasePlayer;
  2355.             if (!player || !IsAllowedMsg(player, PermTpB) || !player.IsConnected || player.IsSleeping()) return;
  2356.             if (args.Length != 0)
  2357.             {
  2358.                 PrintMsgL(player, "SyntaxCommandTPB");
  2359.                 return;
  2360.             }
  2361.             AdminData adminData;
  2362.             if (!Admin.TryGetValue(player.userID, out adminData) || adminData.PreviousLocation == Zero)
  2363.             {
  2364.                 PrintMsgL(player, "NoPreviousLocationSaved");
  2365.                 return;
  2366.             }
  2367.  
  2368.             Teleport(player, adminData.PreviousLocation);
  2369.             adminData.PreviousLocation = Zero;
  2370.             changedAdmin = True;
  2371.             PrintMsgL(player, "AdminTPBack");
  2372.             Puts(_("LogTeleportBack", null, player.displayName));
  2373.         }
  2374.  
  2375.         private void CommandSetHome(IPlayer p, string command, string[] args)
  2376.         {
  2377.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2378.             var player = p.Object as BasePlayer;
  2379.             if (!player || !IsAllowed(player, PermHome) || !player.IsConnected || player.IsSleeping()) return;
  2380.             if (!config.Settings.HomesEnabled) { p.Reply("Homes are not enabled in the config."); return; }
  2381.             if (args.Length != 1)
  2382.             {
  2383.                 PrintMsgL(player, "SyntaxCommandSetHome");
  2384.                 return;
  2385.             }
  2386.             var err = CheckPlayer(player, False, CanCraftHome(player), True, "home");
  2387.             if (err != null)
  2388.             {
  2389.                 PrintMsgL(player, err);
  2390.                 return;
  2391.             }
  2392.             if (!player.CanBuild())
  2393.             {
  2394.                 PrintMsgL(player, "HomeTPBuildingBlocked");
  2395.                 return;
  2396.             }
  2397.             if (!args[0].All(char.IsLetterOrDigit))
  2398.             {
  2399.                 PrintMsgL(player, "InvalidCharacter");
  2400.                 return;
  2401.             }
  2402.             HomeData homeData;
  2403.             if (!Home.TryGetValue(player.userID, out homeData))
  2404.                 Home[player.userID] = homeData = new HomeData();
  2405.             var limit = GetHigher(player, config.Home.VIPHomesLimits, config.Home.HomesLimit, true);
  2406.             if (limit > 0 && homeData.Locations.Count >= limit)
  2407.             {
  2408.                 PrintMsgL(player, "HomeMaxLocations", limit);
  2409.                 return;
  2410.             }
  2411.             Vector3 location;
  2412.             if (homeData.Locations.TryGetValue(args[0], out location))
  2413.             {
  2414.                 PrintMsgL(player, "HomeExists", location);
  2415.                 return;
  2416.             }
  2417.             var positionCoordinates = player.transform.position;
  2418.             foreach (var loc in homeData.Locations)
  2419.             {
  2420.                 if ((positionCoordinates - loc.Value).magnitude < config.Home.LocationRadius)
  2421.                 {
  2422.                     PrintMsgL(player, "HomeExistsNearby", loc.Key);
  2423.                     return;
  2424.                 }
  2425.             }
  2426.             err = CanPlayerTeleport(player);
  2427.             if (err != null)
  2428.             {
  2429.                 SendReply(player, err);
  2430.                 return;
  2431.             }
  2432.  
  2433.             if (player.IsAdmin && config.Settings.DrawHomeSphere) player.SendConsoleCommand("ddraw.sphere", 30f, Color.blue, GetGround(positionCoordinates), 2.5f);
  2434.  
  2435.             err = CheckFoundation(player.userID, positionCoordinates);
  2436.             if (err != null)
  2437.             {
  2438.                 PrintMsgL(player, err);
  2439.                 return;
  2440.             }
  2441.             err = CheckInsideBlock(positionCoordinates);
  2442.             if (err != null)
  2443.             {
  2444.                 PrintMsgL(player, err);
  2445.                 return;
  2446.             }
  2447.             err = CheckInsideBattery(positionCoordinates);
  2448.             if (err != null)
  2449.             {
  2450.                 PrintMsgL(player, err);
  2451.                 return;
  2452.             }
  2453.             homeData.Locations[args[0]] = positionCoordinates;
  2454.             changedHome = True;
  2455.             PrintMsgL(player, "HomeSave");
  2456.             PrintMsgL(player, "HomeQuota", homeData.Locations.Count, limit);
  2457.         }
  2458.  
  2459.         private void CommandRemoveHome(IPlayer p, string command, string[] args)
  2460.         {
  2461.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2462.             if (!config.Settings.HomesEnabled) { p.Reply("Homes are not enabled in the config."); return; }
  2463.             var player = p.Object as BasePlayer;
  2464.             if (!player || !IsAllowed(player, PermHome) || !player.IsConnected || player.IsSleeping()) return;
  2465.             if (args.Length != 1)
  2466.             {
  2467.                 PrintMsgL(player, "SyntaxCommandRemoveHome");
  2468.                 return;
  2469.             }
  2470.             HomeData homeData;
  2471.             if (!Home.TryGetValue(player.userID, out homeData) || homeData.Locations.Count <= 0)
  2472.             {
  2473.                 PrintMsgL(player, "HomeListEmpty");
  2474.                 return;
  2475.             }
  2476.             if (homeData.Locations.Remove(args[0]))
  2477.             {
  2478.                 changedHome = True;
  2479.                 PrintMsgL(player, "HomeRemove", args[0]);
  2480.             }
  2481.             else
  2482.                 PrintMsgL(player, "HomeNotFound");
  2483.         }
  2484.  
  2485.         private void CommandHome(IPlayer p, string command, string[] args)
  2486.         {
  2487.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2488.             if (!config.Settings.HomesEnabled) { p.Reply("Homes are not enabled in the config."); return; }
  2489.             var player = p.Object as BasePlayer;
  2490.             if (!player || !IsAllowed(player, PermHome) || !player.IsConnected || player.IsSleeping()) return;
  2491.             if (args.Length == 0)
  2492.             {
  2493.                 PrintMsgL(player, "SyntaxCommandHome");
  2494.                 if (IsAllowed(player)) PrintMsgL(player, "SyntaxCommandHomeAdmin");
  2495.                 return;
  2496.             }
  2497.             switch (args[0].ToLower())
  2498.             {
  2499.                 case "add":
  2500.                     CommandSetHome(p, command, args.Skip(1).ToArray());
  2501.                     break;
  2502.                 case "list":
  2503.                     CommandListHomes(p, command, args.Skip(1).ToArray());
  2504.                     break;
  2505.                 case "remove":
  2506.                     CommandRemoveHome(p, command, args.Skip(1).ToArray());
  2507.                     break;
  2508.                 case "radius":
  2509.                     CommandHomeRadius(p, command, args.Skip(1).ToArray());
  2510.                     break;
  2511.                 case "delete":
  2512.                     CommandHomeDelete(p, command, args.Skip(1).ToArray());
  2513.                     break;
  2514.                 case "tp":
  2515.                     CommandHomeAdminTP(p, command, args.Skip(1).ToArray());
  2516.                     break;
  2517.                 case "homes":
  2518.                     CommandHomeHomes(p, command, args.Skip(1).ToArray());
  2519.                     break;
  2520.                 case "wipe":
  2521.                     CommandWipeHomes(p, command, args.Skip(1).ToArray());
  2522.                     break;
  2523.                 default:
  2524.                     cmdChatHomeTP(player, command, args);
  2525.                     break;
  2526.             }
  2527.         }
  2528.  
  2529.         private void CommandHomeRadius(IPlayer p, string command, string[] args)
  2530.         {
  2531.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2532.             var player = p.Object as BasePlayer;
  2533.             if (!player || !IsAllowedMsg(player, PermRadiusHome) || !player.IsConnected || player.IsSleeping()) return;
  2534.             float radius;
  2535.             if (args.Length != 1 || !float.TryParse(args[0], out radius)) radius = 10;
  2536.             var found = False;
  2537.             foreach (var homeData in Home)
  2538.             {
  2539.                 var toRemove = new List<string>();
  2540.                 var target = RustCore.FindPlayerById(homeData.Key)?.displayName ?? homeData.Key.ToString();
  2541.                 foreach (var location in homeData.Value.Locations)
  2542.                 {
  2543.                     if ((player.transform.position - location.Value).magnitude <= radius)
  2544.                     {
  2545.                         if (CheckFoundation(homeData.Key, location.Value) != null)
  2546.                         {
  2547.                             toRemove.Add(location.Key);
  2548.                             continue;
  2549.                         }
  2550.                         var entity = GetFoundationOwned(location.Value, homeData.Key);
  2551.                         if (entity == null) continue;
  2552.                         player.SendConsoleCommand("ddraw.text", 30f, Color.blue, entity.CenterPoint() + new Vector3(0, .5f), $"<size=20>{target} - {location.Key} {location.Value}</size>");
  2553.                         DrawBox(player, entity.CenterPoint(), entity.transform.rotation, entity.bounds.size);
  2554.                         PrintMsg(player, $"{target} - {location.Key} {location.Value}");
  2555.                         found = True;
  2556.                     }
  2557.                 }
  2558.                 foreach (var loc in toRemove)
  2559.                 {
  2560.                     homeData.Value.Locations.Remove(loc);
  2561.                     changedHome = True;
  2562.                 }
  2563.             }
  2564.             if (!found)
  2565.                 PrintMsgL(player, "HomeNoFound");
  2566.         }
  2567.  
  2568.         private void CommandHomeDelete(IPlayer p, string command, string[] args)
  2569.         {
  2570.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2571.             var player = p.Object as BasePlayer;
  2572.             if (!player || !IsAllowedMsg(player, PermDeleteHome) || !player.IsConnected || player.IsSleeping()) return;
  2573.             if (args.Length != 2)
  2574.             {
  2575.                 PrintMsgL(player, "SyntaxCommandHomeDelete");
  2576.                 return;
  2577.             }
  2578.             var userId = FindPlayersSingleId(args[0], player);
  2579.             if (userId <= 0) return;
  2580.             HomeData targetHome;
  2581.             if (!Home.TryGetValue(userId, out targetHome) || !targetHome.Locations.Remove(args[1]))
  2582.             {
  2583.                 PrintMsgL(player, "HomeNotFound");
  2584.                 return;
  2585.             }
  2586.             changedHome = True;
  2587.             PrintMsgL(player, "HomeDelete", args[0], args[1]);
  2588.         }
  2589.  
  2590.         private void CommandHomeAdminTP(IPlayer p, string command, string[] args)
  2591.         {
  2592.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2593.             var player = p.Object as BasePlayer;
  2594.             if (!player || !IsAllowedMsg(player, PermTpHome) || !player.IsConnected || player.IsSleeping()) return;
  2595.             if (args.Length != 2)
  2596.             {
  2597.                 PrintMsgL(player, "SyntaxCommandHomeAdminTP");
  2598.                 return;
  2599.             }
  2600.             var userId = FindPlayersSingleId(args[0], player);
  2601.             if (userId <= 0) return;
  2602.             HomeData targetHome;
  2603.             Vector3 location;
  2604.             if (!Home.TryGetValue(userId, out targetHome) || !targetHome.Locations.TryGetValue(args[1], out location))
  2605.             {
  2606.                 PrintMsgL(player, "HomeNotFound");
  2607.                 return;
  2608.             }
  2609.  
  2610.             Teleport(player, location);
  2611.             PrintMsgL(player, "HomeAdminTP", args[0], args[1]);
  2612.         }
  2613.  
  2614.         // Check that plugins are available and enabled for CheckEconomy()
  2615.         private bool UseEconomy()
  2616.         {
  2617.             if ((config.Settings.UseEconomics && Economics) ||
  2618.                 (config.Settings.UseServerRewards && ServerRewards))
  2619.             {
  2620.                 return True;
  2621.             }
  2622.             return False;
  2623.         }
  2624.  
  2625.         // Check balance on multiple plugins and optionally withdraw money from the player
  2626.         private bool CheckEconomy(BasePlayer player, double bypass, bool withdraw = False, bool deposit = False)
  2627.         {
  2628.             double balance = 0;
  2629.             bool foundmoney = False;
  2630.  
  2631.             // Check Economics first.  If not in use or balance low, check ServerRewards below
  2632.             if (config.Settings.UseEconomics && Economics)
  2633.             {
  2634.                 balance = (double)Economics?.CallHook("Balance", player.UserIDString);
  2635.                 if (balance >= bypass)
  2636.                 {
  2637.                     foundmoney = True;
  2638.                     if (withdraw)
  2639.                     {
  2640.                         var w = (bool)Economics?.CallHook("Withdraw", player.userID, bypass);
  2641.                         return w;
  2642.                     }
  2643.                     else if (deposit)
  2644.                     {
  2645.                         Economics?.CallHook("Deposit", player.userID, bypass);
  2646.                     }
  2647.                 }
  2648.             }
  2649.  
  2650.             // No money via Economics, or plugin not in use.  Try ServerRewards.
  2651.             if (config.Settings.UseServerRewards && ServerRewards)
  2652.             {
  2653.                 object bal = ServerRewards?.Call("CheckPoints", player.userID);
  2654.                 balance = Convert.ToDouble(bal);
  2655.                 if (balance >= bypass && !foundmoney)
  2656.                 {
  2657.                     foundmoney = True;
  2658.                     if (withdraw)
  2659.                     {
  2660.                         var w = (bool)ServerRewards?.Call("TakePoints", player.userID, (int)bypass);
  2661.                         return w;
  2662.                     }
  2663.                     else if (deposit)
  2664.                     {
  2665.                         ServerRewards?.Call("AddPoints", player.userID, (int)bypass);
  2666.                     }
  2667.                 }
  2668.             }
  2669.  
  2670.             // Just checking balance without withdrawal - did we find anything?
  2671.             if (foundmoney)
  2672.             {
  2673.                 return True;
  2674.             }
  2675.             return False;
  2676.         }
  2677.  
  2678.         private void cmdChatHomeTP(BasePlayer player, string command, string[] args)
  2679.         {
  2680.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { player.ChatMessage("Disabled command."); return; }
  2681.             if (!IsAllowed(player, PermHome) || !player.IsConnected || player.IsSleeping()) return;
  2682.             bool paidmoney = False;
  2683.             if (!config.Settings.HomesEnabled) { player.ChatMessage("Homes are not enabled in the config."); return; }
  2684.             if (args.Length < 1)
  2685.             {
  2686.                 PrintMsgL(player, "SyntaxCommandHome");
  2687.                 return;
  2688.             }
  2689.             var err = CheckPlayer(player, config.Home.UsableOutOfBuildingBlocked, CanCraftHome(player), True, "home");
  2690.             if (err != null)
  2691.             {
  2692.                 PrintMsgL(player, err);
  2693.                 return;
  2694.             }
  2695.             HomeData homeData;
  2696.             if (!Home.TryGetValue(player.userID, out homeData) || homeData.Locations.Count <= 0)
  2697.             {
  2698.                 PrintMsgL(player, "HomeListEmpty");
  2699.                 return;
  2700.             }
  2701.             Vector3 location;
  2702.             if (!homeData.Locations.TryGetValue(args[0], out location))
  2703.             {
  2704.                 PrintMsgL(player, "HomeNotFound");
  2705.                 return;
  2706.             }
  2707.             err = CheckFoundation(player.userID, location) ?? CheckTargetLocation(player, location, config.Home.UsableIntoBuildingBlocked, config.Home.CupOwnerAllowOnBuildingBlocked);
  2708.             if (err != null)
  2709.             {
  2710.                 PrintMsgL(player, "HomeRemovedInvalid", args[0]);
  2711.                 homeData.Locations.Remove(args[0]);
  2712.                 changedHome = True;
  2713.                 return;
  2714.             }
  2715.             err = CheckInsideBlock(location);
  2716.             if (err != null)
  2717.             {
  2718.                 PrintMsgL(player, "HomeRemovedInsideBlock", args[0]);
  2719.                 homeData.Locations.Remove(args[0]);
  2720.                 changedHome = True;
  2721.                 return;
  2722.             }
  2723.             var timestamp = Facepunch.Math.Epoch.Current;
  2724.             var currentDate = DateTime.Now.ToString("d");
  2725.             if (homeData.Teleports.Date != currentDate)
  2726.             {
  2727.                 homeData.Teleports.Amount = 0;
  2728.                 homeData.Teleports.Date = currentDate;
  2729.             }
  2730.             var cooldown = GetLower(player, config.Home.VIPCooldowns, config.Home.Cooldown);
  2731.             if (cooldown > 0 && timestamp - homeData.Teleports.Timestamp < cooldown)
  2732.             {
  2733.                 var cmdSent = "";
  2734.                 bool foundmoney = CheckEconomy(player, config.Home.Bypass);
  2735.                 try
  2736.                 {
  2737.                     cmdSent = args[1].ToLower();
  2738.                 }
  2739.                 catch { }
  2740.  
  2741.                 bool payalso = False;
  2742.                 if (config.Home.Pay > 0)
  2743.                 {
  2744.                     payalso = True;
  2745.                 }
  2746.                 if ((config.Settings.BypassCMD != null) && (cmdSent == config.Settings.BypassCMD.ToLower()))
  2747.                 {
  2748.                     if (foundmoney)
  2749.                     {
  2750.                         CheckEconomy(player, config.Home.Bypass, True);
  2751.                         paidmoney = True;
  2752.                         PrintMsgL(player, "HomeTPCooldownBypass", config.Home.Bypass);
  2753.                         if (payalso)
  2754.                         {
  2755.                             PrintMsgL(player, "PayToHome", config.Home.Pay);
  2756.                         }
  2757.                     }
  2758.                     else
  2759.                     {
  2760.                         PrintMsgL(player, "HomeTPCooldownBypassF", config.Home.Bypass);
  2761.                         return;
  2762.                     }
  2763.                 }
  2764.                 else if (UseEconomy())
  2765.                 {
  2766.                     var remain = cooldown - (timestamp - homeData.Teleports.Timestamp);
  2767.                     PrintMsgL(player, "HomeTPCooldown", FormatTime(remain));
  2768.                     if (config.Home.Bypass > 0 && config.Settings.BypassCMD != null)
  2769.                     {
  2770.                         PrintMsgL(player, "HomeTPCooldownBypassP", config.Home.Bypass);
  2771.                         PrintMsgL(player, "HomeTPCooldownBypassP2", config.Settings.BypassCMD);
  2772.                     }
  2773.                     return;
  2774.                 }
  2775.                 else
  2776.                 {
  2777.                     var remain = cooldown - (timestamp - homeData.Teleports.Timestamp);
  2778.                     PrintMsgL(player, "HomeTPCooldown", FormatTime(remain));
  2779.                     return;
  2780.                 }
  2781.             }
  2782.             var limit = GetHigher(player, config.Home.VIPDailyLimits, config.Home.DailyLimit, true);
  2783.             if (limit > 0 && homeData.Teleports.Amount >= limit)
  2784.             {
  2785.                 PrintMsgL(player, "HomeTPLimitReached", limit);
  2786.                 return;
  2787.             }
  2788.             if (TeleportTimers.ContainsKey(player.userID))
  2789.             {
  2790.                 PrintMsgL(player, "TeleportPending");
  2791.                 return;
  2792.             }
  2793.             err = CanPlayerTeleport(player);
  2794.             if (err != null)
  2795.             {
  2796.                 SendReply(player, err);
  2797.                 return;
  2798.             }
  2799.             err = CheckItems(player);
  2800.             if (err != null)
  2801.             {
  2802.                 PrintMsgL(player, "TPBlockedItem", err);
  2803.                 return;
  2804.             }
  2805.  
  2806.             var countdown = GetLower(player, config.Home.VIPCountdowns, config.Home.Countdown);
  2807.             TeleportTimers[player.userID] = new TeleportTimer
  2808.             {
  2809.                 OriginPlayer = player,
  2810.                 Timer = timer.Once(countdown, () =>
  2811.                 {
  2812. #if DEBUG
  2813.                     Puts("Calling CheckPlayer from cmdChatHomeTP");
  2814. #endif
  2815.                     err = CheckPlayer(player, config.Home.UsableOutOfBuildingBlocked, CanCraftHome(player), True, "home");
  2816.                     if (err != null)
  2817.                     {
  2818.                         PrintMsgL(player, "Interrupted");
  2819.                         PrintMsgL(player, err);
  2820.                         if (paidmoney)
  2821.                         {
  2822.                             paidmoney = False;
  2823.                             CheckEconomy(player, config.Home.Bypass, False, True);
  2824.                         }
  2825.                         TeleportTimers.Remove(player.userID);
  2826.                         return;
  2827.                     }
  2828.                     err = CanPlayerTeleport(player);
  2829.                     if (err != null)
  2830.                     {
  2831.                         PrintMsgL(player, "Interrupted");
  2832.                         PrintMsgL(player, err);
  2833.                         if (paidmoney)
  2834.                         {
  2835.                             paidmoney = False;
  2836.                             CheckEconomy(player, config.Home.Bypass, False, True);
  2837.                         }
  2838.                         TeleportTimers.Remove(player.userID);
  2839.                         return;
  2840.                     }
  2841.                     err = CheckItems(player);
  2842.                     if (err != null)
  2843.                     {
  2844.                         PrintMsgL(player, "Interrupted");
  2845.                         PrintMsgL(player, "TPBlockedItem", err);
  2846.                         if (paidmoney)
  2847.                         {
  2848.                             paidmoney = False;
  2849.                             CheckEconomy(player, config.Home.Bypass, False, True);
  2850.                         }
  2851.                         TeleportTimers.Remove(player.userID);
  2852.                         return;
  2853.                     }
  2854.                     err = CheckFoundation(player.userID, location) ?? CheckTargetLocation(player, location, config.Home.UsableIntoBuildingBlocked, config.Home.CupOwnerAllowOnBuildingBlocked);
  2855.                     if (err != null)
  2856.                     {
  2857.                         PrintMsgL(player, "HomeRemovedInvalid", args[0]);
  2858.                         homeData.Locations.Remove(args[0]);
  2859.                         changedHome = True;
  2860.                         if (paidmoney)
  2861.                         {
  2862.                             paidmoney = False;
  2863.                             CheckEconomy(player, config.Home.Bypass, False, True);
  2864.                         }
  2865.                         return;
  2866.                     }
  2867.                     err = CheckInsideBlock(location);
  2868.                     if (err != null)
  2869.                     {
  2870.                         PrintMsgL(player, "HomeRemovedInsideBlock", args[0]);
  2871.                         homeData.Locations.Remove(args[0]);
  2872.                         changedHome = True;
  2873.                         if (paidmoney)
  2874.                         {
  2875.                             paidmoney = False;
  2876.                             CheckEconomy(player, config.Home.Bypass, False, True);
  2877.                         }
  2878.                         return;
  2879.                     }
  2880.  
  2881.                     if (UseEconomy())
  2882.                     {
  2883.                         if (config.Home.Pay > 0 && !CheckEconomy(player, config.Home.Pay))
  2884.                         {
  2885.                             PrintMsgL(player, "Interrupted");
  2886.                             PrintMsgL(player, "TPNoMoney", config.Home.Pay);
  2887.  
  2888.                             TeleportTimers.Remove(player.userID);
  2889.                             return;
  2890.                         }
  2891.                         else if (config.Home.Pay > 0)
  2892.                         {
  2893.                             var w = CheckEconomy(player, (double)config.Home.Pay, True);
  2894.                             PrintMsgL(player, "TPMoney", (double)config.Home.Pay);
  2895.                         }
  2896.                     }
  2897.                    
  2898.                     Teleport(player, location);
  2899.                     homeData.Teleports.Amount++;
  2900.                     homeData.Teleports.Timestamp = timestamp;
  2901.                     changedHome = True;
  2902.                     PrintMsgL(player, "HomeTP", args[0]);
  2903.                     if (limit > 0) PrintMsgL(player, "HomeTPAmount", limit - homeData.Teleports.Amount);
  2904.                     TeleportTimers.Remove(player.userID);
  2905.                 })
  2906.             };
  2907.             PrintMsgL(player, "HomeTPStarted", args[0], countdown);
  2908.         }
  2909.  
  2910.         private void CommandListHomes(IPlayer p, string command, string[] args)
  2911.         {
  2912.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2913.             var player = p.Object as BasePlayer;
  2914.             if (!player || !player.IsConnected || player.IsSleeping()) return;
  2915.             if (!config.Settings.HomesEnabled) { p.Reply("Homes are not enabled in the config."); return; }
  2916.             if (args.Length != 0)
  2917.             {
  2918.                 PrintMsgL(player, "SyntaxCommandListHomes");
  2919.                 return;
  2920.             }
  2921.             HomeData homeData;
  2922.             if (!Home.TryGetValue(player.userID, out homeData) || homeData.Locations.Count <= 0)
  2923.             {
  2924.                 PrintMsgL(player, "HomeListEmpty");
  2925.                 return;
  2926.             }
  2927.             PrintMsgL(player, "HomeList");
  2928.             if (config.Home.CheckValidOnList)
  2929.             {
  2930.                 var toRemove = new List<string>();
  2931.                 foreach (var location in homeData.Locations)
  2932.                 {
  2933.                     var err = CheckFoundation(player.userID, location.Value);
  2934.                     if (err != null)
  2935.                     {
  2936.                         toRemove.Add(location.Key);
  2937.                         continue;
  2938.                     }
  2939.                     PrintMsgL(player, $"{location.Key} {location.Value}");
  2940.                 }
  2941.                 foreach (var loc in toRemove)
  2942.                 {
  2943.                     PrintMsgL(player, "HomeRemovedInvalid", loc);
  2944.                     homeData.Locations.Remove(loc);
  2945.                     changedHome = True;
  2946.                 }
  2947.                 return;
  2948.             }
  2949.             foreach (var location in homeData.Locations)
  2950.                 PrintMsgL(player, $"{location.Key} {location.Value}");
  2951.         }
  2952.  
  2953.         private void CommandHomeHomes(IPlayer p, string command, string[] args)
  2954.         {
  2955.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2956.             var player = p.Object as BasePlayer;
  2957.             if (!player || !IsAllowedMsg(player, PermHomeHomes) || !player.IsConnected || player.IsSleeping()) return;
  2958.             if (args.Length != 1)
  2959.             {
  2960.                 PrintMsgL(player, "SyntaxCommandHomeHomes");
  2961.                 return;
  2962.             }
  2963.             var userId = FindPlayersSingleId(args[0], player);
  2964.             if (userId <= 0) return;
  2965.             HomeData homeData;
  2966.             if (!Home.TryGetValue(userId, out homeData) || homeData.Locations.Count <= 0)
  2967.             {
  2968.                 PrintMsgL(player, "HomeListEmpty");
  2969.                 return;
  2970.             }
  2971.             PrintMsgL(player, "HomeList");
  2972.             var toRemove = new List<string>();
  2973.             foreach (var location in homeData.Locations)
  2974.             {
  2975.                 var err = CheckFoundation(userId, location.Value);
  2976.                 if (err != null)
  2977.                 {
  2978.                     toRemove.Add(location.Key);
  2979.                     continue;
  2980.                 }
  2981.                 PrintMsgL(player, $"{location.Key} {location.Value}");
  2982.             }
  2983.             foreach (var loc in toRemove)
  2984.             {
  2985.                 PrintMsgL(player, "HomeRemovedInvalid", loc);
  2986.                 homeData.Locations.Remove(loc);
  2987.                 changedHome = True;
  2988.             }
  2989.         }
  2990.  
  2991.         private void CommandTeleportTeam(IPlayer p, string command, string[] args)
  2992.         {
  2993.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  2994.             if (!config.TPT.UseClans && !config.TPT.UseFriends && !config.TPT.UseTeams)
  2995.                 return;
  2996.  
  2997.             var player = p.Object as BasePlayer;
  2998.             if (!player || !IsAllowedMsg(player, PermTpT))
  2999.                 return;
  3000.  
  3001.             if (args.Length < 1)
  3002.             {
  3003.                 PrintMsgL(player, "TPTInfo");
  3004.                 return;
  3005.             }
  3006.  
  3007.             switch (args[0].ToLower())
  3008.             {
  3009.                 case "friend":
  3010.                 case "clan":
  3011.                 case "team":
  3012.                     {
  3013.                         SetDisabled(player, args[0].ToLower());
  3014.                         return;
  3015.                     }
  3016.             }
  3017.  
  3018.             PrintMsgL(player, "TPTInfo");
  3019.         }
  3020.  
  3021.         public bool IsOnSameTeam(ulong playerId, ulong targetId)
  3022.         {
  3023.             if (!config.TPT.UseTeams || !IsEnabled(targetId.ToString(), "team"))
  3024.             {
  3025.                 return false;
  3026.             }
  3027.  
  3028.             RelationshipManager.PlayerTeam team1;
  3029.             if (!RelationshipManager.Instance.playerToTeam.TryGetValue(playerId, out team1))
  3030.             {
  3031.                 return false;
  3032.             }
  3033.  
  3034.             RelationshipManager.PlayerTeam team2;
  3035.             if (!RelationshipManager.Instance.playerToTeam.TryGetValue(targetId, out team2))
  3036.             {
  3037.                 return false;
  3038.             }
  3039.  
  3040.             return team1.teamID == team2.teamID;
  3041.         }
  3042.  
  3043.         private bool AreFriends(string playerId, string targetId)
  3044.         {
  3045.             if (!config.TPT.UseFriends || !IsEnabled(targetId, "friend") || !Friends || !Friends.IsLoaded)
  3046.             {
  3047.                 return False;
  3048.             }
  3049.  
  3050.             return Friends?.Call<bool>("AreFriends", playerId, targetId) ?? False;
  3051.         }
  3052.  
  3053.         private bool IsInSameClan(string playerId, string targetId)
  3054.         {
  3055.             if (!config.TPT.UseClans || !IsEnabled(targetId, "clan") || !Clans || !Clans.IsLoaded)
  3056.             {
  3057.                 return false;
  3058.             }
  3059.  
  3060.             string targetClan = Clans?.Call<string>("GetClanOf", targetId);
  3061.  
  3062.             if (targetClan == null)
  3063.             {
  3064.                 return false;
  3065.             }
  3066.  
  3067.             string playerClan = Clans?.Call<string>("GetClanOf", playerId);
  3068.  
  3069.             if (playerClan == null)
  3070.             {
  3071.                 return false;
  3072.             }
  3073.  
  3074.             return targetClan == playerClan;
  3075.         }
  3076.  
  3077.         private void OnTeleportRequested(BasePlayer target, BasePlayer player)
  3078.         {
  3079.             if (IsInSameClan(player.UserIDString, target.UserIDString) || AreFriends(player.UserIDString, target.UserIDString) || IsOnSameTeam(player.userID, target.userID))
  3080.             {
  3081.                 target.SendConsoleCommand("chat.say /tpa");
  3082.             }
  3083.         }
  3084.  
  3085.         bool IsEnabled(string targetId, string value)
  3086.         {
  3087.             if (TPT.ContainsKey(targetId) && TPT[targetId].Contains(value))
  3088.             {
  3089.                 return false;
  3090.             }
  3091.  
  3092.             return true;
  3093.         }
  3094.  
  3095.         void SetDisabled(BasePlayer target, string value)
  3096.         {
  3097.             List<string> list;
  3098.             if (!TPT.TryGetValue(target.UserIDString, out list))
  3099.             {
  3100.                 TPT[target.UserIDString] = list = new List<string>();
  3101.             }
  3102.  
  3103.             if (list.Contains(value))
  3104.             {
  3105.                 list.Remove(value);
  3106.             }
  3107.             else
  3108.             {
  3109.                 list.Add(value);
  3110.             }
  3111.  
  3112.             string status = lang.GetMessage($"TPT_{!list.Contains(value)}", this, target.UserIDString);
  3113.             string message = string.Format(lang.GetMessage($"TPT_{value}", this, target.UserIDString), status);
  3114.  
  3115.             PrintMsg(target, message);
  3116.             changedTPT = True;
  3117.         }
  3118.  
  3119.         private void CommandTeleportRequest(IPlayer p, string command, string[] args)
  3120.         {
  3121.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  3122.             var player = p.Object as BasePlayer;
  3123.             if (!player || !IsAllowedMsg(player, PermTpR) || !player.IsConnected || player.IsSleeping()) return;
  3124.             if (!config.Settings.TPREnabled) { p.Reply("TPR is not enabled in the config."); return; }
  3125.             if (args.Length == 0)
  3126.             {
  3127.                 PrintMsgL(player, "SyntaxCommandTPR");
  3128.                 return;
  3129.             }
  3130.             var targets = FindPlayersOnline(args[0]);
  3131.             if (targets.Count <= 0)
  3132.             {
  3133.                 PrintMsgL(player, "PlayerNotFound");
  3134.                 return;
  3135.             }
  3136.             if (targets.Count > 1)
  3137.             {
  3138.                 PrintMsgL(player, "MultiplePlayers", string.Join(", ", targets.Select(x => x.displayName).ToArray()));
  3139.                 return;
  3140.             }
  3141.             var target = targets[0];
  3142.             if (target == player && !player.IsAdmin)
  3143.             {
  3144. #if DEBUG
  3145.                 Puts("Debug mode - allowing self teleport.");
  3146. #else
  3147.         PrintMsgL(player, "CantTeleportToSelf");
  3148.         return;
  3149. #endif
  3150.             }
  3151. #if DEBUG
  3152.             Puts("Calling CheckPlayer from cmdChatTeleportRequest");
  3153. #endif
  3154.  
  3155.             var err = CheckPlayer(player, config.TPR.UsableOutOfBuildingBlocked, CanCraftTPR(player), True, "tpr");
  3156.             if (err != null)
  3157.             {
  3158.                 PrintMsgL(player, err);
  3159.                 return;
  3160.             }
  3161.             err = CheckTargetLocation(target, target.transform.position, config.TPR.UsableIntoBuildingBlocked, config.TPR.CupOwnerAllowOnBuildingBlocked);
  3162.             if (err != null)
  3163.             {
  3164.                 PrintMsgL(player, err);
  3165.                 return;
  3166.             }
  3167.             var timestamp = Facepunch.Math.Epoch.Current;
  3168.             var currentDate = DateTime.Now.ToString("d");
  3169.             TeleportData tprData;
  3170.             if (!TPR.TryGetValue(player.userID, out tprData))
  3171.                 TPR[player.userID] = tprData = new TeleportData();
  3172.             if (tprData.Date != currentDate)
  3173.             {
  3174.                 tprData.Amount = 0;
  3175.                 tprData.Date = currentDate;
  3176.             }
  3177.  
  3178.             var cooldown = player.IsAdmin ? 0 : GetLower(player, config.TPR.VIPCooldowns, config.TPR.Cooldown);
  3179.             if (cooldown > 0 && timestamp - tprData.Timestamp < cooldown)
  3180.             {
  3181.                 var cmdSent = "";
  3182.                 bool foundmoney = CheckEconomy(player, config.TPR.Bypass);
  3183.                 try
  3184.                 {
  3185.                     cmdSent = args[1].ToLower();
  3186.                 }
  3187.                 catch { }
  3188.  
  3189.                 bool payalso = False;
  3190.                 if (config.TPR.Pay > 0)
  3191.                 {
  3192.                     payalso = True;
  3193.                 }
  3194.                 if ((config.Settings.BypassCMD != null) && (cmdSent == config.Settings.BypassCMD.ToLower()))
  3195.                 {
  3196.                     if (foundmoney)
  3197.                     {
  3198.                         CheckEconomy(player, config.TPR.Bypass, True);
  3199.                         PrintMsgL(player, "TPRCooldownBypass", config.TPR.Bypass);
  3200.                         if (payalso)
  3201.                         {
  3202.                             PrintMsgL(player, "PayToTPR", config.TPR.Pay);
  3203.                         }
  3204.                     }
  3205.                     else
  3206.                     {
  3207.                         PrintMsgL(player, "TPRCooldownBypassF", config.TPR.Bypass);
  3208.                         return;
  3209.                     }
  3210.                 }
  3211.                 else if (UseEconomy())
  3212.                 {
  3213.                     var remain = cooldown - (timestamp - tprData.Timestamp);
  3214.                     PrintMsgL(player, "TPRCooldown", FormatTime(remain));
  3215.                     if (config.TPR.Bypass > 0 && config.Settings.BypassCMD != null)
  3216.                     {
  3217.                         PrintMsgL(player, "TPRCooldownBypassP", config.TPR.Bypass);
  3218.                         if (payalso)
  3219.                         {
  3220.                             PrintMsgL(player, "PayToTPR", config.TPR.Pay);
  3221.                         }
  3222.                         PrintMsgL(player, "TPRCooldownBypassP2a", config.Settings.BypassCMD);
  3223.                     }
  3224.                     return;
  3225.                 }
  3226.                 else
  3227.                 {
  3228.                     var remain = cooldown - (timestamp - tprData.Timestamp);
  3229.                     PrintMsgL(player, "TPRCooldown", FormatTime(remain));
  3230.                     return;
  3231.                 }
  3232.             }
  3233.             var limit = GetHigher(player, config.TPR.VIPDailyLimits, config.TPR.DailyLimit, true);
  3234.             if (limit > 0 && tprData.Amount >= limit)
  3235.             {
  3236.                 PrintMsgL(player, "TPRLimitReached", limit);
  3237.                 return;
  3238.             }
  3239.             if (TeleportTimers.ContainsKey(player.userID))
  3240.             {
  3241.                 PrintMsgL(player, "TeleportPending");
  3242.                 return;
  3243.             }
  3244.             if (TeleportTimers.ContainsKey(target.userID))
  3245.             {
  3246.                 PrintMsgL(player, "TeleportPendingTarget");
  3247.                 return;
  3248.             }
  3249.             if (PlayersRequests.ContainsKey(player.userID))
  3250.             {
  3251.                 PrintMsgL(player, "PendingRequest");
  3252.                 return;
  3253.             }
  3254.             if (PlayersRequests.ContainsKey(target.userID))
  3255.             {
  3256.                 PrintMsgL(player, "PendingRequestTarget");
  3257.                 return;
  3258.             }
  3259.             err = CanPlayerTeleport(player);
  3260.             if (err != null)
  3261.             {
  3262.                 SendReply(player, err);
  3263.                 return;
  3264.             }
  3265.             err = CanPlayerTeleport(target);
  3266.             if (err != null)
  3267.             {
  3268.                 PrintMsgL(player, "TPRTarget");
  3269.                 return;
  3270.             }
  3271.             err = CheckItems(player);
  3272.             if (err != null)
  3273.             {
  3274.                 PrintMsgL(player, "TPBlockedItem", err);
  3275.                 return;
  3276.             }
  3277.  
  3278.             PlayersRequests[player.userID] = target;
  3279.             PlayersRequests[target.userID] = player;
  3280.             PendingRequests[target.userID] = timer.Once(config.TPR.RequestDuration, () => { RequestTimedOut(player, target); });
  3281.             PrintMsgL(player, "Request", target.displayName);
  3282.             PrintMsgL(target, "RequestTarget", player.displayName);
  3283.             Interface.CallHook("OnTeleportRequested", target, player);
  3284.         }
  3285.  
  3286.         private void CommandTeleportAccept(IPlayer p, string command, string[] args)
  3287.         {
  3288.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  3289.             var player = p.Object as BasePlayer;
  3290.             if (!player || !player.IsConnected || player.IsSleeping()) return;
  3291.             if (!config.Settings.TPREnabled) { p.Reply("TPR is not enabled in the config."); return; }
  3292.             if (args.Length != 0)
  3293.             {
  3294.                 PrintMsgL(player, "SyntaxCommandTPA");
  3295.                 return;
  3296.             }
  3297.             Timer reqTimer;
  3298.             if (!PendingRequests.TryGetValue(player.userID, out reqTimer))
  3299.             {
  3300.                 PrintMsgL(player, "NoPendingRequest");
  3301.                 return;
  3302.             }
  3303. #if DEBUG
  3304.             Puts("Calling CheckPlayer from cmdChatTeleportAccept");
  3305. #endif
  3306.             var err = CheckPlayer(player, False, CanCraftTPR(player), False, "tpa");
  3307.             if (err != null)
  3308.             {
  3309.                 PrintMsgL(player, err);
  3310.                 return;
  3311.             }
  3312.             err = CanPlayerTeleport(player);
  3313.             if (err != null)
  3314.             {
  3315.                 SendReply(player, err);
  3316.                 return;
  3317.             }
  3318.             var originPlayer = PlayersRequests[player.userID];
  3319.             err = CheckTargetLocation(originPlayer, player.transform.position, config.TPR.UsableIntoBuildingBlocked, config.TPR.CupOwnerAllowOnBuildingBlocked);
  3320.             if (err != null)
  3321.             {
  3322.                 SendReply(player, err);
  3323.                 return;
  3324.             }
  3325.             if (config.TPR.BlockTPAOnCeiling)
  3326.             {
  3327.                 if (GetFloor(player.transform.position).Count > 0)
  3328.                 {
  3329.                     PrintMsgL(player, "AcceptOnRoof");
  3330.                     return;
  3331.                 }
  3332.             }
  3333.             var countdown = GetLower(originPlayer, config.TPR.VIPCountdowns, config.TPR.Countdown);
  3334.             PrintMsgL(originPlayer, "Accept", player.displayName, countdown);
  3335.             PrintMsgL(player, "AcceptTarget", originPlayer.displayName);
  3336.             var timestamp = Facepunch.Math.Epoch.Current;
  3337.             TeleportTimers[originPlayer.userID] = new TeleportTimer
  3338.             {
  3339.                 OriginPlayer = originPlayer,
  3340.                 TargetPlayer = player,
  3341.                 Timer = timer.Once(countdown, () =>
  3342.                 {
  3343. #if DEBUG
  3344.                     Puts("Calling CheckPlayer from cmdChatTeleportAccept timer loop");
  3345. #endif
  3346.                     err = CheckPlayer(originPlayer, config.TPR.UsableOutOfBuildingBlocked, CanCraftTPR(originPlayer), True, "tpa") ?? CheckPlayer(player, False, CanCraftTPR(player), True, "tpa");
  3347.                     if (err != null)
  3348.                     {
  3349.                         PrintMsgL(player, "InterruptedTarget", originPlayer.displayName);
  3350.                         PrintMsgL(originPlayer, "Interrupted");
  3351.                         PrintMsgL(originPlayer, err);
  3352.                         TeleportTimers.Remove(originPlayer.userID);
  3353.                         return;
  3354.                     }
  3355.                     err = CheckTargetLocation(originPlayer, player.transform.position, config.TPR.UsableIntoBuildingBlocked, config.TPR.CupOwnerAllowOnBuildingBlocked);
  3356.                     if (err != null)
  3357.                     {
  3358.                         SendReply(player, err);
  3359.                         PrintMsgL(originPlayer, "Interrupted");
  3360.                         SendReply(originPlayer, err);
  3361.                         TeleportTimers.Remove(originPlayer.userID);
  3362.                         return;
  3363.                     }
  3364.                     err = CanPlayerTeleport(originPlayer) ?? CanPlayerTeleport(player);
  3365.                     if (err != null)
  3366.                     {
  3367.                         SendReply(player, err);
  3368.                         PrintMsgL(originPlayer, "Interrupted");
  3369.                         SendReply(originPlayer, err);
  3370.                         TeleportTimers.Remove(originPlayer.userID);
  3371.                         return;
  3372.                     }
  3373.                     err = CheckItems(originPlayer);
  3374.                     if (err != null)
  3375.                     {
  3376.                         PrintMsgL(player, "InterruptedTarget", originPlayer.displayName);
  3377.                         PrintMsgL(originPlayer, "Interrupted");
  3378.                         PrintMsgL(originPlayer, "TPBlockedItem", err);
  3379.                         TeleportTimers.Remove(originPlayer.userID);
  3380.                         return;
  3381.                     }
  3382.                     if (UseEconomy())
  3383.                     {
  3384.                         if (config.TPR.Pay > 0)
  3385.                         {
  3386.                             if (!CheckEconomy(originPlayer, config.TPR.Pay))
  3387.                             {
  3388.                                 PrintMsgL(player, "InterruptedTarget", originPlayer.displayName);
  3389.                                 PrintMsgL(originPlayer, "TPNoMoney", config.TPR.Pay);
  3390.                                 TeleportTimers.Remove(originPlayer.userID);
  3391.                                 return;
  3392.                             }
  3393.                             else
  3394.                             {
  3395.                                 CheckEconomy(originPlayer, config.TPR.Pay, True);
  3396.                                 PrintMsgL(originPlayer, "TPMoney", (double)config.TPR.Pay);
  3397.                             }
  3398.                         }
  3399.                     }
  3400.                     Teleport(originPlayer, player.transform.position, config.TPR.AllowTPB);
  3401.                     var tprData = TPR[originPlayer.userID];
  3402.                     tprData.Amount++;
  3403.                     tprData.Timestamp = timestamp;
  3404.                     changedTPR = True;
  3405.                     PrintMsgL(player, "SuccessTarget", originPlayer.displayName);
  3406.                     PrintMsgL(originPlayer, "Success", player.displayName);
  3407.                     var limit = GetHigher(player, config.TPR.VIPDailyLimits, config.TPR.DailyLimit, true);
  3408.                     if (limit > 0) PrintMsgL(originPlayer, "TPRAmount", limit - tprData.Amount);
  3409.                     TeleportTimers.Remove(originPlayer.userID);
  3410.                 })
  3411.             };
  3412.             reqTimer.Destroy();
  3413.             PendingRequests.Remove(player.userID);
  3414.             PlayersRequests.Remove(player.userID);
  3415.             PlayersRequests.Remove(originPlayer.userID);
  3416.         }
  3417.  
  3418.         private void CommandWipeHomes(IPlayer p, string command, string[] args)
  3419.         {
  3420.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  3421.             var player = p.Object as BasePlayer;
  3422.             if (!player || !IsAllowedMsg(player, PermWipeHomes) || !player.IsConnected || player.IsSleeping()) return;
  3423.             Home.Clear();
  3424.             changedHome = True;
  3425.             PrintMsgL(player, "HomesListWiped");
  3426.         }
  3427.  
  3428.         private void CommandTeleportHelp(IPlayer p, string command, string[] args)
  3429.         {
  3430.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  3431.             var player = p.Object as BasePlayer;
  3432.             if (!player || !player.IsConnected || player.IsSleeping()) return;
  3433.             if (!config.Settings.HomesEnabled && !config.Settings.TPREnabled && !IsAllowedMsg(player)) return;
  3434.             if (args.Length == 1)
  3435.             {
  3436.                 var key = $"TPHelp{args[0].ToLower()}";
  3437.                 var msg = _(key, player);
  3438.                 if (key.Equals(msg))
  3439.                     PrintMsgL(player, "InvalidHelpModule");
  3440.                 else
  3441.                     PrintMsg(player, msg);
  3442.             }
  3443.             else
  3444.             {
  3445.                 var msg = _("TPHelpGeneral", player);
  3446.                 if (IsAllowed(player))
  3447.                     msg += NewLine + "/tphelp AdminTP";
  3448.                 if (config.Settings.HomesEnabled)
  3449.                     msg += NewLine + "/tphelp Home";
  3450.                 if (config.Settings.TPREnabled)
  3451.                     msg += NewLine + "/tphelp TPR";
  3452.                 PrintMsg(player, msg);
  3453.             }
  3454.         }
  3455.  
  3456.         private void CommandTeleportInfo(IPlayer p, string command, string[] args)
  3457.         {
  3458.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  3459.             if (!config.Settings.HomesEnabled && !config.Settings.TPREnabled && !config.Settings.TownEnabled) { p.Reply($"{command} is not enabled in the config."); return; }
  3460.             var player = p.Object as BasePlayer;
  3461.             if (!player || !player.IsConnected || player.IsSleeping()) return;
  3462.             if (args.Length == 1)
  3463.             {
  3464.                 var module = args[0].ToLower();
  3465.                 var msg = _($"TPSettings{module}", player);
  3466.                 var timestamp = Facepunch.Math.Epoch.Current;
  3467.                 var currentDate = DateTime.Now.ToString("d");
  3468.                 TeleportData teleportData;
  3469.                 int limit;
  3470.                 int cooldown;
  3471.                 switch (module)
  3472.                 {
  3473.                     case "home":
  3474.                         limit = GetHigher(player, config.Home.VIPDailyLimits, config.Home.DailyLimit, true);
  3475.                         cooldown = GetLower(player, config.Home.VIPCooldowns, config.Home.Cooldown);
  3476.                         PrintMsg(player, string.Format(msg, FormatTime(cooldown), limit > 0 ? limit.ToString() : _("Unlimited", player), GetLower(player, config.Home.VIPHomesLimits, config.Home.HomesLimit)));
  3477.                         HomeData homeData;
  3478.                         if (!Home.TryGetValue(player.userID, out homeData))
  3479.                             Home[player.userID] = homeData = new HomeData();
  3480.                         if (homeData.Teleports.Date != currentDate)
  3481.                         {
  3482.                             homeData.Teleports.Amount = 0;
  3483.                             homeData.Teleports.Date = currentDate;
  3484.                         }
  3485.                         if (limit > 0) PrintMsgL(player, "HomeTPAmount", limit - homeData.Teleports.Amount);
  3486.                         if (cooldown > 0 && timestamp - homeData.Teleports.Timestamp < cooldown)
  3487.                         {
  3488.                             var remain = cooldown - (timestamp - homeData.Teleports.Timestamp);
  3489.                             PrintMsgL(player, "HomeTPCooldown", FormatTime(remain));
  3490.                         }
  3491.                         break;
  3492.                     case "tpr":
  3493.                         limit = GetHigher(player, config.TPR.VIPDailyLimits, config.TPR.DailyLimit, true);
  3494.                         cooldown = GetLower(player, config.TPR.VIPCooldowns, config.TPR.Cooldown);
  3495.                         PrintMsg(player, string.Format(msg, FormatTime(cooldown), limit > 0 ? limit.ToString() : _("Unlimited", player)));
  3496.                         if (!TPR.TryGetValue(player.userID, out teleportData))
  3497.                             TPR[player.userID] = teleportData = new TeleportData();
  3498.                         if (teleportData.Date != currentDate)
  3499.                         {
  3500.                             teleportData.Amount = 0;
  3501.                             teleportData.Date = currentDate;
  3502.                         }
  3503.                         if (limit > 0) PrintMsgL(player, "TPRAmount", limit - teleportData.Amount);
  3504.                         if (cooldown > 0 && timestamp - teleportData.Timestamp < cooldown)
  3505.                         {
  3506.                             var remain = cooldown - (timestamp - teleportData.Timestamp);
  3507.                             PrintMsgL(player, "TPRCooldown", FormatTime(remain));
  3508.                         }
  3509.                         break;
  3510.                     case "town":
  3511.                         limit = GetHigher(player, config.Town.VIPDailyLimits, config.Town.DailyLimit, true);
  3512.                         cooldown = GetLower(player, config.Town.VIPCooldowns, config.Town.Cooldown);
  3513.                         PrintMsg(player, string.Format(msg, FormatTime(cooldown), limit > 0 ? limit.ToString() : _("Unlimited", player)));
  3514.                         if (!Town.TryGetValue(player.userID, out teleportData))
  3515.                             Town[player.userID] = teleportData = new TeleportData();
  3516.                         if (teleportData.Date != currentDate)
  3517.                         {
  3518.                             teleportData.Amount = 0;
  3519.                             teleportData.Date = currentDate;
  3520.                         }
  3521.                         if (limit > 0) PrintMsgL(player, "TownTPAmount", limit - teleportData.Amount);
  3522.                         if (cooldown > 0 && timestamp - teleportData.Timestamp < cooldown)
  3523.                         {
  3524.                             var remain = cooldown - (timestamp - teleportData.Timestamp);
  3525.                             PrintMsgL(player, "TownTPCooldown", FormatTime(remain));
  3526.                             PrintMsgL(player, "TownTPCooldownBypassP", config.Town.Bypass);
  3527.                             PrintMsgL(player, "TownTPCooldownBypassP2", config.Settings.BypassCMD);
  3528.                         }
  3529.                         break;
  3530.                     case "outpost":
  3531.                         limit = GetHigher(player, config.Outpost.VIPDailyLimits, config.Outpost.DailyLimit, true);
  3532.                         cooldown = GetLower(player, config.Outpost.VIPCooldowns, config.Outpost.Cooldown);
  3533.                         PrintMsg(player, string.Format(msg, FormatTime(cooldown), limit > 0 ? limit.ToString() : _("Unlimited", player)));
  3534.                         if (!Outpost.TryGetValue(player.userID, out teleportData))
  3535.                             Outpost[player.userID] = teleportData = new TeleportData();
  3536.                         if (teleportData.Date != currentDate)
  3537.                         {
  3538.                             teleportData.Amount = 0;
  3539.                             teleportData.Date = currentDate;
  3540.                         }
  3541.                         if (limit > 0) PrintMsgL(player, "OutpostTPAmount", limit - teleportData.Amount);
  3542.                         if (cooldown > 0 && timestamp - teleportData.Timestamp < cooldown)
  3543.                         {
  3544.                             var remain = cooldown - (timestamp - teleportData.Timestamp);
  3545.                             PrintMsgL(player, "OutpostTPCooldown", FormatTime(remain));
  3546.                             PrintMsgL(player, "OutpostTPCooldownBypassP", config.Outpost.Bypass);
  3547.                             PrintMsgL(player, "OutpostTPCooldownBypassP2", config.Settings.BypassCMD);
  3548.                         }
  3549.                         break;
  3550.                     case "bandit":
  3551.                         limit = GetHigher(player, config.Bandit.VIPDailyLimits, config.Bandit.DailyLimit, true);
  3552.                         cooldown = GetLower(player, config.Bandit.VIPCooldowns, config.Bandit.Cooldown);
  3553.                         PrintMsg(player, string.Format(msg, FormatTime(cooldown), limit > 0 ? limit.ToString() : _("Unlimited", player)));
  3554.                         if (!Bandit.TryGetValue(player.userID, out teleportData))
  3555.                             Bandit[player.userID] = teleportData = new TeleportData();
  3556.                         if (teleportData.Date != currentDate)
  3557.                         {
  3558.                             teleportData.Amount = 0;
  3559.                             teleportData.Date = currentDate;
  3560.                         }
  3561.                         if (limit > 0) PrintMsgL(player, "BanditTPAmount", limit - teleportData.Amount);
  3562.                         if (cooldown > 0 && timestamp - teleportData.Timestamp < cooldown)
  3563.                         {
  3564.                             var remain = cooldown - (timestamp - teleportData.Timestamp);
  3565.                             PrintMsgL(player, "BanditTPCooldown", FormatTime(remain));
  3566.                             PrintMsgL(player, "BanditTPCooldownBypassP", config.Bandit.Bypass);
  3567.                             PrintMsgL(player, "BanditTPCooldownBypassP2", config.Settings.BypassCMD);
  3568.                         }
  3569.                         break;
  3570.                     default:
  3571.                         PrintMsgL(player, "InvalidHelpModule");
  3572.                         break;
  3573.                 }
  3574.             }
  3575.             else
  3576.             {
  3577.                 var msg = _("TPInfoGeneral", player);
  3578.                 if (config.Settings.HomesEnabled)
  3579.                     msg += NewLine + "/tpinfo Home";
  3580.                 if (config.Settings.TPREnabled)
  3581.                     msg += NewLine + "/tpinfo TPR";
  3582.                 if (config.Settings.TownEnabled)
  3583.                     msg += NewLine + "/tpinfo Town";
  3584.                 if (outpostEnabled)
  3585.                     msg += NewLine + "/tpinfo Outpost";
  3586.                 if (banditEnabled)
  3587.                     msg += NewLine + "/tpinfo Bandit";
  3588.                 PrintMsgL(player, msg);
  3589.             }
  3590.         }
  3591.  
  3592.         private void CommandTeleportCancel(IPlayer p, string command, string[] args)
  3593.         {
  3594.             var player = p.Object as BasePlayer;
  3595.             if (!player || !player.IsConnected || player.IsSleeping()) return;
  3596.             if (args.Length != 0)
  3597.             {
  3598.                 PrintMsgL(player, "SyntaxCommandTPC");
  3599.                 return;
  3600.             }
  3601.             TeleportTimer teleportTimer;
  3602.             if (TeleportTimers.TryGetValue(player.userID, out teleportTimer))
  3603.             {
  3604.                 teleportTimer.Timer?.Destroy();
  3605.                 PrintMsgL(player, "TPCancelled");
  3606.                 PrintMsgL(teleportTimer.TargetPlayer, "TPCancelledTarget", player.displayName);
  3607.                 TeleportTimers.Remove(player.userID);
  3608.                 return;
  3609.             }
  3610.             foreach (var keyValuePair in TeleportTimers)
  3611.             {
  3612.                 if (keyValuePair.Value.TargetPlayer != player) continue;
  3613.                 keyValuePair.Value.Timer?.Destroy();
  3614.                 PrintMsgL(keyValuePair.Value.OriginPlayer, "TPCancelledTarget", player.displayName);
  3615.                 PrintMsgL(player, "TPYouCancelledTarget", keyValuePair.Value.OriginPlayer.displayName);
  3616.                 TeleportTimers.Remove(keyValuePair.Key);
  3617.                 return;
  3618.             }
  3619.             BasePlayer target;
  3620.             if (!PlayersRequests.TryGetValue(player.userID, out target))
  3621.             {
  3622.                 PrintMsgL(player, "NoPendingRequest");
  3623.                 return;
  3624.             }
  3625.             Timer reqTimer;
  3626.             if (PendingRequests.TryGetValue(player.userID, out reqTimer))
  3627.             {
  3628.                 reqTimer.Destroy();
  3629.                 PendingRequests.Remove(player.userID);
  3630.             }
  3631.             else if (PendingRequests.TryGetValue(target.userID, out reqTimer))
  3632.             {
  3633.                 reqTimer.Destroy();
  3634.                 PendingRequests.Remove(target.userID);
  3635.                 var temp = player;
  3636.                 player = target;
  3637.                 target = temp;
  3638.             }
  3639.             PlayersRequests.Remove(target.userID);
  3640.             PlayersRequests.Remove(player.userID);
  3641.             PrintMsgL(player, "Cancelled", target.displayName);
  3642.             PrintMsgL(target, "CancelledTarget", player.displayName);
  3643.         }
  3644.  
  3645.         private void CommandOutpost(IPlayer p, string command, string[] args)
  3646.         {
  3647.             CommandTown(p, "outpost", args);
  3648.         }
  3649.  
  3650.         private void CommandBandit(IPlayer p, string command, string[] args)
  3651.         {
  3652.             CommandTown(p, "bandit", args);
  3653.         }
  3654.  
  3655.         private void CommandTown(IPlayer p, string command, string[] args)
  3656.         {
  3657.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  3658.             var player = p.Object as BasePlayer;
  3659.             if (!player || !player.IsConnected || player.IsSleeping()) return;
  3660. #if DEBUG
  3661.             Puts($"cmdChatTown: command={command}");
  3662. #endif
  3663.             switch (command)
  3664.             {
  3665.                 case "outpost":
  3666.                     if (!IsAllowedMsg(player, PermTpOutpost)) return;
  3667.                     break;
  3668.                 case "bandit":
  3669.                     if (!IsAllowedMsg(player, PermTpBandit)) return;
  3670.                     break;
  3671.                 case "town":
  3672.                 default:
  3673.                     if (!IsAllowedMsg(player, PermTpTown)) return;
  3674.                     break;
  3675.             }
  3676.  
  3677.             // For admin using set command
  3678.             if (args.Length == 1 && IsAllowed(player) && args[0].ToLower().Equals("set"))
  3679.             {
  3680.                 switch (command)
  3681.                 {
  3682.                     case "outpost":
  3683.                         config.Outpost.Location = player.transform.position;
  3684.                         SaveConfig();
  3685.                         PrintMsgL(player, "OutpostTPLocation", config.Outpost.Location);
  3686.                         break;
  3687.                     case "bandit":
  3688.                         config.Bandit.Location = player.transform.position;
  3689.                         SaveConfig();
  3690.                         PrintMsgL(player, "BanditTPLocation", config.Bandit.Location);
  3691.                         break;
  3692.                     case "town":
  3693.                     default:
  3694.                         config.Town.Location = player.transform.position;
  3695.                         SaveConfig();
  3696.                         PrintMsgL(player, "TownTPLocation", config.Town.Location);
  3697.                         break;
  3698.                 }
  3699.                 return;
  3700.             }
  3701.  
  3702.             bool paidmoney = False;
  3703.  
  3704.             // Is outpost/bandit/town usage enabled?
  3705.             if (!outpostEnabled && command == "outpost")
  3706.             {
  3707.                 PrintMsgL(player, OutpostTPDisabledMessage);
  3708.                 return;
  3709.             }
  3710.             else if (!banditEnabled && command == "bandit")
  3711.             {
  3712.                 PrintMsgL(player, BanditTPDisabledMessage);
  3713.                 return;
  3714.             }
  3715.             else if (!config.Settings.TownEnabled && command == "town")
  3716.             {
  3717.                 PrintMsgL(player, "TownTPDisabled");
  3718.                 return;
  3719.             }
  3720.  
  3721.             // Are they trying to bypass cooldown or did they just type something else?
  3722.             if (args.Length == 1 && (args[0].ToLower() != config.Settings.BypassCMD.ToLower()))
  3723.             {
  3724.                 string com = command ?? "town";
  3725.                 string msg = "SyntaxCommand" + char.ToUpper(com[0]) + com.Substring(1);
  3726.                 PrintMsgL(player, msg);
  3727.                 if (IsAllowed(player)) PrintMsgL(player, msg + "Admin");
  3728.                 return;
  3729.             }
  3730.  
  3731.             // Is outpost/bandit/town location set?
  3732.             if (config.Outpost.Location == Zero && command == "outpost")
  3733.             {
  3734.                 PrintMsgL(player, "OutpostTPNotSet");
  3735.                 return;
  3736.             }
  3737.             else if (config.Bandit.Location == Zero && command == "bandit")
  3738.             {
  3739.                 PrintMsgL(player, "BanditTPNotSet");
  3740.                 return;
  3741.             }
  3742.             else if (config.Town.Location == Zero && command == "town")
  3743.             {
  3744.                 PrintMsgL(player, "TownTPNotSet");
  3745.                 return;
  3746.             }
  3747.  
  3748.             TeleportData teleportData = new TeleportData();
  3749.             var timestamp = Facepunch.Math.Epoch.Current;
  3750.             var currentDate = DateTime.Now.ToString("d");
  3751.  
  3752.             string err = null;
  3753.             int cooldown = 0;
  3754.             int limit = 0;
  3755.             int targetPay = 0;
  3756.             int targetBypass = 0;
  3757.             string msgPay = null;
  3758.             string msgCooldown = null;
  3759.             string msgCooldownBypass = null;
  3760.             string msgCooldownBypassF = null;
  3761.             string msgCooldownBypassP = null;
  3762.             string msgCooldownBypassP2 = null;
  3763.             string msgLimitReached = null;
  3764. #if DEBUG
  3765.             Puts("Calling CheckPlayer from cmdChatTown");
  3766. #endif
  3767.             // Setup vars for checks below
  3768.             switch (command)
  3769.             {
  3770.                 case "outpost":
  3771.                     err = CheckPlayer(player, config.Outpost.UsableOutOfBuildingBlocked, CanCraftOutpost(player), True, "outpost");
  3772.                     if (err != null)
  3773.                     {
  3774.                         PrintMsgL(player, err);
  3775.                         if (err == "TPHostile")
  3776.                         {
  3777.                             double stateHostileTime = Math.Round((player.State.unHostileTimestamp - TimeEx.currentTimestamp) / 60, 0, MidpointRounding.AwayFromZero);
  3778.                             PrintMsgL(player, "HostileTimer", stateHostileTime);
  3779.                         }
  3780.                         return;
  3781.                     }
  3782.                     cooldown = GetLower(player, config.Outpost.VIPCooldowns, config.Outpost.Cooldown);
  3783.                     if (!Outpost.TryGetValue(player.userID, out teleportData))
  3784.                     {
  3785.                         Outpost[player.userID] = teleportData = new TeleportData();
  3786.                     }
  3787.                     if (teleportData.Date != currentDate)
  3788.                     {
  3789.                         teleportData.Amount = 0;
  3790.                         teleportData.Date = currentDate;
  3791.                     }
  3792.  
  3793.                     targetPay = config.Outpost.Pay;
  3794.                     targetBypass = config.Outpost.Bypass;
  3795.  
  3796.                     msgPay = "PayToOutpost";
  3797.                     msgCooldown = "OutpostTPCooldown";
  3798.                     msgCooldownBypass = "OutpostTPCooldownBypass";
  3799.                     msgCooldownBypassF = "OutpostTPCooldownBypassF";
  3800.                     msgCooldownBypassP = "OutpostTPCooldownBypassP";
  3801.                     msgCooldownBypassP2 = "OutpostTPCooldownBypassP2";
  3802.                     msgLimitReached = "OutpostTPLimitReached";
  3803.                     limit = GetHigher(player, config.Outpost.VIPDailyLimits, config.Outpost.DailyLimit, true);
  3804.                     break;
  3805.                 case "bandit":
  3806.                     err = CheckPlayer(player, config.Bandit.UsableOutOfBuildingBlocked, CanCraftBandit(player), True, "bandit");
  3807.                     if (err != null)
  3808.                     {
  3809.                         PrintMsgL(player, err);
  3810.                         if (err == "TPHostile")
  3811.                         {
  3812.                             double stateHostileTime = Math.Round((player.State.unHostileTimestamp - TimeEx.currentTimestamp) / 60, 0, MidpointRounding.AwayFromZero);
  3813.                             PrintMsgL(player, "HostileTimer", stateHostileTime);
  3814.                         }
  3815.                         return;
  3816.                     }
  3817.                     cooldown = GetLower(player, config.Bandit.VIPCooldowns, config.Bandit.Cooldown);
  3818.                     if (!Bandit.TryGetValue(player.userID, out teleportData))
  3819.                     {
  3820.                         Bandit[player.userID] = teleportData = new TeleportData();
  3821.                     }
  3822.                     if (teleportData.Date != currentDate)
  3823.                     {
  3824.                         teleportData.Amount = 0;
  3825.                         teleportData.Date = currentDate;
  3826.                     }
  3827.                     targetPay = config.Bandit.Pay;
  3828.                     targetBypass = config.Bandit.Bypass;
  3829.  
  3830.                     msgPay = "PayToBandit";
  3831.                     msgCooldown = "BanditTPCooldown";
  3832.                     msgCooldownBypass = "BanditTPCooldownBypass";
  3833.                     msgCooldownBypassF = "BanditTPCooldownBypassF";
  3834.                     msgCooldownBypassP = "BanditTPCooldownBypassP";
  3835.                     msgCooldownBypassP2 = "BanditTPCooldownBypassP2";
  3836.                     msgLimitReached = "BanditTPLimitReached";
  3837.                     limit = GetHigher(player, config.Bandit.VIPDailyLimits, config.Bandit.DailyLimit, true);
  3838.                     break;
  3839.                 case "town":
  3840.                 default:
  3841.                     err = CheckPlayer(player, config.Town.UsableOutOfBuildingBlocked, CanCraftTown(player), True, "town");
  3842.                     if (err != null)
  3843.                     {
  3844.                         PrintMsgL(player, err);
  3845.                         return;
  3846.                     }
  3847.                     cooldown = GetLower(player, config.Town.VIPCooldowns, config.Town.Cooldown);
  3848.                     if (!Town.TryGetValue(player.userID, out teleportData))
  3849.                     {
  3850.                         Town[player.userID] = teleportData = new TeleportData();
  3851.                     }
  3852.                     if (teleportData.Date != currentDate)
  3853.                     {
  3854.                         teleportData.Amount = 0;
  3855.                         teleportData.Date = currentDate;
  3856.                     }
  3857.                     targetPay = config.Town.Pay;
  3858.                     targetBypass = config.Town.Bypass;
  3859.  
  3860.                     msgPay = "PayToTown";
  3861.                     msgCooldown = "TownTPCooldown";
  3862.                     msgCooldownBypass = "TownTPCooldownBypass";
  3863.                     msgCooldownBypassF = "TownTPCooldownBypassF";
  3864.                     msgCooldownBypassP = "TownTPCooldownBypassP";
  3865.                     msgCooldownBypassP2 = "TownTPCooldownBypassP2";
  3866.                     msgLimitReached = "TownTPLimitReached";
  3867.                     limit = GetHigher(player, config.Town.VIPDailyLimits, config.Town.DailyLimit, true);
  3868.                     break;
  3869.             }
  3870.  
  3871.             // Check and process cooldown, bypass, and payment for all modes
  3872.             if (cooldown > 0 && timestamp - teleportData.Timestamp < cooldown)
  3873.             {
  3874.                 var cmdSent = "";
  3875.                 bool foundmoney = CheckEconomy(player, targetBypass);
  3876.                 try
  3877.                 {
  3878.                     cmdSent = args[0].ToLower();
  3879.                 }
  3880.                 catch { }
  3881.  
  3882.                 bool payalso = False;
  3883.                 if (targetPay > 0)
  3884.                 {
  3885.                     payalso = True;
  3886.                 }
  3887.                 if ((config.Settings.BypassCMD != null) && (cmdSent == config.Settings.BypassCMD.ToLower()))
  3888.                 {
  3889.                     if (foundmoney)
  3890.                     {
  3891.                         CheckEconomy(player, targetBypass, True);
  3892.                         paidmoney = True;
  3893.                         PrintMsgL(player, msgCooldownBypass, targetBypass);
  3894.                         if (payalso)
  3895.                         {
  3896.                             PrintMsgL(player, msgPay, targetPay);
  3897.                         }
  3898.                     }
  3899.                     else
  3900.                     {
  3901.                         PrintMsgL(player, msgCooldownBypassF, targetBypass);
  3902.                         return;
  3903.                     }
  3904.                 }
  3905.                 else if (UseEconomy())
  3906.                 {
  3907.                     var remain = cooldown - (timestamp - teleportData.Timestamp);
  3908.                     PrintMsgL(player, msgCooldown, FormatTime(remain));
  3909.                     if (targetBypass > 0 && config.Settings.BypassCMD != null)
  3910.                     {
  3911.                         PrintMsgL(player, msgCooldownBypassP, targetBypass);
  3912.                         PrintMsgL(player, msgCooldownBypassP2, config.Settings.BypassCMD);
  3913.                     }
  3914.                     return;
  3915.                 }
  3916.                 else
  3917.                 {
  3918.                     var remain = cooldown - (timestamp - teleportData.Timestamp);
  3919.                     PrintMsgL(player, msgCooldown, FormatTime(remain));
  3920.                     return;
  3921.                 }
  3922.             }
  3923.  
  3924.             if (limit > 0 && teleportData.Amount >= limit)
  3925.             {
  3926.                 PrintMsgL(player, msgLimitReached, limit);
  3927.                 return;
  3928.             }
  3929.             if (TeleportTimers.ContainsKey(player.userID))
  3930.             {
  3931.                 PrintMsgL(player, "TeleportPending");
  3932.                 return;
  3933.             }
  3934.             err = CanPlayerTeleport(player);
  3935.             if (err != null)
  3936.             {
  3937.                 SendReply(player, err);
  3938.                 return;
  3939.             }
  3940.             err = CheckItems(player);
  3941.             if (err != null)
  3942.             {
  3943.                 PrintMsgL(player, "TPBlockedItem", err);
  3944.                 return;
  3945.             }
  3946.  
  3947.             int countdown = 0;
  3948.             switch (command)
  3949.             {
  3950.                 case "outpost":
  3951.                     countdown = GetLower(player, config.Outpost.VIPCountdowns, config.Outpost.Countdown);
  3952.                     TeleportTimers[player.userID] = new TeleportTimer
  3953.                     {
  3954.                         OriginPlayer = player,
  3955.                         Timer = timer.Once(countdown, () =>
  3956.                         {
  3957. #if DEBUG
  3958.                             Puts("Calling CheckPlayer from cmdChatTown outpost timer loop");
  3959. #endif
  3960.                             err = CheckPlayer(player, config.Outpost.UsableOutOfBuildingBlocked, CanCraftOutpost(player), True, "outpost");
  3961.                             if (err != null)
  3962.                             {
  3963.                                 PrintMsgL(player, "Interrupted");
  3964.                                 PrintMsgL(player, err);
  3965.                                 if (paidmoney)
  3966.                                 {
  3967.                                     paidmoney = False;
  3968.                                     CheckEconomy(player, config.Outpost.Bypass, False, True);
  3969.                                 }
  3970.                                 TeleportTimers.Remove(player.userID);
  3971.                                 return;
  3972.                             }
  3973.                             err = CanPlayerTeleport(player);
  3974.                             if (err != null)
  3975.                             {
  3976.                                 PrintMsgL(player, "Interrupted");
  3977.                                 PrintMsgL(player, err);
  3978.                                 if (paidmoney)
  3979.                                 {
  3980.                                     paidmoney = False;
  3981.                                     CheckEconomy(player, config.Outpost.Bypass, False, True);
  3982.                                 }
  3983.                                 TeleportTimers.Remove(player.userID);
  3984.                                 return;
  3985.                             }
  3986.                             err = CheckItems(player);
  3987.                             if (err != null)
  3988.                             {
  3989.                                 PrintMsgL(player, "Interrupted");
  3990.                                 PrintMsgL(player, "TPBlockedItem", err);
  3991.                                 if (paidmoney)
  3992.                                 {
  3993.                                     paidmoney = False;
  3994.                                     CheckEconomy(player, config.Outpost.Bypass, False, True);
  3995.                                 }
  3996.                                 TeleportTimers.Remove(player.userID);
  3997.                                 return;
  3998.                             }
  3999.  
  4000.                             if (UseEconomy())
  4001.                             {
  4002.                                 if (config.Outpost.Pay > 0 && !CheckEconomy(player, config.Outpost.Pay))
  4003.                                 {
  4004.                                     PrintMsgL(player, "Interrupted");
  4005.                                     PrintMsgL(player, "TPNoMoney", config.Outpost.Pay);
  4006.                                     TeleportTimers.Remove(player.userID);
  4007.                                     return;
  4008.                                 }
  4009.                                 else if (config.Outpost.Pay > 0)
  4010.                                 {
  4011.                                     CheckEconomy(player, config.Outpost.Pay, True);
  4012.                                     PrintMsgL(player, "TPMoney", (double)config.Outpost.Pay);
  4013.                                 }
  4014.                             }
  4015.                             Teleport(player, config.Outpost.Location);
  4016.                             teleportData.Amount++;
  4017.                             teleportData.Timestamp = timestamp;
  4018.  
  4019.                             changedOutpost = True;
  4020.                             PrintMsgL(player, "OutpostTP");
  4021.                             if (limit > 0) PrintMsgL(player, "OutpostTPAmount", limit - teleportData.Amount);
  4022.                             TeleportTimers.Remove(player.userID);
  4023.                         })
  4024.                     };
  4025.                     PrintMsgL(player, "OutpostTPStarted", countdown);
  4026.                     break;
  4027.                 case "bandit":
  4028.                     countdown = GetLower(player, config.Bandit.VIPCountdowns, config.Bandit.Countdown);
  4029.                     TeleportTimers[player.userID] = new TeleportTimer
  4030.                     {
  4031.                         OriginPlayer = player,
  4032.                         Timer = timer.Once(countdown, () =>
  4033.                         {
  4034. #if DEBUG
  4035.                             Puts("Calling CheckPlayer from cmdChatTown bandit timer loop");
  4036. #endif
  4037.                             err = CheckPlayer(player, config.Bandit.UsableOutOfBuildingBlocked, CanCraftBandit(player), True, "bandit");
  4038.                             if (err != null)
  4039.                             {
  4040.                                 PrintMsgL(player, "Interrupted");
  4041.                                 PrintMsgL(player, err);
  4042.                                 if (paidmoney)
  4043.                                 {
  4044.                                     paidmoney = False;
  4045.                                     CheckEconomy(player, config.Bandit.Bypass, False, True);
  4046.                                 }
  4047.                                 TeleportTimers.Remove(player.userID);
  4048.                                 return;
  4049.                             }
  4050.                             err = CanPlayerTeleport(player);
  4051.                             if (err != null)
  4052.                             {
  4053.                                 PrintMsgL(player, "Interrupted");
  4054.                                 PrintMsgL(player, err);
  4055.                                 if (paidmoney)
  4056.                                 {
  4057.                                     paidmoney = False;
  4058.                                     CheckEconomy(player, config.Bandit.Bypass, False, True);
  4059.                                 }
  4060.                                 TeleportTimers.Remove(player.userID);
  4061.                                 return;
  4062.                             }
  4063.                             err = CheckItems(player);
  4064.                             if (err != null)
  4065.                             {
  4066.                                 PrintMsgL(player, "Interrupted");
  4067.                                 PrintMsgL(player, "TPBlockedItem", err);
  4068.                                 if (paidmoney)
  4069.                                 {
  4070.                                     paidmoney = False;
  4071.                                     CheckEconomy(player, config.Bandit.Bypass, False, True);
  4072.                                 }
  4073.                                 TeleportTimers.Remove(player.userID);
  4074.                                 return;
  4075.                             }
  4076.  
  4077.                             if (UseEconomy())
  4078.                             {
  4079.                                 if (config.Bandit.Pay > 0 && !CheckEconomy(player, config.Bandit.Pay))
  4080.                                 {
  4081.                                     PrintMsgL(player, "Interrupted");
  4082.                                     PrintMsgL(player, "TPNoMoney", config.Bandit.Pay);
  4083.                                     TeleportTimers.Remove(player.userID);
  4084.                                     return;
  4085.                                 }
  4086.                                 else if (config.Bandit.Pay > 0)
  4087.                                 {
  4088.                                     CheckEconomy(player, config.Bandit.Pay, True);
  4089.                                     PrintMsgL(player, "TPMoney", (double)config.Bandit.Pay);
  4090.                                 }
  4091.                             }
  4092.                             Teleport(player, config.Bandit.Location);
  4093.                             teleportData.Amount++;
  4094.                             teleportData.Timestamp = timestamp;
  4095.  
  4096.                             changedBandit = True;
  4097.                             PrintMsgL(player, "BanditTP");
  4098.                             if (limit > 0) PrintMsgL(player, "BanditTPAmount", limit - teleportData.Amount);
  4099.                             TeleportTimers.Remove(player.userID);
  4100.                         })
  4101.                     };
  4102.                     PrintMsgL(player, "BanditTPStarted", countdown);
  4103.                     break;
  4104.                 case "town":
  4105.                 default:
  4106.                     countdown = GetLower(player, config.Town.VIPCountdowns, config.Town.Countdown);
  4107.                     TeleportTimers[player.userID] = new TeleportTimer
  4108.                     {
  4109.                         OriginPlayer = player,
  4110.                         Timer = timer.Once(countdown, () =>
  4111.                         {
  4112. #if DEBUG
  4113.                             Puts("Calling CheckPlayer from cmdChatTown town timer loop");
  4114. #endif
  4115.                             err = CheckPlayer(player, config.Town.UsableOutOfBuildingBlocked, CanCraftTown(player), True, "town");
  4116.                             if (err != null)
  4117.                             {
  4118.                                 PrintMsgL(player, "Interrupted");
  4119.                                 PrintMsgL(player, err);
  4120.                                 if (paidmoney)
  4121.                                 {
  4122.                                     paidmoney = False;
  4123.                                     CheckEconomy(player, config.Town.Bypass, False, True);
  4124.                                 }
  4125.                                 TeleportTimers.Remove(player.userID);
  4126.                                 return;
  4127.                             }
  4128.                             err = CanPlayerTeleport(player);
  4129.                             if (err != null)
  4130.                             {
  4131.                                 PrintMsgL(player, "Interrupted");
  4132.                                 PrintMsgL(player, err);
  4133.                                 if (paidmoney)
  4134.                                 {
  4135.                                     paidmoney = False;
  4136.                                     CheckEconomy(player, config.Town.Bypass, False, True);
  4137.                                 }
  4138.                                 TeleportTimers.Remove(player.userID);
  4139.                                 return;
  4140.                             }
  4141.                             err = CheckItems(player);
  4142.                             if (err != null)
  4143.                             {
  4144.                                 PrintMsgL(player, "Interrupted");
  4145.                                 PrintMsgL(player, "TPBlockedItem", err);
  4146.                                 if (paidmoney)
  4147.                                 {
  4148.                                     paidmoney = False;
  4149.                                     CheckEconomy(player, config.Town.Bypass, False, True);
  4150.                                 }
  4151.                                 TeleportTimers.Remove(player.userID);
  4152.                                 return;
  4153.                             }
  4154.  
  4155.                             if (UseEconomy())
  4156.                             {
  4157.                                 if (config.Town.Pay > 0 && !CheckEconomy(player, config.Town.Pay))
  4158.                                 {
  4159.                                     PrintMsgL(player, "Interrupted");
  4160.                                     PrintMsgL(player, "TPNoMoney", config.Town.Pay);
  4161.                                     TeleportTimers.Remove(player.userID);
  4162.                                     return;
  4163.                                 }
  4164.                                 else if (config.Town.Pay > 0)
  4165.                                 {
  4166.                                     CheckEconomy(player, config.Town.Pay, True);
  4167.                                     PrintMsgL(player, "TPMoney", (double)config.Town.Pay);
  4168.                                 }
  4169.                             }
  4170.                             Teleport(player, config.Town.Location);
  4171.                             teleportData.Amount++;
  4172.                             teleportData.Timestamp = timestamp;
  4173.  
  4174.                             changedTown = True;
  4175.                             PrintMsgL(player, "TownTP");
  4176.                             if (limit > 0) PrintMsgL(player, "TownTPAmount", limit - teleportData.Amount);
  4177.                             TeleportTimers.Remove(player.userID);
  4178.                         })
  4179.                     };
  4180.                     PrintMsgL(player, "TownTPStarted", countdown);
  4181.                     break;
  4182.             }
  4183.         }
  4184.  
  4185.         private void CommandTeleportII(IPlayer p, string command, string[] args)
  4186.         {
  4187.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  4188.             var player = p.Object as BasePlayer;
  4189.             if (player != null && (!IsAllowedMsg(player, PermTpConsole) || !player.IsConnected || player.IsSleeping())) return;
  4190.            
  4191.             List<BasePlayer> players;
  4192.             switch (command)
  4193.             {
  4194.                 case "teleport.topos":
  4195.                     if (args.Length < 4)
  4196.                     {
  4197.                         p.Reply(_("SyntaxConsoleCommandToPos", player));
  4198.                         return;
  4199.                     }
  4200.                     players = FindPlayers(args[0]);
  4201.                     if (players.Count <= 0)
  4202.                     {
  4203.                         p.Reply(_("PlayerNotFound", player));
  4204.                         return;
  4205.                     }
  4206.                     if (players.Count > 1)
  4207.                     {
  4208.                         p.Reply(_("MultiplePlayers", player, string.Join(", ", players.Select(t => t.displayName).ToArray())));
  4209.                         return;
  4210.                     }
  4211.                     var targetPlayer = players.First();
  4212.                     players.Clear();
  4213.                     float x;
  4214.                     if (!float.TryParse(args[1], out x)) x = -10000f;
  4215.                     float y;
  4216.                     if (!float.TryParse(args[2], out y)) y = -10000f;
  4217.                     float z;
  4218.                     if (!float.TryParse(args[3], out z)) z = -10000f;
  4219.                     if (!CheckBoundaries(x, y, z))
  4220.                     {
  4221.                         p.Reply(_("AdminTPOutOfBounds", player) + Environment.NewLine + _("AdminTPBoundaries", player, boundary));
  4222.                         return;
  4223.                     }
  4224.                     Teleport(targetPlayer, x, y, z);
  4225.                     if (config.Admin.AnnounceTeleportToTarget)
  4226.                         PrintMsgL(targetPlayer, "AdminTPConsoleTP", targetPlayer.transform.position);
  4227.                     p.Reply(_("AdminTPTargetCoordinates", player, targetPlayer.displayName, targetPlayer.transform.position));
  4228.                     Puts(_("LogTeleportPlayer", null, player?.displayName, targetPlayer.displayName, targetPlayer.transform.position));
  4229.                     break;
  4230.                 case "teleport.toplayer":
  4231.                     if (args.Length < 2)
  4232.                     {
  4233.                         p.Reply(_("SyntaxConsoleCommandToPlayer", player));
  4234.                         return;
  4235.                     }
  4236.                     players = FindPlayers(args[0]);
  4237.                     if (players.Count <= 0)
  4238.                     {
  4239.                         p.Reply(_("PlayerNotFound", player));
  4240.                         return;
  4241.                     }
  4242.                     if (players.Count > 1)
  4243.                     {
  4244.                         p.Reply(_("MultiplePlayers", player, string.Join(", ", players.Select(t => t.displayName).ToArray())));
  4245.                         return;
  4246.                     }
  4247.                     var originPlayer = players.First();
  4248.                     players = FindPlayers(args[1]);
  4249.                     if (players.Count <= 0)
  4250.                     {
  4251.                         p.Reply(_("PlayerNotFound", player));
  4252.                         return;
  4253.                     }
  4254.                     if (players.Count > 1)
  4255.                     {
  4256.                         p.Reply(_("MultiplePlayers", player, string.Join(", ", players.Select(t => t.displayName).ToArray())));
  4257.                         players.Clear();
  4258.                         return;
  4259.                     }
  4260.                     targetPlayer = players.First();
  4261.                     if (targetPlayer == originPlayer)
  4262.                     {
  4263.                         players.Clear();
  4264.                         p.Reply(_("CantTeleportPlayerToSelf", player));
  4265.                         return;
  4266.                     }
  4267.                     players.Clear();
  4268.                     Teleport(originPlayer, targetPlayer);
  4269.                     p.Reply(_("AdminTPPlayers", player, originPlayer.displayName, targetPlayer.displayName));
  4270.                     PrintMsgL(originPlayer, "AdminTPConsoleTPPlayer", targetPlayer.displayName);
  4271.                     if (config.Admin.AnnounceTeleportToTarget)
  4272.                         PrintMsgL(targetPlayer, "AdminTPConsoleTPPlayerTarget", originPlayer.displayName);
  4273.                     Puts(_("LogTeleportPlayer", null, player?.displayName, originPlayer.displayName, targetPlayer.displayName));
  4274.                     break;
  4275.             }
  4276.         }
  4277.  
  4278.         float GetMonumentFloat(string monumentName)
  4279.         {
  4280.             string name = monumentName.Contains(":") ? monumentName.Substring(0, monumentName.LastIndexOf(":")) : monumentName.TrimEnd();
  4281.  
  4282.             switch (name)
  4283.             {
  4284.                 case "Abandoned Cabins":
  4285.                     return 24f + 30f;
  4286.                 case "Abandoned Supermarket":
  4287.                     return 50f;
  4288.                 case "Airfield":
  4289.                     return 200f;
  4290.                 case "Bandit Camp":
  4291.                     return 100f + 25f;
  4292.                 case "Giant Excavator Pit":
  4293.                     return 200f + 25f;
  4294.                 case "Harbor":
  4295.                     return 100f + 50f;
  4296.                 case "HQM Quarry":
  4297.                     return 27.5f + 10f;
  4298.                 case "Large Oil Rig":
  4299.                     return 200f;
  4300.                 case "Launch Site":
  4301.                     return 200f + 100f;
  4302.                 case "Lighthouse":
  4303.                     return 24f + 24f;
  4304.                 case "Military Tunnel":
  4305.                     return 100f;
  4306.                 case "Mining Outpost":
  4307.                     return 25f + 15f;
  4308.                 case "Oil Rig":
  4309.                     return 100f;
  4310.                 case "Outpost":
  4311.                     return 100f + 25f;
  4312.                 case "Oxum's Gas Station":
  4313.                     return 50f + 15f;
  4314.                 case "Power Plant":
  4315.                     return 100f + 40f;
  4316.                 case "power_sub_small_1":
  4317.                 case "power_sub_small_2":
  4318.                 case "power_sub_big_1":
  4319.                 case "power_sub_big_2":
  4320.                     return 30f;
  4321.                 case "Satellite Dish":
  4322.                     return 75f + 15f;
  4323.                 case "Sewer Branch":
  4324.                     return 75f + 25f;
  4325.                 case "Stone Quarry":
  4326.                     return 27.5f;
  4327.                 case "Sulfur Quarry":
  4328.                     return 27.5f;
  4329.                 case "The Dome":
  4330.                     return 50f + 20f;
  4331.                 case "Train Yard":
  4332.                     return 100 + 50f;
  4333.                 case "Water Treatment Plant":
  4334.                     return 100f + 85f;
  4335.                 case "Water Well":
  4336.                     return 24f;
  4337.                 case "Wild Swamp":
  4338.                     return 24f;
  4339.             }
  4340.  
  4341.             return config.Settings.DefaultMonumentSize;
  4342.         }
  4343.  
  4344.         private void CommandSphereMonuments(IPlayer p, string command, string[] args)
  4345.         {
  4346.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  4347.             var player = p?.Object as BasePlayer;
  4348.             if (!player || !player.IsAdmin || !player.IsConnected || player.IsSleeping()) return;
  4349.  
  4350.             foreach (var monument in monuments)
  4351.             {
  4352.                 string name = monument.Key.Contains(":") ? monument.Key.Substring(0, monument.Key.LastIndexOf(":")) : monument.Key.TrimEnd();
  4353.  
  4354.                 player.SendConsoleCommand("ddraw.sphere", 30f, Color.red, monument.Value.Position, GetMonumentFloat(name));
  4355.                 player.SendConsoleCommand("ddraw.text", 30f, Color.blue, monument.Value.Position, name);
  4356.             }
  4357.  
  4358.             foreach (var cave in caves)
  4359.             {
  4360.                 string name = cave.Key.Contains(":") ? cave.Key.Substring(0, cave.Key.LastIndexOf(":")) : cave.Key.TrimEnd();
  4361.                 float realdistance = cave.Key.Contains("Small") ? config.Settings.CaveDistanceSmall : cave.Key.Contains("Medium") ? config.Settings.CaveDistanceMedium : config.Settings.CaveDistanceLarge;
  4362.                 realdistance += 50f;
  4363.  
  4364.                 player.SendConsoleCommand("ddraw.sphere", 30f, Color.black, cave.Value, realdistance);
  4365.                 player.SendConsoleCommand("ddraw.text", 30f, Color.cyan, cave.Value, name);
  4366.             }
  4367.         }
  4368.  
  4369.         private void CommandImportHomes(IPlayer p, string command, string[] args)
  4370.         {
  4371.             if (DisabledTPT.DisabledCommands.Contains(command.ToLower())) { p.Reply("Disabled command: " + command); return; }
  4372.             var player = p.Object as BasePlayer;
  4373.  
  4374.             if (player != null && (!IsAllowedMsg(player, PermImportHomes) || !player.IsConnected || player.IsSleeping()))
  4375.             {
  4376.                 p.Reply(_("NotAllowed", player));
  4377.                 return;
  4378.             }
  4379.             var datafile = Interface.Oxide.DataFileSystem.GetFile("m-Teleportation");
  4380.             if (!datafile.Exists())
  4381.             {
  4382.                 p.Reply("No m-Teleportation.json exists.");
  4383.                 return;
  4384.             }
  4385.             datafile.Load();
  4386.             var allHomeData = datafile["HomeData"] as Dictionary<string, object>;
  4387.             if (allHomeData == null)
  4388.             {
  4389.                 p.Reply(_("HomeListEmpty", player));
  4390.                 return;
  4391.             }
  4392.             var count = 0;
  4393.             foreach (var kvp in allHomeData)
  4394.             {
  4395.                 var homeDataOld = kvp.Value as Dictionary<string, object>;
  4396.                 if (homeDataOld == null) continue;
  4397.                 if (!homeDataOld.ContainsKey("HomeLocations")) continue;
  4398.                 var homeList = homeDataOld["HomeLocations"] as Dictionary<string, object>;
  4399.                 if (homeList == null) continue;
  4400.                 var userId = Convert.ToUInt64(kvp.Key);
  4401.                 HomeData homeData;
  4402.                 if (!Home.TryGetValue(userId, out homeData))
  4403.                     Home[userId] = homeData = new HomeData();
  4404.                 foreach (var kvp2 in homeList)
  4405.                 {
  4406.                     var positionData = kvp2.Value as Dictionary<string, object>;
  4407.                     if (positionData == null) continue;
  4408.                     if (!positionData.ContainsKey("x") || !positionData.ContainsKey("y") || !positionData.ContainsKey("z")) continue;
  4409.                     var position = new Vector3(Convert.ToSingle(positionData["x"]), Convert.ToSingle(positionData["y"]), Convert.ToSingle(positionData["z"]));
  4410.                     homeData.Locations[kvp2.Key] = position;
  4411.                     changedHome = True;
  4412.                     count++;
  4413.                 }
  4414.             }
  4415.             p.Reply(string.Format("Imported {0} homes.", count));
  4416.         }
  4417.  
  4418.         private void RequestTimedOut(BasePlayer player, BasePlayer target)
  4419.         {
  4420.             PlayersRequests.Remove(player.userID);
  4421.             PlayersRequests.Remove(target.userID);
  4422.             PendingRequests.Remove(target.userID);
  4423.             PrintMsgL(player, "TimedOut", target.displayName);
  4424.             PrintMsgL(target, "TimedOutTarget", player.displayName);
  4425.         }
  4426.  
  4427.         #region Util
  4428.         private string FormatTime(long seconds)
  4429.         {
  4430.             var timespan = TimeSpan.FromSeconds(seconds);
  4431.             return string.Format(timespan.TotalHours >= 1 ? "{2:00}:{0:00}:{1:00}" : "{0:00}:{1:00}", timespan.Minutes, timespan.Seconds, System.Math.Floor(timespan.TotalHours));
  4432.         }
  4433.  
  4434.         private double ConvertToRadians(double angle)
  4435.         {
  4436.             return System.Math.PI / 180 * angle;
  4437.         }
  4438.         #endregion
  4439.  
  4440.         #region Teleport
  4441.         public void Teleport(BasePlayer player, BasePlayer target) => Teleport(player, target.transform.position);
  4442.  
  4443.         public void Teleport(BasePlayer player, float x, float y, float z) => Teleport(player, new Vector3(x, y, z));
  4444.  
  4445.         public void Teleport(BasePlayer player, Vector3 newPosition, bool save = True)
  4446.         {
  4447.             if (!player.IsValid() || Vector3.Distance(newPosition, Zero) < 5f) return;
  4448.  
  4449.             if (save) SaveLocation(player);
  4450.             if (!teleporting.ContainsKey(player.userID))
  4451.                 teleporting.Add(player.userID, newPosition);
  4452.             else teleporting[player.userID] = newPosition;
  4453.  
  4454.             var oldPosition = player.transform.position;
  4455.            
  4456.             try
  4457.             {
  4458.                 player.EnsureDismounted(); // 1.1.2 @Def
  4459.  
  4460.                 if (player.HasParent())
  4461.                 {
  4462.                     player.SetParent(null, True, True);
  4463.                 }
  4464.  
  4465.                 if (player.IsConnected) // 1.1.2 @Def
  4466.                 {
  4467.                     player.EndLooting();
  4468.                     StartSleeping(player);
  4469.                 }
  4470.  
  4471.                 player.RemoveFromTriggers(); // 1.1.2 @Def recommendation to use natural method for issue with triggers
  4472.                 player.EnableServerFall(True); // redundant, in OnEntityTakeDamage hook
  4473.                 player.Teleport(newPosition); // 1.1.6
  4474.  
  4475.                 if (player.IsConnected && !Network.Net.sv.visibility.IsInside(player.net.group, newPosition))
  4476.                 {
  4477.                     player.SetPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot, True);
  4478.                     player.ClientRPCPlayer(null, player, "StartLoading");
  4479.                     player.SendEntityUpdate();
  4480.                     if (!IsInvisible(player)) // fix for becoming networked briefly with vanish while teleporting
  4481.                     {
  4482.                         player.UpdateNetworkGroup(); // 1.1.1 building fix @ctv
  4483.                         player.SendNetworkUpdateImmediate(False);
  4484.                     }
  4485.                 }
  4486.             }
  4487.             finally
  4488.             {
  4489.                 player.EnableServerFall(False);
  4490.                 player.ForceUpdateTriggers(); // 1.1.4 exploit fix for looting sleepers in safe zones
  4491.             }
  4492.  
  4493.             Interface.CallHook("OnPlayerTeleported", player, oldPosition, newPosition);
  4494.         }
  4495.  
  4496.         bool IsInvisible(BasePlayer player)
  4497.         {
  4498.             return Vanish != null && Vanish.Call<bool>("IsInvisible", player);
  4499.         }
  4500.  
  4501.         public void StartSleeping(BasePlayer player) // custom as to not cancel crafting, or remove player from vanish
  4502.         {
  4503.             if (!player.IsSleeping())
  4504.             {
  4505.                 Interface.CallHook("OnPlayerSleep", player);
  4506.                 player.SetPlayerFlag(BasePlayer.PlayerFlags.Sleeping, True);
  4507.                 player.sleepStartTime = Time.time;
  4508.                 BasePlayer.sleepingPlayerList.Add(player);
  4509.                 BasePlayer.bots.Remove(player);
  4510.                 player.CancelInvoke("InventoryUpdate");
  4511.                 player.CancelInvoke("TeamUpdate");
  4512.             }
  4513.         }
  4514.         #endregion
  4515.  
  4516.         #region Checks
  4517.         private string CanPlayerTeleport(BasePlayer player)
  4518.         {
  4519.             return Interface.Oxide.CallHook("CanTeleport", player) as string;
  4520.         }
  4521.  
  4522.         private bool CanCraftHome(BasePlayer player)
  4523.         {
  4524.             return config.Home.AllowCraft || permission.UserHasPermission(player.UserIDString, PermCraftHome);
  4525.         }
  4526.  
  4527.         private bool CanCraftTown(BasePlayer player)
  4528.         {
  4529.             return config.Town.AllowCraft || permission.UserHasPermission(player.UserIDString, PermCraftTown);
  4530.         }
  4531.  
  4532.         private bool CanCraftOutpost(BasePlayer player)
  4533.         {
  4534.             return config.Outpost.AllowCraft || permission.UserHasPermission(player.UserIDString, PermCraftOutpost);
  4535.         }
  4536.  
  4537.         private bool CanCraftBandit(BasePlayer player)
  4538.         {
  4539.             return config.Bandit.AllowCraft || permission.UserHasPermission(player.UserIDString, PermCraftBandit);
  4540.         }
  4541.  
  4542.         private bool CanCraftTPR(BasePlayer player)
  4543.         {
  4544.             return config.TPR.AllowCraft || permission.UserHasPermission(player.UserIDString, PermCraftTpR);
  4545.         }
  4546.  
  4547.         public bool AboveWater(BasePlayer player)
  4548.         {
  4549.             var pos = player.transform.position;
  4550. #if DEBUG
  4551.             Puts($"Player position: {pos.ToString()}.  Checking for water...");
  4552. #endif
  4553.             if ((TerrainMeta.HeightMap.GetHeight(pos) - TerrainMeta.WaterMap.GetHeight(pos)) >= 0)
  4554.             {
  4555. #if DEBUG
  4556.                 Puts("Player not above water.");
  4557. #endif
  4558.                 return False;
  4559.             }
  4560.             else
  4561.             {
  4562. #if DEBUG
  4563.                 Puts("Player is above water!");
  4564. #endif
  4565.                 return True;
  4566.             }
  4567.         }
  4568.  
  4569.         private string NearMonument(BasePlayer player)
  4570.         {
  4571.             foreach (var entry in monuments)
  4572.             {
  4573.                 if (entry.Key.ToLower().Contains("power")) continue;
  4574.  
  4575.                 var pos = entry.Value.Position;
  4576.                 pos.y = player.transform.position.y;
  4577.                 float dist = (player.transform.position - pos).magnitude;
  4578. #if DEBUG
  4579.                 Puts($"Checking {entry.Key} dist: {dist}, realdistance: {entry.Value.Radius}");
  4580. #endif
  4581.                 if (dist < entry.Value.Radius)
  4582.                 {
  4583. #if DEBUG
  4584.                     Puts($"Player in range of {entry.Key}");
  4585. #endif
  4586.                     return entry.Key;
  4587.                 }
  4588.             }
  4589.             return null;
  4590.         }
  4591.  
  4592.         private bool belowGround(Vector3 a, Vector3 b)
  4593.         {
  4594.             return a.y < TerrainMeta.HeightMap.GetHeight(b);
  4595.         }
  4596.  
  4597.         private string NearCave(BasePlayer player)
  4598.         {
  4599.             foreach (var entry in caves)
  4600.             {
  4601.                 string caveName = entry.Key.Contains(":") ? entry.Key.Substring(0, entry.Key.LastIndexOf(":")) : entry.Key;
  4602.                 float realdistance = entry.Key.Contains("Small") ? config.Settings.CaveDistanceSmall : entry.Key.Contains("Medium") ? config.Settings.CaveDistanceMedium : config.Settings.CaveDistanceLarge;
  4603.  
  4604.                 if (Vector3.Distance(player.transform.position, entry.Value) < realdistance + 50f && !belowGround(player.transform.position, entry.Value))
  4605.                 {
  4606. #if DEBUG
  4607.                     Puts($"NearCave: {caveName} nearby.");
  4608. #endif
  4609.                     return caveName;
  4610.                 }
  4611.                 else
  4612.                 {
  4613. #if DEBUG
  4614.                     Puts("NearCave: Not near this cave, or above it.");
  4615. #endif
  4616.                 }
  4617.             }
  4618.             return null;
  4619.         }
  4620.  
  4621.         private string CheckPlayer(BasePlayer player, bool build = False, bool craft = False, bool origin = True, string mode = "home")
  4622.         {
  4623.             var onship = player.GetComponentInParent<CargoShip>();
  4624.             var onballoon = player.GetComponentInParent<HotAirBalloon>();
  4625.             var inlift = player.GetComponentInParent<Lift>();
  4626.             var pos = player.transform.position;
  4627.  
  4628.             string monname = NearMonument(player);
  4629.             if (config.Settings.Interrupt.Monument)
  4630.             {
  4631.                 if (monname != null)
  4632.                 {
  4633.                     return _("TooCloseToMon", player, monname);
  4634.                 }
  4635.             }
  4636.             if (config.Settings.Interrupt.Oilrig)
  4637.             {
  4638.                 if (monname != null && monname.Contains("Oil Rig"))
  4639.                 {
  4640.                     return _("TooCloseToMon", player, monname);
  4641.                 }
  4642.             }
  4643.             bool allowcave = True;
  4644.  
  4645. #if DEBUG
  4646.             Puts($"CheckPlayer(): called mode is {mode}");
  4647. #endif
  4648.             switch (mode)
  4649.             {
  4650.                 case "tpt":
  4651.                     allowcave = config.TPT.AllowCave;
  4652.                     break;
  4653.                 case "home":
  4654.                     allowcave = config.Home.AllowCave;
  4655.                     break;
  4656.                 case "tpa":
  4657.                 case "tpr":
  4658.                     allowcave = config.TPR.AllowCave;
  4659.                     break;
  4660.                 case "town":
  4661.                     allowcave = config.Town.AllowCave;
  4662.                     break;
  4663.                 case "outpost":
  4664.                     allowcave = config.Outpost.AllowCave;
  4665.                     break;
  4666.                 case "bandit":
  4667.                     allowcave = config.Bandit.AllowCave;
  4668.                     break;
  4669.                 default:
  4670. #if DEBUG
  4671.                     Puts("Skipping cave check...");
  4672. #endif
  4673.                     break;
  4674.             }
  4675.             if (!allowcave)
  4676.             {
  4677. #if DEBUG
  4678.                 Puts("Checking cave distance...");
  4679. #endif
  4680.                 string cavename = NearCave(player);
  4681.                 if (cavename != null)
  4682.                 {
  4683.                     return "TooCloseToCave";
  4684.                 }
  4685.             }
  4686.  
  4687.             if (config.Settings.Interrupt.Hostile && (mode == "bandit" || mode == "outpost"))
  4688.             {
  4689.                 if (player.IsHostile())
  4690.                 {
  4691.                     return "TPHostile";
  4692.                 }
  4693.             }
  4694.             if (player.isMounted && config.Settings.Interrupt.Mounted)
  4695.                 return "TPMounted";
  4696.             if (!player.IsAlive())
  4697.                 return "TPDead";
  4698.             // Block if hurt if the config is enabled.  If the player is not the target in a tpa condition, allow.
  4699.             if ((player.IsWounded() && origin) && config.Settings.Interrupt.Hurt)
  4700.                 return "TPWounded";
  4701.  
  4702.             if (player.metabolism.temperature.value <= config.Settings.MinimumTemp && config.Settings.Interrupt.Cold)
  4703.             {
  4704.                 return "TPTooCold";
  4705.             }
  4706.             if (player.metabolism.temperature.value >= config.Settings.MaximumTemp && config.Settings.Interrupt.Hot)
  4707.             {
  4708.                 return "TPTooHot";
  4709.             }
  4710.  
  4711.             if (config.Settings.Interrupt.AboveWater)
  4712.                 if (AboveWater(player))
  4713.                     return "TPAboveWater";
  4714.             if (!build && !player.CanBuild())
  4715.                 return "TPBuildingBlocked";
  4716.             if (player.IsSwimming() && config.Settings.Interrupt.Swimming)
  4717.                 return "TPSwimming";
  4718.             // This will have to do until we have a proper parent name for this
  4719.             if (monname != null && monname.Contains("Oil Rig") && config.Settings.Interrupt.Oilrig)
  4720.                 return "TPOilRig";
  4721.             if (monname != null && monname.Contains("Excavator") && config.Settings.Interrupt.Excavator)
  4722.                 return "TPExcavator";
  4723.             if (onship && config.Settings.Interrupt.Cargo)
  4724.                 return "TPCargoShip";
  4725.             if (onballoon && config.Settings.Interrupt.Balloon)
  4726.                 return "TPHotAirBalloon";
  4727.             if (inlift && config.Settings.Interrupt.Lift)
  4728.                 return "TPBucketLift";
  4729.             if (GetLift(pos) && config.Settings.Interrupt.Lift)
  4730.                 return "TPRegLift";
  4731.             if (player.InSafeZone() && config.Settings.Interrupt.Safe)
  4732.                 return "TPSafeZone";
  4733.             if (!craft && player.inventory.crafting.queue.Count > 0)
  4734.                 return "TPCrafting";
  4735.  
  4736.             if (config.Settings.BlockZoneFlag && ZoneManager != null)
  4737.             {
  4738.                 var success = ZoneManager?.Call("PlayerHasFlag", player, "notp");
  4739.  
  4740.                 if (success is bool && (bool)success)
  4741.                 {
  4742.                     return "TPFlagZone";
  4743.                 }
  4744.             }
  4745.  
  4746.             if (config.Settings.BlockNoEscape && NoEscape != null)
  4747.             {
  4748.                 var success = NoEscape?.Call("IsBlocked", player);
  4749.  
  4750.                 if (success is bool && (bool)success)
  4751.                 {
  4752.                     return "TPNoEscapeBlocked";
  4753.                 }
  4754.             }
  4755.  
  4756.             return null;
  4757.         }
  4758.  
  4759.         private string CheckTargetLocation(BasePlayer player, Vector3 targetLocation, bool ubb, bool obb)
  4760.         {
  4761.             // ubb == UsableIntoBuildingBlocked
  4762.             // obb == CupOwnerAllowOnBuildingBlocked
  4763.             var entities = Pool.GetList<BuildingBlock>();
  4764.             Vis.Entities(targetLocation, 3f, entities, Layers.Mask.Construction, QueryTriggerInteraction.Ignore);
  4765.             bool denied = False;
  4766.  
  4767.             foreach (var block in entities)
  4768.             {
  4769.                 if (CheckCupboardBlock(block, player, obb))
  4770.                 {
  4771.                     denied = False;
  4772. #if DEBUG
  4773.                     Puts("Cupboard either owned or there is no cupboard");
  4774. #endif
  4775.                 }
  4776.                 else if (ubb && (player.userID != block.OwnerID))
  4777.                 {
  4778.                     denied = False;
  4779. #if DEBUG
  4780.                     Puts("Player does not own block, but UsableIntoBuildingBlocked=true");
  4781. #endif
  4782.                 }
  4783.                 else if (player.userID == block.OwnerID)
  4784.                 {
  4785. #if DEBUG
  4786.                     Puts("Player owns block");
  4787. #endif
  4788.  
  4789.                     if (!player.IsBuildingBlocked(targetLocation, new Quaternion(), block.bounds))
  4790.                     {
  4791. #if DEBUG
  4792.                         Puts("Player not BuildingBlocked. Likely unprotected building.");
  4793. #endif
  4794.                         denied = False;
  4795.                         break;
  4796.                     }
  4797.                     else if (ubb)
  4798.                     {
  4799. #if DEBUG
  4800.                         Puts("Player not blocked because UsableIntoBuildingBlocked=true");
  4801. #endif
  4802.                         denied = False;
  4803.                         break;
  4804.                     }
  4805.                     else
  4806.                     {
  4807. #if DEBUG
  4808.                         Puts("Player owns block but blocked by UsableIntoBuildingBlocked=false");
  4809. #endif
  4810.                         denied = True;
  4811.                         break;
  4812.                     }
  4813.                 }
  4814.                 else
  4815.                 {
  4816. #if DEBUG
  4817.                     Puts("Player blocked");
  4818. #endif
  4819.                     denied = True;
  4820.                     break;
  4821.                 }
  4822.             }
  4823.             Pool.FreeList(ref entities);
  4824.  
  4825.             return denied ? "TPTargetBuildingBlocked" : null;
  4826.         }
  4827.  
  4828.         // Check that a building block is owned by/attached to a cupboard, allow tp if not blocked unless allowed by config
  4829.         private bool CheckCupboardBlock(BuildingBlock block, BasePlayer player, bool obb)
  4830.         {
  4831.             // obb == CupOwnerAllowOnBuildingBlocked
  4832.             var building = block.GetBuilding();
  4833.             if (building != null)
  4834.             {
  4835. #if DEBUG
  4836.                 Puts("Found building, checking privileges...");
  4837.                 Puts($"Building ID: {building.ID}");
  4838. #endif
  4839.                 // cupboard overlap.  Check privs.
  4840.                 if (building.buildingPrivileges == null)
  4841.                 {
  4842. #if DEBUG
  4843.                     Puts("No cupboard found, allowing teleport");
  4844. #endif
  4845.                     return player.CanBuild();
  4846.                 }
  4847.  
  4848.                 foreach (var priv in building.buildingPrivileges)
  4849.                 {
  4850.                     if (priv.IsAuthed(player))
  4851.                     {
  4852.                         // player is authorized to the cupboard
  4853. #if DEBUG
  4854.                         Puts("Player owns cupboard with auth");
  4855. #endif
  4856.                         return True;
  4857.                     }
  4858.                 }
  4859.  
  4860.                 if (player.userID == block.OwnerID)
  4861.                 {
  4862.                     if (obb)
  4863.                     {
  4864. #if DEBUG
  4865.                         // player set the cupboard and is allowed in by config
  4866.                         Puts("Player owns cupboard with no auth, but allowed by CupOwnerAllowOnBuildingBlocked=true");
  4867. #endif
  4868.                         return True;
  4869.                     }
  4870. #if DEBUG
  4871.                     // player set the cupboard but is blocked by config
  4872.                     Puts("Player owns cupboard with no auth, but blocked by CupOwnerAllowOnBuildingBlocked=false");
  4873. #endif
  4874.                     return False;
  4875.                 }
  4876.  
  4877. #if DEBUG
  4878.                 // player not authed
  4879.                 Puts("Player does not own cupboard and is not authorized");
  4880. #endif
  4881.                 return False;
  4882.             }
  4883. #if DEBUG
  4884.             Puts("No cupboard or building found - we cannot tell the status of this block");
  4885. #endif
  4886.             return True;
  4887.         }
  4888.  
  4889.         private string CheckInsideBlock(Vector3 targetLocation)
  4890.         {
  4891.             List<BuildingBlock> blocks = Pool.GetList<BuildingBlock>();
  4892.             Vis.Entities(targetLocation + new Vector3(0, 0.25f), 0.1f, blocks, blockLayer);
  4893.             bool inside = blocks.Count > 0;
  4894.             Pool.FreeList(ref blocks);
  4895.  
  4896.             return inside ? "TPTargetInsideBlock" : null;
  4897.         }
  4898.  
  4899.         private string CheckInsideBattery(Vector3 targetLocation)
  4900.         {
  4901.             var batteries = new List<ElectricBattery>();
  4902.             Vis.Entities(targetLocation, 0.35f, batteries, deployedLayer);
  4903.             return batteries.Count > 0 ? "TPTargetInsideBlock" : null;
  4904.         }
  4905.        
  4906.         private string CheckItems(BasePlayer player)
  4907.         {
  4908.             foreach (var blockedItem in ReverseBlockedItems)
  4909.             {
  4910.                 if (player.inventory.FindItemID(blockedItem.Key) != null)
  4911.                 {
  4912.                     return blockedItem.Value;
  4913.                 }
  4914.             }
  4915.             return null;
  4916.         }
  4917.  
  4918.         private string CheckFoundation(ulong userID, Vector3 position)
  4919.         {
  4920.             if (CheckInsideBattery(position) != null)
  4921.             {
  4922.                 return "HomeNoFoundation";
  4923.             }
  4924.             if (!config.Home.ForceOnTopOfFoundation) return null; // Foundation/floor not required
  4925.             if (UnderneathFoundation(position))
  4926.             {
  4927.                 return "HomeFoundationUnderneathFoundation";
  4928.             }
  4929.  
  4930.             var entities = new List<BuildingBlock>();
  4931.             if (config.Home.AllowAboveFoundation) // Can set on a foundation or floor
  4932.             {
  4933. #if DEBUG
  4934.                 Puts($"CheckFoundation() looking for foundation or floor at {position}");
  4935. #endif
  4936.                 entities = GetFoundationOrFloor(position);
  4937.             }
  4938.             else // Can only use foundation, not floor/ceiling
  4939.             {
  4940. #if DEBUG
  4941.                 Puts($"CheckFoundation() looking for foundation at {position}");
  4942. #endif
  4943.                 entities = GetFoundation(position);
  4944.             }
  4945.  
  4946.             entities.RemoveAll(x => !x.IsValid() || x.IsDestroyed);
  4947.             if (entities.Count == 0) return "HomeNoFoundation";
  4948.  
  4949.             if (!config.Home.CheckFoundationForOwner) return null;
  4950.             for (var i = 0; i < entities.Count; i++)
  4951.             {
  4952.                 if (entities[i].OwnerID == userID || IsFriend(userID, entities[i].OwnerID)) return null;
  4953.             }
  4954.  
  4955.             return "HomeFoundationNotFriendsOwned";
  4956.         }
  4957.  
  4958.         private BuildingBlock GetFoundationOwned(Vector3 position, ulong userID)
  4959.         {
  4960. #if DEBUG
  4961.             Puts("GetFoundationOwned() called...");
  4962. #endif
  4963.             var entities = GetFoundation(position);
  4964.             if (entities.Count == 0) return null;
  4965.             if (!config.Home.CheckFoundationForOwner) return entities[0];
  4966.  
  4967.             for (var i = 0; i < entities.Count; i++)
  4968.             {
  4969.                 if (entities[i].OwnerID == userID) return entities[i];
  4970.                 else if (IsFriend(userID, entities[i].OwnerID)) return entities[i];
  4971.             }
  4972.             return null;
  4973.         }
  4974.  
  4975.         // Borrowed/modified from PreventLooting and Rewards
  4976.         // playerid = active player, ownerid = owner of building block, who may be offline
  4977.         bool IsFriend(ulong playerid, ulong ownerid)
  4978.         {
  4979.             if (config.Home.UseFriends && Friends != null && Friends.IsLoaded)
  4980.             {
  4981. #if DEBUG
  4982.                 Puts("Checking Friends...");
  4983. #endif
  4984.                 var fr = Friends?.CallHook("AreFriends", playerid, ownerid);
  4985.                 if (fr != null && (bool)fr)
  4986.                 {
  4987. #if DEBUG
  4988.                     Puts("  IsFriend: true based on Friends plugin");
  4989. #endif
  4990.                     return True;
  4991.                 }
  4992.             }
  4993.             if (config.Home.UseClans && Clans != null && Clans.IsLoaded)
  4994.             {
  4995. #if DEBUG
  4996.                 Puts("Checking Clans...");
  4997. #endif
  4998.                 string playerclan = (string)Clans?.CallHook("GetClanOf", playerid);
  4999.                 string ownerclan = (string)Clans?.CallHook("GetClanOf", ownerid);
  5000.                 if (playerclan != null && ownerclan != null && playerclan == ownerclan)
  5001.                 {
  5002. #if DEBUG
  5003.                     Puts("  IsFriend: true based on Clans plugin");
  5004. #endif
  5005.                     return True;
  5006.                 }
  5007.             }
  5008.             if (config.Home.UseTeams)
  5009.             {
  5010. #if DEBUG
  5011.                 Puts("Checking Rust teams...");
  5012. #endif
  5013.                 BasePlayer player = BasePlayer.FindByID(playerid);
  5014.                 if (player.currentTeam != (long)0)
  5015.                 {
  5016.                     RelationshipManager.PlayerTeam playerTeam = RelationshipManager.Instance.FindTeam(player.currentTeam);
  5017.                     if (playerTeam == null) return False;
  5018.                     if (playerTeam.members.Contains(ownerid))
  5019.                     {
  5020. #if DEBUG
  5021.                         Puts("  IsFriend: true based on Rust teams");
  5022. #endif
  5023.                         return True;
  5024.                     }
  5025.                 }
  5026.             }
  5027.             return False;
  5028.         }
  5029.  
  5030.         // Check that we are near the middle of a block.  Also check for high wall overlap
  5031.         private bool ValidBlock(BaseEntity entity, Vector3 position)
  5032.         {
  5033.             if (!config.Settings.StrictFoundationCheck)
  5034.             {
  5035.                 return True;
  5036.             }
  5037. #if DEBUG
  5038.             Puts($"ValidBlock() called for {entity.ShortPrefabName}");
  5039. #endif
  5040.             Vector3 center = entity.CenterPoint();
  5041.  
  5042.             List<BaseEntity> ents = new List<BaseEntity>();
  5043.             Vis.Entities<BaseEntity>(center, 1.5f, ents);
  5044.             foreach (BaseEntity wall in ents)
  5045.             {
  5046.                 if (wall.name.Contains("external.high"))
  5047.                 {
  5048. #if DEBUG
  5049.                     Puts($"    Found: {wall.name} @ center {center}, pos {position}");
  5050. #endif
  5051.                     return False;
  5052.                 }
  5053.             }
  5054. #if DEBUG
  5055.             Puts($"  Checking block: {entity.name} @ center {center}, pos: {position.ToString()}");
  5056. #endif
  5057.             if (entity.PrefabName.Contains("triangle.prefab"))
  5058.             {
  5059.                 if (Math.Abs(center.x - position.x) < 0.45f && Math.Abs(center.z - position.z) < 0.45f)
  5060.                 {
  5061. #if DEBUG
  5062.                     Puts($"    Found: {entity.ShortPrefabName} @ center: {center}, pos: {position}");
  5063. #endif
  5064.                     return True;
  5065.                 }
  5066.             }
  5067.             else if (entity.PrefabName.Contains("foundation.prefab") || entity.PrefabName.Contains("floor.prefab"))
  5068.             {
  5069.                 if (Math.Abs(center.x - position.x) < 0.7f && Math.Abs(center.z - position.z) < 0.7f)
  5070.                 {
  5071. #if DEBUG
  5072.                     Puts($"    Found: {entity.ShortPrefabName} @ center: {center}, pos: {position}");
  5073. #endif
  5074.                     return True;
  5075.                 }
  5076.             }
  5077.  
  5078.             return False;
  5079.         }
  5080.  
  5081.         private List<BuildingBlock> GetFoundation(Vector3 position)
  5082.         {
  5083.             RaycastHit hitinfo;
  5084.             var entities = new List<BuildingBlock>();
  5085.  
  5086.             if (Physics.Raycast(position, Down, out hitinfo, 2.5f, blockLayer) && hitinfo.GetEntity().IsValid())
  5087.             {
  5088.                 var entity = hitinfo.GetEntity();
  5089.                 if (entity.PrefabName.Contains("foundation") || position.y < entity.WorldSpaceBounds().ToBounds().max.y)
  5090.                 {
  5091.                     if (ValidBlock(entity, position))
  5092.                     {
  5093. #if DEBUG
  5094.                         Puts($"  GetFoundation() found {entity.PrefabName} at {entity.transform.position}");
  5095. #endif
  5096.                         entities.Add(entity as BuildingBlock);
  5097.                     }
  5098.                 }
  5099.             }
  5100.             else
  5101.             {
  5102. #if DEBUG
  5103.                 Puts("  GetFoundation() none found.");
  5104. #endif
  5105.             }
  5106.  
  5107.             return entities;
  5108.         }
  5109.  
  5110.         private List<BuildingBlock> GetFloor(Vector3 position)
  5111.         {
  5112.             RaycastHit hitinfo;
  5113.             var entities = new List<BuildingBlock>();
  5114.  
  5115.             if (Physics.Raycast(position, Down, out hitinfo, 0.25f, Layers.Mask.Construction, QueryTriggerInteraction.Ignore) && hitinfo.GetEntity().IsValid())
  5116.             {
  5117.                 var entity = hitinfo.GetEntity();
  5118.  
  5119.                 if (entity.IsValid() && entity.PrefabName.Contains("floor"))
  5120.                 {
  5121. #if DEBUG
  5122.                     Puts($"  GetFloor() found {entity.PrefabName} at {entity.transform.position}");
  5123. #endif
  5124.                     entities.Add(entity as BuildingBlock);
  5125.                 }
  5126.             }
  5127.             else
  5128.             {
  5129. #if DEBUG
  5130.                 Puts("  GetFloor() none found.");
  5131. #endif
  5132.             }
  5133.  
  5134.             return entities;
  5135.         }
  5136.  
  5137.         private List<BuildingBlock> GetFoundationOrFloor(Vector3 position)
  5138.         {
  5139.             RaycastHit hitinfo;
  5140.             var entities = new List<BuildingBlock>();
  5141.  
  5142.             if (Physics.Raycast(position, Down, out hitinfo, 0.25f, blockLayer) && hitinfo.GetEntity().IsValid())
  5143.             {
  5144.                 var entity = hitinfo.GetEntity();
  5145.                 if (entity.PrefabName.Contains("floor") || entity.PrefabName.Contains("foundation"))// || position.y < entity.WorldSpaceBounds().ToBounds().max.y))
  5146.                 {
  5147. #if DEBUG
  5148.                     Puts($"  GetFoundationOrFloor() found {entity.PrefabName} at {entity.transform.position}");
  5149. #endif
  5150.                     if (ValidBlock(entity, position))
  5151.                     {
  5152.                         entities.Add(entity as BuildingBlock);
  5153.                     }
  5154.                 }
  5155.             }
  5156.             else
  5157.             {
  5158. #if DEBUG
  5159.                 Puts("  GetFoundationOrFloor() none found.");
  5160. #endif
  5161.             }
  5162.  
  5163.             return entities;
  5164.         }
  5165.  
  5166.         private bool CheckBoundaries(float x, float y, float z)
  5167.         {
  5168.             return x <= boundary && x >= -boundary && y <= 2000 && y >= -100 && z <= boundary && z >= -boundary;
  5169.         }
  5170.  
  5171.         private Vector3 GetGround(Vector3 sourcePos)
  5172.         {
  5173.             if (!config.Home.AllowAboveFoundation) return sourcePos;
  5174.             var newPos = sourcePos;
  5175.             newPos.y = TerrainMeta.HeightMap.GetHeight(newPos);
  5176.             sourcePos.y += .5f;
  5177.             RaycastHit hitinfo;
  5178.             var done = False;
  5179.  
  5180. #if DEBUG
  5181.             Puts("GetGround(): Looking for iceberg or cave");
  5182. #endif
  5183.             //if (Physics.SphereCast(sourcePos, .1f, down, out hitinfo, 250, groundLayer))
  5184.             if (Physics.Raycast(sourcePos, Down, out hitinfo, 250f, groundLayer))
  5185.             {
  5186.                 if ((config.Home.AllowIceberg && hitinfo.collider.name.Contains("iceberg")) || (config.Home.AllowCave && hitinfo.collider.name.Contains("cave_")))
  5187.                 {
  5188. #if DEBUG
  5189.                     Puts("GetGround():   found iceberg or cave");
  5190. #endif
  5191.                     sourcePos.y = hitinfo.point.y;
  5192.                     done = True;
  5193.                 }
  5194.                 else
  5195.                 {
  5196.                     var mesh = hitinfo.collider.GetComponentInChildren<MeshCollider>();
  5197.                     if (mesh != null && mesh.sharedMesh.name.Contains("rock_"))
  5198.                     {
  5199.                         sourcePos.y = hitinfo.point.y;
  5200.                         done = True;
  5201.                     }
  5202.                 }
  5203.             }
  5204. #if DEBUG
  5205.             Puts("GetGround(): Looking for cave or rock");
  5206. #endif
  5207.             //if (!_config.Home.AllowCave && Physics.SphereCast(sourcePos, .1f, up, out hitinfo, 250, groundLayer) && hitinfo.collider.name.Contains("rock_"))
  5208.             if (!config.Home.AllowCave && Physics.Raycast(sourcePos, Up, out hitinfo, 250f, groundLayer) && hitinfo.collider.name.Contains("rock_"))
  5209.             {
  5210. #if DEBUG
  5211.                 Puts("GetGround():   found cave or rock");
  5212. #endif
  5213.                 sourcePos.y = newPos.y - 10;
  5214.                 done = True;
  5215.             }
  5216.             return done ? sourcePos : newPos;
  5217.         }
  5218.  
  5219.         private bool GetLift(Vector3 position)
  5220.         {
  5221.             List<ProceduralLift> nearObjectsOfType = new List<ProceduralLift>();
  5222.             Vis.Entities<ProceduralLift>(position, 0.5f, nearObjectsOfType);
  5223.             if (nearObjectsOfType.Count > 0)
  5224.             {
  5225.                 return True;
  5226.             }
  5227.             return False;
  5228.         }
  5229.  
  5230.         private Vector3 GetGroundBuilding(Vector3 sourcePos)
  5231.         {
  5232.             sourcePos.y = TerrainMeta.HeightMap.GetHeight(sourcePos);
  5233.             RaycastHit hitinfo;
  5234.             if (Physics.Raycast(sourcePos, Down, out hitinfo, buildingLayer))
  5235.             {
  5236.                 sourcePos.y = Mathf.Max(hitinfo.point.y, sourcePos.y);
  5237.                 return sourcePos;
  5238.             }
  5239.             if (Physics.Raycast(sourcePos, Up, out hitinfo, buildingLayer))
  5240.                 sourcePos.y = Mathf.Max(hitinfo.point.y, sourcePos.y);
  5241.             return sourcePos;
  5242.         }
  5243.  
  5244.         private bool UnderneathFoundation(Vector3 position)
  5245.         {
  5246.             // Check for foundation half-height above where home was set
  5247.             foreach (var hit in Physics.RaycastAll(position, Up, 2f, buildingLayer))
  5248.             {
  5249.                 if (hit.GetCollider().name.Contains("foundation"))
  5250.                 {
  5251.                     return True;
  5252.                 }
  5253.             }
  5254.             // Check for foundation full-height above where home was set
  5255.             // Since you can't see from inside via ray, start above.
  5256.             foreach (var hit in Physics.RaycastAll(position + Up + Up + Up + Up, Down, 2f, buildingLayer))
  5257.             {
  5258.                 if (hit.GetCollider().name.Contains("foundation"))
  5259.                 {
  5260.                     return True;
  5261.                 }
  5262.             }
  5263.  
  5264.             return False;
  5265.         }
  5266.  
  5267.         private bool IsAllowed(BasePlayer player, string perm = null)
  5268.         {
  5269.             var playerAuthLevel = player.net?.connection?.authLevel;
  5270.  
  5271.             int requiredAuthLevel = 3;
  5272.             if (config.Admin.UseableByModerators)
  5273.             {
  5274.                 requiredAuthLevel = 1;
  5275.             }
  5276.             else if (config.Admin.UseableByAdmins)
  5277.             {
  5278.                 requiredAuthLevel = 2;
  5279.             }
  5280.             if (playerAuthLevel >= requiredAuthLevel) return True;
  5281.  
  5282.             return !string.IsNullOrEmpty(perm) && permission.UserHasPermission(player.UserIDString, perm);
  5283.         }
  5284.  
  5285.         private bool IsAllowedMsg(BasePlayer player, string perm = null)
  5286.         {
  5287.             if (IsAllowed(player, perm)) return True;
  5288.             PrintMsg(player, "NotAllowed");
  5289.             return False;
  5290.         }
  5291.  
  5292.         private int GetHigher(BasePlayer player, Dictionary<string, int> limits, int limit, bool unlimited)
  5293.         {
  5294.             if (unlimited && limit == 0) return limit;
  5295.  
  5296.             foreach (var l in limits)
  5297.             {
  5298.                 if (permission.UserHasPermission(player.UserIDString, l.Key))
  5299.                 {
  5300.                     if (unlimited && l.Value == 0) return l.Value;
  5301.  
  5302.                     limit = Math.Max(l.Value, limit);
  5303.                 }
  5304.             }
  5305.             return limit;
  5306.         }
  5307.  
  5308.         private int GetLower(BasePlayer player, Dictionary<string, int> times, int time)
  5309.         {
  5310.             foreach (var l in times)
  5311.             {
  5312.                 if (permission.UserHasPermission(player.UserIDString, l.Key))
  5313.                 {
  5314.                     time = Math.Min(l.Value, time);
  5315.                 }
  5316.             }
  5317.             return time;
  5318.         }
  5319.  
  5320.         private void CheckPerms(Dictionary<string, int> limits)
  5321.         {
  5322.             foreach (var limit in limits)
  5323.             {
  5324.                 if (!permission.PermissionExists(limit.Key))
  5325.                 {
  5326.                     permission.RegisterPermission(limit.Key, this);
  5327.                 }
  5328.             }
  5329.         }
  5330.         #endregion
  5331.  
  5332.         #region Message
  5333.         private string _(string msgId, BasePlayer player, params object[] args)
  5334.         {
  5335.             var msg = lang.GetMessage(msgId, this, player?.UserIDString);
  5336.             return args.Length > 0 ? string.Format(msg, args) : msg;
  5337.         }
  5338.  
  5339.         private void PrintMsgL(BasePlayer player, string msgId, params object[] args)
  5340.         {
  5341.             if (player == null) return;
  5342.             PrintMsg(player, _(msgId, player, args));
  5343.         }
  5344.  
  5345.         private void PrintMsg(BasePlayer player, string msg)
  5346.         {
  5347.             if (player == null) return;
  5348.             //SendReply(player, $"{config.Settings.ChatName}{msg}");
  5349.             Player.Message(player, $"{config.Settings.ChatName}{msg}", config.Settings.ChatID);
  5350.         }
  5351.         #endregion
  5352.  
  5353.         #region DrawBox
  5354.         private static void DrawBox(BasePlayer player, Vector3 center, Quaternion rotation, Vector3 size)
  5355.         {
  5356.             size = size / 2;
  5357.             var point1 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y + size.y, center.z + size.z), center, rotation);
  5358.             var point2 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y - size.y, center.z + size.z), center, rotation);
  5359.             var point3 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y + size.y, center.z - size.z), center, rotation);
  5360.             var point4 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y - size.y, center.z - size.z), center, rotation);
  5361.             var point5 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y + size.y, center.z + size.z), center, rotation);
  5362.             var point6 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y - size.y, center.z + size.z), center, rotation);
  5363.             var point7 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y + size.y, center.z - size.z), center, rotation);
  5364.             var point8 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y - size.y, center.z - size.z), center, rotation);
  5365.  
  5366.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point1, point2);
  5367.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point1, point3);
  5368.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point1, point5);
  5369.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point4, point2);
  5370.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point4, point3);
  5371.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point4, point8);
  5372.  
  5373.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point5, point6);
  5374.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point5, point7);
  5375.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point6, point2);
  5376.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point8, point6);
  5377.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point8, point7);
  5378.             player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point7, point3);
  5379.         }
  5380.  
  5381.         private static Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Quaternion rotation)
  5382.         {
  5383.             return rotation * (point - pivot) + pivot;
  5384.         }
  5385.         #endregion
  5386.  
  5387.         #region FindPlayer
  5388.         private ulong FindPlayersSingleId(string nameOrIdOrIp, BasePlayer player)
  5389.         {
  5390.             var targets = FindPlayers(nameOrIdOrIp);
  5391.             if (targets.Count > 1)
  5392.             {
  5393.                 PrintMsgL(player, "MultiplePlayers", string.Join(", ", targets.Select(p => p.displayName).ToArray()));
  5394.                 targets.Clear();
  5395.                 return 0;
  5396.             }
  5397.             ulong userId;
  5398.             if (targets.Count <= 0)
  5399.             {
  5400.                 if (ulong.TryParse(nameOrIdOrIp, out userId)) return userId;
  5401.                 PrintMsgL(player, "PlayerNotFound");
  5402.                 return 0;
  5403.             }
  5404.             else
  5405.                 userId = targets.First().userID;
  5406.             targets.Clear();
  5407.             return userId;
  5408.         }
  5409.  
  5410.         private BasePlayer FindPlayersSingle(string nameOrIdOrIp, BasePlayer player)
  5411.         {
  5412.             var targets = FindPlayers(nameOrIdOrIp);
  5413.             if (targets.Count <= 0)
  5414.             {
  5415.                 PrintMsgL(player, "PlayerNotFound");
  5416.                 return null;
  5417.             }
  5418.             if (targets.Count > 1)
  5419.             {
  5420.                 PrintMsgL(player, "MultiplePlayers", string.Join(", ", targets.Select(p => p.displayName).ToArray()));
  5421.                 targets.Clear();
  5422.                 return null;
  5423.             }
  5424.             var t = targets.First();
  5425.             targets.Clear();
  5426.             return t;
  5427.         }
  5428.  
  5429.         private static List<BasePlayer> FindPlayers(string nameOrIdOrIp)
  5430.         {
  5431.             if (string.IsNullOrEmpty(nameOrIdOrIp)) return new List<BasePlayer>();
  5432.             return BasePlayer.allPlayerList.Where(p => p && (p.UserIDString == nameOrIdOrIp || p.displayName.Contains(nameOrIdOrIp, CompareOptions.OrdinalIgnoreCase) || (p.IsConnected && p.net.connection.ipaddress.Contains(nameOrIdOrIp)))).ToList();
  5433.         }
  5434.  
  5435.         private static List<BasePlayer> FindPlayersOnline(string nameOrIdOrIp)
  5436.         {
  5437.             if (string.IsNullOrEmpty(nameOrIdOrIp)) return new List<BasePlayer>();
  5438.             return BasePlayer.activePlayerList.Where(p => p.UserIDString == nameOrIdOrIp || p.displayName.Contains(nameOrIdOrIp, CompareOptions.OrdinalIgnoreCase) || (p.IsConnected && p.net.connection.ipaddress.Contains(nameOrIdOrIp))).ToList();
  5439.         }
  5440.         #endregion
  5441.  
  5442.         #region API
  5443.         private Dictionary<string, Vector3> GetHomes(object playerObj)
  5444.         {
  5445.             if (playerObj == null) return null;
  5446.             if (playerObj is string) playerObj = Convert.ToUInt64(playerObj);
  5447.             if (!(playerObj is ulong)) throw new ArgumentException("playerObj");
  5448.             var playerId = (ulong)playerObj;
  5449.             HomeData homeData;
  5450.             if (!Home.TryGetValue(playerId, out homeData) || homeData.Locations.Count == 0) return null;
  5451.             return homeData.Locations;
  5452.         }
  5453.  
  5454.         private int GetLimitRemaining(BasePlayer player, string type)
  5455.         {
  5456.             if (player == null || string.IsNullOrEmpty(type)) return 0;
  5457.             var currentDate = DateTime.Now.ToString("d");
  5458.             int limit;
  5459.             var remaining = -1;
  5460.             switch (type.ToLower())
  5461.             {
  5462.                 case "home":
  5463.                     limit = GetHigher(player, config.Home.VIPDailyLimits, config.Home.DailyLimit, true);
  5464.                     HomeData homeData;
  5465.                     if (!Home.TryGetValue(player.userID, out homeData))
  5466.                     {
  5467.                         Home[player.userID] = homeData = new HomeData();
  5468.                     }
  5469.                     if (homeData.Teleports.Date != currentDate)
  5470.                     {
  5471.                         homeData.Teleports.Amount = 0;
  5472.                         homeData.Teleports.Date = currentDate;
  5473.                     }
  5474.                     if (limit > 0)
  5475.                     {
  5476.                         remaining = limit - homeData.Teleports.Amount;
  5477.                     }
  5478.                     break;
  5479.                 case "town":
  5480.                     limit = GetHigher(player, config.Town.VIPDailyLimits, config.Town.DailyLimit, true);
  5481.                     TeleportData townData;
  5482.                     if (!Town.TryGetValue(player.userID, out townData))
  5483.                     {
  5484.                         Town[player.userID] = townData = new TeleportData();
  5485.                     }
  5486.                     if (townData.Date != currentDate)
  5487.                     {
  5488.                         townData.Amount = 0;
  5489.                         townData.Date = currentDate;
  5490.                     }
  5491.                     if (limit > 0)
  5492.                     {
  5493.                         remaining = limit - townData.Amount;
  5494.                     }
  5495.                     break;
  5496.                 case "outpost":
  5497.                     limit = GetHigher(player, config.Outpost.VIPDailyLimits, config.Outpost.DailyLimit, true);
  5498.                     TeleportData outpostData;
  5499.                     if (!Outpost.TryGetValue(player.userID, out outpostData))
  5500.                     {
  5501.                         Outpost[player.userID] = outpostData = new TeleportData();
  5502.                     }
  5503.                     if (outpostData.Date != currentDate)
  5504.                     {
  5505.                         outpostData.Amount = 0;
  5506.                         outpostData.Date = currentDate;
  5507.                     }
  5508.                     if (limit > 0)
  5509.                     {
  5510.                         remaining = limit - outpostData.Amount;
  5511.                     }
  5512.                     break;
  5513.                 case "bandit":
  5514.                     limit = GetHigher(player, config.Bandit.VIPDailyLimits, config.Bandit.DailyLimit, true);
  5515.                     TeleportData banditData;
  5516.                     if (!Bandit.TryGetValue(player.userID, out banditData))
  5517.                     {
  5518.                         Bandit[player.userID] = banditData = new TeleportData();
  5519.                     }
  5520.                     if (banditData.Date != currentDate)
  5521.                     {
  5522.                         banditData.Amount = 0;
  5523.                         banditData.Date = currentDate;
  5524.                     }
  5525.                     if (limit > 0)
  5526.                     {
  5527.                         remaining = limit - banditData.Amount;
  5528.                     }
  5529.                     break;
  5530.                 case "tpr":
  5531.                     limit = GetHigher(player, config.TPR.VIPDailyLimits, config.TPR.DailyLimit, true);
  5532.                     TeleportData tprData;
  5533.                     if (!TPR.TryGetValue(player.userID, out tprData))
  5534.                     {
  5535.                         TPR[player.userID] = tprData = new TeleportData();
  5536.                     }
  5537.                     if (tprData.Date != currentDate)
  5538.                     {
  5539.                         tprData.Amount = 0;
  5540.                         tprData.Date = currentDate;
  5541.                     }
  5542.                     if (limit > 0)
  5543.                     {
  5544.                         remaining = limit - tprData.Amount;
  5545.                     }
  5546.                     break;
  5547.             }
  5548.             return remaining;
  5549.         }
  5550.  
  5551.         private int GetCooldownRemaining(BasePlayer player, string type)
  5552.         {
  5553.             if (player == null || string.IsNullOrEmpty(type)) return 0;
  5554.             var currentDate = DateTime.Now.ToString("d");
  5555.             var timestamp = Facepunch.Math.Epoch.Current;
  5556.             int cooldown;
  5557.             var remaining = -1;
  5558.             switch (type.ToLower())
  5559.             {
  5560.                 case "home":
  5561.                     cooldown = GetLower(player, config.Home.VIPCooldowns, config.Home.Cooldown);
  5562.                     HomeData homeData;
  5563.                     if (!Home.TryGetValue(player.userID, out homeData))
  5564.                     {
  5565.                         Home[player.userID] = homeData = new HomeData();
  5566.                     }
  5567.                     if (homeData.Teleports.Date != currentDate)
  5568.                     {
  5569.                         homeData.Teleports.Amount = 0;
  5570.                         homeData.Teleports.Date = currentDate;
  5571.                     }
  5572.                     if (cooldown > 0 && timestamp - homeData.Teleports.Timestamp < cooldown)
  5573.                     {
  5574.                         remaining = cooldown - (timestamp - homeData.Teleports.Timestamp);
  5575.                     }
  5576.                     break;
  5577.                 case "town":
  5578.                     cooldown = GetLower(player, config.Town.VIPCooldowns, config.Town.Cooldown);
  5579.                     TeleportData townData;
  5580.                     if (!Town.TryGetValue(player.userID, out townData))
  5581.                     {
  5582.                         Town[player.userID] = townData = new TeleportData();
  5583.                     }
  5584.                     if (townData.Date != currentDate)
  5585.                     {
  5586.                         townData.Amount = 0;
  5587.                         townData.Date = currentDate;
  5588.                     }
  5589.                     if (cooldown > 0 && timestamp - townData.Timestamp < cooldown)
  5590.                     {
  5591.                         remaining = cooldown - (timestamp - townData.Timestamp);
  5592.                     }
  5593.                     break;
  5594.                 case "outpost":
  5595.                     cooldown = GetLower(player, config.Outpost.VIPCooldowns, config.Outpost.Cooldown);
  5596.                     TeleportData outpostData;
  5597.                     if (!Outpost.TryGetValue(player.userID, out outpostData))
  5598.                     {
  5599.                         Outpost[player.userID] = outpostData = new TeleportData();
  5600.                     }
  5601.                     if (outpostData.Date != currentDate)
  5602.                     {
  5603.                         outpostData.Amount = 0;
  5604.                         outpostData.Date = currentDate;
  5605.                     }
  5606.                     if (cooldown > 0 && timestamp - outpostData.Timestamp < cooldown)
  5607.                     {
  5608.                         remaining = cooldown - (timestamp - outpostData.Timestamp);
  5609.                     }
  5610.                     break;
  5611.                 case "bandit":
  5612.                     cooldown = GetLower(player, config.Bandit.VIPCooldowns, config.Bandit.Cooldown);
  5613.                     TeleportData banditData;
  5614.                     if (!Bandit.TryGetValue(player.userID, out banditData))
  5615.                     {
  5616.                         Bandit[player.userID] = banditData = new TeleportData();
  5617.                     }
  5618.                     if (banditData.Date != currentDate)
  5619.                     {
  5620.                         banditData.Amount = 0;
  5621.                         banditData.Date = currentDate;
  5622.                     }
  5623.                     if (cooldown > 0 && timestamp - banditData.Timestamp < cooldown)
  5624.                     {
  5625.                         remaining = cooldown - (timestamp - banditData.Timestamp);
  5626.                     }
  5627.                     break;
  5628.                 case "tpr":
  5629.                     cooldown = GetLower(player, config.TPR.VIPCooldowns, config.TPR.Cooldown);
  5630.                     TeleportData tprData;
  5631.                     if (!TPR.TryGetValue(player.userID, out tprData))
  5632.                     {
  5633.                         TPR[player.userID] = tprData = new TeleportData();
  5634.                     }
  5635.                     if (tprData.Date != currentDate)
  5636.                     {
  5637.                         tprData.Amount = 0;
  5638.                         tprData.Date = currentDate;
  5639.                     }
  5640.                     if (cooldown > 0 && timestamp - tprData.Timestamp < cooldown)
  5641.                     {
  5642.                         remaining = cooldown - (timestamp - tprData.Timestamp);
  5643.                     }
  5644.                     break;
  5645.             }
  5646.             return remaining;
  5647.         }
  5648.         #endregion
  5649.  
  5650.         private class UnityVector3Converter : JsonConverter
  5651.         {
  5652.             public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  5653.             {
  5654.                 var vector = (Vector3)value;
  5655.                 writer.WriteValue($"{vector.x} {vector.y} {vector.z}");
  5656.             }
  5657.  
  5658.             public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  5659.             {
  5660.                 if (reader.TokenType == JsonToken.String)
  5661.                 {
  5662.                     var values = reader.Value.ToString().Trim().Split(' ');
  5663.                     return new Vector3(Convert.ToSingle(values[0]), Convert.ToSingle(values[1]), Convert.ToSingle(values[2]));
  5664.                 }
  5665.                 var o = JObject.Load(reader);
  5666.                 return new Vector3(Convert.ToSingle(o["x"]), Convert.ToSingle(o["y"]), Convert.ToSingle(o["z"]));
  5667.             }
  5668.  
  5669.             public override bool CanConvert(Type objectType)
  5670.             {
  5671.                 return objectType == typeof(Vector3);
  5672.             }
  5673.         }
  5674.  
  5675.         private class CustomComparerDictionaryCreationConverter<T> : CustomCreationConverter<IDictionary>
  5676.         {
  5677.             private readonly IEqualityComparer<T> comparer;
  5678.  
  5679.             public CustomComparerDictionaryCreationConverter(IEqualityComparer<T> comparer)
  5680.             {
  5681.                 if (comparer == null)
  5682.                     throw new ArgumentNullException(nameof(comparer));
  5683.                 this.comparer = comparer;
  5684.             }
  5685.  
  5686.             public override bool CanConvert(Type objectType)
  5687.             {
  5688.                 return HasCompatibleInterface(objectType) && HasCompatibleConstructor(objectType);
  5689.             }
  5690.  
  5691.             private static bool HasCompatibleInterface(Type objectType)
  5692.             {
  5693.                 return objectType.GetInterfaces().Where(i => HasGenericTypeDefinition(i, typeof(IDictionary<,>))).Any(i => typeof(T).IsAssignableFrom(i.GetGenericArguments().First()));
  5694.             }
  5695.  
  5696.             private static bool HasGenericTypeDefinition(Type objectType, Type typeDefinition)
  5697.             {
  5698.                 return objectType.GetTypeInfo().IsGenericType && objectType.GetGenericTypeDefinition() == typeDefinition;
  5699.             }
  5700.  
  5701.             private static bool HasCompatibleConstructor(Type objectType)
  5702.             {
  5703.                 return objectType.GetConstructor(new[] { typeof(IEqualityComparer<T>) }) != null;
  5704.             }
  5705.  
  5706.             public override IDictionary Create(Type objectType)
  5707.             {
  5708.                 return Activator.CreateInstance(objectType, comparer) as IDictionary;
  5709.             }
  5710.         }
  5711.  
  5712.         [HookMethod("SendHelpText")]
  5713.         private void SendHelpText(BasePlayer player)
  5714.         {
  5715.             PrintMsgL(player, "<size=14>NTeleportation</size> by <color=#ce422b>Nogrod</color>\n<color=#ffd479>/sethome NAME</color> - Set home on current foundation\n<color=#ffd479>/home NAME</color> - Go to one of your homes\n<color=#ffd479>/home list</color> - List your homes\n<color=#ffd479>/town</color> - Go to town, if set\n/tpb - Go back to previous location\n/tpr PLAYER - Request teleport to PLAYER\n/tpa - Accept teleport request");
  5716.         }
  5717.  
  5718.         private bool API_HavePendingRequest(BasePlayer player)
  5719.         {
  5720.             return PendingRequests.ContainsKey(player.userID) || PlayersRequests.ContainsKey(player.userID) || TeleportTimers.ContainsKey(player.userID);
  5721.         }
  5722.  
  5723.         private bool API_HaveAvailableHomes(BasePlayer player)
  5724.         {
  5725.             HomeData homeData;
  5726.             if (!Home.TryGetValue(player.userID, out homeData))
  5727.             {
  5728.                 Home[player.userID] = homeData = new HomeData();
  5729.             }
  5730.  
  5731.             var limit = GetHigher(player, config.Home.VIPHomesLimits, config.Home.HomesLimit, true);
  5732.  
  5733.             if (limit == 0) return True;
  5734.  
  5735.             return homeData.Locations.Count < limit;
  5736.         }
  5737.  
  5738.         private List<string> API_GetHomes(BasePlayer player)
  5739.         {
  5740.             HomeData homeData;
  5741.             if (!Home.TryGetValue(player.userID, out homeData))
  5742.             {
  5743.                 Home[player.userID] = homeData = new HomeData();
  5744.             }
  5745.  
  5746.             return homeData.Locations.Keys.ToList();
  5747.         }
  5748.     }
  5749. }
Add Comment
Please, Sign In to add comment