C#:
using System;
using System.Collections.Generic;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("SetSpawn", "Kalvi", "1.0.0")]
[Description("Plugin for setting and teleporting to a custom spawn point with delay and first-time spawn override")]
public class SetSpawn : CovalencePlugin
{
private Vector3? spawnPoint = null;
private const string permAdmin = "setspawn.admin";
private const string permUse = "setspawn.use";
private float teleportDelay;
private Dictionary<BasePlayer, Timer> teleportTimers = new Dictionary<BasePlayer, Timer>();
private Dictionary<BasePlayer, Vector3> initialPositions = new Dictionary<BasePlayer, Vector3>();
private HashSet<ulong> playersWhoSpawned = new HashSet<ulong>();
private void LoadSpawnPoint()
{
var storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>("SetSpawn");
if (storedData != null && storedData.SpawnPoint != null)
{
spawnPoint = new Vector3(storedData.SpawnPoint[0], storedData.SpawnPoint[1], storedData.SpawnPoint[2]);
}
}
private void SaveSpawnPoint()
{
var storedData = new StoredData
{
SpawnPoint = spawnPoint.HasValue ? new float[] { spawnPoint.Value.x, spawnPoint.Value.y, spawnPoint.Value.z } : null
};
Interface.Oxide.DataFileSystem.WriteObject("SetSpawn", storedData);
}
protected override void LoadDefaultConfig()
{
Config["TeleportDelaySeconds"] = 10f; // Default value
SaveConfig();
}
private void OnServerInitialized()
{
teleportDelay = GetConfig("TeleportDelaySeconds", 10f);
LoadSpawnPoint();
}
private T GetConfig<T>(string key, T defaultValue)
{
if (Config[key] == null)
{
Config[key] = defaultValue;
}
return (T)Convert.ChangeType(Config[key], typeof(T));
}
void Init()
{
permission.RegisterPermission(permAdmin, this);
permission.RegisterPermission(permUse, this);
LoadDefaultConfig();
OnServerInitialized(); // Load config and data
lang.RegisterMessages(new Dictionary<string, string>
{
["NoPermission"] = "<color=#FF0000>You don't have permission to use this command.</color>",
["SpawnSet"] = "<color=#00FF00>Spawn point set to {0}.</color>",
["Teleporting"] = "<color=#00FFFF>Teleporting to spawn point in {0} seconds...</color>",
["Teleported"] = "<color=#00FF00>You have been teleported to the spawn point.</color>",
["NoSpawnSet"] = "<color=#FF0000>Spawn point has not been set.</color>",
["TeleportCancelled"] = "<color=#FF0000>Teleport cancelled due to movement.</color>",
["PluginReloaded"] = "<color=#00FF00>Plugin has been reloaded successfully.</color>",
["ReloadFailed"] = "<color=#FF0000>Failed to reload the plugin.</color>",
["DelaySet"] = "<color=#00FF00>Teleport delay has been set to {0} seconds.</color>",
["InvalidDelay"] = "<color=#FF0000>Invalid delay value. Please enter a positive number.</color>"
}, this);
// Register commands explicitly with unique names
AddCommand("setspawn", "SetSpawnCommand");
AddCommand("spawn", "SpawnCommand");
AddCommand("setspawn-reload", "ReloadCommand");
AddCommand("setspawn-delay", "SetDelayCommand");
}
private void AddCommand(string command, string methodName)
{
AddCovalenceCommand(command, methodName);
}
private void SetSpawnCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(permAdmin))
{
player.Reply(Lang("NoPermission", player.Id));
return;
}
BasePlayer basePlayer = player.Object as BasePlayer;
if (basePlayer != null)
{
spawnPoint = basePlayer.transform.position;
SaveSpawnPoint();
player.Reply(string.Format(Lang("SpawnSet", player.Id), spawnPoint.Value));
Puts($"Spawn point set to {spawnPoint.Value} by {player.Name}");
}
}
private void SpawnCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(permUse))
{
player.Reply(Lang("NoPermission", player.Id));
return;
}
BasePlayer basePlayer = player.Object as BasePlayer;
if (basePlayer != null)
{
if (spawnPoint.HasValue)
{
// Clear any existing teleport timers for this player
if (teleportTimers.TryGetValue(basePlayer, out var existingTimer))
{
existingTimer.Destroy();
teleportTimers.Remove(basePlayer);
initialPositions.Remove(basePlayer);
player.Reply(Lang("TeleportCancelled", player.Id));
Puts($"Previous teleportation of {player.Name} was cancelled.");
}
player.Reply(string.Format(Lang("Teleporting", player.Id), teleportDelay));
Vector3 initialPosition = basePlayer.transform.position;
initialPositions[basePlayer] = initialPosition;
bool hasMoved = false;
Timer movementTimer = null;
movementTimer = timer.Every(0.1f, () =>
{
if (initialPositions.ContainsKey(basePlayer))
{
Vector3 currentPosition = basePlayer.transform.position;
if (Vector3.Distance(initialPositions[basePlayer], currentPosition) > 0.1f)
{
hasMoved = true;
movementTimer.Destroy(); // Destroy movement timer if moved
if (teleportTimers.TryGetValue(basePlayer, out var teleportTimer))
{
teleportTimer.Destroy();
teleportTimers.Remove(basePlayer);
initialPositions.Remove(basePlayer);
player.Reply(Lang("TeleportCancelled", player.Id));
Puts($"Teleportation of {player.Name} to spawn was cancelled due to movement.");
}
}
}
});
Timer teleportTimer = timer.Once(teleportDelay, () =>
{
if (!hasMoved)
{
basePlayer.Teleport(spawnPoint.Value);
player.Reply(Lang("Teleported", player.Id));
Puts($"Player {player.Name} teleported to spawn at {spawnPoint.Value}");
teleportTimers.Remove(basePlayer);
movementTimer.Destroy(); // Ensure movement timer is destroyed after teleport
initialPositions.Remove(basePlayer);
}
});
teleportTimers[basePlayer] = teleportTimer;
}
else
{
player.Reply(Lang("NoSpawnSet", player.Id));
}
}
}
private void ReloadCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(permAdmin))
{
player.Reply(Lang("NoPermission", player.Id));
return;
}
try
{
Unload();
OnServerInitialized(); // Reload configuration
player.Reply(Lang("PluginReloaded", player.Id));
Puts($"Plugin reloaded by {player.Name}");
}
catch (Exception ex)
{
player.Reply(Lang("ReloadFailed", player.Id));
Puts($"Failed to reload plugin: {ex.Message}");
}
}
private void SetDelayCommand(IPlayer player, string command, string[] args)
{
if (!player.HasPermission(permAdmin))
{
player.Reply(Lang("NoPermission", player.Id));
return;
}
if (args.Length < 1 || !float.TryParse(args[0], out float newDelay) || newDelay <= 0)
{
player.Reply(Lang("InvalidDelay", player.Id));
return;
}
teleportDelay = newDelay;
Config["TeleportDelaySeconds"] = teleportDelay;
SaveConfig();
player.Reply(string.Format(Lang("DelaySet", player.Id), teleportDelay));
Puts($"Teleport delay set to {teleportDelay} seconds by {player.Name}");
}
void OnPlayerRespawn(BasePlayer player)
{
if (spawnPoint.HasValue && !player.IsSleeping() && player.net?.connection != null)
{
NextTick(() =>
{
if (!playersWhoSpawned.Contains(player.userID))
{
player.Teleport(spawnPoint.Value);
Puts($"Player {player.displayName} teleported to spawn at {spawnPoint.Value} on first connection.");
playersWhoSpawned.Add(player.userID);
}
else
{
player.Teleport(spawnPoint.Value);
Puts($"Player {player.displayName} teleported to spawn at {spawnPoint.Value} after respawn.");
}
});
}
}
void Unload()
{
spawnPoint = null;
foreach (var timer in teleportTimers.Values)
{
timer.Destroy();
}
teleportTimers.Clear();
}
private string Lang(string key, string id = null) => lang.GetMessage(key, this, id);
private class StoredData
{
public float[] SpawnPoint { get; set; }
}
}
}