C#:
/*
* Copyright © 2025 Scalbox - All rights reserved.
* Developer: Scalbox - Contact: https://discord.gg/yryp3MjkF8
*
* DIGITAL CONTENT COPYRIGHT LICENSE
*
* INTELLECTUAL PROPERTY:
* This digital content is protected by copyright under international and local laws.
* All rights are reserved and any unauthorized use is prohibited.
* The content purchased may not be reproduced, distributed, transmitted, or used in any form or by any means
* without the written permission of the copyright holder, except as required by law.
*
* TERMS OF USE:
* 1. Personal Use: Your purchase of this digital content grants you a non-exclusive, non-transferable, revocable license for personal use. The content may not be shared or distributed to third parties.
* 2. Limitations: You may not modify, alter, adapt, create derivative works from, sell, or license this content without the written permission of the copyright holder.
* 3. Backup: You may make one backup copy of the content for your personal use, provided that it is not distributed.
*
* WARRANTIES AND RESPONSIBILITIES:
* The copyright holder makes no warranties regarding the accuracy, completeness or suitability of the content for a particular purpose.
* In no event shall the copyright holder be liable for any damages arising from the use or inability to use the purchased digital content.
*
* PERMISSION REQUESTS:
* For requests for permission to use or other information, please contact:
*
* Scalbox
* info@scalbox.com
*/
using System.Collections;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using ConVar;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using UnityEngine;
using HarmonyLib;
using Rust;
using Harmony = HarmonyLib.Harmony;
using Physics = UnityEngine.Physics;
using Pool = Facepunch.Pool;
using Quaternion = UnityEngine.Quaternion;
using Vector3 = UnityEngine.Vector3;
//==================================================
//CHANGELOG
//==================================================
//1.3.1 => 15/07/2025
// - Updated: Compatibility with SentryTurrets plugin.
//1.3.2 => 15/07/2025
// - Updated: SentryTurrets add interference effect
//1.3.3 => 15/07/2025
// - Implemented: Compatibility with SentryTurrets plugin
//1.3.4 => 29/07/2025
// - Improved: High performance improvements
//1.3.5 => 30/07/2025
// - Fix: Bug fix
//1.3.6 => 01/08/2025
// - Improved: Speed up interference calculation
namespace Oxide.Plugins {
[Info("AutoTurretInterference", "Scalbox", "1.3.6")]
[Description("Change Auto Turret interference & Settings")]
public class AutoTurretInterference : RustPlugin {
#region Fields
[PluginReference]
private Plugin? Clans;
[PluginReference]
private Plugin? SentryTurrets;
private int _serverMaxInterference = Sentry.maxinterference;
private int _serverInterferenceRadius = (int)Sentry.interferenceradius;
private readonly Queue<AutoTurret> _interferenceOthersUpdateQueue = new();
private bool _isProcessingInterferenceOthersUpdate;
private readonly string _rolePermissionPrefix = $"{nameof(AutoTurretInterference).ToLower()}";
private const string PermissionAdmin = "autoturretinterference.admin";
private const string PermissionShowAllowed = "autoturretinterference.show.allowed";
//Permission - Priority
private readonly Dictionary<string, int> _requiredPermission = new();
private enum AutoTurretStatusType {
All = 0, Active = 1, SwitchedOff = 2, NotConnected = 3, HasInterference = 4, WeaponAmmunition = 5, NoWeapon = 6, NoAmmunition = 7
}
private readonly int _statusTypeMin = Enum.GetValues(typeof(AutoTurretStatusType)).Cast<int>().Min();
private readonly int _statusTypeMax = Enum.GetValues(typeof(AutoTurretStatusType)).Cast<int>().Max();
private const string AutoTurretItemShortname = "autoturret";
private const string WiretoolItemShortname = "wiretool";
private const int MaximumNumberAutoTurretsNoLimits = -1;
private const int DefaultAutoTurretRotateDegrees = 90;
private const int DefaultAutoTurretViewingAngleAndTargetScanning = 180;
private const int DefaultAutoTurretDrawTime = 60;
private const int DefaultAutoTurretDrawFontSize = 16;
private const bool DefaultInfiniteAmmo = false;
private const float DefaultHealth = 1000f;
private const float DefaultRange = 30f;
private const float DefaultBulletSpeed = 200f;
private const float DefaultAimCone = 4f;
private const float DefaultDamageScale = 1f;
private const string InterferenceEffect = "assets/prefabs/locks/keypad/effects/lock.code.shock.prefab";
private readonly Vector3 _sentryTurretInterferenceEffectPosition = new(0f, 1f, 0.5f);
private const int AutoTurretsPerCoroutine = 1;
private const int AutoTurretsDestroyedPerCoroutine = 10;
private const float CoroutineAutoTurretsWait = 0.25F;
private const float CoroutineAutoTurretsInterferenceHandlerWait = 0.01f;
private readonly List<Coroutine> _coroutines = new();
//NetID : Coroutine
private readonly Dictionary<ulong, Coroutine> _interferenceEffectCoroutines = new();
//Network ID - Timer
private Dictionary<ulong, Timer> _entityDrawTimers = new();
private Configuration _config;
private Data _data;
private readonly Dictionary<ulong, RolePermission?> _cachedRolePermission = new();
private readonly Dictionary<ulong, AutoTurret> _cachedAutoTurrets = new();
private static readonly Translate.Phrase CurrentActiveAutoTurretsPhrase = new("current_active_auto_turrets_phrase", "You have now {0}/{1} active Auto Turrets.");
private static readonly Translate.Phrase NearbyAutoTurretsPhrase = new("nearby_auto_turrets_phrase", "You now have {0}/{1} active Auto Turrets within a {2}m Radius of this auto turret location.");
private const string NoPermissions = "<color=red>You don't have permission to use this command.</color>";
private const string PlayerNotFound = "<color=red>The player could not be found.</color>";
private static AutoTurretInterference? self;
private Harmony _harmony;
#endregion
#region Hook
void Init() {
Unsubscribe(nameof(OnPluginLoaded));
_data = Interface.Oxide.DataFileSystem.ReadObject<Data>(Name);
}
private void OnNewSave(string filename) {
_data.AutoTurretCustomizedData.Clear();
SaveData();
}
private void OnServerInitialized() {
Subscribe(nameof(OnPluginLoaded));
CacheAllAutoTurrets();
//Register all required permissions
foreach (var rolePermission in _config.RolePermission.OrderBy(x => x.Value.Priority)) {
_requiredPermission.Add($"{_rolePermissionPrefix}.{rolePermission.Key}", rolePermission.Value.Priority);
}
permission.RegisterPermission(PermissionAdmin, this);
permission.RegisterPermission(PermissionShowAllowed, this);
foreach (var perm in _requiredPermission) permission.RegisterPermission(perm.Key, this);
StartHandleInterferenceCoroutine();
self = this;
_harmony = new Harmony($"{Name}_Patch_{Version.Major}_{Version.Minor}_{Version.Patch}");
//Apply patche only if [AutoTurretViewingAngleAndTargetScanning] is different from the default value in all configured roles
if (_config.RolePermission.Values.Any(rp => rp.AutoTurretViewingAngleAndTargetScanning != DefaultAutoTurretViewingAngleAndTargetScanning && rp.AutoTurretViewingAngleAndTargetScanning is > 0 and <= 360)) {
Puts("Apply patch AutoTurret.InFiringArc");
_harmony.Patch(original : AccessTools.Method(typeof(AutoTurret), nameof(AutoTurret.InFiringArc)), prefix : new HarmonyMethod(typeof(AutoTurret_Settings), nameof(AutoTurret_Settings.Prefix_InFiringArc)));
}
//Apply patche only if [AutoTurretRotate180Degrees, AutoTurretRotate270Degrees, AutoTurretRotate360Degrees] is different from the default value (false) in all configured roles
if (_config.RolePermission.Values.Any(rp => rp.AutoTurretRotate180Degrees || rp.AutoTurretRotate270Degrees || rp.AutoTurretRotate360Degrees)) {
Puts("Apply patch AutoTurret.IdleTick");
_harmony.Patch(original : AccessTools.Method(typeof(AutoTurret), nameof(AutoTurret.IdleTick)), prefix : new HarmonyMethod(typeof(AutoTurret_Settings), nameof(AutoTurret_Settings.Prefix_IdleTick)));
}
SentryTurretsPluginIntegration();
if (_config.ChatCommand.IsNullOrEmpty()) {
Puts("Command missing in configuration");
Interface.Oxide.UnloadPlugin(Name);
return;
}
foreach (var command in _config.ChatCommand) {
AddCovalenceCommand(command, nameof(CmdHandler));
}
}
private void StartHandleInterferenceCoroutine() {
_coroutines.Add(ServerMgr.Instance.StartCoroutine(HandleInterferenceStartup()));
if (_config.EnableAutomaticsStartAndStop) _coroutines.Add(ServerMgr.Instance.StartCoroutine(HandleAutomaticsStartAndStopOnStartup()));
}
private void SentryTurretsPluginIntegration() {
if (SentryTurrets != null && _config.EnabledSentryTurretsPluginIntegration) {
var onInterferenceUpdateMethod = AccessTools.Method(SentryTurrets.GetType(), "OnInterferenceUpdate");
if (onInterferenceUpdateMethod != null) {
_harmony.Patch(onInterferenceUpdateMethod, prefix : new HarmonyMethod(typeof(SentryTurretsPlugin_Patch), nameof(SentryTurretsPlugin_Patch.Prefix_OnInterferenceUpdate)) );
}
var onNearbyTurretsScanMethod = AccessTools.Method(SentryTurrets.GetType(), "OnNearbyTurretsScan");
if (onNearbyTurretsScanMethod != null) {
_harmony.Patch(onNearbyTurretsScanMethod, prefix : new HarmonyMethod(typeof(SentryTurretsPlugin_Patch), nameof(SentryTurretsPlugin_Patch.Prefix_OnNearbyTurretsScan)) );
}
if (onInterferenceUpdateMethod != null || onNearbyTurretsScanMethod != null) Puts("########## SentryTurrets plugin detected! Handling interference updates... ##########");
}
}
private void Unload() {
ServerMgr.Instance.StartCoroutine(HandleUnload());
_interferenceOthersUpdateQueue.Clear();
_isProcessingInterferenceOthersUpdate = false;
if (!_interferenceEffectCoroutines.IsNullOrEmpty()) {
foreach (var coroutine in _interferenceEffectCoroutines.Values.Where(c => c != null)) {
ServerMgr.Instance.StopCoroutine(coroutine);
}
}
if (!_coroutines.IsNullOrEmpty()) {
foreach (var coroutine in _coroutines.Where(c => c != null)) {
ServerMgr.Instance.StopCoroutine(coroutine);
}
}
if (!_entityDrawTimers.IsNullOrEmpty()) {
foreach (var drawTimer in _entityDrawTimers.Values.Where(t => t is {
Destroyed : false
}
)) {
drawTimer.Destroy();
}
}
_coroutines.Clear();
_entityDrawTimers.Clear();
_cachedRolePermission.Clear();
_requiredPermission.Clear();
_cachedAutoTurrets.Clear();
_harmony.UnpatchAll($"{Name}_Patch_{Version.Major}_{Version.Minor}_{Version.Patch}");
self = null;
}
protected override void LoadConfig() {
base.LoadConfig();
_config = Config.ReadObject<Configuration>();
if (!Equals(_config.VersionNumber, Version)) {
UpdateConfigValues();
_config.VersionNumber = Version;
}
ReorderRolePermissionsByPriority();
SaveConfig();
}
private void ReorderRolePermissionsByPriority() {
var orderedRolePermissions = _config.RolePermission .OrderBy(rp => rp.Value.Priority) .ToDictionary(rp => rp.Key, rp => rp.Value);
_config.RolePermission.Clear();
foreach (var rolePermission in orderedRolePermissions) {
_config.RolePermission.Add(rolePermission.Key, rolePermission.Value);
}
}
private void UpdateConfigValues() {
if (_config.VersionNumber < new VersionNumber(1, 0, 1)) {
_config.PlayerShowTurretCountInfoMessage = true;
}
if (_config.VersionNumber < new VersionNumber(1, 0, 2)) {
_config.EnableMessageInfo = true;
_config.ChatCommand = new HashSet<string> {
"ati", "autoturretinterference"
}
;
}
if (_config.VersionNumber < new VersionNumber(1, 0, 8)) {
DeleteLangFiles();
}
if (_config.VersionNumber < new VersionNumber(1, 1, 1)) {
_config.AllowCommandsToStartAndStop = false;
_config.EnableAutomaticsStartAndStop = false;
}
if (_config.VersionNumber < new VersionNumber(1, 1, 81)) {
DeleteLangFiles();
}
if (_config.VersionNumber < new VersionNumber(1, 1, 84)) {
DeleteLangFiles();
}
if (_config.VersionNumber < new VersionNumber(1, 1, 88)) {
DeleteLangFiles();
}
if (_config.VersionNumber < new VersionNumber(1, 1, 90)) {
DeleteLangFiles();
}
if (_config.VersionNumber < new VersionNumber(1, 1, 91)) {
DeleteLangFiles();
}
if (_config.VersionNumber < new VersionNumber(1, 2, 0)) {
Puts("Configuration file is outdated. Updating...");
foreach (var rolePermission in _config.RolePermission) {
var priority = rolePermission.Key.ToLower() switch {
"default" => 100, "vip1" => 1, "vip2" => 2, "vip3" => 3, _ => 0
}
;
if (priority <= 0) continue;
rolePermission.Value.Priority = priority;
}
SaveConfig();
Puts("Configuration file updated.");
}
if (_config.VersionNumber < new VersionNumber(1, 2, 7)) {
DeleteLangFiles();
}
}
private void DeleteLangFiles() {
var langDir = Interface.Oxide.LangDirectory;
string[] languages = lang.GetLanguages(this);
foreach (var language in languages) {
var langFile = Path.Combine(langDir, language, $"{Name}.json");
if (!File.Exists(langFile)) continue;
File.Delete(langFile);
Puts($"########## Delete old lang file: {langFile} ##########");
}
}
protected override void LoadDefaultConfig() {
_config = Configuration.CreateConfig();
}
protected override void SaveConfig() => Config.WriteObject(_config);
private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(Name, _data);
private void OnActiveItemChanged(BasePlayer player, Item oldItem, Item newItem) {
if (newItem == null || string.IsNullOrEmpty(newItem.info.shortname)) return;
if (_config.EnableMessageInfo && (newItem.info.shortname.Equals(AutoTurretItemShortname) /*|| newItem.info.shortname.Equals(WiretoolItemShortname)*/
)) {
var sb = new StringBuilder();
sb.AppendLine(Lang("MessageInfoText", player.UserIDString, _config.ChatCommand.First()));
if (permission.UserHasPermission(player.UserIDString, PermissionShowAllowed) || permission.UserHasPermission(player.UserIDString, PermissionAdmin)) {
sb.AppendLine("----------\n");
sb.AppendLine(Lang("Show_Command_Help_Usage", player.UserIDString, _statusTypeMin, _statusTypeMax, _config.ChatCommand.First()));
}
player.ChatMessage(sb.ToString());
}
}
//Riapplica le patch per la gestione dell'integrazione con il plugin SentryTurrets, quando viene caricato/ricaricato il plugin SentryTurrets
private void OnPluginLoaded(Plugin plugin) {
if (!_config.EnabledSentryTurretsPluginIntegration || plugin != SentryTurrets) return;
SentryTurretsPluginIntegration();
}
private void OnGroupPermissionGranted(string name, string perm) {
if (!_requiredPermission.ContainsKey(perm)) return;
_cachedRolePermission.Clear();
_coroutines.Add(ServerMgr.Instance.StartCoroutine(HandleInterferenceStartup()));
}
private void OnGroupPermissionRevoked(string name, string perm) {
if (!_requiredPermission.ContainsKey(perm)) return;
_cachedRolePermission.Clear();
_coroutines.Add(ServerMgr.Instance.StartCoroutine(HandleInterferenceStartup()));
}
private void OnUserPermissionRevoked(string id, string permName) {
if (!_requiredPermission.ContainsKey(permName)) return;
if (ulong.TryParse(id, out var steamId)) _cachedRolePermission.Remove(steamId);
_coroutines.Add(ServerMgr.Instance.StartCoroutine(HandleInterferenceStartup()));
}
private void OnUserPermissionGranted(string id, string permName) {
if (!_requiredPermission.ContainsKey(permName)) return;
if (ulong.TryParse(id, out var steamId)) _cachedRolePermission.Remove(steamId);
_coroutines.Add(ServerMgr.Instance.StartCoroutine(HandleInterferenceStartup()));
}
private void OnUserGroupAdded(string id, string groupName) {
if (!permission.GroupExists(groupName)) return;
if (!_requiredPermission.Keys.Any(perm => permission.GroupHasPermission(groupName, perm))) return;
if (ulong.TryParse(id, out var steamId)) _cachedRolePermission.Remove(steamId);
_coroutines.Add(ServerMgr.Instance.StartCoroutine(HandleInterferenceStartup()));
}
private void OnUserGroupRemoved(string id, string groupName) {
if (!permission.GroupExists(groupName)) return;
if (!_requiredPermission.Keys.Any(perm => permission.GroupHasPermission(groupName, perm))) return;
if (ulong.TryParse(id, out var steamId)) _cachedRolePermission.Remove(steamId);
_coroutines.Add(ServerMgr.Instance.StartCoroutine(HandleInterferenceStartup()));
}
private object? OnInterferenceUpdate(AutoTurret autoTurret) {
return HandleAutoTurretInterference(autoTurret);
}
private object OnInterferenceOthersUpdate(AutoTurret autoTurret) {
// // TODO vecchio metodo, da rimuovere se il nuovo metodo funziona senza problemi
// _coroutines.Add(ServerMgr.Instance.StartCoroutine(HandleAutoTurretInterferenceOthersUpdate_OLD(autoTurret)));
if (autoTurret == null) return true;
_interferenceOthersUpdateQueue.Enqueue(autoTurret);
if (!_isProcessingInterferenceOthersUpdate) {
_coroutines.Add(ServerMgr.Instance.StartCoroutine(ProcessInterferenceOthersUpdateQueue()));
}
return true;
}
private void OnPlayerConnected(BasePlayer player) {
if (player == null) return;
HandlePlayerConnection(player, null, false);
}
private void OnPlayerDisconnected(BasePlayer player, string reason) {
if (player == null) return;
HandlePlayerConnection(player, reason, true);
}
private void OnPlayerKicked(BasePlayer player, string reason) {
if (player == null) return;
HandlePlayerConnection(player, reason, true);
}
private void OnEntitySpawned(AutoTurret autoTurret) {
if (autoTurret == null) return;
if (autoTurret.net is {
ID : {
IsValid : true
}
}
) _cachedAutoTurrets.TryAdd(autoTurret.net.ID.Value, autoTurret);
if (!autoTurret.OwnerID.IsSteamId()) return;
var rolePermission = GetCachedRolePermission(autoTurret.OwnerID);
if (rolePermission is not {
EnableCustomSettings : true
}
) return;
UpdateAutoTurretSettings(autoTurret, rolePermission, false);
}
private object? OnEntityKill(AutoTurret autoTurret) {
if (autoTurret == null) return null;
if (autoTurret.net is {
ID : {
IsValid : true
}
}
) {
if (_cachedAutoTurrets.ContainsKey(autoTurret.net.ID.Value)) {
if (autoTurret.OwnerID.IsSteamId()) _coroutines.Add(ServerMgr.Instance.StartCoroutine(HandleAutoTurretInterferenceOthersUpdateForAllNearAutoTurrets(autoTurret)));
_cachedAutoTurrets.Remove(autoTurret.net.ID.Value);
}
}
if (!autoTurret.OwnerID.IsSteamId()) return null;
RemoveAutoTurretCustomizationData(autoTurret);
return null;
}
private void OnEntityTakeDamage(BasePlayer entity, HitInfo info) {
if (info == null || info.Initiator == null) return;
if (info.Initiator is AutoTurret autoTurret && autoTurret.OwnerID.IsSteamId()) {
var rolePermission = GetCachedRolePermission(autoTurret.OwnerID);
info.damageTypes.ScaleAll(rolePermission.DamageScale);
}
}
#endregion
#region Core
private void CacheAllAutoTurrets() {
foreach (var autoTurret in BaseNetworkable.serverEntities.Where(e => e is AutoTurret).Cast<AutoTurret>()) {
if (autoTurret.net is {
ID : {
IsValid : true
}
}
) _cachedAutoTurrets.TryAdd(autoTurret.net.ID.Value, autoTurret);
}
Puts($"Auto Turret cached: {_cachedAutoTurrets.Count}");
}
private static PlayerInfo? FindPlayerInfoBySteamID(ulong steamID) {
var basePlayer = BasePlayer.allPlayerList.FirstOrDefault(p => p.userID == steamID);
var serverUser = ServerUsers.Get(steamID);
return ConvertToPlayerInfo(basePlayer, serverUser);
}
private static PlayerInfo? ConvertToPlayerInfo(BasePlayer? basePlayer, ServerUsers.User? serverUser = null) {
if (basePlayer == null && serverUser == null) return null;
var playerInfo = new PlayerInfo {
SteamId = basePlayer != null ? basePlayer.userID : serverUser!.steamid, DisplayName = basePlayer != null ? basePlayer.displayName : serverUser!.username, Transform = basePlayer != null ? basePlayer.transform : null, IsBasePlayer = basePlayer != null, PlayerObject = basePlayer != null ? basePlayer : serverUser
}
;
return playerInfo;
}
private void HandlePlayerConnection(BasePlayer player, string reason, bool isDisconnected) {
if (!_config.EnableAutomaticsStartAndStop) return;
if (player == null) return;
if (!isDisconnected) {
timer.Once(5f, () => {
var autoTurretsStartList = _cachedAutoTurrets.Values .Where(at => IsAutoTurretOwner(at, player.userID)) .Where(at => at.OwnerID.IsSteamId() && at.IsOffline() && !at.HasInterference() && IsAutoTurretPowered(at)) .ToList();
_coroutines.Add(ServerMgr.Instance.StartCoroutine(StartAutoTurrets(autoTurretsStartList)));
}
);
}
else {
var clanInfo = GetClanInfo(player.userID);
var playerHasClanTeam = clanInfo != null && !clanInfo.ClanMemberUserIdList.IsNullOrEmpty();
//Some clan/team members are online, don't turn off the auto turrets
if (playerHasClanTeam && BasePlayer.activePlayerList.Any(p => !p.UserIDString.Equals(player.UserIDString) && clanInfo != null && clanInfo.ClanMemberUserIdList.Contains(p.UserIDString))) {
return;
}
var autoTurretsStopList = _cachedAutoTurrets.Values .Where(at => IsAutoTurretOwner(at, player.userID)) .Where(at => at.OwnerID.IsSteamId() && at.IsOn() && at.GetConnectedInputCount() > 0) .ToList();
_coroutines.Add(ServerMgr.Instance.StartCoroutine(StopAutoTurrets(autoTurretsStopList)));
}
}
private IEnumerator StartAutoTurrets(List<AutoTurret>? autoTurretsList) {
if (autoTurretsList == null) yield break;
var count = 0;
foreach (var autoTurret in autoTurretsList) {
autoTurret.SetFlag(IOEntity.Flag_HasPower, true);
autoTurret.SetIsOnline(true);
if (count % AutoTurretsPerCoroutine == 0) yield return CoroutineEx.waitForSeconds(CoroutineAutoTurretsWait);
count++;
}
}
private static IEnumerator StopAutoTurrets(List<AutoTurret>? autoTurretsList) {
if (autoTurretsList == null) yield break;
var count = 0;
foreach (var autoTurret in autoTurretsList) {
autoTurret.SetFlag(IOEntity.Flag_HasPower, false);
autoTurret.SetIsOnline(false);
if (count % AutoTurretsPerCoroutine == 0) yield return CoroutineEx.waitForSeconds(CoroutineAutoTurretsWait);
count++;
}
}
private void CmdHandler(IPlayer ipPlayer, string command, string[] arg) {
var playerCmdCaller = ipPlayer?.Object as BasePlayer;
if (playerCmdCaller == null) return;
if (arg.Length == 0) return;
var action = arg[0].ToLower();
var isAdmin = permission.UserHasPermission(playerCmdCaller.UserIDString, PermissionAdmin);
PlayerInfo? playerToCheck;
var targetSteamID = 0UL;
var isSteamID = arg.Length > 1 && ulong.TryParse(arg[1], out targetSteamID);
switch (action) {
case "starta" : case "startall" : if (isAdmin || _config.AllowCommandsToStartAndStop) {
if (isAdmin && arg.Length > 1 && arg[1] != null) {
if (FindPlayerInfoBySteamID(targetSteamID) == null) {
PrintToChat(playerCmdCaller, PlayerNotFound);
return;
}
}
if (!isAdmin && arg.Length > 1 && arg[1] != null) {
playerCmdCaller.ChatMessage(NoPermissions);
return;
}
var autoTurretsStartList = _cachedAutoTurrets.Values // .Where(at => isAdmin && isSteamID ? at.OwnerID.Equals(targetSteamID) : at.OwnerID.Equals(playerCmdCaller.userID))
.Where(at => IsAutoTurretOwner(at, isAdmin && isSteamID ? targetSteamID : playerCmdCaller.userID)) .Where(at => at.OwnerID.IsSteamId() && at.IsOffline() && !at.HasInterference() && IsAutoTurretPowered(at)) .ToList();
_coroutines.Add(ServerMgr.Instance.StartCoroutine(StartAutoTurrets(autoTurretsStartList)));
}
else playerCmdCaller.ChatMessage(NoPermissions);
break;
case "stopa" : case "stopall" : if (isAdmin || _config.AllowCommandsToStartAndStop) {
if (isAdmin && arg.Length > 1 && arg[1] != null) {
if (FindPlayerInfoBySteamID(targetSteamID) == null) {
PrintToChat(playerCmdCaller, PlayerNotFound);
return;
}
}
if (!isAdmin && arg.Length > 1 && arg[1] != null) {
playerCmdCaller.ChatMessage(NoPermissions);
return;
}
var autoTurretsStopList = _cachedAutoTurrets.Values // .Where(at => isAdmin && isSteamID ? at.OwnerID.Equals(targetSteamID) : at.OwnerID.Equals(playerCmdCaller.userID))
.Where(at => IsAutoTurretOwner(at, isAdmin && isSteamID ? targetSteamID : playerCmdCaller.userID)) .Where(at => at.OwnerID.IsSteamId() && at.IsOn() && at.GetConnectedInputCount() > 0) .ToList();
_coroutines.Add(ServerMgr.Instance.StartCoroutine(StopAutoTurrets(autoTurretsStopList)));
}
else playerCmdCaller.ChatMessage(NoPermissions);
break;
case "start" : if (isAdmin || _config.AllowCommandsToStartAndStop) {
if (isAdmin && arg.Length > 1 && arg[1] != null) {
if (FindPlayerInfoBySteamID(targetSteamID) == null) {
PrintToChat(playerCmdCaller, PlayerNotFound);
return;
}
}
if (!isAdmin && arg.Length > 1 && arg[1] != null) {
playerCmdCaller.ChatMessage(NoPermissions);
return;
}
var autoTurret = GetPlayerAutoTurretLookingAt(isAdmin && isSteamID ? targetSteamID : playerCmdCaller.userID);
if (autoTurret == null) {
playerCmdCaller.ChatMessage(Lang("Look_Auto_Turret_For_Start_Error_Message", playerCmdCaller.UserIDString));
return;
}
if (autoTurret.IsOffline() && !autoTurret.HasInterference() && IsAutoTurretPowered(autoTurret)) {
_coroutines.Add(ServerMgr.Instance.StartCoroutine(StartAutoTurrets(new List<AutoTurret> {
autoTurret
}
)));
}
else {
playerCmdCaller.ChatMessage(Lang("Power_On_Auto_Turret_Not_Allowed", playerCmdCaller.UserIDString));
}
}
else playerCmdCaller.ChatMessage(NoPermissions);
break;
case "stop" : if (isAdmin || _config.AllowCommandsToStartAndStop) {
if (isAdmin && arg.Length > 1 && arg[1] != null) {
if (FindPlayerInfoBySteamID(targetSteamID) == null) {
PrintToChat(playerCmdCaller, PlayerNotFound);
return;
}
}
if (!isAdmin && arg.Length > 1 && arg[1] != null) {
playerCmdCaller.ChatMessage(NoPermissions);
return;
}
var autoTurret = GetPlayerAutoTurretLookingAt(isAdmin && isSteamID ? targetSteamID : playerCmdCaller.userID);
if (autoTurret == null) {
playerCmdCaller.ChatMessage(Lang("Look_Auto_Turret_For_Stop_Error_Message", playerCmdCaller.UserIDString));
return;
}
if (autoTurret.IsOn() && autoTurret.GetConnectedInputCount() > 0) {
_coroutines.Add(ServerMgr.Instance.StartCoroutine(StopAutoTurrets(new List<AutoTurret> {
autoTurret
}
)));
}
else {
playerCmdCaller.ChatMessage(Lang("Power_Off_Auto_Turret_Not_Allowed", playerCmdCaller.UserIDString));
}
}
else playerCmdCaller.ChatMessage(NoPermissions);
break;
case "st" : case "status" : if (isAdmin && isSteamID) {
playerToCheck = FindPlayerInfoBySteamID(targetSteamID);
if (playerToCheck == null) {
PrintToChat(playerCmdCaller, PlayerNotFound);
return;
}
PrintAutoTurretStatistics(playerCmdCaller, playerToCheck);
return;
}
PrintAutoTurretStatistics(playerCmdCaller, ConvertToPlayerInfo(playerCmdCaller)!);
break;
case "sh" : case "show" : if (!permission.UserHasPermission(playerCmdCaller.UserIDString, PermissionShowAllowed) && !isAdmin) {
playerCmdCaller.ChatMessage(NoPermissions);
return;
}
if (arg.Length == 1) {
var sb = new StringBuilder();
sb.AppendLine(Lang("Show_Command_Help_Usage", playerCmdCaller.UserIDString, _statusTypeMin, _statusTypeMax, _config.ChatCommand.First()));
for (var i = _statusTypeMin; i <= _statusTypeMax; i++) {
var atst = (AutoTurretStatusType)i;
sb.AppendLine($"<color=#4A95CC>/{_config.ChatCommand.First()} show {i}</color> - <color={GetColorByAutoTurretStatusType(atst, true)}>{GetTextByAutoTurretStatusType(playerCmdCaller, atst)}</color>\n");
}
playerCmdCaller.ChatMessage(sb.ToString());
return;
}
var statusTypeID = 0;
//show - status type
if (arg.Length == 2) {
if (!int.TryParse(arg[1], out statusTypeID)) {
playerCmdCaller.ChatMessage(Lang("Invalid_Show_Type", playerCmdCaller.UserIDString));
return;
}
targetSteamID = 0UL;
isSteamID = false;
}
//show - status type - steamID
if (arg.Length == 3) {
if (!int.TryParse(arg[1], out statusTypeID)) {
playerCmdCaller.ChatMessage(Lang("Invalid_Show_Type", playerCmdCaller.UserIDString));
return;
}
isSteamID = arg.Length > 1 && ulong.TryParse(arg[2], out targetSteamID);
if (!isSteamID) {
playerCmdCaller.ChatMessage(Lang("Invalid_SteamID", playerCmdCaller.UserIDString));
return;
}
}
if (!Enum.IsDefined(typeof(AutoTurretStatusType), statusTypeID)) {
playerCmdCaller.ChatMessage(Lang("Invalid_Show_Type_Value", playerCmdCaller.UserIDString, _statusTypeMin, _statusTypeMax));
return;
}
var statusTypeEnum = (AutoTurretStatusType)statusTypeID;
if (isAdmin && isSteamID) playerToCheck = FindPlayerInfoBySteamID(targetSteamID);
else playerToCheck = FindPlayerInfoBySteamID(playerCmdCaller.userID);
if (playerToCheck == null) {
PrintToChat(playerCmdCaller, PlayerNotFound);
return;
}
var playerAllAutoTurrets = PlayerClanAllAutoTurrets(playerToCheck);
if (playerAllAutoTurrets.IsNullOrEmpty()) {
playerAllAutoTurrets = PlayerAllAutoTurrets(playerToCheck);
}
if (playerAllAutoTurrets.IsNullOrEmpty()) {
playerCmdCaller.ChatMessage(Lang("No_Auto_Turrets_Found", playerCmdCaller.UserIDString));
return;
}
if (statusTypeEnum == AutoTurretStatusType.All) {
foreach (AutoTurretStatusType autoTurretsStatusType in Enum.GetValues(typeof(AutoTurretStatusType))) {
if (autoTurretsStatusType is AutoTurretStatusType.All or AutoTurretStatusType.WeaponAmmunition or AutoTurretStatusType.NoWeapon or AutoTurretStatusType.NoAmmunition) continue;
AutoTurretFilterByStatusType(playerAllAutoTurrets, autoTurretsStatusType) .ForEach(at => DrawText(playerCmdCaller, at, autoTurretsStatusType));
}
}
else AutoTurretFilterByStatusType(playerAllAutoTurrets, statusTypeEnum).ForEach(at => DrawText(playerCmdCaller, at, statusTypeEnum));
break;
}
}
private static List<AutoTurret> AutoTurretFilterByStatusType(List<AutoTurret> autoTurrets, AutoTurretStatusType autoTurretStatusType) {
if (autoTurrets.IsNullOrEmpty()) return new List<AutoTurret>();
return autoTurretStatusType switch {
AutoTurretStatusType.Active => autoTurrets.Where(at => at.IsOn() && !at.HasInterference()).ToList(), AutoTurretStatusType.SwitchedOff => autoTurrets.Where(at => !at.IsOn() && at.GetConnectedInputCount() > 0).ToList(), AutoTurretStatusType.NotConnected => autoTurrets.Where(at => !at.IsOn() && at.GetConnectedInputCount().Equals(0)).ToList(), AutoTurretStatusType.HasInterference => autoTurrets.Where(at => at.HasInterference()).ToList(), AutoTurretStatusType.WeaponAmmunition => autoTurrets.ToList(), AutoTurretStatusType.NoWeapon => autoTurrets.Where(at => at.GetAttachedWeapon() == null).ToList(), AutoTurretStatusType.NoAmmunition => autoTurrets.Where(at => at.GetAttachedWeapon() != null && at.GetAttachedWeapon().primaryMagazine.contents == 0).ToList(), _ => autoTurrets
}
;
}
private static string GetColorByAutoTurretStatusType(AutoTurretStatusType autoTurretStatusType, bool hexMode = false) {
return autoTurretStatusType switch {
AutoTurretStatusType.Active => !hexMode ? "0,1,0" : "#00FF00", AutoTurretStatusType.SwitchedOff => !hexMode ? "1,0.984,0" : "#FFFB00", AutoTurretStatusType.NotConnected => !hexMode ? "1,0.592,0" : "#FF9700", AutoTurretStatusType.HasInterference => !hexMode ? "1,0,0" : "#FF0000", AutoTurretStatusType.WeaponAmmunition => !hexMode ? "0,1,0" : "#00FF00", AutoTurretStatusType.NoWeapon => !hexMode ? "1,0,0" : "#FF0000", AutoTurretStatusType.NoAmmunition => !hexMode ? "1,0,0" : "#FF0000", _ => !hexMode ? "0.29,0.584,0.8" : "#4A95CC"
}
;
}
private string GetTextByAutoTurretStatusType(BasePlayer player, AutoTurretStatusType autoTurretStatusType) {
return autoTurretStatusType switch {
AutoTurretStatusType.Active => Lang("Status_Active", player.UserIDString), AutoTurretStatusType.SwitchedOff => Lang("Status_Switched_Off", player.UserIDString), AutoTurretStatusType.NotConnected => Lang("Status_Not_Connected", player.UserIDString), AutoTurretStatusType.HasInterference => Lang("Status_HasInterference", player.UserIDString), AutoTurretStatusType.WeaponAmmunition => Lang("Status_Weapon_Ammunition_Text", player.UserIDString), AutoTurretStatusType.NoWeapon => Lang("Status_No_Weapon_Text", player.UserIDString), AutoTurretStatusType.NoAmmunition => Lang("Status_No_Ammunition_Text", player.UserIDString), _ => Lang("Show_All_Status", player.UserIDString)
}
;
}
private void DrawText(BasePlayer player, AutoTurret? autoTurret, AutoTurretStatusType autoTurretStatusType) {
if (player == null || autoTurret == null) return;
if (_entityDrawTimers.ContainsKey(autoTurret.net.ID.Value)) {
if (!_entityDrawTimers[autoTurret.net.ID.Value].Destroyed) _entityDrawTimers[autoTurret.net.ID.Value].Destroy();
_entityDrawTimers.Remove(autoTurret.net.ID.Value);
}
var drawTimer = timer.Repeat(1f, _config.AutoTurretDrawTime, () => {
RunCommandAsAdmin(player, () => {
var position = autoTurret.transform.position;
if (autoTurretStatusType is not (AutoTurretStatusType.WeaponAmmunition or AutoTurretStatusType.NoWeapon or AutoTurretStatusType.NoAmmunition)) player.SendConsoleCommand("ddraw.text", 1, GetColorByAutoTurretStatusType(autoTurretStatusType), position + Vector3.up * 1.20f, $"<size={_config.AutoTurretDrawFontSize}>{GetTextByAutoTurretStatusType(player, autoTurretStatusType)}</size>");
if (autoTurretStatusType is AutoTurretStatusType.WeaponAmmunition or AutoTurretStatusType.NoWeapon or AutoTurretStatusType.NoAmmunition) {
var attachedWeapon = autoTurret.GetAttachedWeapon();
if (attachedWeapon == null) {
if (autoTurretStatusType is AutoTurretStatusType.NoWeapon or AutoTurretStatusType.NoAmmunition) player.SendConsoleCommand("ddraw.text", 1, Color.red, autoTurret.transform.position + Vector3.up * 1.20f, $"<size={_config.AutoTurretDrawFontSize}>{GetTextByAutoTurretStatusType(player, autoTurretStatusType)}</size>");
return;
}
if (autoTurretStatusType != AutoTurretStatusType.WeaponAmmunition) return;
var autoTurretInventoryWeapon = autoTurret.inventory.itemList.FirstOrDefault(i => i.info.category == ItemCategory.Weapon);
var autoTurretInventoryAmmunition = autoTurret.inventory.itemList.Where(i => i.info.category == ItemCategory.Ammunition).ToList();
var weaponName = autoTurretInventoryWeapon != null ? autoTurretInventoryWeapon.info.displayName.english : "No weapon";
var ammunitionName = autoTurretInventoryAmmunition.FirstOrDefault()?.info.displayName.english ?? "No ammunition";
var ammunitionCount = autoTurretInventoryAmmunition.Sum(i => i?.amount ?? 0);
ammunitionCount += attachedWeapon.primaryMagazine.contents;
if (ammunitionCount == 0 || autoTurretStatusType == AutoTurretStatusType.NoAmmunition) {
player.SendConsoleCommand("ddraw.text", 1, Color.red, autoTurret.transform.position + Vector3.up * 1.30f, $"<size={_config.AutoTurretDrawFontSize}>{GetTextByAutoTurretStatusType(player, AutoTurretStatusType.NoAmmunition)}</size>");
return;
}
var finalWeaponText = $"<color=white>{Lang("Status_Weapon_Label", player.UserIDString)}:</color> <color=#FFFB00>{weaponName}</color>";
var finalAmmunitionText = $"<color=white>{Lang("Status_Ammunition_Label", player.UserIDString)}:</color> <color=#FFFB00>{ammunitionName}</color> - <color=#00FF00>{ammunitionCount}</color>";
player.SendConsoleCommand("ddraw.text", 1, Color.clear, autoTurret.transform.position + Vector3.up * 1.20f, $"<size={_config.AutoTurretDrawFontSize}>{finalWeaponText} - {finalAmmunitionText}</size>");
}
}
);
}
);
_entityDrawTimers.Add(autoTurret.net.ID.Value, drawTimer);
}
private void PrintAutoTurretStatistics(BasePlayer playerCmdCaller, PlayerInfo? playerToCheck, bool isRcon = false) {
if (playerCmdCaller == null || playerToCheck == null) return;
var rolePermission = GetCachedRolePermission(playerToCheck.SteamId);
var playerAllAutoTurrets = PlayerAllAutoTurrets(playerToCheck);
var playerAutoTurretsNearby = AutoTurretsNearby(playerToCheck, rolePermission.PlayerMaxInterferenceRadius);
var playerClanAllAutoTurrets = PlayerClanAllAutoTurrets(playerToCheck);
var sb = new StringBuilder();
sb.AppendLine(Lang("Stats_Header_Start", playerCmdCaller.UserIDString));
sb.AppendLine(Lang("Stats_Player_Info", playerCmdCaller.UserIDString, playerToCheck.DisplayName));
// sb.AppendLine(Lang("Stats_Player_Info", playerCmdCaller.UserIDString, playerToCheck.displayName,
// !playerToCheck.net.connection.info.GetBool("global.streamermode")
// ? playerToCheck.userID
// : "***********"));
sb.AppendLine(Lang("Stats_Player_At_Total", playerCmdCaller.UserIDString, playerAllAutoTurrets.Count));
sb.AppendLine(Lang("Stats_Player_At_Active", playerCmdCaller.UserIDString, playerAllAutoTurrets.Count(at => at.IsOn() && !at.HasInterference())));
sb.AppendLine(Lang("Stats_Player_At_Switched_Off", playerCmdCaller.UserIDString, playerAllAutoTurrets.Count(at => !at.IsOn() && at.GetConnectedInputCount() > 0)));
sb.AppendLine(Lang("Stats_Player_At_Not_Connected", playerCmdCaller.UserIDString, playerAllAutoTurrets.Count(at => !at.IsOn() && at.GetConnectedInputCount().Equals(0))));
sb.AppendLine(Lang("Stats_Player_At_HasInterference", playerCmdCaller.UserIDString, playerAllAutoTurrets.Count(at => at.HasInterference())));
if (playerToCheck.Transform != null) {
sb.AppendLine("----------");
sb.AppendLine(Lang("Stats_Player_At_Nearby_Active", playerCmdCaller.UserIDString, playerAutoTurretsNearby.Count(at => at.IsOn() && !at.HasInterference()).ToString()));
}
sb.AppendLine("--------------------");
if (!playerClanAllAutoTurrets.IsNullOrEmpty()) {
sb.AppendLine(Lang("Stats_Clan", playerCmdCaller.UserIDString));
sb.AppendLine(Lang("Stats_Clan_At_Total", playerCmdCaller.UserIDString, playerClanAllAutoTurrets.Count));
sb.AppendLine(Lang("Stats_Clan_At_Active", playerCmdCaller.UserIDString, playerClanAllAutoTurrets.Count(at => at.IsOn() && !at.HasInterference())));
sb.AppendLine(Lang("Stats_Clan_At_Switched_Off", playerCmdCaller.UserIDString, playerClanAllAutoTurrets.Count(at => !at.IsOn() && at.GetConnectedInputCount() > 0)));
sb.AppendLine(Lang("Stats_Clan_At_Not_Connected", playerCmdCaller.UserIDString, playerClanAllAutoTurrets.Count(at => !at.IsOn() && at.GetConnectedInputCount().Equals(0))));
sb.AppendLine(Lang("Stats_Clan_At_HasInterference", playerCmdCaller.UserIDString, playerClanAllAutoTurrets.Count(at => at.HasInterference())));
sb.AppendLine("--------------------");
}
sb.AppendLine(Lang("Stats_Player_Settings", playerCmdCaller.UserIDString));
sb.AppendLine(Lang("Stats_Player_Settings_At_Limits", playerCmdCaller.UserIDString, rolePermission.PlayerNoInterferenceLimits));
sb.AppendLine(Lang("Stats_Player_Settings_At_Radius", playerCm
// ... [Code preview truncated due to length. Full source in attached file] ...