Teleportation
Teleportation is one of the most commonly implemented features in RocketMod administrative plugins. Moving players around the map, teleporting to other players, and teleporting to named locations are standard capabilities in any moderation toolkit. This article covers the complete RocketMod API surface for player teleportation, including the three overloads of UnturnedPlayer.Teleport, position-based teleportation, target-based teleportation, node-based teleportation, vehicle teleportation, cooldown enforcement, and teleport request (TPA) system patterns.
The patterns documented here are drawn from teleportation plugins used on 57 Studios™ Horizon Life RP servers. They have been validated against Unturned 3.x with RocketMod 4.x.

Prerequisites
- A working Unturned dedicated server with RocketMod installed. See RocketMod and OpenMod Plugin Basics for setup.
- Visual Studio 2022 with .NET Framework 4.7.2 targeting.
- Familiarity with
UnturnedPlayer,IRocketCommand, and the RocketMod event model. - Basic understanding of Unity's
Vector3andQuaterniontypes for position and rotation.
What you'll learn
- How to use the three
UnturnedPlayer.Teleportoverloads: to another player, to coordinates, and to a node. - How to implement a
/tpcommand that teleports to a target player. - How to implement a
/tpposcommand that teleports to specific coordinates. - How to implement a
/tplocationcommand that teleports to a named node. - How to implement a teleport request (TPA) system with accept and deny.
- How to enforce teleport cooldowns and combat-tag blocking.
- How to handle vehicle teleportation alongside player teleportation.
- How to avoid common pitfalls: stale references, position bounds, and rotation defaults.
The Teleport method
RocketMod exposes three overloads of UnturnedPlayer.Teleport for different teleportation scenarios. These overloads cover the vast majority of teleportation use cases in administrative plugins.
Overload 1: Teleport to another player
csharp
public void Teleport(UnturnedPlayer target)Teleports the calling player to the specified target player's position. The teleported player appears at the target's exact position with the same rotation as the target.
csharp
UnturnedPlayer source = UnturnedPlayer.FromName("Alice");
UnturnedPlayer target = UnturnedPlayer.FromName("Bob");
source.Teleport(target); // Alice teleports to Bob's positionThis overload is the simplest teleportation pattern. It is used for /tp commands where a player or admin teleports to another player.
Overload 2: Teleport to coordinates
csharp
public void Teleport(float x, float y, float z)Teleports the player to the specified world coordinates. The player retains their current rotation. The x, y, and z parameters are world-space coordinates in the Unturned map.
csharp
UnturnedPlayer player = UnturnedPlayer.FromName("Lloyd");
// Teleport to coordinates: x=100, y=10, z=200
player.Teleport(100f, 10f, 200f);This overload is used for /tppos commands and for teleporting players to fixed locations defined in configuration files.
Overload 3: Teleport to a node
csharp
public void Teleport(PlayerNode node)Teleports the player to a predefined navigation node on the map. PlayerNode instances are obtained from the map's node system, typically through the LevelNodes or NodeManager API.
csharp
using SDG.Unturned;
using System.Linq;
public static void TeleportToNearestNode(UnturnedPlayer player)
{
PlayerNode nearestNode = LevelNodes.nodes
.OfType<PlayerNode>()
.OrderBy(n => Vector3.Distance(player.Position, n.point))
.FirstOrDefault();
if (nearestNode != null)
{
player.Teleport(nearestNode);
}
}This overload is used for location-based teleportation systems where named points on the map are defined as nodes during map creation.
Implementing teleport commands
/tp command (teleport to player)
csharp
using Rocket.API;
using Rocket.Unturned.Chat;
using Rocket.Unturned.Player;
using System.Collections.Generic;
using UnityEngine;
namespace MyAdminSuite.Commands
{
public class TpCommand : IRocketCommand
{
public string Name => "tp";
public string Help => "Teleport to a player.";
public string Syntax => "/tp <player>";
public List<string> Aliases => new List<string> { "teleport" };
public List<string> Permissions => new List<string> { "myadminsuite.tp" };
public AllowedCaller AllowedCaller => AllowedCaller.Player;
public void Execute(IRocketPlayer caller, string[] command)
{
if (command.Length < 1)
{
UnturnedChat.Say(caller, "Usage: /tp <player>", Color.red);
return;
}
UnturnedPlayer source = (UnturnedPlayer)caller;
UnturnedPlayer target = UnturnedPlayer.FromName(command[0]);
if (target == null)
{
UnturnedChat.Say(caller, $"Player '{command[0]}' not found.", Color.red);
return;
}
source.Teleport(target);
UnturnedChat.Say(caller, $"Teleported to {target.CharacterName}.", Color.green);
// Teleport effect on arrival
source.TriggerEffect("5d8c9a03-f1b2-4e4a-9d7c-8b3e6f0a2c15");
}
}
}/tppos command (teleport to coordinates)
csharp
using Rocket.API;
using Rocket.Unturned.Chat;
using Rocket.Unturned.Player;
using System.Collections.Generic;
using UnityEngine;
namespace MyAdminSuite.Commands
{
public class TpPosCommand : IRocketCommand
{
public string Name => "tppos";
public string Help => "Teleport to specific coordinates.";
public string Syntax => "/tppos <x> <y> <z>";
public List<string> Aliases => new List<string>();
public List<string> Permissions => new List<string> { "myadminsuite.tppos" };
public AllowedCaller AllowedCaller => AllowedCaller.Player;
public void Execute(IRocketPlayer caller, string[] command)
{
if (command.Length < 3)
{
UnturnedChat.Say(caller, "Usage: /tppos <x> <y> <z>", Color.red);
return;
}
if (!float.TryParse(command[0], out float x) ||
!float.TryParse(command[1], out float y) ||
!float.TryParse(command[2], out float z))
{
UnturnedChat.Say(caller, "Invalid coordinates. Must be numeric floats.", Color.red);
return;
}
UnturnedPlayer player = (UnturnedPlayer)caller;
player.Teleport(x, y, z);
UnturnedChat.Say(caller, $"Teleported to ({x:F1}, {y:F1}, {z:F1}).", Color.green);
}
}
}/tplocation command (teleport to a named location)
For location-based teleportation, define a set of named locations in the plugin configuration and teleport to them by name:
csharp
public class TpLocationCommand : IRocketCommand
{
public string Name => "tplocation";
public string Help => "Teleport to a named location.";
public string Syntax => "/tplocation <name>";
public List<string> Aliases => new List<string> { "tploc" };
public List<string> Permissions => new List<string> { "myadminsuite.tplocation" };
public AllowedCaller AllowedCaller => AllowedCaller.Player;
public void Execute(IRocketPlayer caller, string[] command)
{
if (command.Length < 1)
{
UnturnedChat.Say(caller, "Usage: /tplocation <name>", Color.red);
return;
}
UnturnedPlayer player = (UnturnedPlayer)caller;
string locationName = command[0].ToLowerInvariant();
TeleportLocation location = TpPlugin.Instance.Configuration.Instance.Locations
.FirstOrDefault(l => l.Name.ToLowerInvariant() == locationName);
if (location == null)
{
UnturnedChat.Say(caller, $"Location '{command[0]}' not found.", Color.red);
return;
}
player.Teleport(location.X, location.Y, location.Z);
UnturnedChat.Say(caller, $"Teleported to {location.Name}.", Color.green);
}
}Location configuration:
csharp
public class TeleportLocation
{
public string Name;
public float X;
public float Y;
public float Z;
}Teleport request (TPA) system
A teleport request system allows non-admin players to request teleportation to another player who must accept or deny. This is a standard feature on roleplay servers.
Core TPA logic
csharp
using System;
using System.Collections.Generic;
public class TpaManager
{
private readonly Dictionary<ulong, PendingRequest> _pendingRequests = new Dictionary<ulong, PendingRequest>();
private readonly double _timeoutSeconds;
public TpaManager(double timeoutSeconds)
{
_timeoutSeconds = timeoutSeconds;
}
public bool SendRequest(UnturnedPlayer requester, UnturnedPlayer target)
{
if (_pendingRequests.ContainsKey(target.CSteamID.m_SteamID))
{
return false; // Target already has a pending request
}
_pendingRequests[target.CSteamID.m_SteamID] = new PendingRequest
{
RequesterSteamId = requester.CSteamID.m_SteamID,
RequesterName = requester.CharacterName,
Timestamp = DateTime.UtcNow
};
return true;
}
public bool AcceptRequest(UnturnedPlayer target, out UnturnedPlayer requester)
{
requester = null;
if (!_pendingRequests.TryGetValue(target.CSteamID.m_SteamID, out PendingRequest request))
{
return false;
}
_pendingRequests.Remove(target.CSteamID.m_SteamID);
if ((DateTime.UtcNow - request.Timestamp).TotalSeconds > _timeoutSeconds)
{
return false; // Request expired
}
requester = UnturnedPlayer.FromCSteamID(new Steamworks.CSteamID(request.RequesterSteamId));
return requester != null && requester.IsConnected;
}
public void DenyRequest(UnturnedPlayer target)
{
_pendingRequests.Remove(target.CSteamID.m_SteamID);
}
private class PendingRequest
{
public ulong RequesterSteamId;
public string RequesterName;
public DateTime Timestamp;
}
}TPA commands
csharp
public class TpaCommand : IRocketCommand
{
public string Name => "tpa";
public string Help => "Request to teleport to another player.";
public string Syntax => "/tpa <player>";
public List<string> Aliases => new List<string>();
public List<string> Permissions => new List<string> { "myadminsuite.tpa" };
public AllowedCaller AllowedCaller => AllowedCaller.Player;
public void Execute(IRocketPlayer caller, string[] command)
{
if (command.Length < 1)
{
UnturnedChat.Say(caller, "Usage: /tpa <player>", Color.red);
return;
}
UnturnedPlayer requester = (UnturnedPlayer)caller;
UnturnedPlayer target = UnturnedPlayer.FromName(command[0]);
if (target == null)
{
UnturnedChat.Say(caller, $"Player '{command[0]}' not found.", Color.red);
return;
}
if (requester.CSteamID == target.CSteamID)
{
UnturnedChat.Say(caller, "You cannot request to teleport to yourself.", Color.yellow);
return;
}
if (TpPlugin.Instance.TpaManager.SendRequest(requester, target))
{
UnturnedChat.Say(caller, $"Teleport request sent to {target.CharacterName}.", Color.green);
UnturnedChat.Say(target, $"{requester.CharacterName} wants to teleport to you. Type /tpaccept or /tpdeny.", Color.cyan);
}
else
{
UnturnedChat.Say(caller, $"{target.CharacterName} already has a pending request.", Color.yellow);
}
}
}csharp
public class TpAcceptCommand : IRocketCommand
{
public string Name => "tpaccept";
public string Help => "Accept a teleport request.";
public string Syntax => "/tpaccept";
public List<string> Aliases => new List<string>();
public List<string> Permissions => new List<string> { "myadminsuite.tpaccept" };
public AllowedCaller AllowedCaller => AllowedCaller.Player;
public void Execute(IRocketPlayer caller, string[] command)
{
UnturnedPlayer target = (UnturnedPlayer)caller;
if (TpPlugin.Instance.TpaManager.AcceptRequest(target, out UnturnedPlayer requester))
{
requester.Teleport(target);
UnturnedChat.Say(requester, $"Teleported to {target.CharacterName}.", Color.green);
UnturnedChat.Say(target, $"{requester.CharacterName} has teleported to you.", Color.green);
}
else
{
UnturnedChat.Say(caller, "No pending teleport request found.", Color.yellow);
}
}
}Combat-tag blocking
On roleplay servers, teleportation should be blocked during combat to prevent combat logging. The following pattern checks a combat-tag state before allowing teleportation:
csharp
public static class CombatTag
{
private static readonly Dictionary<ulong, DateTime> _combatTags = new Dictionary<ulong, DateTime>();
public static void Tag(UnturnedPlayer player, double durationSeconds = 30.0)
{
_combatTags[player.CSteamID.m_SteamID] = DateTime.UtcNow.AddSeconds(durationSeconds);
}
public static bool IsTagged(UnturnedPlayer player)
{
if (_combatTags.TryGetValue(player.CSteamID.m_SteamID, out DateTime expiry))
{
if (DateTime.UtcNow < expiry)
return true;
_combatTags.Remove(player.CSteamID.m_SteamID);
}
return false;
}
public static void Clear(UnturnedPlayer player)
{
_combatTags.Remove(player.CSteamID.m_SteamID);
}
}Integrate combat-tag checking into the teleport command:
csharp
if (CombatTag.IsTagged(player))
{
UnturnedChat.Say(caller, "You are in combat and cannot teleport.", Color.red);
return;
}Teleport cooldown enforcement
Teleport commands should have a per-player cooldown to prevent spam. Use the same CooldownTracker pattern from the earlier articles:
csharp
if (TpPlugin.Instance.TpCooldown.IsOnCooldown(caller.Id))
{
double remaining = TpPlugin.Instance.TpCooldown.Remaining(caller.Id);
UnturnedChat.Say(caller, $"Teleport is on cooldown. Wait {remaining:F1}s.", Color.yellow);
return;
}
TpPlugin.Instance.TpCooldown.SetUsed(caller.Id);Teleport safety checks
Before teleporting, validate that the destination is safe — not inside a structure, not underground, and not in a restricted zone:
csharp
public static bool IsSafeTeleportPosition(Vector3 position)
{
// Check for ground below the position
if (Physics.Raycast(position + Vector3.up * 2f, Vector3.down, out RaycastHit hit, 10f, RayMasks.GROUND))
{
// Position is above ground
return true;
}
return false; // No ground found — position is in the void
}
public static Vector3 FindSafePosition(Vector3 desiredPosition)
{
// Try the desired position first
if (IsSafeTeleportPosition(desiredPosition))
return desiredPosition;
// Search upward for a safe position
for (float yOffset = 1f; yOffset <= 10f; yOffset += 1f)
{
Vector3 testPos = desiredPosition + Vector3.up * yOffset;
if (IsSafeTeleportPosition(testPos))
return testPos;
}
// Fallback to the top of the nearest structure
return desiredPosition + Vector3.up * 10f;
}Full teleport plugin structure
csharp
using Rocket.Core.Plugins;
using Rocket.Unturned.Events;
using Rocket.Unturned.Player;
using System;
using System.Collections.Generic;
namespace TpPlugin
{
public class TpPlugin : RocketPlugin<TpPluginConfiguration>
{
public static TpPlugin Instance { get; private set; }
public TpaManager TpaManager { get; private set; }
public CooldownTracker TpCooldown { get; private set; }
protected override void Load()
{
Instance = this;
TpaManager = new TpaManager(Configuration.Instance.TpaTimeoutSeconds);
TpCooldown = new CooldownTracker(Configuration.Instance.TpCooldownSeconds);
UnturnedPlayerEvents.OnPlayerConnected += OnPlayerConnected;
Logger.Log("[TpPlugin] Loaded");
}
protected override void Unload()
{
UnturnedPlayerEvents.OnPlayerConnected -= OnPlayerConnected;
Instance = null;
Logger.Log("[TpPlugin] Unloaded");
}
private void OnPlayerConnected(UnturnedPlayer player)
{
// Clear any stale combat tag on reconnect
CombatTag.Clear(player);
}
}
public class TpPluginConfiguration : IRocketPluginConfiguration
{
public double TpCooldownSeconds;
public double TpaTimeoutSeconds;
public List<TeleportLocation> Locations;
public void LoadDefaults()
{
TpCooldownSeconds = 5.0;
TpaTimeoutSeconds = 30.0;
Locations = new List<TeleportLocation>
{
new TeleportLocation { Name = "Spawn", X = 0f, Y = 5f, Z = 0f },
new TeleportLocation { Name = "Market", X = 150f, Y = 8f, Z = -200f },
};
}
}
}Common errors and diagnostics
| Symptom | Cause | Resolution |
|---|---|---|
'UnturnedPlayer' does not contain a definition for 'Teleport' with 3 float arguments | The Teleport method does not accept individual float parameters — it takes a Vector3 | Use player.Teleport(new Vector3(x, y, z)) instead of player.Teleport(x, y, z) |
| Player teleports but falls through the world | Teleport position is in the void, below the terrain | Use FindSafePosition to validate and adjust the destination |
| Player teleports but direction is wrong | Rotation not preserved or set | When teleporting to coordinates, set rotation explicitly after teleport: player.Player.look.yaw = targetYaw |
| TPA request accepted but teleport fails | Requester disconnected during the timeout window | Check requester.IsConnected before executing the teleport |
| Teleport cooldown resets on server restart | Cooldown state is in-memory only | Persist cooldown state to disk if it must survive restarts |
/tppos command throws FormatException | Non-numeric input passed for coordinates | Validate all three coordinate parameters before calling Teleport |
| Player teleports into a structure and gets stuck | No collision check at destination | Add IsSafeTeleportPosition check before teleporting |
| Teleport to player works but both players appear at wrong height | Target player is on a slope or structure | The target's position includes their exact y value; this is correct behavior for accurate teleportation |
Console teleport NullReferenceException | AllowedCaller.Both with caller as UnturnedPlayer being null | Restrict to AllowedCaller.Player or add console-specific handling |
Frequently asked questions
How do I find the coordinates of my current position?
Use the UnturnedPlayer.Position property while in-game. The position returns a Vector3 with x, y, and z components. Some RocketMod plugins implement a /pos or /whereami command that echoes the player's position to chat.
Can I teleport a player to a location on a different map?
No. Teleportation is map-local. You cannot teleport a player to a different map through RocketMod's Teleport method. Map transitions require the player to reconnect to a different server or use Unturned's built-in map-change mechanism.
How do I teleport all players to a single location?
Iterate over all connected players and call Teleport on each:
csharp
foreach (var pair in Provider.clients)
{
UnturnedPlayer player = UnturnedPlayer.FromSteamPlayer(pair);
player.Teleport(targetPosition);
}Does Teleport work on players in vehicles?
Yes. When a player is in a vehicle and Teleport is called, both the player and the vehicle are teleported to the destination. The player remains in their current seat.
How do I teleport a player and set their facing direction?
After calling Teleport, set the player's yaw (horizontal rotation):
csharp
player.Teleport(target);
player.Player.look.yaw = 180f; // Face southThe look.yaw value is in degrees. 0 = north, 90 = east, 180 = south, 270 = west.
Can I prevent teleportation in certain zones?
Yes. Check if the destination or origin is within a restricted zone before allowing the teleport. Zone definitions can be stored in the plugin configuration as position-radius pairs.
Cross-references
- RocketMod and OpenMod Plugin Basics — plugin lifecycle, event subscription, permission system.
- Triggering Effects — the previous article; playing teleport arrival effects.
- Kick, Ban, and Admin Controls — the next article; moderation commands.
- Vehicles — vehicle teleportation and management.
- Chat Messaging — sending teleport notifications and TPA messages.
- Player God Mode and Vanish — god mode for invulnerable teleportation.
- Server Commands Reference — built-in teleport commands.
Document history
| Version | Date | Author | Notes |
|---|---|---|---|
| 1.0 | 2025-07-27 | 57 Studios | Initial publication. Teleport overloads, TPA system, combat-tag blocking, cooldown enforcement, safety checks, and diagnostics. |
