C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Core.Libraries.Covalence;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("PlayerManagerRust", "PlayerManager", "1.1.0")]
[Description("Exports Rust player stats, inventory, bans, and roles for the Pterodactyl Player Manager addon.")]
public class PlayerManagerRust : CovalencePlugin
{
[PluginReference]
private Plugin Backpacks;
private const string DataFileName = "PlayerManagerRust";
private void Init()
{
timer.Every(15f, ExportSnapshot);
}
private void OnServerInitialized()
{
timer.Once(2f, ExportSnapshot);
}
private void OnServerSave()
{
ExportSnapshot();
}
private void OnUserConnected(IPlayer player)
{
timer.Once(1f, ExportSnapshot);
}
private void OnUserDisconnected(IPlayer player)
{
timer.Once(1f, ExportSnapshot);
}
private void Unload()
{
ExportSnapshot();
}
[Command("pm.setmetabolism")]
private void CmdSetMetabolism(IPlayer caller, string command, string[] args)
{
if (!caller.IsAdmin) { caller.Reply("No permission."); return; }
if (args.Length < 3) { caller.Reply("Usage: pm.setmetabolism <player> <type> <value>"); return; }
var target = BasePlayer.Find(args[0]);
if (target == null) { caller.Reply("Player not found."); return; }
var type = args[1].ToLower();
if (!float.TryParse(args[2], out var value)) { caller.Reply("Invalid value."); return; }
switch (type)
{
case "health":
target.SetHealth(Mathf.Clamp(value, 0f, target.MaxHealth()));
break;
case "calories":
if (target.metabolism?.calories != null)
target.metabolism.calories.SetValue(Mathf.Clamp(value, 0f, 500f));
break;
case "hydration":
if (target.metabolism?.hydration != null)
target.metabolism.hydration.SetValue(Mathf.Clamp(value, 0f, 250f));
break;
default:
caller.Reply($"Unknown type: {type}. Use health, calories, or hydration.");
return;
}
caller.Reply($"Set {type} to {value} for {target.displayName}.");
timer.Once(1f, ExportSnapshot);
}
private void ExportSnapshot()
{
try
{
Interface.Oxide.DataFileSystem.WriteObject(DataFileName, BuildSnapshot());
}
catch (Exception ex)
{
PrintError($"Failed to export player snapshot: {ex.Message}");
}
}
private Snapshot BuildSnapshot()
{
var all = new Dictionary<string, PlayerRecord>();
foreach (var player in BasePlayer.activePlayerList)
{
if (player == null) continue;
all[player.UserIDString] = SerializePlayer(player, true);
}
foreach (var player in BasePlayer.sleepingPlayerList)
{
if (player == null || all.ContainsKey(player.UserIDString)) continue;
all[player.UserIDString] = SerializePlayer(player, false);
}
return new Snapshot
{
GeneratedAt = DateTime.UtcNow.ToString("o"),
PluginVersion = "1.1.0",
ServerInfo = new ServerInfoRecord
{
Hostname = ConVar.Server.hostname ?? "Rust Server",
Description = ConVar.Server.description ?? "",
MaxPlayers = ConVar.Server.maxplayers,
MapName = ConVar.Server.level ?? "Procedural Map",
WorldSize = ConVar.Server.worldsize,
Seed = ConVar.Server.seed,
Url = ConVar.Server.url ?? "",
HeaderImage = ConVar.Server.headerimage ?? "",
},
OnlinePlayers = all.Values.Where(p => p.Online).OrderBy(p => p.Name).ToList(),
SleepingPlayers = all.Values.Where(p => !p.Online).OrderBy(p => p.Name).ToList(),
AllPlayers = all.Values.OrderBy(p => p.Name).ToList(),
BannedPlayers = GetBannedPlayers(),
Admins = GetAdmins(),
Moderators = GetModerators(),
BackpacksPluginDetected = Backpacks != null,
};
}
private List<BannedRecord> GetBannedPlayers()
{
var banned = new List<BannedRecord>();
try
{
foreach (var user in ServerUsers.GetAll(ServerUsers.UserGroup.Banned))
{
if (user == null) continue;
banned.Add(new BannedRecord
{
Id = user.steamid.ToString(),
Name = user.username ?? user.steamid.ToString(),
Reason = user.notes ?? "",
});
}
}
catch (Exception ex)
{
PrintWarning($"Failed to read ban list: {ex.Message}");
}
return banned;
}
private List<RoleRecord> GetAdmins()
{
var list = new List<RoleRecord>();
try
{
foreach (var user in ServerUsers.GetAll(ServerUsers.UserGroup.Owner))
{
if (user == null) continue;
list.Add(new RoleRecord
{
Id = user.steamid.ToString(),
Name = user.username ?? user.steamid.ToString(),
Role = "owner",
});
}
}
catch { }
try
{
var group = permission.GetUsersInGroup("admin");
if (group != null)
{
foreach (var entry in group)
{
var id = entry.Contains("(") ? entry.Substring(0, entry.IndexOf('(')).Trim() : entry.Trim();
if (list.Any(a => a.Id == id)) continue;
var p = players.FindPlayerById(id);
list.Add(new RoleRecord { Id = id, Name = p?.Name ?? id, Role = "admin" });
}
}
}
catch { }
return list;
}
private List<RoleRecord> GetModerators()
{
var list = new List<RoleRecord>();
try
{
foreach (var user in ServerUsers.GetAll(ServerUsers.UserGroup.Moderator))
{
if (user == null) continue;
list.Add(new RoleRecord
{
Id = user.steamid.ToString(),
Name = user.username ?? user.steamid.ToString(),
Role = "moderator",
});
}
}
catch { }
try
{
var group = permission.GetUsersInGroup("moderator");
if (group != null)
{
foreach (var entry in group)
{
var id = entry.Contains("(") ? entry.Substring(0, entry.IndexOf('(')).Trim() : entry.Trim();
if (list.Any(m => m.Id == id)) continue;
var p = players.FindPlayerById(id);
list.Add(new RoleRecord { Id = id, Name = p?.Name ?? id, Role = "moderator" });
}
}
}
catch { }
return list;
}
private PlayerRecord SerializePlayer(BasePlayer player, bool online)
{
var record = new PlayerRecord
{
Id = player.UserIDString,
Name = player.displayName ?? player.UserIDString,
Online = online,
IsSleeping = player.IsSleeping(),
IsAlive = player.IsAlive(),
IsWounded = player.IsWounded(),
Ping = online ? GetPing(player) : 0,
Address = online ? GetAddress(player) : null,
Position = new PositionRecord
{
X = player.transform.position.x,
Y = player.transform.position.y,
Z = player.transform.position.z,
},
Stats = new PlayerStats
{
Health = player.health,
MaxHealth = player.MaxHealth(),
Hydration = player.metabolism?.hydration?.value ?? 0f,
Calories = player.metabolism?.calories?.value ?? 0f,
Radiation = player.metabolism?.radiation_level?.value ?? 0f,
RadiationPoison = player.metabolism?.radiation_poison?.value ?? 0f,
Temperature = player.metabolism?.temperature?.value ?? 0f,
Comfort = player.metabolism?.comfort?.value ?? 0f,
Bleeding = player.metabolism?.bleeding?.value ?? 0f,
Oxygen = player.metabolism?.oxygen?.value ?? 0f,
Wetness = player.metabolism?.wetness?.value ?? 0f,
PlayTimeSeconds = (int)(player.lifeStory != null ? player.lifeStory.secondsAlive : 0f),
},
Inventory = new InventorySnapshot
{
Main = SerializeContainer(player.inventory?.containerMain),
Belt = SerializeContainer(player.inventory?.containerBelt),
Wear = SerializeContainer(player.inventory?.containerWear),
Backpack = SerializeContainer(GetBackpackContainer(player)),
},
ActiveItem = GetActiveItemName(player),
TeamId = player.currentTeam != 0 ? player.currentTeam.ToString() : null,
TeamMembers = GetTeamMembers(player),
HasBuildingPrivilege = player.IsBuildingAuthed(),
BlueprintsLearned = GetBlueprintCount(player),
IsBanned = ServerUsers.Is(player.userID, ServerUsers.UserGroup.Banned),
IsAdmin = player.IsAdmin,
IsModerator = ServerUsers.Is(player.userID, ServerUsers.UserGroup.Moderator),
ConnectedAt = online ? DateTime.UtcNow.ToString("o") : null,
};
try
{
if (permission.UserHasGroup(player.UserIDString, "admin"))
record.IsAdmin = true;
if (permission.UserHasGroup(player.UserIDString, "moderator"))
record.IsModerator = true;
}
catch { }
return record;
}
private string GetActiveItemName(BasePlayer player)
{
try
{
var held = player.GetActiveItem();
if (held != null && held.info != null)
return held.info.shortname;
}
catch { }
return null;
}
private List<string> GetTeamMembers(BasePlayer player)
{
try
{
if (player.currentTeam == 0) return null;
var team = RelationshipManager.ServerInstance?.FindTeam(player.currentTeam);
if (team == null) return null;
return team.members
.Select(id =>
{
var p = RelationshipManager.FindByID(id);
return p != null ? p.displayName : id.ToString();
})
.ToList();
}
catch { return null; }
}
private int GetBlueprintCount(BasePlayer player)
{
try
{
var bp = player.blueprints;
if (bp == null) return 0;
var learned = 0;
foreach (var item in ItemManager.GetItemDefinitions())
{
if (bp.HasUnlocked(item)) learned++;
}
return learned;
}
catch { return 0; }
}
private int GetPing(BasePlayer player)
{
try
{
return Network.Net.sv.GetAveragePing(player.net.connection);
}
catch
{
return 0;
}
}
private string GetAddress(BasePlayer player)
{
try
{
var addr = player.net.connection.ipaddress;
if (addr != null && addr.Contains(":"))
addr = addr.Substring(0, addr.LastIndexOf(':'));
return addr;
}
catch
{
return null;
}
}
private ItemContainer GetBackpackContainer(BasePlayer player)
{
if (Backpacks == null) return null;
try { return Backpacks.Call("API_GetExistingBackpack", player.userID) as ItemContainer; }
catch { return null; }
}
private List<ItemRecord> SerializeContainer(ItemContainer container)
{
var items = new List<ItemRecord>();
if (container?.itemList == null) return items;
foreach (var item in container.itemList.OrderBy(i => i.position))
{
if (item == null || item.info == null) continue;
items.Add(SerializeItem(item));
}
return items;
}
private ItemRecord SerializeItem(Item item)
{
var maxCond = item.maxCondition > 0 ? item.maxCondition : 1f;
return new ItemRecord
{
Id = item.info.shortname,
Name = item.name ?? item.info.displayName?.english ?? item.info.shortname,
Count = item.amount,
Slot = item.position,
Condition = item.condition,
MaxCondition = item.maxCondition,
DurabilityPercent = item.hasCondition ? Math.Round(item.condition / maxCond * 100, 1) : 100,
Skin = item.skin,
Ammo = item.GetHeldEntity() is BaseProjectile projectile ? projectile.primaryMagazine?.contents ?? 0 : 0,
Contents = item.contents?.itemList?.Select(SerializeItem).ToList() ?? new List<ItemRecord>(),
};
}
#region Data Classes
private class ServerInfoRecord
{
[JsonProperty("hostname")] public string Hostname { get; set; }
[JsonProperty("description")] public string Description { get; set; }
[JsonProperty("max_players")] public int MaxPlayers { get; set; }
[JsonProperty("map_name")] public string MapName { get; set; }
[JsonProperty("world_size")] public int WorldSize { get; set; }
[JsonProperty("seed")] public int Seed { get; set; }
[JsonProperty("url")] public string Url { get; set; }
[JsonProperty("header_image")] public string HeaderImage { get; set; }
}
private class Snapshot
{
[JsonProperty("generated_at")] public string GeneratedAt { get; set; }
[JsonProperty("plugin_version")] public string PluginVersion { get; set; }
[JsonProperty("server_info")] public ServerInfoRecord ServerInfo { get; set; }
[JsonProperty("online_players")] public List<PlayerRecord> OnlinePlayers { get; set; }
[JsonProperty("sleeping_players")] public List<PlayerRecord> SleepingPlayers { get; set; }
[JsonProperty("all_players")] public List<PlayerRecord> AllPlayers { get; set; }
[JsonProperty("banned_players")] public List<BannedRecord> BannedPlayers { get; set; }
[JsonProperty("admins")] public List<RoleRecord> Admins { get; set; }
[JsonProperty("moderators")] public List<RoleRecord> Moderators { get; set; }
[JsonProperty("backpacks_plugin_detected")] public bool BackpacksPluginDetected { get; set; }
}
private class PlayerRecord
{
[JsonProperty("id")] public string Id { get; set; }
[JsonProperty("name")] public string Name { get; set; }
[JsonProperty("online")] public bool Online { get; set; }
[JsonProperty("is_sleeping")] public bool IsSleeping { get; set; }
[JsonProperty("is_alive")] public bool IsAlive { get; set; }
[JsonProperty("is_wounded")] public bool IsWounded { get; set; }
[JsonProperty("ping")] public int Ping { get; set; }
[JsonProperty("address")] public string Address { get; set; }
[JsonProperty("position")] public PositionRecord Position { get; set; }
[JsonProperty("stats")] public PlayerStats Stats { get; set; }
[JsonProperty("inventory")] public InventorySnapshot Inventory { get; set; }
[JsonProperty("active_item")] public string ActiveItem { get; set; }
[JsonProperty("team_id")] public string TeamId { get; set; }
[JsonProperty("team_members")] public List<string> TeamMembers { get; set; }
[JsonProperty("has_building_privilege")] public bool HasBuildingPrivilege { get; set; }
[JsonProperty("blueprints_learned")] public int BlueprintsLearned { get; set; }
[JsonProperty("is_banned")] public bool IsBanned { get; set; }
[JsonProperty("is_admin")] public bool IsAdmin { get; set; }
[JsonProperty("is_moderator")] public bool IsModerator { get; set; }
[JsonProperty("connected_at")] public string ConnectedAt { get; set; }
}
private class BannedRecord
{
[JsonProperty("id")] public string Id { get; set; }
[JsonProperty("name")] public string Name { get; set; }
[JsonProperty("reason")] public string Reason { get; set; }
}
private class RoleRecord
{
[JsonProperty("id")] public string Id { get; set; }
[JsonProperty("name")] public string Name { get; set; }
[JsonProperty("role")] public string Role { get; set; }
}
private class PositionRecord
{
[JsonProperty("x")] public float X { get; set; }
[JsonProperty("y")] public float Y { get; set; }
[JsonProperty("z")] public float Z { get; set; }
}
private class PlayerStats
{
[JsonProperty("health")] public float Health { get; set; }
[JsonProperty("max_health")] public float MaxHealth { get; set; }
[JsonProperty("hydration")] public float Hydration { get; set; }
[JsonProperty("calories")] public float Calories { get; set; }
[JsonProperty("radiation")] public float Radiation { get; set; }
[JsonProperty("radiation_poison")] public float RadiationPoison { get; set; }
[JsonProperty("temperature")] public float Temperature { get; set; }
[JsonProperty("comfort")] public float Comfort { get; set; }
[JsonProperty("bleeding")] public float Bleeding { get; set; }
[JsonProperty("oxygen")] public float Oxygen { get; set; }
[JsonProperty("wetness")] public float Wetness { get; set; }
[JsonProperty("play_time_seconds")] public int PlayTimeSeconds { get; set; }
}
private class InventorySnapshot
{
[JsonProperty("main")] public List<ItemRecord> Main { get; set; }
[JsonProperty("belt")] public List<ItemRecord> Belt { get; set; }
[JsonProperty("wear")] public List<ItemRecord> Wear { get; set; }
[JsonProperty("backpack")] public List<ItemRecord> Backpack { get; set; }
}
private class ItemRecord
{
[JsonProperty("id")] public string Id { get; set; }
[JsonProperty("name")] public string Name { get; set; }
[JsonProperty("count")] public int Count { get; set; }
[JsonProperty("slot")] public int Slot { get; set; }
[JsonProperty("condition")] public float Condition { get; set; }
[JsonProperty("max_condition")] public float MaxCondition { get; set; }
[JsonProperty("durability_percent")] public double DurabilityPercent { get; set; }
[JsonProperty("skin")] public ulong Skin { get; set; }
[JsonProperty("ammo")] public int Ammo { get; set; }
[JsonProperty("contents")] public List<ItemRecord> Contents { get; set; }
}
#endregion
}
}