C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
// Reference: RustBuild
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.8", ResourceId = 739)]
public class ZoneManager : RustPlugin
{
private const string PermZone = "zonemanager.zone";
private const string PermCanDeploy = "zonemanager.candeploy";
private const string PermCanBuild = "zonemanager.canbuild";
[PluginReference]
Plugin PopupNotifications;
////////////////////////////////////////////
/// Configs
////////////////////////////////////////////
private bool usePopups = false;
private bool Changed;
private bool Initialized;
private float AutolightOnTime;
private float AutolightOffTime;
private string prefix;
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 static BasePlayer FindPlayer(string nameOrIdOrIp)
{
foreach (var activePlayer in BasePlayer.activePlayerList)
{
if (activePlayer.UserIDString == nameOrIdOrIp)
return activePlayer;
if (activePlayer.displayName.Contains(nameOrIdOrIp, CompareOptions.OrdinalIgnoreCase))
return activePlayer;
if (activePlayer.net?.connection != null && activePlayer.net.connection.ipaddress == nameOrIdOrIp)
return activePlayer;
}
foreach (var sleepingPlayer in BasePlayer.sleepingPlayerList)
{
if (sleepingPlayer.UserIDString == nameOrIdOrIp)
return sleepingPlayer;
if (sleepingPlayer.displayName.Contains(nameOrIdOrIp, CompareOptions.OrdinalIgnoreCase))
return sleepingPlayer;
}
return null;
}
private void LoadVariables()
{
AutolightOnTime = Convert.ToSingle(GetConfig("AutoLights", "Lights On Time", "18.0"));
AutolightOffTime = Convert.ToSingle(GetConfig("AutoLights", "Lights Off Time", "8.0"));
prefix = Convert.ToString(GetConfig("Chat", "Prefix", "<color=#FA58AC>ZoneManager:</color> "));
if (!Changed) return;
SaveConfig();
Changed = false;
}
protected override void LoadDefaultConfig()
{
Config.Clear();
LoadVariables();
}
////////////////////////////////////////////
/// FIELDS
////////////////////////////////////////////
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 ZoneFlags disabledFlags = ZoneFlags.None;
private DynamicConfigFile ZoneManagerData;
private StoredData storedData;
private Zone[] zoneObjects = new Zone[0];
private static readonly FieldInfo decay = typeof(DecayEntity).GetField("decay", BindingFlags.Instance | BindingFlags.NonPublic);
private static readonly FieldInfo decayTimer = typeof(DecayEntity).GetField("decayTimer", BindingFlags.Instance | BindingFlags.NonPublic);
private static readonly FieldInfo decayDelayTime = typeof(DecayEntity).GetField("decayDelayTime", BindingFlags.Instance | BindingFlags.NonPublic);
private static readonly FieldInfo decayDeltaTime = typeof(DecayEntity).GetField("decayDeltaTime", BindingFlags.Instance | BindingFlags.NonPublic);
private readonly FieldInfo npcNextTick = typeof(NPCAI).GetField("nextTick", (BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic));
//private static readonly int triggerLayer = LayerMask.NameToLayer("Trigger");
private static readonly int playersMask = LayerMask.GetMask("Player (Server)");
//private static readonly int buildingMask = LayerMask.GetMask("Deployed", "Player (Server)", "Default", "Prevent Building");
private static readonly Collider[] colBuffer = (Collider[])typeof(Vis).GetField("colBuffer", (BindingFlags.Static | BindingFlags.NonPublic))?.GetValue(null);
/////////////////////////////////////////
// Zone
// is a Monobehavior
// used to detect the colliders with players
// and created everything on it's own (radiations, locations, etc)
/////////////////////////////////////////
private static float GetSkyHour()
{
return TOD_Sky.Instance.Cycle.Hour;
}
public class Zone : MonoBehaviour
{
public ZoneDefinition Info;
public ZoneManager ZoneManagerPlugin;
public ZoneFlags disabledFlags = ZoneFlags.None;
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 InstancesField = typeof(MeshColliderBatch).GetField("instances", BindingFlags.Instance | BindingFlags.NonPublic);
private void Awake()
{
gameObject.layer = (int)Layer.Reserved1; //hack to get all trigger layers...otherwise child zones
gameObject.name = "Zone Manager";
var rigidbody = gameObject.AddComponent<Rigidbody>();
rigidbody.useGravity = false;
rigidbody.isKinematic = true;
rigidbody.detectCollisions = true;
rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;
}
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;
}
}
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;
if (ZoneManagerPlugin.HasZoneFlag(this, ZoneFlags.AlwaysLights))
{
if (IsInvoking("CheckAlwaysLights")) CancelInvoke("CheckAlwaysLights");
InvokeRepeating("CheckAlwaysLights", 5f, 60f);
}
else if (ZoneManagerPlugin.HasZoneFlag(this, ZoneFlags.AutoLights))
{
var currentTime = GetSkyHour();
if (currentTime > ZoneManagerPlugin.AutolightOffTime && currentTime < ZoneManagerPlugin.AutolightOnTime)
lightsOn = true;
else
lightsOn = false;
if (IsInvoking("CheckLights")) CancelInvoke("CheckLights");
InvokeRepeating("CheckLights", 5f, 30f);
}
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;
//Destroy(radiation);
}
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;
//Destroy(comfort);
}
if (IsInvoking("CheckEntites")) CancelInvoke("CheckEntites");
InvokeRepeating("CheckEntites", 10f, 10f);
/*if (HasAnyFlag(info.flags, ZoneFlags.Eject | ZoneFlags.EjectSleepers
| ZoneFlags.KillSleepers | ZoneFlags.NoBleed | ZoneFlags.NoBoxLoot | ZoneFlags.NoBuild
| ZoneFlags.NoChat | ZoneFlags.NoDeploy | ZoneFlags.NoDrown | ZoneFlags.NoKits
| ZoneFlags.NoPlayerLoot | ZoneFlags.NoRemove | ZoneFlags.NoSuicide | ZoneFlags.NoTp
| ZoneFlags.NoUpgrade | ZoneFlags.NoWounded | ZoneFlags.PveGod | ZoneFlags.PvpGod
| ZoneFlags.SleepGod | ZoneFlags.AutoLights))
{
Interface.Oxide.LogInfo("Mask: Player (Server)");
}*/
}
private void CheckEntites()
{
if (ZoneManagerPlugin == null) return;
var oldPlayers = players;
players = new HashSet<BasePlayer>();
int entities;
if (Info.Size != Vector3.zero)
entities = Physics.OverlapBoxNonAlloc(Info.Location, Info.Size, 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))
ZoneManagerPlugin.OnPlayerEnterZone(this, player);
}
}
foreach (var player in oldPlayers)
{
if (!players.Contains(player))
ZoneManagerPlugin.OnPlayerExitZone(this, player);
}
}
private void OnDestroy()
{
CancelInvoke("CheckLights");
CancelInvoke("CheckAlwaysLights");
ZoneManagerPlugin.OnZoneDestroy(this);
ZoneManagerPlugin = null;
Destroy(gameObject);
}
private void CheckLights()
{
if (ZoneManagerPlugin == null) return;
var currentTime = GetSkyHour();
if (currentTime > ZoneManagerPlugin.AutolightOffTime && currentTime < ZoneManagerPlugin.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 (ZoneManagerPlugin == 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 (ZoneManagerPlugin.HasZoneFlag(this, ZoneFlags.NoDecay))
{
var decayEntity = col.GetComponentInParent<DecayEntity>();
if (decayEntity != null && decay.GetValue(decayEntity) != null)
{
decayEntity.CancelInvoke("RunDecay");
decayTimer.SetValue(decayEntity, 0f);
}
}
var resourceDispenser = col.GetComponentInParent<ResourceDispenser>();
if (resourceDispenser != null) //also BaseCorpse
{
ZoneManagerPlugin.OnResourceEnterZone(this, resourceDispenser);
return;
}
var entity = col.GetComponentInParent<BaseEntity>();
if (entity == null) return;
var npc = entity as BaseNPC;
if (npc != null)
{
ZoneManagerPlugin.OnNpcEnterZone(this, npc);
return;
}
var combatEntity = entity as BaseCombatEntity;
if (combatEntity != null && !(entity is LootContainer) && !(entity is BaseHelicopter))
{
buildings.Add(combatEntity);
ZoneManagerPlugin.OnBuildingEnterZone(this, combatEntity);
}
else
{
ZoneManagerPlugin.OnOtherEnterZone(this, entity);
}
}
private void CheckCollisionLeave(Collider col)
{
if (ZoneManagerPlugin.HasZoneFlag(this, ZoneFlags.NoDecay))
{
var decayEntity = col.GetComponentInParent<DecayEntity>();
if (decayEntity != null && decay.GetValue(decayEntity) != null && !decayEntity.IsInvoking("RunDecay"))
decayEntity.InvokeRepeating("RunDecay", (float) decayDelayTime.GetValue(decayEntity), (float) decayDeltaTime.GetValue(decayEntity));
}
var resourceDispenser = col.GetComponentInParent<ResourceDispenser>();
if (resourceDispenser != null)
{
ZoneManagerPlugin.OnResourceExitZone(this, resourceDispenser);
return;
}
var entity = col.GetComponentInParent<BaseEntity>();
if (entity == null) return;
var npc = entity as BaseNPC;
if (npc != null)
{
ZoneManagerPlugin.OnNpcExitZone(this, npc);
return;
}
var combatEntity = entity as BaseCombatEntity;
if (combatEntity != null && !(entity is LootContainer) && !(entity is BaseHelicopter))
{
buildings.Remove(combatEntity);
ZoneManagerPlugin.OnBuildingExitZone(this, combatEntity);
}
else
{
ZoneManagerPlugin.OnOtherExitZone(this, entity);
}
}
private void OnTriggerEnter(Collider col)
{
//Interface.Oxide.LogInfo("Enter {0}: {1}", Info.ID, col.name);
var player = col.GetComponentInParent<BasePlayer>();
if (player != null)
{
if (!players.Add(player)) return;
ZoneManagerPlugin.OnPlayerEnterZone(this, player);
}
else if (!col.transform.CompareTag("MeshColliderBatch"))
CheckCollisionEnter(col);
else
{
var colliderBatch = col.GetComponent<MeshColliderBatch>();
if (colliderBatch == null) return;
var colliders = (ListDictionary<Component, ColliderCombineInstance>) InstancesField.GetValue(colliderBatch);
foreach (var instance in colliders.Values)
CheckCollisionEnter(instance.collider);
}
}
private void OnTriggerExit(Collider col)
{
//Interface.Oxide.LogInfo("Exit {0}: {1}", Info.ID, col.name);
var player = col.GetComponentInParent<BasePlayer>();
if (player != null)
{
if (!players.Remove(player)) return;
ZoneManagerPlugin.OnPlayerExitZone(this, player);
}
else if(!col.transform.CompareTag("MeshColliderBatch"))
CheckCollisionLeave(col);
else
{
var colliderBatch = col.GetComponent<MeshColliderBatch>();
if (colliderBatch == null) return;
var colliders = (ListDictionary<Component, ColliderCombineInstance>) InstancesField.GetValue(colliderBatch);
foreach (var instance in colliders.Values)
CheckCollisionLeave(instance.collider);
}
}
}
/////////////////////////////////////////
// ZoneDefinition
// Stored informations on the zones
/////////////////////////////////////////
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 bool Enabled = true;
public ZoneFlags Flags;
public ZoneDefinition()
{
}
public ZoneDefinition(Vector3 position)
{
Radius = 20f;
Location = position;
}
}
[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
}
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;
}
/////////////////////////////////////////
// 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;
}
private void SetupCollectibleEntity()
{
var collectibleEntities = Resources.FindObjectsOfTypeAll<CollectibleEntity>();
//Puts("Found {0} CollectibleEntities.", collectibleEntities.Length);
for (var i = 0; i < collectibleEntities.Length; i++)
{
var collectibleEntity = collectibleEntities[i];
var collider = collectibleEntity.GetComponent<Collider>() ?? collectibleEntity.gameObject.AddComponent<BoxCollider>();
collider.isTrigger = true;
}
}
/////////////////////////////////////////
// OXIDE HOOKS
/////////////////////////////////////////
/////////////////////////////////////////
// Loaded()
// Called when the plugin is loaded
/////////////////////////////////////////
private void Loaded()
{
//Puts("ZoneManager loaded: {0}", GetHashCode());
ZoneManagerData = Interface.Oxide.DataFileSystem.GetFile("ZoneManager");
ZoneManagerData.Settings.Converters = new JsonConverter[] { new StringEnumConverter(), new UnityVector3Converter(), };
permission.RegisterPermission(PermZone, this);
permission.RegisterPermission(PermCanDeploy, this);
permission.RegisterPermission(PermCanBuild, this);
/* for(int i = 0; i < 25; i ++)
{
Debug.Log(UnityEngine.LayerMask.LayerToName(i));
}*/
LoadData();
LoadVariables();
/*string[] options = new string[32];
for (int i = 0; i < 32; i++)
{ // get layer names
options[i] = i + " : " + LayerMask.LayerToName(i);
}
Puts("Layers: {0}", string.Join(", ", options));
var sb = new StringBuilder();
sb.AppendLine();
for (int i = 0; i < 32; i++)
{
sb.Append(i + ":\t");
for (int j = 0; j < 32; j++)
{
sb.Append(Physics.GetIgnoreLayerCollision(i, j) ? " " : "X ");
}
sb.AppendLine();
}
Puts(sb.ToString());*/
}
/////////////////////////////////////////
// Unload()
// Called when the plugin is unloaded
/////////////////////////////////////////
private void Unload()
{
foreach (var zone in zoneObjects)
UnityEngine.Object.Destroy(zone);
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;
}
/////////////////////////////////////////
// OnEntityBuilt(Planner planner, GameObject gameobject)
// Called when a buildingblock was created
/////////////////////////////////////////
private void OnEntityBuilt(Planner planner, GameObject gameobject)
{
var player = planner.GetOwnerPlayer();
if (player == null) return;
if (HasPlayerFlag(player, ZoneFlags.NoBuild) && !hasPermission(player, PermCanBuild))
{
gameobject.GetComponentInParent<BaseCombatEntity>().Kill(BaseNetworkable.DestroyMode.Gib);
SendMessage(player, "You are not allowed to build here");
}
}
private object OnStructureUpgrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum grade)
{
if (HasPlayerFlag(player, ZoneFlags.NoUpgrade) && !isAdmin(player)) return false;
return null;
}
/////////////////////////////////////////
// OnItemDeployed(Deployer deployer, BaseEntity deployedEntity)
// Called when an item was deployed
/////////////////////////////////////////
private void OnItemDeployed(Deployer deployer, BaseEntity deployedEntity)
{
var player = deployer.GetOwnerPlayer();
if (player == null) return;
if (HasPlayerFlag(player, ZoneFlags.NoDeploy) && !hasPermission(player, PermCanDeploy))
{
deployedEntity.Kill(BaseNetworkable.DestroyMode.Gib);
SendMessage(player, "You are not allowed to deploy here");
}
else if (HasPlayerFlag(player, ZoneFlags.NoCup) && deployedEntity.PrefabName.Contains("cupboard"))
{
deployedEntity.Kill(BaseNetworkable.DestroyMode.Gib);
SendMessage(player, "You are not allowed to deploy here");
}
}
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))
metabolism.bleeding.value = 0f;
if (metabolism.oxygen.value < 1 && HasPlayerFlag(player, ZoneFlags.NoDrown))
metabolism.oxygen.value = 1;
}
/////////////////////////////////////////
// OnPlayerChat(ConsoleSystem.Arg arg)
// Called when a user writes something in the chat, doesn't take in count the commands
/////////////////////////////////////////
private object OnPlayerChat(ConsoleSystem.Arg arg)
{
if (arg.Player() == null) return null;
if (HasPlayerFlag(arg.Player(), ZoneFlags.NoChat))
{
SendMessage(arg.Player(), "You are not allowed to chat here");
return false;
}
return null;
}
/////////////////////////////////////////
// OnServerCommand(ConsoleSystem.Arg arg)
// Called when a user executes a command
/////////////////////////////////////////
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))
{
SendMessage(arg.Player(), "You are not allowed to suicide here");
return false;
}
return null;
}
/////////////////////////////////////////
// OnPlayerDisconnected(BasePlayer player)
// Called when a user disconnects
/////////////////////////////////////////
private void OnPlayerDisconnected(BasePlayer player)
{
if (HasPlayerFlag(player, ZoneFlags.KillSleepers) && !isAdmin(player)) player.Die();
else if (HasPlayerFlag(player, ZoneFlags.EjectSleepers))
{
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) return;
HashSet<Zone> resourceZone;
if (!resourceZones.TryGetValue(disp, out resourceZone)) return;
foreach (var zone in resourceZone)
{
if (HasZoneFlag(zone, ZoneFlags.NoGather))
{
hitinfo.HitEntity = null;
break;
}
}
}
/////////////////////////////////////////
// OnEntityAttacked(BaseCombatEntity entity, HitInfo hitinfo)
// Called when any entity is attacked
/////////////////////////////////////////
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))
{
CancelDamage(hitinfo);
}
else if (target != null)
{
if (target.userID < 76560000000000000L) return;
if (HasPlayerFlag(player, ZoneFlags.PvpGod))
CancelDamage(hitinfo);
else if (HasPlayerFlag(target, ZoneFlags.PvpGod))
CancelDamage(hitinfo);
}
else if (HasPlayerFlag(player, ZoneFlags.PveGod))
CancelDamage(hitinfo);
else if (hitinfo.Initiator is FireBall && HasPlayerFlag(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))
{
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))
{
CancelDamage(hitinfo);
break;
}
}
}
/*else
{
HashSet<Zone> zones;
if (otherZones.TryGetValue(entity, out zones))
{
}
}*/
}
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);
}
}
/////////////////////////////////////////
// OnEntitySpawned(BaseNetworkable entity)
// Called when any kind of entity is spawned in the world
/////////////////////////////////////////
private void OnEntitySpawned(BaseNetworkable entity)
{
if (entity is BaseCorpse)
{
timer.Once(2f, () =>
{
HashSet<Zone> zones;
if (entity.isDestroyed || !resourceZones.TryGetValue(entity.GetComponent<ResourceDispenser>(), out zones)) return;
foreach (var zone in zones)
{
if (HasZoneFlag(zone, ZoneFlags.NoCorpse))
{
entity.KillMessage();
break;
}
}
});
}
else if (entity is BuildingBlock && zoneObjects != null)
{
var block = (BuildingBlock)entity;
foreach (var zone in zoneObjects)
{
if (HasZoneFlag(zone, ZoneFlags.NoStability))
{
if (zone.Info.Size != Vector3.zero)
{
if (!new Bounds(zone.Info.Location, Quaternion.Euler(zone.Info.Rotation) * zone.Info.Size).Contains(block.transform.position))
continue;
}
else if (Vector3.Distance(block.transform.position, zone.Info.Location) > zone.Info.Radius)
continue;
block.grounded = true;
break;
}
}
}
var npcai = entity.GetComponent<NPCAI>();
if (npcai != null)
npcNextTick.SetValue(npcai, Time.time + 10f);
}
/////////////////////////////////////////
// OnPlayerLoot(PlayerLoot lootInventory, BasePlayer targetPlayer)
// Called when a player tries to loot another player
/////////////////////////////////////////
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) || target != null && HasPlayerFlag(target, ZoneFlags.NoPlayerLoot))
{
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))
{
if ((target as StorageContainer)?.transform.position == Vector3.zero) return;
timer.Once(0.01f, looter.EndLooting);
}
}
private object CanBeWounded(BasePlayer player, HitInfo hitinfo)
{
return HasPlayerFlag(player, ZoneFlags.NoWounded) ? (object) false : null;
}
/////////////////////////////////////////
// Outside Plugin Hooks
/////////////////////////////////////////
private object canRedeemKit(BasePlayer player)
{
return HasPlayerFlag(player, ZoneFlags.NoKits) ? "You may not redeem a kit inside this area" : null;
}
private object CanTeleport(BasePlayer player)
{
return HasPlayerFlag(player, ZoneFlags.NoTp) ? "You may not teleport in this area" : null;
}
private object canRemove(BasePlayer player)
{
return HasPlayerFlag(player, ZoneFlags.NoRemove) ? "You may not use the remover tool in this area" : null;
}
private bool CanChat(BasePlayer player)
{
return !HasPlayerFlag(player, ZoneFlags.NoChat);
}
private object CanTrade(BasePlayer player)
{
return HasPlayerFlag(player, ZoneFlags.NoTrade) ? "You may not trade in this area" : null;
}
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":
zone.Rotation = player?.GetNetworkRotation() ?? Vector3.zero;/* + Quaternion.AngleAxis(90, Vector3.up).eulerAngles*/
zone.Rotation.x = 0;
editvalue = zone.Rotation;
break;
case "location":
if (player != null && args[i + 1].Equals("here", StringComparison.OrdinalIgnoreCase))
{
editvalue = zone.Location = player.transform.position;
break;
}
var loc = args[i + 1].Trim().Split(' ');
if (loc.Length == 3)
editvalue = zone.Location = new Vector3(Convert.ToSingle(loc[0]), Convert.ToSingle(loc[1]), Convert.ToSingle(loc[2]));
else
{
if (player != null) SendMessage(player, "Invalid location format, use: \"x y z\" or here");
continue;
}
break;
case "size":
var size = args[i + 1].Trim().Split(' ');
if (size.Length == 3)
editvalue = zone.Size = new Vector3(Convert.ToSingle(size[0]), Convert.ToSingle(size[1]), Convert.ToSingle(size[2]));
else
{
// ... [Code preview truncated due to length. Full source in attached file] ...