using System; using System.Collections.Generic; using System.Linq; using System.Text; using Facepunch; using Oxide.Core.Libraries.Covalence; using Oxide.Core.Plugins; // needed for Oxide compat using UnityEngine; namespace Oxide.Plugins; [Info("Entity Owner", "Calytic", "3.5.0")] [Description("Modify entity ownership and cupboard/turret authorization")] class EntityOwner : RustPlugin { #region Data & Config private readonly int _layerMasks = LayerMask.GetMask("Construction", "Construction Trigger", "Trigger", "Deployed"); private int _entityLimit = 8000; private float _distanceThreshold = 3f; private float _cupboardDistanceThreshold = 20f; private float _wheelDistanceThreshold = 20f; private bool _debug; private static readonly object FalseObject = false; private static readonly string[] DefaultArg = { "1" }; // this number was chosen based on testing, and looking at Facepunch code // a warning will be logged in the case that it may be too small private const int RaycastHitsMax = 64; private readonly RaycastHit[] _raycastHits = new RaycastHit[RaycastHitsMax]; #endregion #region Data Handling & Initialization private readonly Dictionary _texts = new() { {"Denied: Permission", "You are not allowed to use this command"}, {"Error: Unknown", "Undefined error occurred. Look up the log for more info"}, {"Target: None", "No target found"}, {"Target: Owner", "Owner: {0}"}, {"Target: Limit", "Exceeded entity limit"}, {"Syntax: Owner", "Invalid syntax: /owner"}, {"Syntax: SetOwner", "Incorrect Syntax.\n/setowner "}, {"Syntax: Own", "Invalid Syntax. \n/own type player\nTypes: all/block/storage/cupboard/sign/sleepingbag/plant/oven/door/turret/wheel\n/own player"}, {"Syntax: Unown", "Invalid Syntax. \n/unown type player\nTypes: all/block/storage/cupboard/sign/sleepingbag/plant/oven/door/turret/wheel\n/unown player"}, {"Syntax: Prod2", "Invalid Syntax. \n/prod2 type \nTypes:\n all/block/entity/storage/cupboard/sign/sleepingbag/plant/oven/door/turret/wheel"}, {"Syntax: Auth", "Invalid Syntax. \n/auth turret player\n/auth cupboard player\n/auth wheel player\n/auth player\n/auth"}, {"Syntax: Deauth", "Invalid Syntax. \n/deauth turret player\n/deauth cupboard player\n/deauth wheel player\n/deauth player\n/deauth"}, {"Ownership: Changing", "Changing ownership.."}, {"Ownership: Removing", "Removing ownership.."}, {"Ownership: New", "New owner of all around is: {0}"}, {"Ownership: New Self", "Owner: You were given ownership of this house and nearby deployables"}, {"Ownership: Count", "Count ({0})"}, {"Ownership: Removed", "Ownership removed"}, {"Ownership: Changed", "Ownership changed"}, {"Entities: None", "No entities found"}, {"Entities: Authorized", "({0}) Authorized"}, {"Entities: Count", "Counted {0} entities ({1}/{2})"}, {"Structure: Prodding","Prodding structure.."}, {"Structure: Condition Percent", "Condition: {0}%"}, {"Player: Unknown Percent", "Unknown: {0}%"}, {"Player: None", "Target player not found"}, {"Cupboards: Prodding", "Prodding cupboards.."}, {"Cupboards: Authorizing", "Authorizing cupboards.."}, {"Cupboards: Authorized", "Authorized {0} on {1} cupboards"}, {"Cupboards: Deauthorizing", "Deauthorizing cupboards.."}, {"Cupboards: Deauthorized", "Deauthorized {0} on {1} cupboards"}, {"Turrets: Authorized", "Authorized {0} on {1} turrets"}, {"Turrets: Authorizing", "Authorizing turrets.."}, {"Turrets: Prodding", "Prodding turrets.."}, {"Turrets: Deauthorized", "Deauthorized {0} on {1} turrets"}, {"Turrets: Deauthorizing", "Deauthorizing turrets.."}, {"Wheels: Prodding", "Prodding wheels.."}, {"Wheels: Authorizing", "Authorizing wheels.."}, {"Wheels: Authorized", "Authorized {0} on {1} wheels"}, {"Wheels: Deauthorizing", "Deauthorizing wheels.."}, {"Wheels: Deauthorized", "Deauthorized {0} on {1} wheels"}, {"Lock: Code", "Code: {0}"}, {"Lock: Guest Code", "Guest Code: {0}"}, {"Lock: Owner", "Lock owner: {0}"}, {"Bag: Assignee", "Assigned: {0}"} }; // Loads the default configuration protected override void LoadDefaultConfig() { Config["Debug"] = false; Config["EntityLimit"] = _entityLimit; Config["DistanceThreshold"] = _distanceThreshold; Config["CupboardDistanceThreshold"] = _cupboardDistanceThreshold; Config["WheelDistanceThreshold"] = _wheelDistanceThreshold; Config["VERSION"] = Version.ToString(); Config.Save(); } private new void LoadDefaultMessages() { lang.RegisterMessages(_texts, this); } protected void ReloadConfig() { Config["VERSION"] = Version.ToString(); // NEW CONFIGURATION OPTIONS HERE Config["Debug"] = false; Config["EntityLimit"] = _entityLimit; Config["DistanceThreshold"] = _distanceThreshold; Config["CupboardDistanceThreshold"] = _cupboardDistanceThreshold; Config["WheelDistanceThreshold"] = _wheelDistanceThreshold; // END NEW CONFIGURATION OPTIONS PrintToConsole("Upgrading Configuration File"); SaveConfig(); } // Gets a config value of a specific type private T GetConfig(string name, T defaultValue) => Config[name] == null ? defaultValue : (T)Convert.ChangeType(Config[name], typeof(T)); private string GetMsg(string key, BasePlayer player = null) => lang.GetMessage(key, this, player?.UserIDString); private void OnServerInitialized() { try { LoadConfig(); _debug = GetConfig("Debug", false); _entityLimit = GetConfig("EntityLimit", 8000); _distanceThreshold = GetConfig("DistanceThreshold", 3f); _cupboardDistanceThreshold = GetConfig("CupboardDistanceThreshold", 20f); _wheelDistanceThreshold = GetConfig("WheelDistanceThreshold", 20f); if (_distanceThreshold >= 5) { PrintWarning("ALERT: Distance threshold configuration option is ABOVE 5. This may cause serious performance degradation (lag) when using EntityOwner commands"); } permission.RegisterPermission("entityowner.cancheckowners", this); permission.RegisterPermission("entityowner.cancheckcodes", this); permission.RegisterPermission("entityowner.canchangeowners", this); permission.RegisterPermission("entityowner.seedetails", this); LoadData(); } catch (Exception ex) { PrintError("OnServerInitialized failed: {0}", ex.Message); } } private void LoadData() { if ( // FOR COMPATIBILITY WITH INITIAL VERSIONS WITHOUT VERSIONED CONFIG Config["VERSION"] == null || // ADDS NEW, IF ANY, CONFIGURATION OPTIONS GetConfig("VERSION", Version.ToString()) != Version.ToString()) { ReloadConfig(); } } [HookMethod("SendHelpText")] private void SendHelpText(BasePlayer player) { var sb = Pool.Get(); if (canCheckOwners(player) || canChangeOwners(player)) { sb.Append("EntityOwner by Calytic at http://rustservers.io\n"); } if (canCheckOwners(player)) { sb.Append(" ").Append("/prod - Check ownership of entity you are looking at").Append("\n"); sb.Append(" ").Append("/prod2 - Check ownership of entire structure/all deployables").Append("\n"); sb.Append(" ").Append("/prod2 block - Check ownership structure only").Append("\n"); sb.Append(" ").Append("/prod2 cupboard - Check authorization on all nearby cupboards").Append("\n"); sb.Append(" ").Append("/auth - Check authorization list of tool cupboard you are looking at").Append("\n"); } if (canChangeOwners(player)) { sb.Append(" ").Append("/own [all/block] - Take ownership of entire structure").Append("\n"); sb.Append(" ").Append("/own [all/block] PlayerName - Give ownership of entire structure to specified player").Append("\n"); sb.Append(" ").Append("/unown [all/block] - Remove ownership from entire structure").Append("\n"); sb.Append(" ").Append("/auth PlayerName - Authorize specified player on all nearby cupboards").Append("\n"); } SendReply(player, sb.ToString()); Pool.FreeUnmanaged(ref sb); } #endregion #region Chat Commands [ChatCommand("prod")] private void cmdProd(BasePlayer player, string command, string[] args) { if (!canCheckOwners(player)) { SendReply(player, GetMsg("Denied: Permission", player)); return; } if (args?.Length != 0) { SendReply(player, GetMsg("Syntax: Owner", player)); return; } //var input = serverinput.GetValue(player) as InputState; //var currentRot = Quaternion.Euler(input.current.aimAngles) * Vector3.forward; //var target = RaycastAll(player.transform.position + new Vector3(0f, 1.5f, 0f), currentRot); var target = RaycastAll(player.eyes.HeadRay()); if (target is bool) { SendReply(player, GetMsg("Target: None", player)); return; } if (target is not BaseEntity targetEntity) return; var owner = GetOwnerName(targetEntity); if (string.IsNullOrEmpty(owner)) { owner = "N/A"; } var sb = Pool.Get(); sb.AppendFormat(GetMsg("Target: Owner", player), owner); var baseLock = targetEntity.GetSlot(BaseEntity.Slot.Lock) as BaseLock; if ((baseLock?.OwnerID ?? 0) != 0 && baseLock.OwnerID != targetEntity.OwnerID) { var lockOwnerName = GetOwnerName(baseLock); sb.AppendLine().AppendFormat(GetMsg("Lock: Owner", player), lockOwnerName); } if (canSeeDetails(player)) { sb.AppendLine().Append("Pos: ").Append(targetEntity.transform.position).Append(""); sb.AppendLine().Append("ID (net/prefab/instance): ").Append(targetEntity.net.ID).Append('/') .Append(targetEntity.prefabID).Append('/').Append(targetEntity.GetInstanceID()).Append(""); sb.AppendLine().Append("Name: ").Append(targetEntity.ShortPrefabName).Append(""); sb.AppendLine().Append("Type: ").Append(targetEntity.GetType()).Append(""); if (targetEntity.skinID > 0) { sb.AppendLine().Append("Skin: ").Append(targetEntity.skinID).Append(""); } if (targetEntity.PrefabName != targetEntity.ShortPrefabName) { sb.AppendLine().Append("Prefab: \"").Append(targetEntity.PrefabName).Append("\""); } sb.AppendLine().Append("Outside: ").Append(targetEntity.IsOutside() ? "Yes" : "No").Append(""); if (targetEntity is BaseCombatEntity bcEntity) { sb.AppendLine().Append("Health: ").Append(bcEntity.health).Append('/') .Append(bcEntity.MaxHealth()).Append(" (").Append(bcEntity.healthFraction * 100.0f) .Append("%)"); } if (targetEntity is BuildingBlock buildingBlock) { sb.AppendLine().Append("Grade: ").Append(buildingBlock.grade).Append(""); } } if (canCheckCodes(player)) { var code = baseLock is CodeLock codeLock ? codeLock.code : targetEntity switch { // lock associated with modular car module's chassis BaseVehicleModule { Vehicle: ModularCar modularCar } => modularCar.CarLock?.Code, // lock associated with modular car chassis ModularCar car => car.CarLock?.Code, // completed boat wheel lock PlayerBoat boat => boat.GetSteeringWheel()?.BoatLock?.Code, // camera RF ID PoweredRemoteControlEntity camera => camera.rcIdentifier, // drone RF ID RemoteControlEntity drone => drone.rcIdentifier, // boat in edit mode SteeringWheel wheel => wheel.BoatLock?.Code, _ => null }; if (!string.IsNullOrEmpty(code)) { sb.AppendLine().AppendFormat(GetMsg("Lock: Code", player), code); } var guestCode = (baseLock as CodeLock)?.guestCode; if (!string.IsNullOrEmpty(guestCode)) { sb.AppendLine().AppendFormat(GetMsg("Lock: Guest Code", player), guestCode); } } if (targetEntity is SleepingBag bag && canCheckAssignee(player)) { sb.AppendLine().AppendFormat(GetMsg("Bag: Assignee", player), FindPlayerName(bag.deployerUserID)); } SendReply(player, sb.ToString()); Pool.FreeUnmanaged(ref sb); } //or any wanted new chat command. maybe even integrated in existing /own //this one will only change ownership of the one particular entity you are looking at [ChatCommand("setowner")] private void cmdSetowner(BasePlayer player, string command, string[] args) { //check if user has permission if (!canChangeOwners(player)) { SendReply(player, GetMsg("Denied: Permission", player)); return; } //check if given argument exists and is not empty if (string.IsNullOrEmpty(args[0])) { SendReply(player, GetMsg("Syntax: SetOwner", player)); return; } //getting valid UserID var newOwnerid = FindUserIDByPartialName(args[0]); if (newOwnerid == 0) { SendReply(player, GetMsg("Player: None", player)); return; } try { //try to get the entity user is looking at var targetEntity = RaycastAll(player.eyes.HeadRay()); if (targetEntity is bool) { SendReply(player, GetMsg("Target: None", player)); return; } if (targetEntity is not BaseEntity targetBaseEntity) return; //just to make future usage of the var easier try { //get the current owner var oldOwner = GetOwnerName(targetBaseEntity); if (string.IsNullOrEmpty(oldOwner)) { oldOwner = "N/A"; } ChangeOwner(targetBaseEntity, newOwnerid); //check if the owner was actually changed var newOwner = GetOwnerName(targetBaseEntity); if (string.IsNullOrEmpty(newOwner)) { newOwner = "N/A"; } SendReply(player, "Changed owner of [" + targetBaseEntity.ShortPrefabName + "] from [" + oldOwner + "] to [" + newOwner + "]"); } catch (Exception ex) { SendReply(player, GetMsg("Error: Unknown", player)); Debug.LogException(ex); } } catch (Exception ex) { SendReply(player, GetMsg("Error: Unknown", player)); Debug.LogException(ex); } } [ChatCommand("own")] private void cmdOwn(BasePlayer player, string command, string[] args) { if (!canChangeOwners(player)) { SendReply(player, GetMsg("Denied: Permission", player)); return; } var massTrigger = false; string type = null; ulong target = player.userID; if (args.Length == 0) { args = DefaultArg; } switch (args.Length) { case > 2: SendReply(player, GetMsg("Syntax: Own", player)); return; // this does nothing because type is null // case 1 when type == "all" || type == "storage" || type == "block" || type == "cupboard" || type == "sign" || type == "sleepingbag" || type == "plant" || type == "oven" || type == "door" || type == "turret": // { // massTrigger = true; // target = player.userID; // break; // } // this does nothing because type is null // case 1 when !string.IsNullOrEmpty(type): // { // target = FindUserIDByPartialName(type); // type = "1"; // if (target == 0) // { // SendReply(player, GetMsg("Player: None", player)); // } // else // { // massTrigger = true; // } // // break; // } case 1: { massTrigger = true; type = "1"; break; } case 2: { type = args[0]; target = FindUserIDByPartialName(args[1]); if (target == 0) { SendReply(player, GetMsg("Player: None", player)); } else { massTrigger = true; } break; } } if (!massTrigger || type == null) return; switch (type) { case "1": if (TryGetEntity(player, out var entity)) { ChangeOwner(entity, target); SendReply(player, GetMsg("Ownership: Changed", player)); } else { SendReply(player, GetMsg("Target: None", player)); } break; case "all": massChangeOwner(player, target); break; case "block": massChangeOwner(player, target); break; case "storage": massChangeOwner(player, target); break; case "sign": massChangeOwner(player, target); break; case "sleepingbag": massChangeOwner(player, target); break; case "plant": massChangeOwner(player, target); break; case "oven": massChangeOwner(player, target); break; case "turret": massChangeOwner(player, target); break; case "door": massChangeOwner(player, target); break; case "cupboard": massChangeOwner(player, target); break; case "wheel": massChangeOwner(player, target); break; } } [ChatCommand("unown")] private void cmdUnown(BasePlayer player, string command, string[] args) { if (!canChangeOwners(player)) { SendReply(player, GetMsg("Denied: Permission", player)); return; } if (args.Length == 0) { args = DefaultArg; } if (args.Length > 1) { SendReply(player, GetMsg("Syntax: Unown", player)); return; } if (args.Length != 1) return; switch (args[0]) { case "1": if (TryGetEntity(player, out var entity)) { RemoveOwner(entity); SendReply(player, GetMsg("Ownership: Removed", player)); } else { SendReply(player, GetMsg("Target: None", player)); } break; case "all": massChangeOwner(player); break; case "block": massChangeOwner(player); break; case "storage": massChangeOwner(player); break; case "sign": massChangeOwner(player); break; case "sleepingbag": massChangeOwner(player); break; case "plant": massChangeOwner(player); break; case "oven": massChangeOwner(player); break; case "turret": massChangeOwner(player); break; case "door": massChangeOwner(player); break; case "cupboard": massChangeOwner(player); break; case "wheel": massChangeOwner(player); break; } } [ChatCommand("auth")] private void cmdAuth(BasePlayer player, string command, string[] args) { if (!canChangeOwners(player)) { SendReply(player, GetMsg("Denied: Permission", player)); return; } var massCupboard = false; var massTurret = false; var massWheel = false; var checkApartment = false; var checkCupboard = false; var checkTurret = false; var checkWheel = false; var checkedOne = false; BasePlayer target = null; switch (args.Length) { case 0: checkApartment = checkCupboard = checkTurret = checkWheel = true; break; case 1 when args[0] == "apartment": checkApartment = true; break; case 1 when args[0] == "cupboard": checkCupboard = true; break; case 1 when args[0] == "turret": checkTurret = true; break; case 1 when args[0] == "wheel": checkWheel = true; break; case 1: massCupboard = true; target = FindPlayerByPartialName(args[0]); break; case 2 when args[0] == "cupboard": massCupboard = true; target = FindPlayerByPartialName(args[1]); break; case 2 when args[0] == "turret": massTurret = true; target = FindPlayerByPartialName(args[1]); break; case 2 when args[0] == "wheel": massWheel = true; target = FindPlayerByPartialName(args[1]); break; case 2: case > 2: SendReply(player, GetMsg("Syntax: Auth", player)); return; } if ((massTurret || massCupboard || massWheel) && target?.net?.connection == null) { SendReply(player, GetMsg("Player: None", player)); return; } if (checkApartment && RaycastAll(player.eyes.HeadRay()) is ApartmentUpkeepTerminal terminal) { ProdApartment(player, terminal); checkedOne = true; } if (massCupboard) { massCupboardAuthorize(player, target); } if (checkCupboard && RaycastAll(player.eyes.HeadRay()) is BuildingPrivlidge privlidge) { ProdCupboard(player, privlidge); checkedOne = true; } if (massTurret) { massTurretAuthorize(player, target); } if (checkTurret && RaycastAll(player.eyes.HeadRay()) is AutoTurret autoTurret) { ProdTurret(player, autoTurret); checkedOne = true; } if (massWheel) { massWheelAuthorize(player, target); } if (checkWheel && RaycastAll(player.eyes.HeadRay()) is SteeringWheel wheel) { ProdWheel(player, wheel); checkedOne = true; } if (!checkedOne && (checkApartment || checkCupboard || checkTurret || checkWheel)) { SendReply(player, GetMsg("Target: None", player)); } } [ChatCommand("deauth")] private void cmdDeauth(BasePlayer player, string command, string[] args) { if (!canChangeOwners(player)) { SendReply(player, GetMsg("Denied: Permission", player)); return; } var massCupboard = false; var massTurret = false; var massWheel = false; BasePlayer target = null; switch (args.Length) { case 0: SendReply(player, "Invalid Syntax. /deauth PlayerName\n/deauth turret/cupboard/wheel PlayerName"); return; case 1 when args[0] == "cupboard": SendReply(player, "Invalid Syntax. /deauth cupboard PlayerName"); return; case 1 when args[0] == "turret": SendReply(player, "Invalid Syntax. /deauth turret PlayerName"); return; case 1 when args[0] == "wheel": SendReply(player, "Invalid Syntax. /deauth wheel PlayerName"); return; case 1: massCupboard = true; target = FindPlayerByPartialName(args[0]); break; case 2 when args[0] == "cupboard": massCupboard = true; target = FindPlayerByPartialName(args[1]); break; case 2 when args[0] == "turret": massTurret = true; target = FindPlayerByPartialName(args[1]); break; case 2 when args[0] == "wheel": massWheel = true; target = FindPlayerByPartialName(args[1]); break; case 2: case > 2: SendReply(player, GetMsg("Syntax: Deauth", player)); return; } if ((massTurret || massCupboard || massWheel) && target?.net?.connection == null) { SendReply(player, GetMsg("Player: None", player)); return; } if (massCupboard) { massCupboardDeauthorize(player, target); } if (massTurret) { massTurretDeauthorize(player, target); } if (massWheel) { massWheelDeauthorize(player, target); } } [ChatCommand("prod2")] private void cmdProd2(BasePlayer player, string command, string[] args) { if (!canCheckOwners(player)) { SendReply(player, GetMsg("Denied: Permission", player)); return; } var highlight = false; switch (args.Length) { case 0: massProd(player); break; case > 0: { if (args[0] == "highlight") { highlight = true; args = args.Skip(1).ToArray(); } if (args.Length == 0) { massProd(player, highlight); return; } switch (args[0]) { case "all": args = args.Skip(1).ToArray(); massProd(player, highlight, args); break; case "block": massProd(player, highlight); break; case "storage": massProd(player, highlight); break; case "sign": massProd(player, highlight); break; case "sleepingbag": massProd(player, highlight); break; case "plant": massProd(player, highlight); break; case "oven": massProd(player, highlight); break; case "turret": massProdTurret(player, highlight); break; case "cupboard": massProdCupboard(player, highlight); break; case "wheel": massProdWheel(player, highlight); break; default: massProd(player, highlight, args); break; } break; } default: SendReply(player, GetMsg("Syntax: Prod2", player)); break; } } #endregion #region Permission Checks private bool canCheckOwners(BasePlayer player) => player && (player.net.connection.authLevel > 0 || permission.UserHasPermission(player.UserIDString, "entityowner.cancheckowners")); private bool canCheckCodes(BasePlayer player) => player && (player.net.connection.authLevel > 0 || permission.UserHasPermission(player.UserIDString, "entityowner.cancheckcodes")); private bool canCheckAssignee(BasePlayer player) => player && (player.net.connection.authLevel > 0 || permission.UserHasPermission(player.UserIDString, "entityowner.cancheckassignee")); private bool canSeeDetails(BasePlayer player) => player && (player.net.connection.authLevel > 0 || permission.UserHasPermission(player.UserIDString, "entityowner.seedetails")); private bool canChangeOwners(BasePlayer player) => player && (player.net.connection.authLevel > 0 || permission.UserHasPermission(player.UserIDString, "entityowner.canchangeowners")); #endregion #region Ownership Methods private bool TryGetEntity(BasePlayer player, out BaseEntity entity) where T : BaseEntity { entity = null; var target = RaycastAll(player.eyes.HeadRay()); if (target is not T baseEntity) return false; entity = baseEntity; return true; } private void massChangeOwner(BasePlayer player, ulong target = 0) where T : BaseEntity { var entityObject = typeof(T) == typeof(BuildingBlock) ? FindBuilding(player.transform.position, _distanceThreshold) : FindEntity(player.transform.position, _distanceThreshold); switch (entityObject) { case bool: SendReply(player, GetMsg("Entities: None", player)); return; case null: return; } SendReply(player, target == 0 ? GetMsg("Ownership: Removing", player) : GetMsg("Ownership: Changing", player)); if (entityObject is not T entity || !entity) return; var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); entityList.Add(entity); checkFrom.Add(entity.transform.position); var c = 1; if (target == 0) { RemoveOwner(entity); } else { ChangeOwner(entity, target); } var current = 0; var bbs = 0; var ebs = 0; if (entity is BuildingBlock) { bbs++; } else { ebs++; } while (true) { current++; if (current > _entityLimit) { if (_debug) { SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); } SendReply(player, string.Format(GetMsg("Entities: Count", player), c, bbs, ebs)); break; } if (current > checkFrom.Count) { SendReply(player, string.Format(GetMsg("Entities: Count", player), c, bbs, ebs)); break; } var hits = Pool.Get>(); FindEntities(hits, checkFrom[current - 1], _distanceThreshold); foreach (var entityComponent in hits) { if (!entityList.Add(entityComponent)) continue; c++; checkFrom.Add(entityComponent.transform.position); if (entityComponent is BuildingBlock) { bbs++; } else { ebs++; } if (target == 0) { RemoveOwner(entityComponent); } else { ChangeOwner(entityComponent, target); } } Pool.FreeUnmanaged(ref hits); } Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); if (target == 0) { SendReply(player, string.Format(GetMsg("Ownership: New", player), "No one")); return; } var targetPlayer = BasePlayer.FindByID(target); if (targetPlayer) { SendReply(player, string.Format(GetMsg("Ownership: New", player), targetPlayer.displayName)); SendReply(targetPlayer, GetMsg("Ownership: New Self", player)); return; } var pl = covalence.Players.FindPlayerById(target.ToString()); SendReply(player, string.Format(GetMsg("Target: Owner", player), pl.Name)); } private void massProd(BasePlayer player, bool highlight = false, params string[] filter) where T : BaseEntity { var entityObject = FindEntity(player.transform.position, _distanceThreshold); if (entityObject is bool) { SendReply(player, GetMsg("Entities: None", player)); return; } var health = 0f; var maxHealth = 0f; var prodOwners = Pool.Get>(); if (entityObject is not BaseEntity entity || !entity.transform) { SendReply(player, GetMsg("Entities: None", player)); return; } SendReply(player, GetMsg("Structure: Prodding", player)); var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); if (entity is T baseEntity) { entityList.Add(baseEntity); } var total = 0; var skip = false; if (entity is T) { if (filter.Length > 0) { skip = true; foreach (var f in filter) { if (!entity.name.ToLower().Contains(f.ToLower())) continue; skip = false; break; } } if (!skip) { prodOwners.Add(entity.OwnerID, 1); health += entity.Health(); maxHealth += entity.MaxHealth(); total++; } } var current = -1; var distanceThreshold = _distanceThreshold; if (typeof(T) != typeof(BuildingBlock) && typeof(T) != typeof(BaseEntity)) distanceThreshold += 30; var hits = Pool.Get>(); while (true) { current++; if (current > _entityLimit) { SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); break; } if (current > checkFrom.Count) { break; } hits.Clear(); FindEntities(hits, checkFrom.Count > 0 ? checkFrom[current - 1] : entity.transform.position, distanceThreshold); skip = false; foreach (var fentity in hits) { // BasePlayer check replaces the following check, which wasn't // doing anything except allocating massive amounts of memory: // || fentity.name == "player/player") if (!fentity.transform || !entityList.Add(fentity) || fentity is BasePlayer) continue; if (filter.Length > 0) { skip = true; foreach (var f in filter) { if (!fentity.name.ToLower().Contains(f.ToLower())) continue; skip = false; break; } } checkFrom.Add(fentity.transform.position); if (skip) continue; total++; if (highlight) { SendHighlight(player, fentity.transform.position); } var pid = fentity.OwnerID; if (!prodOwners.TryAdd(pid, 1)) { prodOwners[pid]++; } health += fentity.Health(); maxHealth += fentity.MaxHealth(); } } hits.Clear(); Pool.FreeUnmanaged(ref hits); Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); var unknown = 100; var sb = Pool.Get(); sb.AppendLine("Structure"); sb.Append("Entities: ").Append(total).AppendLine(); if (health > 0 && maxHealth > 0) { var condition = Mathf.Round(health * 100 / maxHealth); sb.AppendFormat(GetMsg("Structure: Condition Percent", player), condition); } SendReply(player, sb.ToString()); sb.Clear(); sb.AppendLine("Ownership"); if (total > 0) { foreach (var kvp in prodOwners) { var perc = kvp.Value * 100 / total; if (kvp.Key == 0) continue; var n = FindPlayerName(kvp.Key); sb.Append(n).Append(": ").Append(perc).Append('%').AppendLine(); unknown -= perc; } } Pool.FreeUnmanaged(ref prodOwners); if (unknown > 0) sb.AppendFormat(GetMsg("Player: Unknown Percent", player), unknown); SendReply(player, sb.ToString()); Pool.FreeUnmanaged(ref sb); } private static void SendHighlight(BasePlayer player, Vector3 position) { player.SendConsoleCommand("ddraw.sphere", 30f, Color.magenta, position, 2f); player.SendNetworkUpdateImmediate(); } private void ProdApartment(BasePlayer player, ApartmentUpkeepTerminal terminal) { var sb = Pool.Get(); var authorizedUsers = Pool.Get>(); if (TryGetApartmentUserNames(authorizedUsers, terminal)) { sb.AppendLine(string.Format(GetMsg("Entities: Authorized", player), authorizedUsers.Count)); foreach (var n in authorizedUsers) sb.AppendLine(n); } else { sb.Append(string.Format(GetMsg("Target: None", player))); } Pool.FreeUnmanaged(ref authorizedUsers); SendReply(player, sb.ToString()); Pool.FreeUnmanaged(ref sb); } private void ProdCupboard(BasePlayer player, BuildingPrivlidge cupboard) { var sb = Pool.Get(); var authorizedUsers = Pool.Get>(); if (TryGetCupboardUserNames(authorizedUsers, cupboard)) { sb.AppendLine(string.Format(GetMsg("Entities: Authorized", player), authorizedUsers.Count)); foreach (var n in authorizedUsers) sb.AppendLine(n); } else { sb.Append(string.Format(GetMsg("Target: None", player))); } Pool.FreeUnmanaged(ref authorizedUsers); SendReply(player, sb.ToString()); Pool.FreeUnmanaged(ref sb); } private void ProdTurret(BasePlayer player, AutoTurret turret) { var sb = Pool.Get(); var authorizedUsers = Pool.Get>(); if (TryGetTurretUserNames(authorizedUsers, turret)) { sb.AppendLine(string.Format(GetMsg("Entities: Authorized", player), authorizedUsers.Count)); foreach (var n in authorizedUsers) sb.AppendLine(n); } else { sb.Append(string.Format(GetMsg("Target: None", player))); } Pool.FreeUnmanaged(ref authorizedUsers); SendReply(player, sb.ToString()); Pool.FreeUnmanaged(ref sb); } private void ProdWheel(BasePlayer player, SteeringWheel wheel) { var sb = Pool.Get(); var authorizedUsers = Pool.Get>(); if (TryGetWheelUserNames(authorizedUsers, wheel)) { sb.AppendLine(string.Format(GetMsg("Entities: Authorized", player), authorizedUsers.Count)); foreach (var n in authorizedUsers) sb.AppendLine(n); } else { sb.Append(string.Format(GetMsg("Target: None", player))); } Pool.FreeUnmanaged(ref authorizedUsers); SendReply(player, sb.ToString()); Pool.FreeUnmanaged(ref sb); } private void massProdCupboard(BasePlayer player, bool highlight = false) { var entityObject = FindEntity(player.transform.position, _distanceThreshold); if (entityObject is bool) { SendReply(player, GetMsg("Entities: None", player)); return; } if (entityObject is not BaseEntity entity || !entity) return; var total = 0; var prodOwners = Pool.Get>(); SendReply(player, GetMsg("Cupboards: Prodding", player)); var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); checkFrom.Add(entity.transform.position); var current = 0; while (true) { current++; if (current > _entityLimit) { if (_debug) SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } if (current > checkFrom.Count) { SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } var entities = Pool.Get>(); FindEntities(entities, checkFrom[current - 1], _cupboardDistanceThreshold); foreach (var e in entities) { if (!entityList.Add(e)) { continue; } if (highlight) { SendHighlight(player, e.transform.position); } checkFrom.Add(e.transform.position); foreach (var userid in e.authorizedPlayers) { if (!prodOwners.TryAdd(userid, 1)) prodOwners[userid]++; } total++; } Pool.FreeUnmanaged(ref entities); } Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); // var percs = new Dictionary(); var unknown = 100; if (total <= 0) return; foreach (var kvp in prodOwners) { var perc = kvp.Value * 100 / total; // percs.Add(kvp.Key, perc); var n = FindPlayerName(kvp.Key); if (n.Contains("Unknown: ")) continue; SendReply(player, n + ": " + perc + "%"); unknown -= perc; } Pool.FreeUnmanaged(ref prodOwners); if (unknown > 0) SendReply(player, string.Format(GetMsg("Player: Unknown Percent", player), unknown)); } private void massProdTurret(BasePlayer player, bool highlight = false) { var entityObject = FindEntity(player.transform.position, _distanceThreshold); if (entityObject is bool) { SendReply(player, GetMsg("Entities: None", player)); return; } if (entityObject is not BaseEntity entity || !entity) return; var total = 0; var prodOwners = Pool.Get>(); SendReply(player, GetMsg("Turrets: Prodding", player)); var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); checkFrom.Add(entity.transform.position); var current = 0; while (true) { current++; if (current > _entityLimit) { if (_debug) SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } if (current > checkFrom.Count) { SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } var entities = Pool.Get>(); FindEntities(entities, checkFrom[current - 1], _distanceThreshold); foreach (var e in entities) { if (!entityList.Add(e)) { continue; } if (highlight) { SendHighlight(player, e.transform.position); } checkFrom.Add(e.transform.position); switch (e) { case AutoTurret autoTurret: { if (autoTurret.OwnerID.IsSteamId() && !prodOwners.TryAdd(autoTurret.OwnerID, 1)) { prodOwners[autoTurret.OwnerID]++; } foreach (var userid in autoTurret.authorizedPlayers) { if (!prodOwners.TryAdd(userid, 1)) prodOwners[userid]++; } break; } case FlameTurret flameTurret: { if (flameTurret.OwnerID.IsSteamId() && !prodOwners.TryAdd(flameTurret.OwnerID, 1)) { prodOwners[flameTurret.OwnerID]++; } break; } default: continue; } total++; } Pool.FreeUnmanaged(ref entities); } Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); // var percs = new Dictionary(); var unknown = 100; if (total <= 0) return; foreach (var kvp in prodOwners) { var perc = kvp.Value * 100 / total; // percs.Add(kvp.Key, perc); var n = FindPlayerName(kvp.Key); if (n.Contains("Unknown: ")) continue; SendReply(player, n + ": " + perc + "%"); unknown -= perc; } Pool.FreeUnmanaged(ref prodOwners); if (unknown > 0) SendReply(player, string.Format(GetMsg("Player: Unknown Percent", player), unknown)); } private void massProdWheel(BasePlayer player, bool highlight = false) { var entityObject = FindEntity(player.transform.position, _distanceThreshold); if (entityObject is bool) { SendReply(player, GetMsg("Entities: None", player)); return; } if (entityObject is not BaseEntity entity || !entity) return; var total = 0; var prodOwners = Pool.Get>(); SendReply(player, GetMsg("Wheels: Prodding", player)); var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); checkFrom.Add(entity.transform.position); var current = 0; while (true) { current++; if (current > _entityLimit) { if (_debug) SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } if (current > checkFrom.Count) { SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } var entities = Pool.Get>(); FindEntities(entities, checkFrom[current - 1], _wheelDistanceThreshold); foreach (var e in entities) { if (null == e?.Privilege?.authorizedPlayers) continue; if (!entityList.Add(e)) { continue; } if (highlight) { SendHighlight(player, e.transform.position); } checkFrom.Add(e.transform.position); foreach (var userid in e.Privilege.authorizedPlayers) { if (!prodOwners.TryAdd(userid, 1)) prodOwners[userid]++; } total++; } Pool.FreeUnmanaged(ref entities); } Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); // var percs = new Dictionary(); var unknown = 100; if (total <= 0) return; foreach (var kvp in prodOwners) { var perc = kvp.Value * 100 / total; // percs.Add(kvp.Key, perc); var n = FindPlayerName(kvp.Key); if (n.Contains("Unknown: ")) continue; SendReply(player, n + ": " + perc + "%"); unknown -= perc; } Pool.FreeUnmanaged(ref prodOwners); if (unknown > 0) SendReply(player, string.Format(GetMsg("Player: Unknown Percent", player), unknown)); } private void massCupboardAuthorize(BasePlayer player, BasePlayer target) { var entityObject = FindEntity(player.transform.position, _distanceThreshold); if (entityObject is bool) { SendReply(player, GetMsg("Entities: None", player)); return; } if (entityObject is not BaseEntity entity || !entity) return; var total = 0; SendReply(player, GetMsg("Cupboards: Authorizing", player)); var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); checkFrom.Add(entity.transform.position); var current = 0; while (true) { current++; if (current > _entityLimit) { if (_debug) SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } if (current > checkFrom.Count) { SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } var entities = Pool.Get>(); FindEntities(entities, checkFrom[current - 1], _cupboardDistanceThreshold); foreach (var priv in entities) { if (!entityList.Add(priv)) continue; checkFrom.Add(priv.transform.position); if (HasCupboardAccess(priv, target)) continue; priv.authorizedPlayers.Add(target.userID); priv.SendNetworkUpdate(); total++; } Pool.FreeUnmanaged(ref entities); } Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); SendReply(player, string.Format(GetMsg("Cupboards: Authorized", player), target.displayName, total)); } private void massCupboardDeauthorize(BasePlayer player, BasePlayer target) { var entityObject = FindEntity(player.transform.position, _distanceThreshold); if (entityObject is bool) { SendReply(player, GetMsg("Entities: None", player)); return; } if (entityObject is not BaseEntity entity || !entity) return; var total = 0; SendReply(player, GetMsg("Cupboards: Deauthorizing", player)); var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); checkFrom.Add(entity.transform.position); var current = 0; while (true) { current++; if (current > _entityLimit) { if (_debug) SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } if (current > checkFrom.Count) { SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } var entities = Pool.Get>(); FindEntities(entities, checkFrom[current - 1], _cupboardDistanceThreshold); foreach (var priv in entities) { if (!entityList.Add(priv)) continue; checkFrom.Add(priv.transform.position); if (!HasCupboardAccess(priv, target)) continue; if( priv.authorizedPlayers.Remove( target.userID ) ) { priv.SendNetworkUpdate(); } total++; } Pool.FreeUnmanaged(ref entities); } Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); SendReply(player, string.Format(GetMsg("Cupboards: Deauthorized", player), target.displayName, total)); } private void massTurretAuthorize(BasePlayer player, BasePlayer target) { var entityObject = FindEntity(player.transform.position, _distanceThreshold); if (entityObject is bool) { SendReply(player, GetMsg("Entities: None", player)); return; } if (entityObject is not BaseEntity entity || !entity) return; var total = 0; SendReply(player, GetMsg("Turrets: Authorizing", player)); var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); checkFrom.Add(entity.transform.position); var current = 0; while (true) { current++; if (current > _entityLimit) { if (_debug) SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } if (current > checkFrom.Count) { SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } var entities = Pool.Get>(); FindEntities(entities, checkFrom[current - 1], _distanceThreshold); foreach (var e in entities) { if (!entityList.Add(e)) continue; checkFrom.Add(e.transform.position); if (e is not AutoTurret turret || !turret || HasTurretAccess(turret, target)) continue; turret.authorizedPlayers.Add(target.userID); turret.SendNetworkUpdate(); turret.SetTarget(null); total++; } Pool.FreeUnmanaged(ref entities); } Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); SendReply(player, string.Format(GetMsg("Turrets: Authorized", player), target.displayName, total)); } private void massTurretDeauthorize(BasePlayer player, BasePlayer target) { var entityObject = FindEntity(player.transform.position, _distanceThreshold); if (entityObject is bool) { SendReply(player, GetMsg("Entities: None", player)); return; } if (entityObject is not BaseEntity entity || !entity) return; var total = 0; SendReply(player, GetMsg("Turrets: Deauthorizing", player)); var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); checkFrom.Add(entity.transform.position); var current = 0; while (true) { current++; if (current > _entityLimit) { if (_debug) SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } if (current > checkFrom.Count) { SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } var entities = Pool.Get>(); FindEntities(entities, checkFrom[current - 1], _distanceThreshold); foreach (var e in entities) { if (!entityList.Add(e)) continue; checkFrom.Add(e.transform.position); if (e is not AutoTurret turret || !turret || !HasTurretAccess(turret, target)) continue; if (turret.authorizedPlayers.Remove(target.userID)) { turret.SetTarget(null); total++; } turret.SendNetworkUpdate(); } Pool.FreeUnmanaged(ref entities); } Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); SendReply(player, string.Format(GetMsg("Turrets: Deauthorized", player), target.displayName, total)); } private void massWheelAuthorize(BasePlayer player, BasePlayer target) { var entityObject = FindEntity(player.transform.position, _distanceThreshold); if (entityObject is bool) { SendReply(player, GetMsg("Entities: None", player)); return; } if (entityObject is not BaseEntity entity || !entity) return; var total = 0; SendReply(player, GetMsg("Wheels: Authorizing", player)); var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); checkFrom.Add(entity.transform.position); var current = 0; while (true) { current++; if (current > _entityLimit) { if (_debug) SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } if (current > checkFrom.Count) { SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } var entities = Pool.Get>(); FindEntities(entities, checkFrom[current - 1], _wheelDistanceThreshold); foreach (var wheel in entities) { if (!entityList.Add(wheel)) continue; checkFrom.Add(wheel.transform.position); if (HasWheelAccess(wheel, target)) continue; wheel.Privilege?.authorizedPlayers?.Add(target.userID); wheel.SendNetworkUpdate(); total++; } Pool.FreeUnmanaged(ref entities); } Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); SendReply(player, string.Format(GetMsg("Wheels: Authorized", player), target.displayName, total)); } private void massWheelDeauthorize(BasePlayer player, BasePlayer target) { var entityObject = FindEntity(player.transform.position, _distanceThreshold); if (entityObject is bool) { SendReply(player, GetMsg("Entities: None", player)); return; } if (entityObject is not BaseEntity entity || !entity) return; var total = 0; SendReply(player, GetMsg("Wheels: Deauthorizing", player)); var entityList = Pool.Get>(); var checkFrom = Pool.Get>(); checkFrom.Add(entity.transform.position); var current = 0; while (true) { current++; if (current > _entityLimit) { if (_debug) SendReply(player, GetMsg("Target: Limit", player) + " " + _entityLimit); SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } if (current > checkFrom.Count) { SendReply(player, string.Format(GetMsg("Ownership: Count", player), total)); break; } var entities = Pool.Get>(); FindEntities(entities, checkFrom[current - 1], _wheelDistanceThreshold); foreach (var wheel in entities) { if (!entityList.Add(wheel)) continue; checkFrom.Add(wheel.transform.position); if (!HasWheelAccess(wheel, target)) continue; if (true == wheel.Privilege?.authorizedPlayers?.Remove(target.userID)) { wheel.SendNetworkUpdate(); } total++; } Pool.FreeUnmanaged(ref entities); } Pool.FreeUnmanaged(ref checkFrom); Pool.FreeUnmanaged(ref entityList); SendReply(player, string.Format(GetMsg("Wheels: Deauthorized", player), target.displayName, total)); } private bool TryGetApartmentUserNames(List names, ApartmentUpkeepTerminal terminal) { var apartment = terminal?.Apartment; if (null == apartment) return false; foreach (var userid in apartment.owners) names.Add($"{FindPlayerName(userid)} - {userid}"); return true; } private bool TryGetCupboardUserNames(List names, BuildingPrivlidge cupboard) { if (cupboard?.authorizedPlayers is not { Count: not 0 }) return false; foreach (var userid in cupboard.authorizedPlayers) names.Add($"{FindPlayerName(userid)} - {userid}"); return true; } private bool TryGetTurretUserNames(List names, AutoTurret turret) { if (turret?.authorizedPlayers is not { Count: not 0 }) return false; foreach (var userid in turret.authorizedPlayers) names.Add($"{FindPlayerName(userid)} - {userid}"); return true; } private bool TryGetWheelUserNames(List names, SteeringWheel wheel) { if (wheel?.Privilege?.authorizedPlayers is not { Count: not 0 }) return false; foreach (var userid in wheel.Privilege.authorizedPlayers) names.Add($"{FindPlayerName(userid)} - {userid}"); return true; } private static bool HasCupboardAccess(BuildingPrivlidge cupboard, BasePlayer player) => true == cupboard?.IsAuthed(player); private static bool HasTurretAccess(AutoTurret turret, BasePlayer player) => true == turret?.IsAuthed(player); private static bool HasWheelAccess(SteeringWheel wheel, BasePlayer player) => true == wheel?.IsAuthed(player); private string GetOwnerName(BaseEntity entity) => entity is not null && entity ? FindPlayerName(entity.OwnerID) : "Unknown: "; // private static BasePlayer GetOwnerPlayer(BaseEntity entity) => // entity.OwnerID.IsSteamId() ? BasePlayer.FindByID(entity.OwnerID) : null; // // private IPlayer GetOwnerIPlayer(BaseEntity entity) => // entity.OwnerID.IsSteamId() ? // covalence.Players.FindPlayerById(entity.OwnerID.ToString()) : null; private static void RemoveOwner(BaseEntity entity) { entity.OwnerID = 0; } private void ChangeOwner(BaseEntity entity, object player) { //get the current owner for debug log var oldOwner = GetOwnerDisplayName(entity); if (string.IsNullOrEmpty(oldOwner)) { oldOwner = "N/A"; } switch (player) { case BasePlayer basePlayer: entity.OwnerID = basePlayer.userID; break; case IPlayer iPlayer: entity.OwnerID = Convert.ToUInt64(iPlayer.Id); break; case ulong playerID when playerID.IsSteamId(): entity.OwnerID = playerID; break; case string playerString: { var basePlayer = BasePlayer.Find(playerString); if (ulong.TryParse(playerString, out var id) && id.IsSteamId()) entity.OwnerID = id; else if (basePlayer) entity.OwnerID = basePlayer.userID; break; } } //get the current owner for the debug log var newOwner = GetOwnerDisplayName(entity); if (string.IsNullOrEmpty(newOwner)) { newOwner = "N/A"; } //Debug if(_debug) Puts("Changed owner of [" + entity.ShortPrefabName + "] from [" + oldOwner + "] to [" + newOwner + "]"); } // private static object FindEntityData(BaseEntity entity) => // entity.OwnerID.IsSteamId() ? entity.OwnerID.ToString() : FalseObject; #endregion #region Utility Methods // private object RaycastAll(Vector3 position, Vector3 aim) where T : BaseEntity // { // var hitCount = Physics.RaycastNonAlloc(position, aim, _raycastHits); // if (hitCount >= RaycastHitsMax) // { // PrintWarning($"Got maximum number of raycast hits ({RaycastHitsMax}); report to developer"); // } // const float distance = 100f; // object target = false; // for (var i = 0; i < hitCount; ++i) // { // var hit = _raycastHits[i]; // var ent = hit.GetEntity(); // if (ent is not T || hit.distance >= distance) continue; // target = ent; // break; // } // return target; // } private object RaycastAll(Ray ray) where T : BaseEntity { var hitCount = Physics.RaycastNonAlloc(ray, _raycastHits, 100f); if (hitCount >= RaycastHitsMax) { PrintWarning($"Got maximum number of raycast hits ({RaycastHitsMax}); report to developer"); } object target = false; var closest = float.MaxValue; for (var i = 0; i < hitCount; ++i) { var hit = _raycastHits[i]; var ent = hit.GetEntity(); if (ent is not T || hit.distance >= closest) continue; // prefer car module to chassis unless chassis is significantly closer if (ent is ModularCar && target is BaseVehicleModule && hit.distance >= closest - 2.5f) continue; target = ent; closest = hit.distance; } return target; } private object FindBuilding(Vector3 position, float distance = 3f) { var hit = FindEntity(position, distance); return hit ? hit : FalseObject; } private object FindEntity(Vector3 position, float distance = 3f, params string[] filter) { var hit = FindEntity(position, distance, filter); return hit ? hit : FalseObject; } private T FindEntity(Vector3 position, float distance = 3f, params string[] filter) where T : BaseEntity { var list = Pool.Get>(); Vis.Entities(position, distance, list, _layerMasks); foreach (var e in list) { if (filter.Length <= 0) { Pool.FreeUnmanaged(ref list); return e; } foreach (var f in filter) { if (!e.name.Contains(f)) continue; Pool.FreeUnmanaged(ref list); return e; } } Pool.FreeUnmanaged(ref list); return null; } private void FindEntities(List list, Vector3 position, float distance = 3f) where T : BaseEntity => Vis.Entities(position, distance, list, _layerMasks); // private static void ClearProfile(BasePlayer player) // { // foreach (var serverEntity in BaseNetworkable.serverEntities) // { // if (serverEntity is BaseEntity baseEntity and not BuildingBlock // && baseEntity.OwnerID == player.userID) // { // RemoveOwner(baseEntity); // } // } // } // // private void GetProfileConstructions(List result, BasePlayer player) // { // if (!player) return; // foreach (var building in BuildingManager.server.buildingDictionary.Values) // { // foreach (var block in building.buildingBlocks) // { // if (block.OwnerID == player.userID) // { // result.Add(block); // } // } // } // } // // private void GetProfileDeployables(List result, BasePlayer player) // { // if (!player) return; // foreach (var baseNetworkable in BaseNetworkable.serverEntities) // { // if (baseNetworkable is BaseEntity entity and not BuildingBlock && // entity.OwnerID == player.userID) // { // result.Add(entity); // } // } // } private string FindPlayerName(ulong playerID) { if (playerID.IsSteamId()) { var player = FindPlayerByPartialName(playerID.ToString()); if (player) { return player.IsSleeping() ? $"{player.displayName} [Sleeping]" : $"{player.displayName} [Online]"; } var p = covalence.Players.FindPlayerById(playerID.ToString()); if (p != null) { return $"{p.Name} [Offline]"; } } return $"Unknown: {playerID}"; } //only purpose of this function is to provide the same information as GetOwnerName() //but without the color-tag for a debug line added in ChangeOwner() private string GetOwnerDisplayName(BaseEntity entity) { if (!entity) return ""; var playerID = entity.OwnerID; if (playerID.IsSteamId()) { var player = FindPlayerByPartialName(playerID.ToString()); if (player) return player.displayName; var p = covalence.Players.FindPlayerById(playerID.ToString()); if (p != null) return p.Name; } return $"Unknown: {playerID}"; } private ulong FindUserIDByPartialName(string name) { if (string.IsNullOrEmpty(name)) return 0; if (ulong.TryParse(name, out var userID)) { return userID; } var player = covalence.Players.FindPlayer(name); return player == null ? 0UL : Convert.ToUInt64(player.Id); } private BasePlayer FindPlayerByPartialName(string name) => string.IsNullOrEmpty(name) ? null : covalence.Players.FindPlayer(name)?.Object as BasePlayer; #endregion }