C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
#region License (GPL v2)
/*
Teleportication - NextGen Teleportation Plugin
Copyright (c) 2020-2025 RFC1920 <desolationoutpostpve@gmail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License only.This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.Optionally you can also view the license at <http://www.gnu.org/licenses/>.*/
#endregion License (GPL v2)
// Reference: System.Data.SQLite
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
namespace Oxide.Plugins {
[Info("Teleportication", "RFC1920", "1.5.7")]
[Description("NextGen Teleportation plugin")]
internal class Teleportication : RustPlugin {
#region vars
private SortedDictionary<ulong, Vector3> SavedPoints = new();
private SortedDictionary<ulong, ulong> TPRRequests = new();
private SortedDictionary<string, Vector3> monPos = new();
private SortedDictionary<string, Vector3> monSize = new();
private SortedDictionary<string, Vector3> cavePos = new();
private readonly Dictionary<ulong, TPTimer> TeleportTimers = new();
private readonly Dictionary<string, Dictionary<ulong, TPTimer>> CooldownTimers = new();
private Dictionary<string, Dictionary<ulong, float>> DailyUsage = new();
private readonly Dictionary<ulong, TPRTimer> TPRTimers = new();
private int dateInt;
//private Coroutine townPositionsC;
//private List<Vector3> townPositions = new();
private bool newsave;
private const string HGUI = "gui.homes";
private const string permTP_Use = "teleportication.use";
private const string permTP_TP = "teleportication.tp";
private const string permTP_OTHERS = "teleportication.tpothers";
private const string permTP_TPB = "teleportication.tpb";
private const string permTP_TPR = "teleportication.tpr";
private const string permTP_Town = "teleportication.town";
private const string permTP_Bandit = "teleportication.bandit";
private const string permTP_Outpost = "teleportication.outpost";
private const string permTP_Tunnel = "teleportication.tunnel";
private const string permTP_Admin = "teleportication.admin";
private ConfigData configData;
private SQLiteConnection sqlConnection;
public TextInfo TI = CultureInfo.CurrentCulture.TextInfo;
private string connStr;
private readonly string logfilename = "log";
[PluginReference]
private readonly Plugin Friends, Clans, Economics, ServerRewards, GridAPI, NoEscape, Vanish, ZoneManager, BankSystem, SteamFriends;
//, CopyPaste, LootProtect;
private readonly int blockLayer = LayerMask.GetMask("Construction");
private readonly int groundLayer = LayerMask.GetMask("Terrain", "World");
public class TPTimer {
public Timer timer;
public float start;
public float cooldown;
public string type;
public BasePlayer source;
public string targetName;
public Vector3 targetLocation;
public float counter;
// Request count while in cooldown to determine bypass go/no-go
}
public class TPRTimer {
public Timer timer;
public float start;
public float countdown;
public string type;
}
#endregion
#region Message
private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
private void Message(IPlayer player, string key, params object[] args) => player.Message(Lang(key, player.Id, args));
#endregion
#region init
private void OnServerInitialized() {
Puts("HERE!");
sqlConnection = new SQLiteConnection(connStr);
sqlConnection.Open();
LoadData();
LoadConfigVariables();
// Setup permissions from VIPSettings
foreach (KeyValuePair<string, CmdOptions> ttype in configData.Types) {
if (ttype.Value.VIPSettings == null) continue;
if (ttype.Value.VIPSettings.Count > 0) {
foreach (KeyValuePair<string, VIPSetting> x in ttype.Value.VIPSettings) {
if (!permission.PermissionExists(x.Key, this)) permission.RegisterPermission(x.Key, this);
}
}
}
if (configData.Options.WipeOnNewSave && newsave) {
newsave = false;
// Wipe homes and town, etc.CreateOrClearTables(true);
//AutoSpawnTown();
}
FindMonuments();
List<string> target = QuerySingleStringToList("SELECT location FROM rtp_server WHERE name='town'");
if (target.Count > 0) {
Vector3 townPos = StringToVector3(target[0]);
//Puts($"Town position: {townPos}");
NextTick(() => SetTownMapMarker(townPos));
}
MidnightDetect(true);
}
private void Init() {
// Dummy file, creates the directory for us.DynamicConfigFile dataFile = Interface.GetMod().DataFileSystem.GetDatafile(Name + "/teleportication");
dataFile.Save();
connStr = $"Data Source={Path.Combine(Interface.GetMod().DataDirectory, Name, "teleportication.db")};";
CooldownTimers.Add("Home", new Dictionary<ulong, TPTimer>());
CooldownTimers.Add("Town", new Dictionary<ulong, TPTimer>());
CooldownTimers.Add("TPA", new Dictionary<ulong, TPTimer>());
CooldownTimers.Add("TPB", new Dictionary<ulong, TPTimer>());
CooldownTimers.Add("TPR", new Dictionary<ulong, TPTimer>());
CooldownTimers.Add("TP", new Dictionary<ulong, TPTimer>());
CooldownTimers.Add("Bandit", new Dictionary<ulong, TPTimer>());
CooldownTimers.Add("Outpost", new Dictionary<ulong, TPTimer>());
CooldownTimers.Add("Tunnel", new Dictionary<ulong, TPTimer>());
DailyUsage.Add("Home", new Dictionary<ulong, float>());
DailyUsage.Add("Town", new Dictionary<ulong, float>());
DailyUsage.Add("TPA", new Dictionary<ulong, float>());
DailyUsage.Add("TPB", new Dictionary<ulong, float>());
DailyUsage.Add("TPR", new Dictionary<ulong, float>());
DailyUsage.Add("TP", new Dictionary<ulong, float>());
DailyUsage.Add("Bandit", new Dictionary<ulong, float>());
DailyUsage.Add("Outpost", new Dictionary<ulong, float>());
DailyUsage.Add("Tunnel", new Dictionary<ulong, float>());
AddCovalenceCommand("home", "CmdHomeTeleport");
AddCovalenceCommand("homeg", "CmdHomeGUI");
AddCovalenceCommand("sethome", "CmdSetHome");
AddCovalenceCommand("town", "CmdTownTeleport");
AddCovalenceCommand("bandit", "CmdTownTeleport");
AddCovalenceCommand("outpost", "CmdTownTeleport");
AddCovalenceCommand("tunnel", "CmdTownTeleport");
AddCovalenceCommand("tpa", "CmdTpa");
AddCovalenceCommand("tpb", "CmdTpb");
AddCovalenceCommand("tpc", "CmdTpc");
AddCovalenceCommand("tpr", "CmdTpr");
AddCovalenceCommand("tp", "CmdTp");
AddCovalenceCommand("tpadmin", "CmdTpAdmin");
permission.RegisterPermission(permTP_Use, this);
permission.RegisterPermission(permTP_TPB, this);
permission.RegisterPermission(permTP_TPR, this);
permission.RegisterPermission(permTP_TP, this);
permission.RegisterPermission(permTP_OTHERS, this);
permission.RegisterPermission(permTP_Town, this);
permission.RegisterPermission(permTP_Bandit, this);
permission.RegisterPermission(permTP_Outpost, this);
permission.RegisterPermission(permTP_Tunnel, this);
permission.RegisterPermission(permTP_Admin, this);
}
private void Unload() {
foreach (BasePlayer player in BasePlayer.activePlayerList) {
if (player == null) continue;
CuiHelper.DestroyUi(player, HGUI);
}
sqlConnection.Close();
}
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
["serverinfo"]
= "Server Info - ", ["locations"] = "Locations:", ["flags"] = "Flags:", ["notauthorized"] = "You are not authorized for this command!", ["homesavail"] = "The following homes have been set:", ["homesavailfor"] = "The following homes have been set by {0}:", ["nohomes"] = "No homes have been set.", ["hometoomany"] = "You cannot set any more homes.Limit is {0}.", ["hometooclose"] = "Too close to another home - minimum distance {0}", ["homeset"] = "Home {0} has been set.", ["homeremoved"] = "Home {0} has been removed.", ["homewasremoved"] = "Home has been removed - {0}.", ["setblocked"] = "Home cannot be set here - {0}", ["blocked"] = "You cannot teleport while blocked!", ["blockedinvis"] = "You cannot teleport while invisible!", ["invalidhome"] = "Home invalid - {0}", ["lastused"] = " Last used: {0} minutes ago", ["lastuse"] = "last use", ["name"] = "name", ["lastday"] = " Not used since server restart", ["list"] = "list", ["home"] = "Home", ["tpb"] = "old location", ["debug"] = "Debug set to {0}", ["tpr"] = "another player", ["town"] = "Town", ["outpost"] = "Outpost", ["outpostset"] = "Outpost location has been set to {0}", ["tunnels"] = "Available Tunnel Entrances:\n{0}", ["bandit"] = "Bandit", ["banditset"] = "Bandit Town location has been set to {0}", ["InCooldownNoticeNoMoney"] = "Currently in cooldown for {0} for another {1} second(s).Insufficient funds to bypass.", ["InCooldownNoticeNoPmt"] = "Currently in cooldown for {0} for another {1} second(s).", ["InCooldownNoticePmt"] = "Currently in cooldown for {0} for another {1} second(s).Run again to pay {2} for bypass.", ["CooldownBypassedNotice"] = "Cooldown for {0} bypassed by paying {1}", ["limit"] = "You have hit the daily limit for {0}: ({1} of {2})", ["reqdenied"] = "Request to teleport to {0} was denied!", ["reqaccepted"] = "Request to teleport to {0} was accepted!", ["homemissing"] = "No such home...", ["crafting"] = "You are not allowed to teleport while crafting.", ["notowned"] = "No privileges at the target location!", ["missingfoundation"] = "Foundation missing or offset.", ["locationnotset"] = "{0} location has not been set!", ["townset"] = "Town location has been set to {0}!", ["cavetooclose"] = "You cannot use /{0} so close to a cave.", ["montooclose"] = "You cannot use /{0} so close to {1}.", ["onhurt"] = "You cannot use /{0} while injured.", ["oncold"] = "You are too cold to use /{0}!", ["onhot"] = "You are too hot to use /{0}!", ["onhostile"] = "You are marked as hostile and cannot use /{0} for {1} minutes...", ["onballoon"] = "You cannot use /{0} while on a balloon.", ["oncargo"] = "You cannot use /{0} while on the cargo ship.", ["onlift"] = "You cannot use /{0} while on a lift.", ["onmounted"] = "You cannot use /{0} while mounted.", ["onswimming"] = "You cannot use /{0} while swimming.", ["onwater"] = "You cannot use /{0} above water.", ["onboat"] = "You cannot use /{0} on a tugboat.", ["oniceberg"] = "You cannot use /{0} on an iceberg.", ["intunnel"] = "You cannot use /{0} to/from the tunnel system.", ["safezone"] = "You cannot use /{0} from a safe zone.", ["remaining"] = "You have {0} {1} teleports remaining for today.", ["teleporting"] = "Teleporting to {0} in {1} second(s)...", ["sortedby"] = "sorted by {0}", ["noprevious"] = "No previous location saved.", ["teleportinghome"] = "Teleporting to home {0} in {1} second(s)...", ["BackupDone"] = "Teleportication database has been backed up to {0}", ["importhelp"] = "/tpadmin import {r/n} {y/1/yes/true}\n\t import RTeleportion or NTeleportation\n\tadd y or 1 or true to actually import\n\totherwise display data only", ["tphelp"] = "/tp X,Z OR /tp X,Y,Z -- e.g./tp 121,-535 will teleport the player to that location on the map.\nIf Y is not specified, player will be moved to ground level.", ["tphelpnew"] = "/tp X,Z OR /tp X,Y,Z -- e.g./tp 121,-535 will teleport the player to that location on the map.\n If Y is not specified, player will be moved to ground level.\n/tp YOURNAME PLAYERNAME\n Teleport yourself to another player.\n/tp PLAYERNAME YOURNAME\n Teleport specified player to your location, if allowed.", ["cannottp"] = "Cannot teleport to desired location.", ["obstructed"] = "The target location is too close to construction.", ["importdone"] = "Homes have been imported from datafile '{0}'", ["importing"] = "Importing data for {0}", ["tpcancelled"] = "Teleport cancelled!", ["tprself"] = "You cannot tpr to yourself.", ["playernotfound"] = "Source or target player not found", ["cooldown"] = "Cooldown:", ["cooldowns"] = "COOLDOWNS:", ["playerhomes"] = "PLAYER HOMES:", ["remaining"] = "Remaining:", ["tprnotify"] = "{0} has requested to be teleported to you.\nType /tpa to accept.", ["tpanotify"] = "{0} has accepted your teleport request.You will be teleported in {1} second(s).", ["tprreject"] = "{0} rejected your request.Or, the request timed out."
}
, this);
}
private void OnNewSave() => newsave = true;
//private object OnPlayerRespawn(BasePlayer player)
//{
// List<string> target = QuerySingleStringToList($"SELECT location FROM rtp_server WHERE name='outpost'");
// if (target[0]?.Length > 0)
// {
// Vector3 position = StringToVector3(target[0]);
// return new BasePlayer.SpawnPoint() { pos = position, rot = new Quaternion(0, 0, 0, 1) };
// }
// return null;
//}
private void LoadData() {
bool found = false;
using (SQLiteConnection c = new(connStr)) {
c.Open();
using (SQLiteCommand r = new("SELECT name FROM sqlite_master WHERE type='table' AND name='rtp_server'", c)) using (SQLiteDataReader rtbl = r.ExecuteReader()) {
while (rtbl.Read()) {
found = true;
}
}
}
if (!found) CreateOrClearTables(true);
}
#endregion
#region commands
[Command("tp")]
private void CmdTp(IPlayer iplayer, string command, string[] args) {
if (configData.Options.debug) {
string debug = string.Join(",", args);
Puts($"{debug}");
}
if (!iplayer.HasPermission(permTP_TP) && !iplayer.HasPermission(permTP_OTHERS) && !iplayer.HasPermission(permTP_Admin)) {
Message(iplayer, "notauthorized");
return;
}
BasePlayer player = iplayer.Object as BasePlayer;
if (args.Length == 1) {
// TP to coordinates X,Y,Z or X,0,Z (/tp 100,0,100 OR /tp 100,100)
// 0 or no Y arg will be translated to the terrain height at the destination
string[] input = args[0].Split(',');
if (input.Length > 1) {
Vector3 pos = default(Vector3);
string parsed;
if (input.Length == 3) {
parsed = input[0] + "," + input[1] + "," + input[2];
DoLog($"Parsed arg input from X,Y,Z into coordinates: s:{parsed}/v:{pos}");
pos = StringToVector3(parsed);
}
else if (input.Length == 2) {
parsed = input[0] + ",0," + input[1];
pos = StringToVector3(parsed);
DoLog($"Parsed arg input from X,Y into coordinates: s:{parsed}/v:{pos}");
if (TerrainMeta.HeightMap.GetHeight(pos) > pos.y) {
// Ensure they are sent above the terrain
pos.y = TerrainMeta.HeightMap.GetHeight(pos);
}
}
else {
Message(iplayer, "tphelpnew");
return;
}
ulong userid = ulong.Parse(iplayer.Id);
if (CanTeleport(player, parsed, "TP")) {
if (!TeleportTimers.ContainsKey(userid)) {
AddTimer(player, pos, "TP", "TP");
HandleTimer(userid, "TP", true);
CreateCooldown(player, "TP");
if (!DailyUsage["TP"].ContainsKey(userid)) DailyUsage["TP"].Add(userid, 0);
float usage = GetDailyLimit(userid, "TP") - DailyUsage["TP"][userid];
if (usage > 0) {
Message(iplayer, "remaining", usage.ToString(), "TPB");
}
}
else if (TeleportTimers[userid].cooldown == 0) {
Teleport(player, pos, "TP");
}
}
}
}
else if (args.Length == 2) {
// Player to player tp (/tp src target), sleeping or not
BasePlayer srcPlayer = FindPlayerByName(args[0], true);
BasePlayer tgtPlayer = FindPlayerByName(args[1], true);
if (srcPlayer == null || tgtPlayer == null) {
Message(iplayer, "playernotfound");
return;
}
// 'player' set above, i.e.the player running the command
bool allowed = false;
if (srcPlayer != player && tgtPlayer != player) {
if (iplayer.HasPermission(permTP_Admin)) {
// Allowed to tp 2nd player to 3rd player based on permTP_Admin
allowed = true;
}
else {
// No permission to tp 2nd player to 3rd player, i.e.not the calling player
Message(iplayer, "notauthorized");
return;
}
}
else if (tgtPlayer == player && iplayer.HasPermission(permTP_OTHERS)) {
// Allowed to tp srcPlayer to tgtPlayer (self) based on permTP_OTHERS
allowed = true;
}
else if (srcPlayer == player) {
// Allowed to tp srcPlayer (self) to tgtPlayer based on perm_TP
allowed = true;
}
if (allowed) {
if (TeleportTimers.ContainsKey(srcPlayer.userID)) TeleportTimers.Remove(srcPlayer.userID);
AddTimer(srcPlayer, tgtPlayer.transform.position, "TP", "TP");
HandleTimer(srcPlayer.userID, "TP", true);
if (!DailyUsage["TP"].ContainsKey(player.userID)) DailyUsage["TP"].Add(player.userID, 0);
float usage = GetDailyLimit(player.userID, "TP") - DailyUsage["TP"][player.userID];
if (usage > 0) {
Message(iplayer, "remaining", usage.ToString(), "TP");
}
return;
}
Message(iplayer, "notauthorized");
}
else {
Message(iplayer, "tphelpnew");
}
}
[Command("tpadmin")]
private void CmdTpAdmin(IPlayer iplayer, string command, string[] args) {
if (configData.Options.debug) {
string debug = string.Join(",", args);
Puts($"{debug}");
}
if (!iplayer.HasPermission(permTP_Admin)) {
Message(iplayer, "notauthorized");
return;
}
if (args.Length > 0) {
switch (args[0]) {
case "import" : // args[1] == r/n
// Import from N/RTeleportation
string otpplug = null;
bool doit = false;
if (args.Length > 1) {
switch (args[1]) {
case "r" : otpplug = "RTeleportation";
break;
case "n" : otpplug = "NTeleportation";
break;
default : Message(iplayer, "importhelp");
return;
}
}
if (args.Length > 2) {
doit = GetBoolValue(args[2]);
}
if (otpplug != null) {
try {
// Get user homes from data file
DynamicConfigFile tpfile = Interface.GetMod().DataFileSystem.GetFile(otpplug + "Home");
tpfile.Settings.NullValueHandling = NullValueHandling.Ignore;
tpfile.Settings.Converters = new JsonConverter[] {
new UnityVector3Converter(), new CustomComparerDictionaryCreationConverter<string>(StringComparer.OrdinalIgnoreCase)
}
;
foreach (KeyValuePair<ulong, HomeData> userHomes in tpfile.ReadObject<Dictionary<ulong, HomeData>>()) {
foreach (KeyValuePair<string, Vector3> home in userHomes.Value.Locations) {
if (doit) {
RunUpdateQuery($"INSERT OR REPLACE INTO rtp_player VALUES('{userHomes.Key}', '{home.Key}', '{home.Value}', '0', 0)");
Message(iplayer, "importing", userHomes.Key);
}
else {
Message(iplayer, $"{userHomes.Key}: Home {home.Key} location {home.Value}");
}
}
}
if (doit) Message(iplayer, "importdone", otpplug + "Home");
}
catch {
Puts($"Failed to open datafile, {otpplug}Home");
}
try {
// Get town location from config
DataFileSystem d = new(Interface.GetMod().ConfigDirectory);
string[] x = d.GetFiles("", $"{otpplug}.json");
OtherConfigData otpcfg = d.GetFile(otpplug).ReadObject<OtherConfigData>();
string townloc = otpcfg.Town.Location.Replace(" ", "").Replace(" ", ",");
if (townloc != null) {
if (doit) {
RunUpdateQuery($"INSERT OR REPLACE INTO rtp_server VALUES('town', '({townloc})')");
Message(iplayer, "importing", $"Town: ({townloc})");
}
else {
Message(iplayer, $"Found town location ({townloc})");
}
}
}
catch {
Puts($"Failed to open cfgfile for {otpplug}");
}
}
break;
case "wipe" : Message(iplayer, "Wiping data!");
CreateOrClearTables(true);
FindMonuments();
break;
case "info" : Message(iplayer, Title);
Message(iplayer, "locations");
string loc = null;
using (SQLiteConnection c = new(connStr)) {
c.Open();
using (SQLiteCommand q = new("SELECT name, location FROM rtp_server ORDER BY name", c)) using (SQLiteDataReader svr = q.ExecuteReader()) {
while (svr.Read()) {
string nm = !svr.IsDBNull(0) ? svr.GetString(0) : "";
string lc = !svr.IsDBNull(1) ? svr.GetString(1) : "";
loc += "\t" + TI.ToTitleCase(nm) + ": " + lc.TrimEnd() + "\n";
}
}
}
Message(iplayer, loc);
string flags = $"\tHomeRequireFoundation:\t{configData.Options.HomeRequireFoundation}\n" + $"\tStrictFoundationCheck:\t{configData.Options.StrictFoundationCheck}\n" + $"\tHomeRemoveInvalid:\t{configData.Options.HomeRemoveInvalid}\n" + $"\tHonorBuildingPrivilege:\t{configData.Options.HonorBuildingPrivilege}\n" + $"\tHonorRelationships:\t{configData.Options.HonorRelationships}\n" + $"\tAutoGenBandit:\t{configData.Options.AutoGenBandit}\n" + $"\tAutoGenOutpost:\t{configData.Options.AutoGenOutpost}\n" + $"\tHomeMinimumDistance:\t{configData.Options.HomeMinimumDistance}\n" + $"\tDefaultMonoumentSize:\t{configData.Options.DefaultMonumentSize}\n" + $"\tCaveDistanceSmall:\t{configData.Options.CaveDistanceSmall}\n" + $"\tCaveDistanceMedium:\t{configData.Options.CaveDistanceMedium}\n" + $"\tCaveDistanceLarge:\t{configData.Options.CaveDistanceLarge}\n" + $"\tMinimumTemp:\t{configData.Options.MinimumTemp}\n" + $"\tMaximumTemp:\t{configData.Options.MaximumTemp}\n" + $"\tSetCommand:\t{configData.Options.SetCommand}\n" + $"\tListCommand:\t{configData.Options.ListCommand}\n" + $"\tRemoveCommand:\t{configData.Options.RemoveCommand}";
Message(iplayer, "flags");
Message(iplayer, flags);
break;
case "playerinfo" : case "pinfo" : Message(iplayer, $"{Title} Player Information");
Message(iplayer, Lang("cooldowns"));
string output = "";
foreach (KeyValuePair<string, Dictionary<ulong, TPTimer>> cdt in CooldownTimers) {
output += "\t" + cdt.Key + ": \n";
foreach (KeyValuePair<ulong, TPTimer> tinfo in cdt.Value) {
output += $"\t\t{BasePlayer.FindAwakeOrSleeping(tinfo.Key.ToString()).displayName}, " + $"{Lang("cooldown")} {tinfo.Value.cooldown}, " + $"{Lang("remaining")} {Math.Abs(Time.realtimeSinceStartup - tinfo.Value.start - tinfo.Value.cooldown)}\n";
}
}
output += $"\n{Lang("playerhomes")}\n";
Dictionary<string, int> pCount = new();
using (SQLiteConnection c = new(connStr)) {
c.Open();
using (SQLiteCommand q = new("SELECT userid FROM rtp_player ORDER BY userid", c)) using (SQLiteDataReader svr = q.ExecuteReader()) {
while (svr.Read()) {
string playerId = !svr.IsDBNull(0) ? svr.GetString(0) : "";
if (playerId.Length == 0) continue;
if (!pCount.ContainsKey(playerId)) {
pCount.Add(playerId, 1);
continue;
}
pCount[playerId]++;
}
}
}
foreach (KeyValuePair<string, int> pHomes in pCount) {
output += $"\t{BasePlayer.FindAwakeOrSleeping(pHomes.Key)?.displayName} has {pHomes.Value} homes\n";
}
Message(iplayer, output);
break;
case "debug" : configData.Options.debug = !configData.Options.debug;
Message(iplayer, "debug", configData.Options.debug.ToString());
break;
case "backup" : string backupfile = "teleportication_" + DateTime.Now.ToString("yyyy-MM-dd_HHmmss") + ".db";
if (args.Length > 1) {
backupfile = args[1] + ".db";
}
using (SQLiteConnection c = new(connStr)) {
c.Open();
string file = $"{Interface.GetMod().DataDirectory}{Path.DirectorySeparatorChar}{Name}{Path.DirectorySeparatorChar}{backupfile}";
SQLiteConnection.CreateFile(file);
SQLiteCommand cmd = c.CreateCommand();
cmd.CommandText = $"VACUUM INTO '{file}'";
cmd.ExecuteNonQuery();
Message(iplayer, "BackupDone", backupfile);
}
break;
}
}
}
[Command("sethome")]
private void CmdSetHome(IPlayer iplayer, string command, string[] args) {
if (args.Length == 1) CmdHomeTeleport(iplayer, "home", new string[] {
configData.Options.SetCommand, args[0]
}
);
}
[Command("home")]
private void CmdHomeTeleport(IPlayer iplayer, string command, string[] args) {
if (configData.Options.debug) {
string debug = string.Join(",", args);
Puts($"{debug}");
}
if (!iplayer.HasPermission(permTP_Use)) {
Message(iplayer, "notauthorized");
return;
}
if (iplayer.Id == "server_console") return;
BasePlayer player = iplayer.Object as BasePlayer;
if (args.Length < 1 || (args.Length == 1 && args[0] == configData.Options.ListCommand)) {
// List homes
string available = Lang("homesavail") + "\n";
bool hashomes = false;
List<Vector3> allhomes = new();
string firstHome = string.Empty;
using (SQLiteConnection c = new(connStr)) {
c.Open();
string qh = $"SELECT name, location, lastused FROM rtp_player WHERE userid='{player.userID}'";
//Puts(qh);
using (SQLiteCommand q = new(qh, c)) using (SQLiteDataReader home = q.ExecuteReader()) {
while (home.Read()) {
string test = !home.IsDBNull(0) ? home.GetString(0) : "";
Vector3 position = StringToVector3(!home.IsDBNull(1) ? home.GetString(1) : "");
string pos = PositionToGrid(position);
if (test != "") {
string timesince = Math.Floor((Time.realtimeSinceStartup / 60) - (Convert.ToSingle(home.GetString(2)) / 60)).ToString();
if (int.Parse(timesince) < 0) {
available += test + ": " + position + " [" + pos + "] " + Lang("lastday") + "\n";
}
else {
available += test + ": " + position + " [" + pos + "] " + Lang("lastused", null, timesince) + "\n";
}
hashomes = true;
allhomes.Add(position);
firstHome = test;
}
}
}
}
if (hashomes) {
if (allhomes.Count == 1 && CanTeleport(player, allhomes[0].ToString(), "Home") && configData.Types["Home"].IfOneHomeJustGoThere) {
if (!TeleportTimers.ContainsKey(player.userID)) {
AddTimer(player, allhomes[0], "Home", "Home");
HandleTimer(player.userID, "Home", true);
CreateCooldown(iplayer.Object as BasePlayer, "Home");
if (!DailyUsage["Home"].ContainsKey(player.userID)) DailyUsage["Home"].Add(player.userID, 0);
float usage = GetDailyLimit(player.userID, "Home") - DailyUsage["Home"][player.userID];
if (usage > 0) {
Message(iplayer, "remaining", usage.ToString(), "Home");
}
Message(iplayer, "teleportinghome", firstHome + "(" + RemoveSpecialCharacters(firstHome) + ")", configData.Types["Home"].CountDown.ToString());
}
else if (TeleportTimers[player.userID].cooldown == 0) {
Teleport(player, allhomes[0], "home");
}
return;
}
Message(iplayer, available);
}
else {
Message(iplayer, "nohomes");
}
}
else if (args.Length == 2 && (args[0] == configData.Options.ListCommand) && configData.Options.HonorRelationships) {
// List a friend's homes
BasePlayer target = BasePlayer.Find(args[1]);
if (target != null && IsFriend(player.userID, target.userID)) {
string available = Lang("homesavailfor", null, RemoveSpecialCharacters(target.displayName)) + "\n";
bool hashomes = false;
using (SQLiteConnection c = new(connStr)) {
c.Open();
using (SQLiteCommand q = new($"SELECT name, location, lastused FROM rtp_player WHERE userid='{target.userID}'", c)) using (SQLiteDataReader home = q.ExecuteReader()) {
while (home.Read()) {
string test = !home.IsDBNull(0) ? home.GetString(0) : "";
string lastused = !home.IsDBNull(2) ? home.GetString(2) : "";
if (test != "") {
string timesince = Math.Floor((Time.realtimeSinceStartup / 60) - (Convert.ToSingle(lastused) / 60)).ToString();
//Puts($"Time since {timesince}");
available += test + ": " + home.GetString(1) + " " + Lang("lastused", null, timesince) + "\n";
hashomes = true;
}
}
}
}
if (hashomes) {
Message(iplayer, available);
}
else {
Message(iplayer, "nohomes");
}
}
else {
Message(iplayer, "notauthorized");
}
}
else if (args.Length == 2 && args[0] == configData.Options.SetCommand) {
// Set home
string reason;
if (CanSetHome(player, player.transform.position, out reason)) {
string home = args[1];
bool found = false;
using (SQLiteConnection c = new(connStr)) {
c.Open();
string q = $"SELECT name FROM rtp_player WHERE userid='{player.userID}' AND name='{home}'";
DoLog(q);
using (SQLiteCommand ct = new(q, c)) using (SQLiteDataReader pl = ct.ExecuteReader()) {
while (pl.Read()) {
if (!pl.IsDBNull(0) && pl.GetString(0) == home) found = true;
}
}
}
if (found) {
RunUpdateQuery($"UPDATE rtp_player SET location='{player.transform.position}' WHERE userid='{player.userID}' AND name='{home}'");
}
else {
RunUpdateQuery($"INSERT INTO rtp_player VALUES('{player.userID}', '{home}', '{player.transform.position}', '{Time.realtimeSinceStartup}', 0)");
}
Message(iplayer, "homeset", home);
}
else {
Message(iplayer, "setblocked", reason);
}
}
else if (args.Length == 2 && args[0] == configData.Options.RemoveCommand) {
// Remove home
string home = args[1];
List<string> found = QuerySingleStringToList($"SELECT location FROM rtp_player WHERE userid='{player.userID}' AND name='{home}'");
if (found.Count > 0) {
RunUpdateQuery($"DELETE FROM rtp_player WHERE userid='{player.userID}' AND name='{home}'");
Message(iplayer, "homeremoved", home);
}
else {
Message(iplayer, "homemissing");
}
}
else if (args.Length == 2) {
// Use a friend's home: /home Playername home1
BasePlayer target = BasePlayer.Find(args[0]);
if (target != null && IsFriend(player.userID, target.userID)) {
string home = args[1];
List<string> homes = QuerySingleStringToList($"SELECT location FROM rtp_player WHERE userid='{target.userID}' AND name='{home}'");
if (homes.Count > 0 && CanTeleport(player, homes[0], "Home")) {
if (!TeleportTimers.ContainsKey(player.userID)) {
AddTimer(player, StringToVector3(homes[0]), "Home", "Home");
HandleTimer(player.userID, "Home", true);
CreateCooldown(iplayer.Object as BasePlayer, "Home");
if (!DailyUsage["Home"].ContainsKey(player.userID)) DailyUsage["Home"].Add(player.userID, 0);
float usage = GetDailyLimit(player.userID, "Home") - DailyUsage["Home"][player.userID];
if (usage > 0) {
Message(iplayer, "remaining", usage.ToString(), "Home");
}
Message(iplayer, "teleportinghome", home + "(" + RemoveSpecialCharacters(target.displayName) + ")", configData.Types["Home"].CountDown.ToString());
}
else if (TeleportTimers[player.userID].cooldown == 0) {
Teleport(player, StringToVector3(homes[0]), "home");
}
}
}
}
else if (args.Length == 1) {
CuiHelper.DestroyUi(player, HGUI);
// Use an already set home
string home = args[0];
List<string> homes = QuerySingleStringToList($"SELECT location FROM rtp_player WHERE userid='{player.userID}' AND name='{home}'");
if (homes.Count == 0) {
Message(iplayer, "homemissing");
return;
}
if (CanTeleport(player, homes[0], "Home")) {
if (!TeleportTimers.ContainsKey(player.userID)) {
AddTimer(player, StringToVector3(homes[0]), "Home", "Home");
HandleTimer(player.userID, "Home", true);
CreateCooldown(iplayer.Object as BasePlayer, "Home");
if (!DailyUsage["Home"].ContainsKey(player.userID)) DailyUsage["Home"].Add(player.userID, 0);
float usage = GetDailyLimit(player.userID, "Home") - DailyUsage["Home"][player.userID];
if (usage > 0) {
Message(iplayer, "remaining", usage.ToString(), "Home");
}
Message(iplayer, "teleportinghome", home, configData.Types["Home"].CountDown.ToString());
}
else if (TeleportTimers[player.userID].cooldown == 0) {
Teleport(player, StringToVector3(homes[0]), "home");
}
}
}
}
[Command("homeg")]
private void CmdHomeGUI(IPlayer iplayer, string command, string[] args) {
if (configData.Options.debug) {
string debug = string.Join(",", args);
Puts($"{debug}");
}
if (!iplayer.HasPermission(permTP_Use)) {
Message(iplayer, "notauthorized");
return;
}
if (iplayer.Id == "server_console") return;
BasePlayer player = iplayer.Object as BasePlayer;
string sort = "alpha";
if (args.Length > 0) {
sort = args[0];
}
if (sort == "closeit") {
CuiHelper.DestroyUi(player, HGUI);
return;
}
HomeGUI(player, sort);
}
[Command("town")]
private void CmdTownTeleport(IPlayer iplayer, string command, string[] args) {
if (iplayer.Id == "server_console") return;
BasePlayer player = iplayer.Object as BasePlayer;
if (args.Length > 0 && args[0] == configData.Options.SetCommand) {
if (!iplayer.HasPermission(permTP_Admin)) {
Message(iplayer, "notauthorized");
return;
}
RunUpdateQuery($"INSERT OR REPLACE INTO rtp_server VALUES('{command}', '{player.transform.position}')");
switch (command) {
case "town" : Message(iplayer, "townset", player.transform.position.ToString());
Puts(player.transform.position.ToString());
if (configData.Options.AddTownMapMarker) {
SetTownMapMarker(player.transform.position);
}
if (configData.Options.TownZoneId?.Length > 0) {
string[] zone_args = {
"name", "Town", "radius", "150"
}
;
object ckzone = ZoneManager?.Call("CheckZoneID", configData.Options.TownZoneId);
if (ckzone != null && ckzone is bool && !(bool)ckzone) {
configData.Options.TownZoneId = UnityEngine.Random.Range(1, 99999999).ToString();
SaveConfig(configData);
}
if (configData.Options.TownZoneEnterMessage.Length > 0) {
List<string> arglist = zone_args.ToList();
arglist.Add("enter_message");
arglist.Add(configData.Options.TownZoneEnterMessage);
zone_args = arglist.ToArray();
}
if (configData.Options.TownZoneLeaveMessage.Length > 0) {
List<string> arglist = zone_args.ToList();
arglist.Add("leave_message");
arglist.Add(configData.Options.TownZoneLeaveMessage);
zone_args = arglist.ToArray();
}
ZoneManager?.Call("CreateOrUpdateZone", configData.Options.TownZoneId, zone_args, player.transform.position);
if (configData.Options.TownZoneFlags.Count > 0) {
foreach (string flag in configData.Options.TownZoneFlags) {
ZoneManager?.Call("AddFlag", configData.Options.TownZoneId, flag);
}
}
}
Interface.CallHook("OnTownSet", player.transform.position);
break;
case "bandit" : Message(iplayer, "banditset", player.transform.position.ToString());
break;
case "outpost" : Message(iplayer, "outpostset", player.transform.position.ToString());
break;
}
return;
}
switch (command) {
case "tunnel" : if (!iplayer.HasPermission(permTP_Tunnel)) {
Message(iplayer, "notauthorized");
return;
}
string dtarget = null;
if (args.Length > 0) {
dtarget = string.Join(" ", args);
}
if (dtarget == null) {
string res = "";
List<string> tunnels = QuerySingleStringToList("SELECT name FROM rtp_server WHERE name LIKE '%Tunnel%' ORDER BY name");
if (tunnels.Count > 0) {
foreach (string tun in tunnels) {
string nm = tun.Replace("Tunnel", "");
res += $" {nm}\n";
}
}
Message(iplayer, "tunnels", res);
return;
}
const string dtype = "Tunnel";
List<string> tunnel = QuerySingleStringToList($"SELECT location FROM rtp_server WHERE name='Tunnel {dtarget}'");
if (tunnel.Count > 0) {
if (CanTeleport(player, tunnel[0], dtype)) {
if (!TeleportTimers.ContainsKey(player.userID)) {
AddTimer(player, StringToVector3(tunnel[0]), dtype, Lang("town"));
HandleTimer(player.userID, dtype, true);
CreateCooldown(iplayer.Object as BasePlayer, "Town");
if (!DailyUsage["Town"].ContainsKey(player.userID)) DailyUsage["Town"].Add(playe
// ... [Code preview truncated due to length. Full source in attached file] ...