using System; using System.Collections.Generic; using UnityEngine; namespace Oxide.Plugins { [Info("EventRF", "skavi", "1.1.1")] [Description("Broadcasts on RF frequencies while events are active")] class EventRF : RustPlugin { private const int SMALL_OIL_RIG_FREQUENCY = 4765; private const int LARGE_OIL_RIG_FREQUENCY = 4768; private const string CONFIG_CARGO_SHIP_ENABLED = "Cargo ship RF enabled"; private const string CONFIG_CARGO_SHIP_FREQ = "Cargo ship RF frequency"; private const string CONFIG_CARGO_PLANE_ENABLED = "Cargo plane RF enabled"; private const string CONFIG_CARGO_PLANE_FREQ = "Cargo plane RF frequency"; private const string CONFIG_CHINOOK_ENABLED = "CH47 helicopter RF enabled"; private const string CONFIG_CHINOOK_FREQ = "CH47 helicopter RF frequency"; private const string CONFIG_BRADLEY_ENABLED = "Bradley APC RF enabled"; private const string CONFIG_BRADLEY_FREQ = "Bradley APC RF frequency"; private const string CONFIG_PATROL_HELI_ENABLED = "Patrol helicopter RF enabled"; private const string CONFIG_PATROL_HELI_FREQ = "Patrol helicopter RF frequency"; private const int DEFAULT_CARGO_SHIP_FREQ = 4785; private const int DEFAULT_CARGO_PLANE_FREQ = 4786; private const int DEFAULT_CHINOOK_FREQ = 4787; private const int DEFAULT_BRADLEY_FREQ = 4788; private const int DEFAULT_PATROL_HELI_FREQ = 4789; private const string MSG_INVALID_SYNTAX = "invalid syntax"; private const string MSG_LIST_USAGE = "list usage"; private const string MSG_CARGO_SHIP_FREQ = "cargo ship frequency"; private const string MSG_CARGO_PLANE_FREQ = "cargo plane frequency"; private const string MSG_CHINOOK_FREQ = "ch47 helicopter frequency"; private const string MSG_BRADLEY_FREQ = "bradley apc frequency"; private const string MSG_PATROL_HELI_FREQ = "patrol heli frequency"; private bool cargoShipEnabled; private int cargoShipFreq; private bool cargoPlaneEnabled; private int cargoPlaneFreq; private bool chinookEnabled; private int chinookFreq; private bool bradleyEnabled; private int bradleyFreq; private bool patrolHeliEnabled; private int patrolHeliFreq; private List broadcasters = new List(); private bool timerLooping = false; #region Hooks void Init() { LoadConfig(); Config[CONFIG_CARGO_PLANE_ENABLED] = cargoPlaneEnabled = GetConfig(CONFIG_CARGO_PLANE_ENABLED, true); Config[CONFIG_CARGO_PLANE_FREQ] = cargoPlaneFreq = GetConfig(CONFIG_CARGO_PLANE_FREQ, DEFAULT_CARGO_PLANE_FREQ); Config[CONFIG_CARGO_SHIP_ENABLED] = cargoShipEnabled = GetConfig(CONFIG_CARGO_SHIP_ENABLED, true); Config[CONFIG_CARGO_SHIP_FREQ] = cargoShipFreq = GetConfig(CONFIG_CARGO_SHIP_FREQ, DEFAULT_CARGO_SHIP_FREQ); Config[CONFIG_CHINOOK_ENABLED] = chinookEnabled = GetConfig(CONFIG_CHINOOK_ENABLED, true); Config[CONFIG_CHINOOK_FREQ] = chinookFreq = GetConfig(CONFIG_CHINOOK_FREQ, DEFAULT_CHINOOK_FREQ); Config[CONFIG_BRADLEY_ENABLED] = bradleyEnabled = GetConfig(CONFIG_BRADLEY_ENABLED, true); Config[CONFIG_BRADLEY_FREQ] = bradleyFreq = GetConfig(CONFIG_BRADLEY_FREQ, DEFAULT_BRADLEY_FREQ); Config[CONFIG_PATROL_HELI_ENABLED] = patrolHeliEnabled = GetConfig(CONFIG_PATROL_HELI_ENABLED, true); Config[CONFIG_PATROL_HELI_FREQ] = patrolHeliFreq = GetConfig(CONFIG_PATROL_HELI_FREQ, DEFAULT_PATROL_HELI_FREQ); SaveConfig(); if (bradleyEnabled) { foreach (BradleyAPC e in UnityEngine.Object.FindObjectsOfType()) { handleNewBradlayInstance(e); } } if (cargoPlaneEnabled) { foreach (CargoPlane e in UnityEngine.Object.FindObjectsOfType()) { handleNewCargoPlaneInstance(e); } } if (cargoShipEnabled) { foreach (CargoShip e in UnityEngine.Object.FindObjectsOfType()) { handleNewCargoShipInstance(e); } } if (chinookEnabled) { foreach (CH47Helicopter e in UnityEngine.Object.FindObjectsOfType()) { handleNewChinookInstance(e); } } if (patrolHeliEnabled) { foreach (BaseHelicopter e in UnityEngine.Object.FindObjectsOfType()) { handleNewPatrolHelicopterInstance(e); } } } void Unload() { DestroyAll(); } protected override void LoadDefaultConfig() { Config.Clear(); Config[CONFIG_CARGO_SHIP_ENABLED] = true; Config[CONFIG_CARGO_SHIP_FREQ] = DEFAULT_CARGO_SHIP_FREQ; Config[CONFIG_CARGO_PLANE_ENABLED] = true; Config[CONFIG_CARGO_PLANE_FREQ] = DEFAULT_CARGO_PLANE_FREQ; Config[CONFIG_CHINOOK_ENABLED] = true; Config[CONFIG_CHINOOK_FREQ] = DEFAULT_CHINOOK_FREQ; Config[CONFIG_BRADLEY_ENABLED] = true; Config[CONFIG_BRADLEY_FREQ] = DEFAULT_BRADLEY_FREQ; Config[CONFIG_PATROL_HELI_ENABLED] = true; Config[CONFIG_PATROL_HELI_FREQ] = DEFAULT_PATROL_HELI_FREQ; } protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { [MSG_INVALID_SYNTAX] = "Invalid command syntax", [MSG_LIST_USAGE] = "To list frequencies type: /eventrf list", [MSG_CARGO_SHIP_FREQ] = "Cargo ship frequency is {0}", [MSG_CARGO_PLANE_FREQ] = "Cargo plane frequency is {0}", [MSG_CHINOOK_FREQ] = "CH47 helicopter frequency is {0}", [MSG_BRADLEY_FREQ] = "Bradley APC frequency is {0}", [MSG_PATROL_HELI_FREQ] = "Patrol helicopter frequency is {0}" }, this); } void OnEntitySpawned(BaseNetworkable entity) { if (entity is CargoShip) { if (cargoShipEnabled) { handleNewCargoShipInstance(entity as CargoShip); } } else if (entity is CargoPlane) { if (cargoPlaneEnabled) { handleNewCargoPlaneInstance(entity as CargoPlane); } } else if (entity is CH47Helicopter) { if (chinookEnabled) { handleNewChinookInstance(entity as CH47Helicopter); } } else if (entity is BradleyAPC) { if (bradleyEnabled) { handleNewBradlayInstance(entity as BradleyAPC); } } else if (entity is BaseHelicopter) { if (patrolHeliEnabled) { handleNewPatrolHelicopterInstance(entity as BaseHelicopter); } } } #endregion #region Commands [ChatCommand("eventrf")] private void eventRfCommand(BasePlayer player, string command, string[] args) { if (args.Length != 1) { commandSyntaxError(player); return; } if ("list".Equals(args[0])) { if (bradleyEnabled) { SendReply(player, lang.GetMessage(MSG_BRADLEY_FREQ, this, player.UserIDString), bradleyFreq); } if (cargoPlaneEnabled) { SendReply(player, lang.GetMessage(MSG_CARGO_PLANE_FREQ, this, player.UserIDString), cargoPlaneFreq); } if (cargoShipEnabled) { SendReply(player, lang.GetMessage(MSG_CARGO_SHIP_FREQ, this, player.UserIDString), cargoShipFreq); } if (chinookEnabled) { SendReply(player, lang.GetMessage(MSG_CHINOOK_FREQ, this, player.UserIDString), chinookFreq); } if (patrolHeliEnabled) { SendReply(player, lang.GetMessage(MSG_PATROL_HELI_FREQ, this, player.UserIDString), patrolHeliFreq); } } else { commandSyntaxError(player); } } private void commandSyntaxError(BasePlayer player) { SendReply(player, lang.GetMessage(MSG_INVALID_SYNTAX, this, player.UserIDString)); SendReply(player, lang.GetMessage(MSG_LIST_USAGE, this, player.UserIDString)); } #endregion #region Helpers T GetConfig(string name, T value) => Config[name] == null ? value : (T)Convert.ChangeType(Config[name], typeof(T)); private static void DestroyAll() { var l = GameObject.FindObjectsOfType(typeof(T)); if (l != null) { foreach (var o in l) { GameObject.Destroy(o); } } } #endregion private void handleNewChinookInstance(CH47Helicopter entity) { // If we don't add the first NextTick here, chinooks break. They hang in the air without moving NextTick(() => { EntityRFObject smallRigListener = entity.gameObject.AddComponent(); smallRigListener.frequency = SMALL_OIL_RIG_FREQUENCY; smallRigListener.entity = entity; RFManager.AddListener(smallRigListener.GetFrequency(), smallRigListener); EntityRFObject largeRigListener = entity.gameObject.AddComponent(); largeRigListener.frequency = LARGE_OIL_RIG_FREQUENCY; largeRigListener.entity = entity; RFManager.AddListener(largeRigListener.GetFrequency(), largeRigListener); // next tick to give listeners a chance to get signal NextTick(() => { if (!smallRigListener.ReceivingSignal && !largeRigListener.ReceivingSignal) { queueAddBroadcaster(entity, chinookFreq); } RFManager.RemoveListener(smallRigListener.GetFrequency(), smallRigListener); RFManager.RemoveListener(largeRigListener.GetFrequency(), largeRigListener); GameObject.Destroy(smallRigListener); GameObject.Destroy(largeRigListener); }); }); } private void handleNewBradlayInstance(BradleyAPC entity) { queueAddBroadcaster(entity, bradleyFreq); } private void handleNewCargoShipInstance(CargoShip entity) { queueAddBroadcaster(entity, cargoShipFreq); } private void handleNewCargoPlaneInstance(CargoPlane entity) { queueAddBroadcaster(entity, cargoPlaneFreq); } private void handleNewPatrolHelicopterInstance(BaseHelicopter entity) { queueAddBroadcaster(entity, patrolHeliFreq); } private bool entityIsValid(BaseEntity entity) { return entity != null && entity.IsValid() && entity.gameObject.activeInHierarchy; } private void queueAddBroadcaster(BaseEntity entity, int frequency) { // NextTick here so that if any other plugin kills the entity on spawn we don't broadcast for a single tick NextTick(() => { if (entityIsValid(entity)) { EntityRFObject b = entity.gameObject.AddComponent() as EntityRFObject; b.frequency = frequency; b.entity = entity; RFManager.AddBroadcaster(frequency, b); broadcasters.Add(b); if (!timerLooping) { timerLooping = true; timer.In(5, updateBroadcasters); } } }); } private void updateBroadcasters() { List activeBroadcasters = new List(); foreach (EntityRFObject b in broadcasters) { if (entityIsValid(b.GetEntity())) { activeBroadcasters.Add(b); } else { RFManager.RemoveBroadcaster(b.GetFrequency(), b); GameObject.Destroy(b); } } broadcasters = activeBroadcasters; if (broadcasters.Count == 0) { timerLooping = false; } else { timer.In(5, updateBroadcasters); } } /* * RFManager requires that IRFObjects are also BaseEntity's (2020-05-16) */ private class EntityRFObject : BaseEntity, IRFObject { public BaseEntity entity; public int frequency; public bool ReceivingSignal { get; private set; } = false; public override BaseEntity GetEntity() { return entity; } public Vector3 GetPosition() { if (entity == null || entity.ServerPosition == null) { return Vector3.zero; } else { return entity.ServerPosition; } } public float GetMaxRange() { return float.MaxValue; } public void RFSignalUpdate(bool on) { ReceivingSignal = on; } public int GetFrequency() { return frequency; } } } }