C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System.Collections.Generic;
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using UnityEngine;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Rust;
namespace Oxide.Plugins
{
[Info("ZoneManager", "Reneb / Nogrod", "2.4.61", ResourceId = 739)]
public class ZoneManager : RustPlugin
{
#region Fields
private const string permZone = "zonemanager.zone";
private const string permIgnoreFlag = "zonemanager.ignoreflag.";
[PluginReference] Plugin PopupNotifications, Spawns;
private ZoneFlags disabledFlags = ZoneFlags.None;
private DynamicConfigFile ZoneManagerData;
private StoredData storedData;
private Hash<string, Zone> zoneObjects = new Hash<string, Zone>();
private readonly Dictionary<string, ZoneDefinition> ZoneDefinitions = new Dictionary<string, ZoneDefinition>();
private readonly Dictionary<ulong, string> LastZone = new Dictionary<ulong, string>();
private readonly Dictionary<BasePlayer, HashSet<Zone>> playerZones = new Dictionary<BasePlayer, HashSet<Zone>>();
private readonly Dictionary<BaseCombatEntity, HashSet<Zone>> buildingZones = new Dictionary<BaseCombatEntity, HashSet<Zone>>();
private readonly Dictionary<BaseNpc, HashSet<Zone>> npcZones = new Dictionary<BaseNpc, HashSet<Zone>>();
private readonly Dictionary<ResourceDispenser, HashSet<Zone>> resourceZones = new Dictionary<ResourceDispenser, HashSet<Zone>>();
private readonly Dictionary<BaseEntity, HashSet<Zone>> otherZones = new Dictionary<BaseEntity, HashSet<Zone>>();
private readonly Dictionary<BasePlayer, ZoneFlags> playerTags = new Dictionary<BasePlayer, ZoneFlags>();
private static readonly int playersMask = LayerMask.GetMask("Player (Server)");
private static readonly Collider[] colBuffer = (Collider[])typeof(Vis).GetField("colBuffer", (BindingFlags.Static | BindingFlags.NonPublic))?.GetValue(null);
#endregion
#region Config
private bool usePopups = false;
private bool Changed;
private bool Initialized;
private float AutolightOnTime;
private float AutolightOffTime;
private string prefix;
private string prefixColor;
private object GetConfig(string menu, string datavalue, object defaultValue)
{
var data = Config[menu] as Dictionary<string, object>;
if (data == null)
{
data = new Dictionary<string, object>();
Config[menu] = data;
Changed = true;
}
object value;
if (!data.TryGetValue(datavalue, out value))
{
value = defaultValue;
data[datavalue] = value;
Changed = true;
}
return value;
}
private static bool GetBoolValue(string value)
{
if (string.IsNullOrEmpty(value)) return false;
value = value.Trim().ToLower();
switch (value)
{
case "t":
case "true":
case "1":
case "yes":
case "y":
case "on":
return true;
default:
return false;
}
}
private void LoadVariables()
{
AutolightOnTime = Convert.ToSingle(GetConfig("AutoLights", "Lights On Time", "18.0"));
AutolightOffTime = Convert.ToSingle(GetConfig("AutoLights", "Lights Off Time", "8.0"));
usePopups = Convert.ToBoolean(GetConfig("Notifications", "Use Popup Notifications", true));
prefix = Convert.ToString(GetConfig("Chat", "Prefix", "ZoneManager: "));
prefixColor = Convert.ToString(GetConfig("Chat", "Prefix Color (hex)", "#d85540"));
if (!Changed) return;
SaveConfig();
Changed = false;
}
protected override void LoadDefaultConfig()
{
Config.Clear();
LoadVariables();
}
#endregion
#region Data Management
private class StoredData
{
public readonly HashSet<ZoneDefinition> ZoneDefinitions = new HashSet<ZoneDefinition>();
}
private void SaveData()
{
ZoneManagerData.WriteObject(storedData);
}
private void LoadData()
{
ZoneDefinitions.Clear();
try
{
ZoneManagerData.Settings.NullValueHandling = NullValueHandling.Ignore;
storedData = ZoneManagerData.ReadObject<StoredData>();
Puts("Loaded {0} Zone definitions", storedData.ZoneDefinitions.Count);
}
catch
{
Puts("Failed to load StoredData");
storedData = new StoredData();
}
ZoneManagerData.Settings.NullValueHandling = NullValueHandling.Include;
foreach (var zonedef in storedData.ZoneDefinitions)
ZoneDefinitions[zonedef.Id] = zonedef;
}
#endregion
#region Zone Management
#region Zone Component
public class Zone : MonoBehaviour
{
public ZoneDefinition Info;
public ZoneFlags disabledFlags = ZoneFlags.None;
public ZoneManager instance;
public readonly HashSet<ulong> WhiteList = new HashSet<ulong>();
public readonly HashSet<ulong> KeepInList = new HashSet<ulong>();
private HashSet<BasePlayer> players = new HashSet<BasePlayer>();
private HashSet<BaseCombatEntity> buildings = new HashSet<BaseCombatEntity>();
private bool lightsOn;
private readonly FieldInfo meshLookupField = typeof(MeshColliderBatch).GetField("meshLookup", BindingFlags.Instance | BindingFlags.NonPublic);
private void Awake()
{
gameObject.layer = (int)Layer.Reserved1;
gameObject.name = "Zone Manager";
var rigidbody = gameObject.AddComponent<Rigidbody>();
rigidbody.useGravity = false;
rigidbody.isKinematic = true;
rigidbody.detectCollisions = true;
rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;
}
private void OnDestroy()
{
CancelInvoke();
instance.OnZoneDestroy(this);
instance = null;
Destroy(gameObject);
}
public void SetInfo(ZoneDefinition info)
{
Info = info;
if (Info == null) return;
gameObject.name = $"Zone Manager({Info.Id})";
transform.position = Info.Location;
transform.rotation = Quaternion.Euler(Info.Rotation);
UpdateCollider();
gameObject.SetActive(Info.Enabled);
enabled = Info.Enabled;
RegisterPermission();
InitializeAutoLights();
InitializeRadiation();
InitializeComfort();
if (IsInvoking("CheckEntites")) CancelInvoke("CheckEntites");
InvokeRepeating("CheckEntites", 10f, 10f);
}
private void UpdateCollider()
{
var sphereCollider = gameObject.GetComponent<SphereCollider>();
var boxCollider = gameObject.GetComponent<BoxCollider>();
if (Info.Size != Vector3.zero)
{
if (sphereCollider != null) Destroy(sphereCollider);
if (boxCollider == null)
{
boxCollider = gameObject.AddComponent<BoxCollider>();
boxCollider.isTrigger = true;
}
boxCollider.size = Info.Size;
}
else
{
if (boxCollider != null) Destroy(boxCollider);
if (sphereCollider == null)
{
sphereCollider = gameObject.AddComponent<SphereCollider>();
sphereCollider.isTrigger = true;
}
sphereCollider.radius = Info.Radius;
}
}
private void RegisterPermission()
{
if (!string.IsNullOrEmpty(Info.Permission) && !instance.permission.PermissionExists(Info.Permission))
instance.permission.RegisterPermission(Info.Permission, instance);
}
private void InitializeAutoLights()
{
if (instance.HasZoneFlag(this, ZoneFlags.AlwaysLights))
{
if (IsInvoking("CheckAlwaysLights")) CancelInvoke("CheckAlwaysLights");
InvokeRepeating("CheckAlwaysLights", 5f, 60f);
}
else if (instance.HasZoneFlag(this, ZoneFlags.AutoLights))
{
var currentTime = GetSkyHour();
if (currentTime > instance.AutolightOffTime && currentTime < instance.AutolightOnTime)
lightsOn = true;
else
lightsOn = false;
if (IsInvoking("CheckLights")) CancelInvoke("CheckLights");
InvokeRepeating("CheckLights", 5f, 30f);
}
}
private void InitializeRadiation()
{
var radiation = gameObject.GetComponent<TriggerRadiation>();
if (Info.Radiation > 0)
{
radiation = radiation ?? gameObject.AddComponent<TriggerRadiation>();
radiation.RadiationAmountOverride = Info.Radiation;
radiation.radiationSize = Info.Radius;
radiation.interestLayers = playersMask;
radiation.enabled = Info.Enabled;
}
else if (radiation != null)
{
radiation.RadiationAmountOverride = 0;
radiation.radiationSize = 0;
radiation.interestLayers = playersMask;
radiation.enabled = false;
}
}
private void InitializeComfort()
{
var comfort = gameObject.GetComponent<TriggerComfort>();
if (Info.Comfort > 0)
{
comfort = comfort ?? gameObject.AddComponent<TriggerComfort>();
comfort.baseComfort = Info.Comfort;
comfort.triggerSize = Info.Radius;
comfort.interestLayers = playersMask;
comfort.enabled = Info.Enabled;
}
else if (comfort != null)
{
comfort.baseComfort = 0;
comfort.triggerSize = 0;
comfort.interestLayers = playersMask;
comfort.enabled = false;
}
}
private void CheckEntites()
{
if (instance == null) return;
var oldPlayers = players;
players = new HashSet<BasePlayer>();
int entities;
if (Info.Size != Vector3.zero)
entities = Physics.OverlapBoxNonAlloc(Info.Location, Info.Size/2, colBuffer, Quaternion.Euler(Info.Rotation), playersMask);
else
entities = Physics.OverlapSphereNonAlloc(Info.Location, Info.Radius, colBuffer, playersMask);
for (var i = 0; i < entities; i++)
{
var player = colBuffer[i].GetComponentInParent<BasePlayer>();
colBuffer[i] = null;
if (player != null)
{
if (players.Add(player) && !oldPlayers.Contains(player))
instance.OnPlayerEnterZone(this, player);
}
}
foreach (var player in oldPlayers)
{
if (!players.Contains(player))
instance.OnPlayerExitZone(this, player);
}
}
private void CheckLights()
{
if (instance == null) return;
var currentTime = GetSkyHour();
if (currentTime > instance.AutolightOffTime && currentTime < instance.AutolightOnTime)
{
if (!lightsOn) return;
foreach (var building in buildings)
{
var oven = building as BaseOven;
if (oven != null && !oven.IsInvoking("Cook"))
{
oven.SetFlag(BaseEntity.Flags.On, false);
continue;
}
var door = building as Door;
if (door != null && door.PrefabName.Contains("shutter"))
door.SetFlag(BaseEntity.Flags.Open, true);
}
foreach (var player in players)
{
if (player.userID >= 76560000000000000L || player.inventory?.containerWear?.itemList == null) continue; //only npc
var items = player.inventory.containerWear.itemList;
foreach (var item in items)
{
if (!item.info.shortname.Equals("hat.miner") && !item.info.shortname.Equals("hat.candle")) continue;
item.SwitchOnOff(false, player);
player.inventory.ServerUpdate(0f);
break;
}
}
lightsOn = false;
}
else
{
if (lightsOn) return;
foreach (var building in buildings)
{
var oven = building as BaseOven;
if (oven != null && !oven.IsInvoking("Cook"))
{
oven.SetFlag(BaseEntity.Flags.On, true);
continue;
}
var door = building as Door;
if (door != null && door.PrefabName.Contains("shutter"))
door.SetFlag(BaseEntity.Flags.Open, false);
}
var fuel = ItemManager.FindItemDefinition("lowgradefuel");
foreach (var player in players)
{
if (player.userID >= 76560000000000000L || player.inventory?.containerWear?.itemList == null) continue; // only npc
var items = player.inventory.containerWear.itemList;
foreach (var item in items)
{
if (!item.info.shortname.Equals("hat.miner") && !item.info.shortname.Equals("hat.candle")) continue;
if (item.contents == null) item.contents = new ItemContainer();
var array = item.contents.itemList.ToArray();
for (var i = 0; i < array.Length; i++)
array[i].Remove(0f);
var newItem = ItemManager.Create(fuel, 100);
newItem.MoveToContainer(item.contents);
item.SwitchOnOff(true, player);
player.inventory.ServerUpdate(0f);
break;
}
}
lightsOn = true;
}
}
private void CheckAlwaysLights()
{
if (instance == null) return;
foreach (var building in buildings)
{
var oven = building as BaseOven;
if (oven == null || oven.IsInvoking("Cook")) continue;
oven.SetFlag(BaseEntity.Flags.On, true);
}
}
public void OnEntityKill(BaseCombatEntity entity)
{
var player = entity as BasePlayer;
if (player != null)
players.Remove(player);
else if (entity != null && !(entity is LootContainer) && !(entity is BaseHelicopter) && !(entity is BaseNpc))
buildings.Remove(entity);
}
private void CheckCollisionEnter(Collider col)
{
if (instance == null) return;
if (instance.HasZoneFlag(this, ZoneFlags.NoDecay))
{
var decayEntity = col.GetComponentInParent<DecayEntity>();
if (decayEntity != null)
typeof(DecayEntity).GetField("decay", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(decayEntity, null);
}
var resourceDispenser = col.GetComponentInParent<ResourceDispenser>();
if (resourceDispenser != null)
{
instance.OnResourceEnterZone(this, resourceDispenser);
return;
}
var entity = col.GetComponentInParent<BaseEntity>();
if (entity == null) return;
var npc = entity as BaseNpc;
if (npc != null)
{
instance.OnNpcEnterZone(this, npc);
return;
}
var combatEntity = entity as BaseCombatEntity;
if (combatEntity != null && !(entity is LootContainer) && !(entity is BaseHelicopter))
{
buildings.Add(combatEntity);
instance.OnBuildingEnterZone(this, combatEntity);
}
else
{
instance.OnOtherEnterZone(this, entity);
}
}
private void CheckCollisionLeave(Collider col)
{
if (instance.HasZoneFlag(this, ZoneFlags.NoDecay))
{
var decayEntity = col.GetComponentInParent<DecayEntity>();
if (decayEntity != null)
typeof(DecayEntity).GetField("decay", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(decayEntity, PrefabAttribute.server.Find<Decay>(decayEntity.prefabID));
}
var resourceDispenser = col.GetComponentInParent<ResourceDispenser>();
if (resourceDispenser != null)
{
instance.OnResourceExitZone(this, resourceDispenser);
return;
}
var entity = col.GetComponentInParent<BaseEntity>();
if (entity == null) return;
var npc = entity as BaseNpc;
if (npc != null)
{
instance.OnNpcExitZone(this, npc);
return;
}
var combatEntity = entity as BaseCombatEntity;
if (combatEntity != null && !(entity is LootContainer) && !(entity is BaseHelicopter))
{
buildings.Remove(combatEntity);
instance.OnBuildingExitZone(this, combatEntity);
}
else
{
instance.OnOtherExitZone(this, entity);
}
}
private void OnTriggerEnter(Collider col)
{
var player = col.GetComponentInParent<BasePlayer>();
if (player != null)
{
if (!players.Add(player)) return;
instance.OnPlayerEnterZone(this, player);
}
else if (!col.transform.CompareTag("MeshColliderBatch"))
CheckCollisionEnter(col);
else
{
var colliderBatch = col.GetComponent<MeshColliderBatch>();
if (colliderBatch == null) return;
var colliders = ((MeshColliderLookup) meshLookupField.GetValue(colliderBatch)).src.data;
var bounds = gameObject.GetComponent<Collider>().bounds;
foreach (var instance in colliders)
if (instance.collider && instance.collider.bounds.Intersects(bounds))
CheckCollisionEnter(instance.collider);
}
}
private void OnTriggerExit(Collider col)
{
var player = col.GetComponentInParent<BasePlayer>();
if (player != null)
{
if (!players.Remove(player)) return;
instance.OnPlayerExitZone(this, player);
}
else if(!col.transform.CompareTag("MeshColliderBatch"))
CheckCollisionLeave(col);
else
{
var colliderBatch = col.GetComponent<MeshColliderBatch>();
if (colliderBatch == null) return;
var colliders = ((MeshColliderLookup)meshLookupField.GetValue(colliderBatch)).src.data;
var bounds = gameObject.GetComponent<Collider>().bounds;
foreach (var instance in colliders)
if (instance.collider && instance.collider.bounds.Intersects(bounds))
CheckCollisionLeave(instance.collider);
}
}
}
#endregion
#region Zone Definition
public class ZoneDefinition
{
public string Name;
public float Radius;
public float Radiation;
public float Comfort;
public Vector3 Location;
public Vector3 Size;
public Vector3 Rotation;
public string Id;
public string EnterMessage;
public string LeaveMessage;
public string Permission;
public string EjectSpawns;
public bool Enabled = true;
public ZoneFlags Flags;
public ZoneDefinition()
{
}
public ZoneDefinition(Vector3 position)
{
Radius = 20f;
Location = position;
}
}
#endregion
private void OnZoneDestroy(Zone zone)
{
HashSet<Zone> zones;
foreach (var key in playerZones.Keys.ToArray())
if (playerZones.TryGetValue(key, out zones) && zones.Contains(zone))
OnPlayerExitZone(zone, key);
foreach (var key in buildingZones.Keys.ToArray())
if (buildingZones.TryGetValue(key, out zones) && zones.Contains(zone))
OnBuildingExitZone(zone, key);
foreach (var key in npcZones.Keys.ToArray())
if (npcZones.TryGetValue(key, out zones) && zones.Contains(zone))
OnNpcExitZone(zone, key);
foreach (var key in resourceZones.Keys.ToArray())
if (resourceZones.TryGetValue(key, out zones) && zones.Contains(zone))
OnResourceExitZone(zone, key);
foreach (var key in otherZones.Keys.ToArray())
{
if (!otherZones.TryGetValue(key, out zones))
{
Puts("Zone: {0} Entity: {1} ({2}) {3}", zone.Info.Id, key.GetType(), key.net?.ID, key.IsDestroyed);
continue;
}
if (zones.Contains(zone))
OnOtherExitZone(zone, key);
}
}
#endregion
#region Flags
[Flags]
public enum ZoneFlags : ulong
{
None = 0L,
AutoLights = 1UL,
Eject = 1UL << 1,
PvpGod = 1UL << 2,
PveGod = 1UL << 3,
SleepGod = 1UL << 4,
UnDestr = 1UL << 5,
NoBuild = 1UL << 6,
NoTp = 1UL << 7,
NoChat = 1UL << 8,
NoGather = 1UL << 9,
NoPve = 1UL << 10,
NoWounded = 1UL << 11,
NoDecay = 1UL << 12,
NoDeploy = 1UL << 13,
NoKits = 1UL << 14,
NoBoxLoot = 1UL << 15,
NoPlayerLoot = 1UL << 16,
NoCorpse = 1UL << 17,
NoSuicide = 1UL << 18,
NoRemove = 1UL << 19,
NoBleed = 1UL << 20,
KillSleepers = 1UL << 21,
NpcFreeze = 1UL << 22,
NoDrown = 1UL << 23,
NoStability = 1UL << 24,
NoUpgrade = 1UL << 25,
EjectSleepers = 1UL << 26,
NoPickup = 1UL << 27,
NoCollect = 1UL << 28,
NoDrop = 1UL << 29,
Kill = 1UL << 30,
NoCup = 1UL << 31,
AlwaysLights = 1UL << 32,
NoTrade = 1UL << 33,
NoShop = 1UL << 34,
NoSignUpdates = 1UL << 35,
NoOvenToggle = 1UL << 36,
NoLootSpawns = 1UL << 37,
NoNPCSpawns = 1UL << 38,
NoVending = 1UL << 39,
NoStash = 1UL << 40,
NoCraft = 1UL << 41,
NoHeliTargeting = 1UL << 42,
NoTurretTargeting = 1UL << 43
}
private bool HasZoneFlag(Zone zone, ZoneFlags flag)
{
if ((disabledFlags & flag) == flag) return false;
return (zone.Info.Flags & ~zone.disabledFlags & flag) == flag;
}
private static bool HasAnyFlag(ZoneFlags flags, ZoneFlags flag)
{
return (flags & flag) != ZoneFlags.None;
}
private static bool HasAnyZoneFlag(Zone zone)
{
return (zone.Info.Flags & ~zone.disabledFlags) != ZoneFlags.None;
}
private static void AddZoneFlag(ZoneDefinition zone, ZoneFlags flag)
{
zone.Flags |= flag;
}
private static void RemoveZoneFlag(ZoneDefinition zone, ZoneFlags flag)
{
zone.Flags &= ~flag;
}
#endregion
#region Oxide Hooks
private void Loaded()
{
lang.RegisterMessages(Messages, this);
ZoneManagerData = Interface.Oxide.DataFileSystem.GetFile("ZoneManager");
ZoneManagerData.Settings.Converters = new JsonConverter[] { new StringEnumConverter(), new UnityVector3Converter(), };
permission.RegisterPermission(permZone, this);
foreach (var flag in Enum.GetValues(typeof(ZoneFlags)))
permission.RegisterPermission(permIgnoreFlag + flag.ToString().ToLower(), this);
LoadData();
LoadVariables();
}
private void Unload()
{
for (int i = zoneObjects.Count - 1; i >= 0; i--)
{
var zone = zoneObjects.ElementAt(i);
UnityEngine.Object.Destroy(zone.Value);
zoneObjects.Remove(zone.Key);
}
var collectibleEntities = Resources.FindObjectsOfTypeAll<CollectibleEntity>();
for (var i = 0; i < collectibleEntities.Length; i++)
{
var collider = collectibleEntities[i].GetComponent<Collider>();
if (collider != null) UnityEngine.Object.Destroy(collider);
}
}
private void OnTerrainInitialized()
{
if (Initialized) return;
SetupCollectibleEntity();
foreach (var zoneDefinition in ZoneDefinitions.Values)
NewZone(zoneDefinition);
Initialized = true;
}
private void OnServerInitialized()
{
if (Initialized) return;
//var values = Enum.GetValues(typeof(ZoneFlags)).Cast<ZoneFlags>();
//foreach (var flagse in values)
//{
// Puts("{0} {1}", flagse, (ulong)flagse);
//}
timer.In(1, () => {
SetupCollectibleEntity();
foreach (var zoneDefinition in ZoneDefinitions.Values)
NewZone(zoneDefinition);
});
Initialized = true;
}
private void OnEntityBuilt(Planner planner, GameObject gameobject)
{
var player = planner.GetOwnerPlayer();
if (player == null) return;
if (HasPlayerFlag(player, ZoneFlags.NoBuild) && !CanBypass(player, ZoneFlags.NoBuild) && !isAdmin(player))
{
gameobject.GetComponentInParent<BaseCombatEntity>().Kill(BaseNetworkable.DestroyMode.Gib);
SendMessage(player, msg("noBuild", player.UserIDString));
}
}
private object OnStructureUpgrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum grade)
{
if (HasPlayerFlag(player, ZoneFlags.NoUpgrade) && !CanBypass(player, ZoneFlags.NoUpgrade) && !isAdmin(player))
{
SendMessage(player, msg("noUpgrade", player.UserIDString));
return false;
}
return null;
}
private void OnItemDeployed(Deployer deployer, BaseEntity deployedEntity)
{
var player = deployer.GetOwnerPlayer();
if (player == null) return;
if (HasPlayerFlag(player, ZoneFlags.NoDeploy) && !CanBypass(player, ZoneFlags.NoDeploy) && !isAdmin(player))
{
deployedEntity.Kill(BaseNetworkable.DestroyMode.Gib);
SendMessage(player, msg("noDeploy", player.UserIDString));
}
else if (HasPlayerFlag(player, ZoneFlags.NoCup) && deployedEntity.PrefabName.Contains("cupboard") && !CanBypass(player, ZoneFlags.NoCup) && !isAdmin(player))
{
deployedEntity.Kill(BaseNetworkable.DestroyMode.Gib);
SendMessage(player, msg("noCup", player.UserIDString));
}
}
private void OnRunPlayerMetabolism(PlayerMetabolism metabolism, BaseCombatEntity ownerEntity, float delta)
{
var player = ownerEntity as BasePlayer;
if (player == null) return;
if (metabolism.bleeding.value > 0 && HasPlayerFlag(player, ZoneFlags.NoBleed) && !CanBypass(player, ZoneFlags.NoBleed))
metabolism.bleeding.value = 0f;
if (metabolism.oxygen.value < 1 && HasPlayerFlag(player, ZoneFlags.NoDrown) && !CanBypass(player, ZoneFlags.NoDrown))
metabolism.oxygen.value = 1;
}
private object OnPlayerChat(ConsoleSystem.Arg arg)
{
if (arg.Player() == null) return null;
if (HasPlayerFlag(arg.Player(), ZoneFlags.NoChat) && !CanBypass(arg.Player(), ZoneFlags.NoChat))
{
SendMessage(arg.Player(), msg("noChat", arg.Player().UserIDString));
return false;
}
return null;
}
private object OnServerCommand(ConsoleSystem.Arg arg)
{
if (arg.Player() == null) return null;
if (arg.cmd?.Name == null) return null;
if (arg.cmd.Name == "kill" && HasPlayerFlag(arg.Player(), ZoneFlags.NoSuicide) && !CanBypass(arg.Player(), ZoneFlags.NoSuicide))
{
SendMessage(arg.Player(), msg("noSuicide", arg.Player().UserIDString));
return false;
}
return null;
}
private void OnPlayerDisconnected(BasePlayer player)
{
if (HasPlayerFlag(player, ZoneFlags.KillSleepers) && !CanBypass(player, ZoneFlags.KillSleepers) && !isAdmin(player))
{
player.Die();
return;
}
if (HasPlayerFlag(player, ZoneFlags.EjectSleepers) && !CanBypass(player, ZoneFlags.EjectSleepers) && !isAdmin(player))
{
HashSet<Zone> zones;
if (!playerZones.TryGetValue(player, out zones) || zones.Count == 0) return;
foreach (var zone in zones)
{
if (HasZoneFlag(zone, ZoneFlags.EjectSleepers))
{
EjectPlayer(zone, player);
break;
}
}
}
}
private void OnPlayerAttack(BasePlayer attacker, HitInfo hitinfo)
{
var disp = hitinfo?.HitEntity?.GetComponent<ResourceDispenser>();
if (disp == null || hitinfo.Weapon.GetComponent<BaseMelee>() == null)
return;
HashSet<Zone> resourceZone;
if (!resourceZones.TryGetValue(disp, out resourceZone))
return;
foreach (var zone in resourceZone)
{
if (HasZoneFlag(zone, ZoneFlags.NoGather) && !CanBypass(attacker, ZoneFlags.NoGather))
{
SendMessage(attacker, msg("noGather", attacker.UserIDString));
hitinfo.HitEntity = null;
break;
}
}
}
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitinfo)
{
if (entity == null || entity.GetComponent<ResourceDispenser>() != null) return;
var player = entity as BasePlayer;
if (player != null)
{
var target = hitinfo.Initiator as BasePlayer;
if (player.IsSleeping() && HasPlayerFlag(player, ZoneFlags.SleepGod) && !CanBypass(player, ZoneFlags.SleepGod))
{
CancelDamage(hitinfo);
}
else if (target != null)
{
if (target.userID < 76560000000000000L) return;
if (HasPlayerFlag(player, ZoneFlags.PvpGod) && !CanBypass(player, ZoneFlags.PvpGod))
CancelDamage(hitinfo);
else if (HasPlayerFlag(target, ZoneFlags.PvpGod) && !CanBypass(target, ZoneFlags.PvpGod))
CancelDamage(hitinfo);
}
else if (HasPlayerFlag(player, ZoneFlags.PveGod) && !CanBypass(player, ZoneFlags.PveGod))
CancelDamage(hitinfo);
else if (hitinfo.Initiator is FireBall && HasPlayerFlag(player, ZoneFlags.PvpGod) && !CanBypass(player, ZoneFlags.PvpGod))
CancelDamage(hitinfo);
return;
}
var npcai = entity as BaseNpc;
if (npcai != null)
{
HashSet<Zone> zones;
if (!npcZones.TryGetValue(npcai, out zones)) return;
foreach (var zone in zones)
{
if (HasZoneFlag(zone, ZoneFlags.NoPve))
{
if (hitinfo.InitiatorPlayer != null && CanBypass(hitinfo.InitiatorPlayer, ZoneFlags.NoPve)) continue;
CancelDamage(hitinfo);
break;
}
}
return;
}
if (!(entity is LootContainer) && !(entity is BaseHelicopter))
{
var resource = entity.GetComponent<ResourceDispenser>();
HashSet<Zone> zones;
if (!buildingZones.TryGetValue(entity, out zones) && (resource == null || !resourceZones.TryGetValue(resource, out zones))) return;
foreach (var zone in zones)
{
if (HasZoneFlag(zone, ZoneFlags.UnDestr))
{
if (hitinfo.InitiatorPlayer != null && CanBypass(hitinfo.InitiatorPlayer, ZoneFlags.UnDestr)) continue;
CancelDamage(hitinfo);
break;
}
}
}
}
private void OnEntityKill(BaseNetworkable networkable)
{
var entity = networkable as BaseEntity;
if (entity == null) return;
var resource = entity.GetComponent<ResourceDispenser>();
if (resource != null)
{
HashSet<Zone> zones;
if (resourceZones.TryGetValue(resource, out zones))
OnResourceExitZone(null, resource, true);
return;
}
var player = entity as BasePlayer;
if (player != null)
{
HashSet<Zone> zones;
if (playerZones.TryGetValue(player, out zones))
OnPlayerExitZone(null, player, true);
return;
}
var npc = entity as BaseNpc;
if (npc != null)
{
HashSet<Zone> zones;
if (npcZones.TryGetValue(npc, out zones))
OnNpcExitZone(null, npc, true);
return;
}
var building = entity as BaseCombatEntity;
if (building != null && !(entity is LootContainer) && !(entity is BaseHelicopter))
{
HashSet<Zone> zones;
if (buildingZones.TryGetValue(building, out zones))
OnBuildingExitZone(null, building, true);
}
else
{
HashSet<Zone> zones;
if (otherZones.TryGetValue(entity, out zones))
OnOtherExitZone(null, entity, true);
}
}
private void OnEntitySpawned(BaseNetworkable entity)
{
if (entity is BaseCorpse)
{
timer.Once(2f, () =>
{
HashSet<Zone> zones;
if (entity == null || entity.IsDestroyed || !entity.GetComponent<ResourceDispenser>() || !resourceZones.TryGetValue(entity.GetComponent<ResourceDispenser>(), out zones)) return;
foreach (var zone in zones)
{
if (HasZoneFlag(zone, ZoneFlags.NoCorpse) && !CanBypass((entity as BaseCorpse).OwnerID, ZoneFlags.NoCorpse))
{
entity.Kill(BaseNetworkable.DestroyMode.None);
break;
}
}
});
}
else if (entity is BuildingBlock && zoneObjects != null)
{
var block = (BuildingBlock)entity;
if (EntityHasFlag(entity as BuildingBlock, "NoStability") && !CanBypass((entity as BuildingBlock).OwnerID, ZoneFlags.NoStability))
block.grounded = true;
}
else if (entity is LootContainer || entity is JunkPile || entity is BaseNpc)
timer.In(2, ()=> CheckSpawnedEntity(entity));
}
private object CanLootPlayer(BasePlayer target, BasePlayer looter)
{
return OnLootPlayerInternal(looter, target) ? null : (object) false;
}
private void OnLootPlayer(BasePlayer looter, BasePlayer target)
{
OnLootPlayerInternal(looter, target);
}
private bool OnLootPlayerInternal(BasePlayer looter, BasePlayer target)
{
if ((HasPlayerFlag(looter, ZoneFlags.NoPlayerLoot) && !CanBypass(looter, ZoneFlags.NoPlayerLoot)) || (target != null && HasPlayerFlag(target, ZoneFlags.NoPlayerLoot) && !CanBypass(target, ZoneFlags.NoPlayerLoot)))
{
SendMessage(looter, msg("noLoot", looter.UserIDString));
NextTick(looter.EndLooting);
return false;
}
return true;
}
private void OnLootEntity(BasePlayer looter, BaseEntity target)
{
if (target is BaseCorpse)
OnLootPlayerInternal(looter, null);
else if (HasPlayerFlag(looter, ZoneFlags.NoBoxLoot) && !CanBypass(looter, ZoneFlags.NoBoxLoot))
{
if ((target as StorageContainer)?.transform.position == Vector3.zero) return;
SendMessage(looter, msg("noLoot", looter.UserIDString));
timer.Once(0.01f, looter.EndLooting);
}
}
private object CanBeWounded(BasePlayer player, HitInfo hitinfo)
{
return HasPlayerFlag(player, ZoneFlags.NoWounded) && !CanBypass(player, ZoneFlags.NoWounded) ? (object) false : null;
}
object CanUpdateSign(BasePlayer player, Signage sign)
{
if (HasPlayerFlag(player, ZoneFlags.NoSignUpdates) && !CanBypass(player, ZoneFlags.NoSignUpdates))
{
SendMessage(player, msg("noSignUpdates", player.UserIDString));
return false;
}
return null;
}
object OnOvenToggle(BaseOven oven, BasePlayer player)
{
if (HasPlayerFlag(player, ZoneFlags.NoOvenToggle) && !CanBypass(player, ZoneFlags.NoOvenToggle))
{
SendMessage(player, msg("noOvenToggle", player.UserIDString));
return false;
}
return null;
}
object CanPickupEntity(BaseCombatEntity entity, BasePlayer player)
{
if (HasPlayerFlag(player, ZoneFlags.NoPickup) && !CanBypass(player, ZoneFlags.NoPickup))
{
SendMessage(player, msg("noPickup", player.UserIDString));
return false;
}
return null;
}
object CanUseVending(VendingMachine machine, BasePlayer player)
{
if (HasPlayerFlag(player, ZoneFlags.NoVending) && !CanBypass(player, ZoneFlags.NoVending))
{
SendMessage(player, msg("noVending", player.UserIDString));
return false;
}
return null;
}
object CanHideStash(StashContainer stash, BasePlayer player)
{
if (HasPlayerFlag(player, ZoneFlags.NoStash) && !CanBypass(player, ZoneFlags.NoStash))
{
SendMessage(player, msg("noStash", player.UserIDString));
return false;
}
return null;
}
object CanCraft(ItemCrafter itemCrafter, ItemBlueprint bp, int amount)
{
var player = itemCrafter.GetComponent<BasePlayer>();
if (player != null)
{
if (HasPlayerFlag(player, ZoneFlags.NoCraft) && !CanBypass(player, ZoneFlags.NoCraft))
{
SendMessage(player, msg("noCraft", player.UserIDString));
return false;
}
}
return null;
}
object CanPickupLock(BasePlayer player, BaseLock baseLock)
{
if (HasPlayerFlag(player, ZoneFlags.NoPickup) && !CanBypass(player, ZoneFlags.NoPickup))
{
SendMessage(player, msg("noPickup", player.UserIDString));
return false;
}
return null;
}
object CanBeTargeted(BaseCombatEntity entity, MonoBehaviour behaviour)
{
var player = entity.ToPlayer();
if (player != null)
{
if (behaviour is AutoTurret || behaviour is FlameTurret || behaviour is GunTrap)
{
if (HasPlayerFlag(player, ZoneFlags.NoTurretTargeting) && !CanBypass(player, ZoneFlags.NoTurretTargeting))
return false;
}
else if (behaviour is HelicopterTurret)
{
if (HasPlayerFlag(player, ZoneFlags.NoHeliTargeting) && !CanBypass(player, ZoneFlags.NoHeliTargeting))
{
var turret = behaviour as HelicopterTurret;
turret.ClearTarget();
turret._heliAI.SetTargetDestination(turret._heliAI.GetRandomPatrolDestination());
return false;
}
}
}
return null;
}
object OnHelicopterTarget(HelicopterTurret turret, BaseCombatEntity entity)
{
var player = entity.ToPlayer();
if (player != null)
{
if (HasPlayerFlag(player, ZoneFlags.NoHeliTargeting) && !CanBypass(player, ZoneFlags.NoHeliTargeting))
return false;
}
return null;
}
#endregion
#region External Plugin Hooks
private object canRedeemKit(BasePlayer player)
{
return HasPlayerFlag(player, ZoneFlags.NoKits) && !CanBypass(player, ZoneFlags.NoKits) ? "You may not redeem a kit inside this area" : null;
}
private object CanTeleport(BasePlayer player)
{
return HasPlayerFlag(player, ZoneFlags.NoTp) && !CanBypass(player, ZoneFlags.NoTp) ? "You may not teleport in this area" : null;
}
private object canRemove(BasePlayer player)
{
return HasPlayerFlag(player, ZoneFlags.NoRemove) && !CanBypass(player, ZoneFlags.NoRemove) ? "You may not use the remover tool in this area" : null;
}
private bool CanChat(BasePlayer player)
{
return HasPlayerFlag(player, ZoneFlags.NoChat) && !CanBypass(player, ZoneFlags.NoChat) ? false : true;
}
private object CanTrade(BasePlayer player)
{
return HasPlayerFlag(player, ZoneFlags.NoTrade) && !CanBypass(player, ZoneFlags.NoTrade) ? "You may not trade in this area" : null;
}
private object canShop(BasePlayer player)
{
return HasPlayerFlag(player, ZoneFlags.NoShop) && !CanBypass(player, ZoneFlags.NoShop) ? "You may not use the store in this area" : null;
}
#endregion
#region Zone Editing
private void UpdateZoneDefinition(ZoneDefinition zone, string[] args, BasePlayer player = null)
{
for (var i = 0; i < args.Length; i = i + 2)
{
object editvalue;
switch (args[i].ToLower())
{
case "name":
editvalue = zone.Name = args[i + 1];
break;
case "id":
editvalue = zone.Id = args[i + 1];
break;
case "comfort":
editvalue = zone.Comfort = Convert.ToSingle(args[i + 1]);
break;
case "radiation":
editvalue = zone.Radiation = Convert.ToSingle(args[i + 1]);
break;
case "radius":
editvalue = zone.Radius = Convert.ToSingle(args[i + 1]);
break;
case "rotation"
// ... [Code preview truncated due to length. Full source in attached file] ...