C#:
using HarmonyLib;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Facepunch;
using JetBrains.Annotations;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("AdminCuff", "Pumpline", "1.1.4")]
[Description("Be able to permanently cuff players.")]
public class AdminCuff : RustPlugin
{
private HashSet<ulong> _cuffedPlayers = new();
private HashSet<ulong> _godPlayers = new();
internal static AdminCuff Ins;
private const string PermUse = "admincuff.use";
private const string PermProtected = "admincuff.protected";
private const int HandcuffItemid = -839576748;
#region Init
[UsedImplicitly]
private void OnServerInitialized()
{
Ins = this;
LoadDefaultMessages();
permission.RegisterPermission(PermUse, this);
permission.RegisterPermission(PermProtected, this);
AddCovalenceCommand("cuff", nameof(CuffCommand));
AddCovalenceCommand("uncuff", nameof(UnCuffCommand));
}
[UsedImplicitly]
private void Unload()
{
Ins = null;
foreach (var cuffedPlayer in _cuffedPlayers.ToArray())
{
var player = BasePlayer.FindByID(cuffedPlayer);
if (player == null) continue;
UncuffPlayer(player);
}
}
#endregion
#region Lang
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["NoPerms"] = "You are not allowed to use this command!",
["InvalidPlayer"] = "Invalid player, please provide a name or steamid.",
["InvalidUsageCuff"] = "Invalid usage! /cuff <player> <true for god mode>",
["InvalidUsageUncuff"] = "Invalid usage! /uncuff <player>",
["TargetNotFound"] = "Target not found.",
["TargetNotCuffed"] = "The target player is not cuffed",
["TargetProtected"] = "The targeted user is protected.",
["TargetCuffed"] = "Cuffed player {0}",
["TargetUncuffed"] = "Uncuffed player {0}",
["TargetGodEnabled"] = "Enabled god mode for {0}",
["ErrorCuffedByAdmin"] = "You cannot uncuff someone who has been cuffed by an admin."
}, this);
}
#endregion
#region Hooks
[UsedImplicitly]
private object CanBeTargeted(BasePlayer player, MonoBehaviour behaviour)
{
if (_godPlayers.Contains(player.userID.Get()))
return false;
return null;
}
[UsedImplicitly]
private object CanBradleyApcTarget(BradleyAPC apc, BasePlayer player)
{
if (_godPlayers.Contains(player.userID.Get()))
return false;
return null;
}
[UsedImplicitly]
private object OnNpcTarget(BaseEntity npc, BasePlayer player)
{
if (_godPlayers.Contains(player.userID.Get()))
return false;
return null;
}
[UsedImplicitly]
private object OnEntityTakeDamage(BasePlayer player, HitInfo info)
{
if (_godPlayers.Contains(player.userID.Get()))
info.damageTypes.ScaleAll(0);
return null;
}
[UsedImplicitly]
private void OnPlayerSleepEnded(BasePlayer player)
{
if (_cuffedPlayers.Contains(player.userID.Get()) && player.GetHeldEntity() is not Handcuffs)
DoHandcuff(player);
}
[UsedImplicitly]
private object CanDropActiveItem(BasePlayer player)
{
if (player != null && _cuffedPlayers.Contains(player.userID.Get()) && player.GetHeldEntity() is Handcuffs)
return false;
return null;
}
[UsedImplicitly]
private void OnPlayerRecovered(BasePlayer player)
{
if (_cuffedPlayers.Contains(player.userID.Get()))
Ins.DoHandcuff(player);
}
[UsedImplicitly]
private void OnPlayerSleep(BasePlayer player)
{
if (_cuffedPlayers.Contains(player.userID.Get()))
{
var item = GetAdminHandcuff(player);
if (item == null) return;
item.Remove();
}
}
[UsedImplicitly]
private object OnPlayerLand(BasePlayer player, float num)
{
if (_cuffedPlayers.Contains(player.userID.Get()))
return false;
return null;
}
[UsedImplicitly]
private void OnPlayerDeath(BasePlayer player, HitInfo info)
{
if (!_cuffedPlayers.Contains(player.userID.Get())) return;
var item = GetAdminHandcuff(player);
if (item == null) return;
item.Remove();
}
#endregion
#region Commands
private void CuffCommand(IPlayer player, string command, string[] args)
{
if (!player.IsServer && !permission.UserHasPermission(player.Id, PermUse))
{
SendLangMessage(player, "NoPerms");
return;
}
if (args.Length >= 1)
{
if (FindPlayer(args[0]) == null)
{
SendLangMessage(player, "InvalidPlayer");
return;
}
BasePlayer target = FindPlayer(args[0]);
if (target == null)
{
SendLangMessage(player, "TargetNotFound");
return;
}
if (permission.UserHasPermission(target.UserIDString, PermProtected))
{
SendLangMessage(player, "TargetProtected");
return;
}
CuffPlayer(target);
SendLangMessage(player, "TargetCuffed", target.displayName);
if (args.Length >= 2)
{
string shouldHaveGod = args[1];
if (bool.TryParse(shouldHaveGod, out bool godMode))
{
if (godMode)
{
_godPlayers.Add(target.userID.Get());
SendLangMessage(player, "TargetGodEnabled", target.displayName);
}
}
}
}
else
{
SendLangMessage(player, "InvalidUsageCuff");
}
}
private void UnCuffCommand(IPlayer player, string command, string[] args)
{
if (!player.IsServer && !permission.UserHasPermission(player.Id, PermUse))
{
SendLangMessage(player, "NoPerms");
return;
}
if (args.Length >= 1)
{
if (FindPlayer(args[0]) == null)
{
SendLangMessage(player, "InvalidPlayer");
return;
}
BasePlayer target = FindPlayer(args[0]);
if (target == null)
{
SendLangMessage(player, "TargetNotFound");
return;
}
if (!_cuffedPlayers.Contains(target.userID))
{
SendLangMessage(player, "TargetNotCuffed");
return;
}
UncuffPlayer(target);
SendLangMessage(player, "TargetUncuffed", target.displayName);
}
else
{
SendLangMessage(player, "InvalidUsageUncuff");
}
}
#endregion
#region Core
private void CuffPlayer(BasePlayer player)
{
if (_cuffedPlayers.Contains(player.userID.Get())) return;
if (DoHandcuff(player))
_cuffedPlayers.Add(player.userID.Get());
}
private void UncuffPlayer(BasePlayer player)
{
if (!_cuffedPlayers.Contains(player.userID.Get())) return;
var ent = player.GetHeldEntity();
if (ent is Handcuffs cuff)
{
cuff.SetLocked(false);
GetOwnerItem(cuff)?.Remove();
}
_cuffedPlayers.Remove(player.userID.Get());
if (_godPlayers.Contains(player.userID.Get()))
_godPlayers.Remove(player.userID.Get());
}
private bool DoHandcuff(BasePlayer player)
{
var cuff = ItemManager.CreateByItemID(HandcuffItemid);
if (!cuff.MoveToContainer(player.inventory.containerBelt))
{
Item slot = player.inventory.containerBelt.GetSlot(0);
if (slot != null)
{
if (!slot.MoveToContainer(player.inventory.containerMain))
slot.DropAndTossUpwards(player.transform.position);
if (!cuff.MoveToContainer(player.inventory.containerBelt))
return false;
}
}
player.ClientRPC(RpcTarget.Player("SetActiveBeltSlot", player), cuff.position, cuff.uid); // to make it his held item
var heldCuff = cuff.GetHeldEntity() as Handcuffs;
if (heldCuff == null) return false;
heldCuff.ConditionLossPerSecond = 0;
player.SetPlayerFlag(BasePlayer.PlayerFlags.IsRestrained, true);
player.SendNetworkUpdateImmediate();
cuff.SetFlag(global::Item.Flag.IsOn, true);
cuff.MarkDirty();
player.Server_CancelGesture();
heldCuff.SetLocked(true, player, cuff);
Effect.server.Run(heldCuff.lockEffect.resourcePath, player, 0U, Vector3.zero, Vector3.zero);
return true;
}
#endregion
#region Helpers
private static Item GetOwnerItem(HeldEntity entity)
{
BasePlayer ownerPlayer = entity.GetOwnerPlayer();
return ownerPlayer == null || ownerPlayer.inventory == null ? null : ownerPlayer.inventory.FindItemByUID(entity.ownerItemUID);
}
private static Item GetAdminHandcuff(BasePlayer player)
{
var pooledList = Pool.Get<List<Item>>();
player.inventory.FindItemsByItemID(pooledList, HandcuffItemid);
Item item = null;
if (pooledList.Count > 0)
item = pooledList[0];
Pool.FreeUnmanaged(ref pooledList);
return item;
}
public static BasePlayer FindPlayer(string prompt)
{
var parse = ulong.TryParse(prompt, out var steamId);
if (parse) return FindPlayer(steamId);
foreach (var player in BasePlayer.allPlayerList)
{
if (!player.displayName.Contains(prompt, CompareOptions.OrdinalIgnoreCase))
continue;
return player;
}
return null;
}
public static BasePlayer FindPlayer(ulong id)
{
foreach (var player in BasePlayer.allPlayerList)
{
if (player.userID.Get() == id)
return player;
}
return null;
}
private void SendLangMessage(IPlayer player, string key, params object[] format)
{
if (format == null || format.Length == 0)
player.Reply(lang.GetMessage(key, this, player.Id));
else
player.Reply(string.Format(lang.GetMessage(key, this, player.Id), format));
}
#endregion
#region Harmony
// Prevent unlocking minigame if they are admin cuffed
[AutoPatch]
[HarmonyPatch(typeof(Handcuffs), "SV_StartUnlockMiniGame")]
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
// ReSharper disable once InconsistentNaming
public static class Handcuffs_SV_StartUnlockMiniGame_Patch
{
[HarmonyPrefix]
// ReSharper disable once InconsistentNaming
public static bool Prefix(Handcuffs __instance, BasePlayer player)
{
if (Ins == null) return true;
if (!Ins._cuffedPlayers.Contains(player.userID.Get())) return true;
__instance.InterruptUnlockMiniGame(true);
return false;
}
}
// Prevent others unlocking admin cuffs :^)
[AutoPatch]
[HarmonyPatch(typeof(Handcuffs), nameof(Handcuffs.UnlockAndReturnToPlayer))]
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
// ReSharper disable once InconsistentNaming
public static class Handcuffs_UnlockAndReturnToPlayer_Patch
{
[HarmonyPrefix]
// ReSharper disable once InconsistentNaming
public static bool Prefix(Handcuffs __instance, BasePlayer returnToPlayer)
{
if (Ins == null) return true;
if (__instance.GetOwnerPlayer() == null) return true;
if (!Ins._cuffedPlayers.Contains(__instance.GetOwnerPlayer().userID.Get())) return true;
Ins.SendLangMessage(returnToPlayer.IPlayer, "ErrorCuffedByAdmin");
return false;
}
}
[AutoPatch]
[HarmonyPatch(typeof(BasePlayer), nameof(BasePlayer.BecomeWounded))]
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
// ReSharper disable once InconsistentNaming
public static class BasePlayer_BecomeWounded_Patch
{
[HarmonyPostfix]
// ReSharper disable once InconsistentNaming
public static void Postfix(BasePlayer __instance)
{
if (Ins == null) return;
if (!Ins._cuffedPlayers.Contains(__instance.userID.Get())) return;
var item = GetAdminHandcuff(__instance);
item?.Remove();
}
}
#endregion
}
}