C#:
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Rust;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using UnityEngine;
using Oxide.Game.Rust.Cui;
namespace Oxide.Plugins {
[Info("ZoneManager", "Reneb / Nogrod", "2.5.15")]
[Description("An advanced management system for creating in-game zones")]
public class ZoneManager : RustPlugin {
#region Fields
private DynamicConfigFile ZoneManagerData;
private StoredData storedData;
[PluginReference]
Plugin PopupNotifications, Spawns;
private static ZoneManager instance;
private ZoneFlags disabledFlags = ZoneFlags.None;
private Hash<string, Zone> zoneObjects = new Hash<string, Zone>();
private readonly Dictionary<string, Zone.Definition> zoneDefinitions = new Dictionary<string, Zone.Definition>();
private readonly Dictionary<ulong, string> lastPlayerZone = new Dictionary<ulong, string>();
private readonly Dictionary<BasePlayer, HashSet<Zone>> playerZones = new Dictionary<BasePlayer, HashSet<Zone>>();
private readonly Dictionary<BaseCombatEntity, HashSet<Zone>> entityZones = 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 = 131072;
private static readonly Collider[] colBuffer = Vis.colBuffer;
private const string permZone = "zonemanager.zone";
private const string permIgnoreFlag = "zonemanager.ignoreflag.";
#endregion
#region Oxide Hooks
private void Loaded() {
instance = this;
lang.RegisterMessages(Messages, this);
ZoneManagerData = Interface.Oxide.DataFileSystem.GetFile("ZoneManager");
ZoneManagerData.Settings.Converters = new JsonConverter[] {
new StringEnumConverter(), new UnityVector3Converter(),
}
;
permission.RegisterPermission(permZone, this);
foreach (ZoneFlags flag in Enum.GetValues(typeof(ZoneFlags))) permission.RegisterPermission(permIgnoreFlag + flag.ToString().ToLower(), this);
LoadVariables();
LoadData();
}
private void OnServerInitialized() => InitializeZones();
private void Unload() {
foreach (BasePlayer player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, ZMUI);
for (int i = zoneObjects.Count - 1; i >= 0; i--) {
var zone = zoneObjects.ElementAt(i);
OnZoneDestroy(zone.Value);
UnityEngine.Object.Destroy(zone.Value);
zoneObjects.Remove(zone.Key);
}
instance = null;
}
private void OnTerrainInitialized() => InitializeZones();
private void InitializeZones() {
if (Initialized) return;
foreach (Zone.Definition zoneDefinition in zoneDefinitions.Values) CreateNewZone(zoneDefinition);
Initialized = true;
}
private void OnEntityBuilt(Planner planner, GameObject gObject) {
BasePlayer player = planner?.GetOwnerPlayer();
if (player == null) return;
BaseEntity entity = gObject?.ToBaseEntity();
if (entity == null) return;
if (entity is BuildingBlock || entity is SimpleBuildingBlock) {
if (HasPlayerFlag(player, ZoneFlags.NoBuild, true)) {
entity.Kill(BaseNetworkable.DestroyMode.Gib);
SendMessage(player, msg("noBuild", player.UserIDString));
}
}
else {
if (entity is BuildingPrivlidge) {
if (HasPlayerFlag(player, ZoneFlags.NoCup, false)) {
entity.Kill(BaseNetworkable.DestroyMode.Gib);
SendMessage(player, msg("noCup", player.UserIDString));
}
}
else {
if (HasPlayerFlag(player, ZoneFlags.NoDeploy, true)) {
entity.Kill(BaseNetworkable.DestroyMode.Gib);
SendMessage(player, msg("noDeploy", player.UserIDString));
}
}
}
}
private object OnStructureUpgrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum grade) {
if (HasPlayerFlag(player, ZoneFlags.NoUpgrade, true)) {
SendMessage(player, msg("noUpgrade", player.UserIDString));
return false;
}
return null;
}
private void OnItemDeployed(Deployer deployer, BaseEntity deployedEntity) {
BasePlayer player = deployer.GetOwnerPlayer();
if (player == null) return;
if (HasPlayerFlag(player, ZoneFlags.NoDeploy, true)) {
deployedEntity.Kill(BaseNetworkable.DestroyMode.Gib);
SendMessage(player, msg("noDeploy", player.UserIDString));
}
}
private void OnItemUse(Item item, int amount) {
BaseEntity entity = item?.parent?.entityOwner;
if (entity == null) return;
if (entity is FlameTurret || entity is AutoTurret || entity is GunTrap) {
if (EntityHasFlag(entity, ZoneFlags.InfiniteTrapAmmo)) {
item.amount += amount;
return;
}
}
if (entity is SearchLight) {
if (EntityHasFlag(entity, ZoneFlags.AlwaysLights)) {
item.amount += amount;
return;
}
Zone zone;
if (EntityHasFlag(entity, ZoneFlags.AutoLights, out zone)) {
if (zone.lightsOn) item.amount += amount;
}
}
}
private void OnRunPlayerMetabolism(PlayerMetabolism metabolism, BaseCombatEntity ownerEntity, float delta) {
BasePlayer player = ownerEntity as BasePlayer;
if (player == null) return;
if (metabolism.bleeding.value > 0 && HasPlayerFlag(player, ZoneFlags.NoBleed, false)) metabolism.bleeding.value = 0f;
if (metabolism.oxygen.value < 1 && HasPlayerFlag(player, ZoneFlags.NoDrown, false)) metabolism.oxygen.value = 1;
}
private object OnPlayerChat(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
if (player == null) return null;
if (HasPlayerFlag(player, ZoneFlags.NoChat, true)) {
SendMessage(player, msg("noChat", player.UserIDString));
return false;
}
return null;
}
private object OnServerCommand(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
if (player == null || arg.cmd?.Name == null) return null;
if (arg.cmd.Name == "kill" && HasPlayerFlag(player, ZoneFlags.NoSuicide, false)) {
SendMessage(player, msg("noSuicide", player.UserIDString));
return false;
}
return null;
}
private void OnPlayerDisconnected(BasePlayer player) {
if (HasPlayerFlag(player, ZoneFlags.KillSleepers, true)) {
player.Die();
return;
}
if (HasPlayerFlag(player, ZoneFlags.EjectSleepers, true)) {
HashSet<Zone> zones;
if (!playerZones.TryGetValue(player, out zones) || zones.Count == 0) return;
foreach (Zone zone in zones) {
if (HasZoneFlag(zone, ZoneFlags.EjectSleepers)) {
EjectPlayer(zone, player);
return;
}
}
}
}
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitinfo) {
if (entity == null || entity.GetComponent<ResourceDispenser>() != null) return;
BasePlayer attacker = hitinfo.InitiatorPlayer;
BasePlayer victim = entity as BasePlayer;
if (victim != null) {
if (hitinfo.damageTypes.GetMajorityDamageType() == DamageType.Fall) {
if (HasPlayerFlag(victim, ZoneFlags.NoFallDamage, false)) {
CancelDamage(hitinfo);
return;
}
}
if (victim.IsSleeping() && HasPlayerFlag(victim, ZoneFlags.SleepGod, false)) {
CancelDamage(hitinfo);
return;
}
else if (attacker != null) {
//if (attacker.userID < 76560000000000000L || attacker.IsNpc)
// return;
if (HasPlayerFlag(victim, ZoneFlags.PvpGod, false) && !victim.IsNpc) {
if (attacker == victim && hitinfo.damageTypes.GetMajorityDamageType() == DamageType.Suicide && !HasPlayerFlag(victim, ZoneFlags.NoSuicide, false)) return;
CancelDamage(hitinfo);
return;
}
else if (HasPlayerFlag(attacker, ZoneFlags.PvpGod, false) && !attacker.IsNpc) {
CancelDamage(hitinfo);
return;
}
}
else if (HasPlayerFlag(victim, ZoneFlags.PveGod, false)) {
CancelDamage(hitinfo);
return;
}
else if (hitinfo.Initiator is FireBall && HasPlayerFlag(victim, ZoneFlags.PvpGod, false)) CancelDamage(hitinfo);
return;
}
BaseNpc baseNpc = entity as BaseNpc;
if (baseNpc != null) {
HashSet<Zone> zones;
if (!npcZones.TryGetValue(baseNpc, 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)) {
ResourceDispenser resource = entity.GetComponent<ResourceDispenser>();
HashSet<Zone> zones;
if (!entityZones.TryGetValue(entity, out zones) && (resource == null || !resourceZones.TryGetValue(resource, out zones))) return;
foreach (Zone 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) {
BaseEntity entity = networkable as BaseEntity;
if (entity == null) return;
ResourceDispenser resource = entity.GetComponent<ResourceDispenser>();
if (resource != null) {
HashSet<Zone> zones;
if (resourceZones.TryGetValue(resource, out zones)) OnResourceExitZone(null, resource, true);
return;
}
BasePlayer player = entity as BasePlayer;
if (player != null) {
HashSet<Zone> zones;
if (playerZones.TryGetValue(player, out zones)) OnPlayerExitZone(null, player, true);
return;
}
BaseNpc npc = entity as BaseNpc;
if (npc != null) {
HashSet<Zone> zones;
if (npcZones.TryGetValue(npc, out zones)) OnNpcExitZone(null, npc, true);
return;
}
BaseCombatEntity building = entity as BaseCombatEntity;
if (building != null && !(entity is LootContainer) && !(entity is BaseHelicopter)) {
HashSet<Zone> zones;
if (entityZones.TryGetValue(building, out zones)) OnEntityExitZone(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 (Zone 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) {
BuildingBlock block = (BuildingBlock)entity;
foreach (Zone zone in zoneObjects.Values) {
if (zone.OnBuildingBlockEnter(block)) {
if (HasZoneFlag(zone, ZoneFlags.NoStability) && !CanBypass(block.OwnerID, ZoneFlags.NoStability)) block.grounded = true;
}
}
}
else if (entity is LootContainer || entity is JunkPile || entity is BaseNpc || entity is WorldItem || entity is DroppedItem || entity is DroppedItemContainer) timer.In(2, () => CheckSpawnedEntity(entity));
}
private object CanBeWounded(BasePlayer player, HitInfo hitinfo) => HasPlayerFlag(player, ZoneFlags.NoWounded, false) ? (object)false : null;
private object CanUpdateSign(BasePlayer player, Signage sign) {
if (HasPlayerFlag(player, ZoneFlags.NoSignUpdates, false)) {
SendMessage(player, msg("noSignUpdates", player.UserIDString));
return false;
}
return null;
}
private object OnOvenToggle(BaseOven oven, BasePlayer player) {
if (HasPlayerFlag(player, ZoneFlags.NoOvenToggle, false)) {
SendMessage(player, msg("noOvenToggle", player.UserIDString));
return false;
}
return null;
}
private object CanUseVending(BasePlayer player, VendingMachine machine) {
if (HasPlayerFlag(player, ZoneFlags.NoVending, false)) {
SendMessage(player, msg("noVending", player.UserIDString));
return false;
}
return null;
}
private object CanHideStash(BasePlayer player, StashContainer stash) {
if (HasPlayerFlag(player, ZoneFlags.NoStash, false)) {
SendMessage(player, msg("noStash", player.UserIDString));
return false;
}
return null;
}
private object CanCraft(ItemCrafter itemCrafter, ItemBlueprint bp, int amount) {
BasePlayer player = itemCrafter.GetComponent<BasePlayer>();
if (player != null) {
if (HasPlayerFlag(player, ZoneFlags.NoCraft, false)) {
SendMessage(player, msg("noCraft", player.UserIDString));
return false;
}
}
return null;
}
private void OnDoorOpened(Door door, BasePlayer player) {
if (HasPlayerFlag(player, ZoneFlags.NoDoorAccess, false)) {
SendMessage(player, msg("noDoor", player.UserIDString));
door.CloseRequest();
}
}
#region Looting Hooks
private object CanLootPlayer(BasePlayer target, BasePlayer looter) => OnLootPlayerInternal(looter, target);
private void OnLootPlayer(BasePlayer looter, BasePlayer target) => OnLootPlayerInternal(looter, target);
private object OnLootPlayerInternal(BasePlayer looter, BasePlayer target) {
if (HasPlayerFlag(looter, ZoneFlags.NoPlayerLoot, false) || (target != null && HasPlayerFlag(target, ZoneFlags.NoPlayerLoot, false))) {
SendMessage(looter, msg("noLoot", looter.UserIDString));
NextTick(looter.EndLooting);
return false;
}
return null;
}
private void OnLootEntity(BasePlayer player, BaseEntity entity) {
if (entity is LootableCorpse) OnLootCorpse(entity as LootableCorpse, player);
if (entity is DroppedItemContainer) OnLootContainer(entity as DroppedItemContainer, player);
if (entity is StorageContainer) OnLootInternal(player, ZoneFlags.NoBoxLoot);
}
private object CanLootEntity(BasePlayer player, LootableCorpse corpse) {
if (corpse.playerSteamID == player.userID && HasPlayerFlag(player, ZoneFlags.LootSelf, false)) return null;
return CanLootInternal(player, ZoneFlags.NoPlayerLoot);
}
private void OnLootCorpse(LootableCorpse corpse, BasePlayer player) {
if (corpse.playerSteamID == player.userID && HasPlayerFlag(player, ZoneFlags.LootSelf, false)) return;
OnLootInternal(player, ZoneFlags.NoPlayerLoot);
}
private void OnLootContainer(DroppedItemContainer container, BasePlayer player) {
if (container.playerSteamID == player.userID && HasPlayerFlag(player, ZoneFlags.LootSelf, false)) return;
OnLootInternal(player, ZoneFlags.NoPlayerLoot);
}
private object CanLootEntity(BasePlayer player, DroppedItemContainer container) {
if (container.playerSteamID == player.userID && HasPlayerFlag(player, ZoneFlags.LootSelf, false)) return null;
return CanLootInternal(player, ZoneFlags.NoPlayerLoot);
}
private object CanLootEntity(BasePlayer player, StorageContainer container) => CanLootInternal(player, ZoneFlags.NoBoxLoot);
private object CanLootInternal(BasePlayer player, ZoneFlags flag) {
if (HasPlayerFlag(player, flag, false)) {
SendMessage(player, msg("noLoot", player.UserIDString));
return false;
}
return null;
}
private void OnLootInternal(BasePlayer player, ZoneFlags flag) {
if (HasPlayerFlag(player, flag, false)) {
SendMessage(player, msg("noLoot", player.UserIDString));
NextTick(player.EndLooting);
}
}
#endregion
#region Pickup Hooks
private object CanPickupEntity(BasePlayer player, BaseCombatEntity entity) => CanPickupInternal(player, ZoneFlags.NoEntityPickup);
private object CanPickupLock(BasePlayer player, BaseLock baseLock) => CanPickupInternal(player, ZoneFlags.NoEntityPickup);
private object OnItemPickup(Item item, BasePlayer player) => CanPickupInternal(player, ZoneFlags.NoPickup);
private object CanPickupInternal(BasePlayer player, ZoneFlags flag) {
if (HasPlayerFlag(player, flag, false)) {
SendMessage(player, msg("noPickup", player.UserIDString));
return false;
}
return null;
}
#endregion
#region Gather Hooks
private object CanLootEntity(ResourceContainer container, BasePlayer player) => OnGatherInternal(player);
private object OnCollectiblePickup(Item item, BasePlayer player) => OnGatherInternal(player);
private object OnCropGather(PlantEntity plant, Item item, BasePlayer player) => OnGatherInternal(player);
private object OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item) => OnGatherInternal(entity?.ToPlayer());
private object OnGatherInternal(BasePlayer player) {
if (player != null) {
if (HasPlayerFlag(player, ZoneFlags.NoGather, false)) {
SendMessage(player, msg("noGather", player.UserIDString));
return false;
}
}
return null;
}
#endregion
#region Targeting Hooks
private object OnTurretTarget(AutoTurret turret, BaseCombatEntity entity) => OnTargetPlayerInternal(entity?.ToPlayer(), ZoneFlags.NoTurretTargeting);
private object CanBradleyApcTarget(BradleyAPC apc, BaseEntity entity) => OnTargetPlayerInternal(entity?.ToPlayer(), ZoneFlags.NoAPCTargeting);
private object CanHelicopterTarget(PatrolHelicopterAI heli, BasePlayer player) {
if (HasPlayerFlag(player, ZoneFlags.NoHeliTargeting, false)) {
heli.interestZoneOrigin = heli.GetRandomPatrolDestination();
return false;
}
return null;
}
private object CanHelicopterStrafeTarget(PatrolHelicopterAI heli, BasePlayer player) => OnTargetPlayerInternal(player, ZoneFlags.NoHeliTargeting);
private object OnHelicopterTarget(HelicopterTurret turret, BaseCombatEntity entity) => OnTargetPlayerInternal(entity?.ToPlayer(), ZoneFlags.NoHeliTargeting);
private object OnNpcPlayerTarget(NPCPlayerApex npcPlayer, BaseEntity entity) => OnTargetPlayerInternal(entity?.ToPlayer(), ZoneFlags.NoNPCTargeting);
private object OnTargetPlayerInternal(BasePlayer player, ZoneFlags flag) {
if (player != null) {
if (HasPlayerFlag(player, flag, false)) return false;
}
return null;
}
#endregion
#region Additional KillSleeper Checks
private void OnPlayerSleep(BasePlayer player) {
if (player == null) return;
player.Invoke(() => KillSleepingPlayer(player), 5f);
}
private void KillSleepingPlayer(BasePlayer player) {
if (player == null || !player.IsSleeping()) return;
if (HasPlayerFlag(player, ZoneFlags.KillSleepers, true)) {
if (player.IsConnected) OnPlayerSleep(player);
else player.Die();
}
}
#endregion
#endregion
#region Zone Management
#region Zone Component
public class Zone : MonoBehaviour {
public Definition definition;
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> entities = new HashSet<BaseCombatEntity>();
private List<TriggerBase> triggers = new List<TriggerBase>();
public bool lightsOn;
private SphereCollider sphereCollider;
private BoxCollider boxCollider;
#region Initialization
private void Awake() {
gameObject.layer = (int)Layer.Reserved1;
gameObject.name = "Zone Manager";
enabled = false;
Rigidbody rigidbody = gameObject.AddComponent<Rigidbody>();
rigidbody.useGravity = false;
rigidbody.isKinematic = true;
rigidbody.detectCollisions = true;
rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;
}
private void OnDestroy() {
Cleanup();
if (instance != null) instance.OnZoneDestroy(this);
Destroy(gameObject);
}
private void Cleanup() {
if (IsInvoking(CheckEntities)) CancelInvoke(CheckEntities);
if (IsInvoking(CheckAlwaysLights)) CancelInvoke(CheckAlwaysLights);
if (IsInvoking(CheckLights)) CancelInvoke(CheckLights);
foreach (TriggerBase trigger in triggers) {
if (trigger.gameObject.name.StartsWith("Trigger")) Destroy(trigger.gameObject);
else Destroy(trigger);
}
triggers.Clear();
}
public void SetInfo(Definition definition) {
this.definition = definition;
Cleanup();
InitializeZone(definition.Enabled);
}
public void InitializeZone(bool active) {
if (definition == null) return;
gameObject.name = $"Zone Manager({definition.Id})";
transform.position = definition.Location;
transform.rotation = Quaternion.Euler(definition.Rotation);
UpdateCollider();
RegisterPermission();
InitializeAutoLights();
InitializeRadiation();
InitializeComfort();
InitializeTemperature();
FindBuildings();
SetZoneStatus(active);
}
private void UpdateCollider() {
sphereCollider = gameObject.GetComponent<SphereCollider>();
boxCollider = gameObject.GetComponent<BoxCollider>();
if (definition.Size != Vector3.zero) {
if (sphereCollider != null) Destroy(sphereCollider);
if (boxCollider == null) {
boxCollider = gameObject.AddComponent<BoxCollider>();
boxCollider.isTrigger = true;
}
boxCollider.size = definition.Size;
}
else {
if (boxCollider != null) Destroy(boxCollider);
if (sphereCollider == null) {
sphereCollider = gameObject.AddComponent<SphereCollider>();
sphereCollider.isTrigger = true;
}
sphereCollider.radius = definition.Radius;
}
}
private void RegisterPermission() {
if (!string.IsNullOrEmpty(definition.Permission) && !instance.permission.PermissionExists(definition.Permission)) instance.permission.RegisterPermission(definition.Permission, instance);
}
private void InitializeAutoLights() {
if (HasZoneFlag(ZoneFlags.AlwaysLights)) {
if (IsInvoking(CheckAlwaysLights)) CancelInvoke(CheckAlwaysLights);
InvokeRepeating(CheckAlwaysLights, 5f, 60f);
}
else if (HasZoneFlag(ZoneFlags.AutoLights)) {
float 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 FindBuildings() {
int entities = definition.Size != Vector3.zero ? Physics.OverlapBoxNonAlloc(definition.Location, definition.Size / 2, colBuffer, Quaternion.Euler(definition.Rotation)) : Physics.OverlapSphereNonAlloc(definition.Location, definition.Radius, colBuffer);
for (var i = 0; i < entities; i++) {
MeshColliderBatch colliderBatch = colBuffer[i].GetComponent<MeshColliderBatch>();
colBuffer[i] = null;
if (colliderBatch == null) continue;
List<MeshColliderLookup.LookupEntry> colliders = colliderBatch.meshLookup.src.data;
Bounds bounds = gameObject.GetComponent<Collider>().bounds;
foreach (MeshColliderLookup.LookupEntry lookupEntry in colliders) {
if (lookupEntry.collider && lookupEntry.collider.bounds.Intersects(bounds) && lookupEntry.collider.gameObject.GetComponentInParent<BuildingBlock>()) {
OnColliderEnterZone(lookupEntry.collider);
}
}
}
}
#region Create Effect Triggers
private void InitializeRadiation() {
if (definition.Radiation > 0) {
GameObject radiationObject = gameObject;
if (definition.Size != Vector3.zero) {
radiationObject = new GameObject();
radiationObject.name = $"Trigger Radiation {definition.Id}";
radiationObject.transform.position = gameObject.transform.position;
SphereCollider collider = radiationObject.AddComponent<SphereCollider>();
collider.radius = definition.Radius;
collider.isTrigger = true;
}
TriggerRadiation radiation = radiationObject.GetComponent<TriggerRadiation>() ?? radiationObject.AddComponent<TriggerRadiation>();
radiation.RadiationAmountOverride = definition.Radiation;
radiation.radiationSize = definition.Radius;
radiation.interestLayers = playersMask;
radiation.enabled = true;
if (!triggers.Contains(radiation)) triggers.Add(radiation);
}
}
private void InitializeComfort() {
if (definition.Comfort > 0) {
GameObject comfortObject = gameObject;
if (definition.Size != Vector3.zero) {
comfortObject = new GameObject();
comfortObject.name = $"Trigger Comfort {definition.Id}";
comfortObject.transform.position = gameObject.transform.position;
SphereCollider collider = comfortObject.AddComponent<SphereCollider>();
collider.radius = definition.Radius;
collider.isTrigger = true;
}
TriggerComfort comfort = comfortObject.GetComponent<TriggerComfort>() ?? comfortObject.AddComponent<TriggerComfort>();
comfort.baseComfort = definition.Comfort;
comfort.triggerSize = definition.Radius;
comfort.interestLayers = playersMask;
comfort.enabled = true;
if (!triggers.Contains(comfort)) triggers.Add(comfort);
}
}
private void InitializeTemperature() {
if (definition.Temperature != 0) {
GameObject temperatureObject = gameObject;
if (definition.Size != Vector3.zero) {
temperatureObject = new GameObject();
temperatureObject.name = $"Trigger Temperature {definition.Id}";
temperatureObject.transform.position = gameObject.transform.position;
SphereCollider collider = temperatureObject.AddComponent<SphereCollider>();
collider.radius = definition.Radius;
collider.isTrigger = true;
}
TriggerTemperature temperature = temperatureObject.GetComponent<TriggerTemperature>() ?? temperatureObject.AddComponent<TriggerTemperature>();
temperature.Temperature = definition.Temperature;
temperature.triggerSize = definition.Radius;
temperature.interestLayers = playersMask;
temperature.enabled = true;
if (!triggers.Contains(temperature)) triggers.Add(temperature);
}
}
#endregion
private void SetZoneStatus(bool active) {
if (active) {
if (!IsInvoking(CheckEntities)) InvokeRandomized(CheckEntities, 1f, 5f, 1f);
gameObject.SetActive(true);
}
else {
if (IsInvoking(CheckEntities)) CancelInvoke(CheckEntities);
if (IsInvoking(CheckAlwaysLights)) CancelInvoke(CheckAlwaysLights);
if (IsInvoking(CheckLights)) CancelInvoke(CheckLights);
foreach (TriggerBase trigger in triggers) {
foreach (BasePlayer player in players) player.LeaveTrigger(trigger);
Destroy(trigger);
}
triggers.Clear();
gameObject.SetActive(false);
}
}
#endregion
#region InvokeHandler
private bool IsInvoking(Action action) => InvokeHandler.IsInvoking(this, action);
private void Invoke(Action action, float time) => InvokeHandler.Invoke(this, action, time);
private void InvokeRepeating(Action action, float time, float repeat) => InvokeHandler.InvokeRepeating(this, action, time, repeat);
private void InvokeRandomized(Action action, float time, float repeat, float random) => InvokeHandler.InvokeRandomized(this, action, time, repeat, random);
private void CancelInvoke(Action action) => InvokeHandler.CancelInvoke(this, action);
#endregion
#region Flag Monitoring
private bool HasZoneFlag(ZoneFlags flag) => ((disabledFlags & flag) == flag) ? false : (definition.Flags & ~disabledFlags & flag) == flag;
private void CheckLights() {
float currentTime = GetSkyHour();
if (currentTime > instance.AutolightOffTime && currentTime < instance.AutolightOnTime) {
if (!lightsOn) return;
foreach (var building in entities) {
BaseOven oven = building as BaseOven;
if (oven != null && !oven.IsInvoking(oven.Cook)) {
oven.SetFlag(BaseEntity.Flags.On, false);
continue;
}
Door door = building as Door;
if (door != null && door.PrefabName.Contains("shutter")) {
door.SetFlag(BaseEntity.Flags.Open, true);
continue;
}
SearchLight searchLight = building as SearchLight;
if (searchLight != null) UpdateSearchlight(searchLight, false);
}
foreach (var player in players) {
if (player.userID >= 76560000000000000L || player.inventory?.containerWear?.itemList == null) continue;
List<Item> 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 entities) {
BaseOven oven = building as BaseOven;
if (oven != null && !oven.IsInvoking(oven.Cook)) {
oven.SetFlag(BaseEntity.Flags.On, true);
continue;
}
Door door = building as Door;
if (door != null && door.PrefabName.Contains("shutter")) {
door.SetFlag(BaseEntity.Flags.Open, false);
continue;
}
SearchLight searchLight = building as SearchLight;
if (searchLight != null) UpdateSearchlight(searchLight, true);
}
ItemDefinition fuel = ItemManager.FindItemDefinition("lowgradefuel");
foreach (BasePlayer player in players) {
if (player.userID >= 76560000000000000L || player.inventory?.containerWear?.itemList == null) continue;
// only npc
List<Item> 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();
Item[] array = item.contents.itemList.ToArray();
for (var i = 0; i < array.Length; i++) array[i].Remove(0f);
Item newItem = ItemManager.Create(fuel, 100);
newItem.MoveToContainer(item.contents);
item.SwitchOnOff(true, player);
player.inventory.ServerUpdate(0f);
break;
}
}
lightsOn = true;
}
}
private void CheckAlwaysLights() {
foreach (BaseCombatEntity building in entities) {
BaseOven oven = building as BaseOven;
if (oven != null && !oven.IsInvoking(oven.Cook)) oven.SetFlag(BaseEntity.Flags.On, true);
SearchLight searchLight = building as SearchLight;
if (searchLight != null) UpdateSearchlight(searchLight, true);
}
}
private void UpdateSearchlight(SearchLight searchLight, bool isOn) {
if (isOn) {
Item slot = searchLight.inventory.GetSlot(0);
if (slot == null || slot.info != searchLight.inventory.onlyAllowedItem) {
searchLight.inventory.Clear();
Item item = ItemManager.Create(searchLight.fuelType);
item.MoveToContainer(searchLight.inventory);
}
if (!searchLight.IsOn()) {
searchLight.SetFlag(BaseEntity.Flags.On, true, false);
searchLight.FuelUpdate();
}
}
else searchLight.SetFlag(BaseEntity.Flags.On, false, false);
}
public void OnEntityKill(BaseCombatEntity entity) {
BasePlayer player = entity as BasePlayer;
if (player != null) players.Remove(player);
else if (entity != null && !(entity is LootContainer) && !(entity is BaseHelicopter) && !(entity is BaseNpc)) entities.Remove(entity);
}
#endregion
#region Trigger Detection
// Need something better then this, it is required to detect when a player is teleported out of the zone and put to sleep since the BasePlayer.Sleep() method destroys the players RigidBody thus making the players exit from the zone undetectable by any trigger/collision messages...private void CheckEntities()
{
HashSet<BasePlayer> oldPlayers = players;
players = new HashSet<BasePlayer>();
int entities = definition.Size != Vector3.zero ? Physics.OverlapBoxNonAlloc(definition.Location, definition.Size / 2, colBuffer, Quaternion.Euler(definition.Rotation), playersMask) : Physics.OverlapSphereNonAlloc(definition.Location, definition.Radius, colBuffer, playersMask);
for (var i = 0; i < entities; i++) {
BasePlayer player = colBuffer[i].GetComponentInParent<BasePlayer>();
colBuffer[i] = null;
if (player != null) {
if (players.Add(player) && !oldPlayers.Contains(player)) instance.OnPlayerEnterZone(this, player);
}
}
foreach (BasePlayer player in oldPlayers) {
if (!players.Contains(player)) instance.OnPlayerExitZone(this, player);
}
}
private void OnTriggerEnter(Collider col) {
BasePlayer player = col.GetComponent<BasePlayer>();
if (player != null) {
OnPlayerEnter(player);
return;
}
else if (!col.transform.CompareTag("MeshColliderBatch")) OnColliderEnterZone(col);
//else
//{
// //MeshColliderBatch colliderBatch = col.GetComponent<MeshColliderBatch>();
// //if (colliderBatch == null)
// // return;
// //var colliders = colliderBatch.meshLookup.src.data;
// //Bounds bounds = gameObject.GetComponent<Collider>().bounds;
// //foreach (var instance in colliders)
// //{
// // if (instance.collider && instance.collider.bounds.Intersects(bounds))
// // OnColliderEnterZone(instance.collider);
// //}
//}
}
private void OnColliderEnterZone(Collider col) {
BaseEntity entity = col.GetComponentInParent<BaseEntity>();
if (entity == null) return;
ResourceDispenser resourceDispenser = col.GetComponentInParent<ResourceDispenser>();
if (resourceDispenser != null) {
instance.OnResourceEnterZone(this, resourceDispenser);
return;
}
BaseCombatEntity baseCombatEntity = entity as BaseCombatEntity;
if (baseCombatEntity != null) {
if (HasZoneFlag(ZoneFlags.NoDecay)) {
DecayEntity decayEntity = col.GetComponentInParent<DecayEntity>();
if (decayEntity != null) decayEntity.decay = null;
}
BaseNpc npc = baseCombatEntity as BaseNpc;
if (npc != null) {
instance.OnNpcEnterZone(this, npc);
return;
}
if (!(baseCombatEntity is LootContainer) && !(baseCombatEntity is BaseHelicopter)) {
entities.Add(baseCombatEntity);
instance.OnEntityEnterZone(this, baseCombatEntity);
}
}
else instance.OnOtherEnterZone(this, entity);
}
private void OnTriggerExit(Collider col) {
BasePlayer player = col.GetComponent<BasePlayer>();
if (player != null) {
OnPlayerExit(player);
return;
}
else if(!col.transform.CompareTag("MeshColliderBatch")) OnColliderExitZone(col);
//else
//{
// //MeshColliderBatch colliderBatch = col.GetComponent<MeshColliderBatch>();
// //if (colliderBatch == null)
// // return;
// //var colliders = colliderBatch.meshLookup.src.data;
// //Bounds bounds = gameObject.GetComponent<Collider>().bounds;
// //foreach (var instance in colliders)
// //{
// // if (instance.collider && instance.collider.bounds.Intersects(bounds))
// // OnColliderExitZone(instance.collider);
// //}
//}
}
private void OnColliderExitZone(Collider col) {
BaseEntity entity = col.GetComponentInParent<BaseEntity>();
if (entity == null) return;
ResourceDispenser resourceDispenser = col.GetComponentInParent<ResourceDispenser>();
if (resourceDispenser != null) {
instance.OnResourceExitZone(this, resourceDispenser);
return;
}
BaseCombatEntity baseCombatEntity = entity as BaseCombatEntity;
if (baseCombatEntity != null) {
DecayEntity decayEntity = col.GetComponentInParent<DecayEntity>();
if (decayEntity != null && decayEntity.decay == null) decayEntity.decay = PrefabAttribute.server.Find<Decay>(decayEntity.prefabID);
BaseNpc npc = baseCombatEntity as BaseNpc;
if (npc != null) {
instance.OnNpcExitZone(this, npc);
return;
}
if (!(baseCombatEntity is LootContainer) && !(baseCombatEntity is BaseHelicopter)) {
entities.Remove(baseCombatEntity);
instance.OnEntityExitZone(this, baseCombatEntity);
return;
}
}
instance.OnOtherExitZone(this, entity);
}
private void OnPlayerEnter(BasePlayer player) {
if (player == null) return;
if (players.Add(player)) {
instance.OnPlayerEnterZone(this, player);
if (definition.Size != Vector3.zero) {
foreach (TriggerBase trigger in triggers) {
if (trigger != null) {
if (trigger.entityContents == null) trigger.entityContents = new HashSet<BaseEntity>();
if (!trigger.entityContents.Contains(player)) player.EnterTrigger(trigger);
}
}
}
}
}
private void OnPlayerExit(BasePlayer player) {
if (player == null) return;
if (players.Remove(player)) {
instance.OnPlayerExitZone(this, player);
if (definition.Size != Vector3.zero) {
foreach (TriggerBase trigger in triggers) {
if (trigger != null) {
if (trigger.entityContents == null) return;
if (!trigger.entityContents.Contains(player)) player.EnterTrigger(trigger);
}
// ... [Code preview truncated due to length. Full source in attached file] ...