Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using Newtonsoft.Json;
- using Newtonsoft.Json.Converters;
- using Oxide.Core;
- using Oxide.Core.Libraries.Covalence;
- using Rust.Instruments;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- using static InstrumentKeyController;
- namespace Oxide.Plugins
- {
- [Info("Car Radio", "TCM420G", "1.0.3")]
- [Description("Allows players to attach radios to vehicles")]
- class CarRadio : CovalencePlugin
- {
- #region variables
- private const string PERMISSION_ATTACHRADIO = "carradio.attachcarradio";
- private const string PERMISSION_DETACHRADIO = "carradio.detachcarradio";
- private const string PERMISSION_ATTACHRADIO_GLOBAL = "carradio.attachallcarradio";
- private const string PERMISSION_DETACHRADIO_GLOBAL = "carradio.detachallcarradio";
- private const string I18N_MISSING_SIREN = "NoRadioForName";
- private const string I18N_COULD_NOT_ATTACH = "CouldNotAttach";
- private const string I18N_NOT_SUPPORTED = "NotSupported";
- private const string I18N_ATTACHED = "Attached";
- private const string I18N_ATTACHED_GLOBAL = "AttachedGlobal";
- private const string I18N_DETACHED = "Detached";
- private const string I18N_DETACHED_GLOBAL = "DetachedGlobal";
- private const string I18N_NOT_A_VEHICLE = "NotAVehicle";
- private const string I18N_RADIO = "Radios";
- private const string I18N_PLAYERS_ONLY = "PlayersOnly";
- // Initial prefabs
- private const string PREFAB_COCKPIT = "assets/content/vehicles/modularcar/module_entities/1module_cockpit.prefab";
- private const string PREFAB_COCKPIT_ARMORED = "assets/content/vehicles/modularcar/module_entities/1module_cockpit_armored.prefab";
- private const string PREFAB_COCKPIT_WITH_ENGINE = "assets/content/vehicles/modularcar/module_entities/1module_cockpit_with_engine.prefab";
- private const string PREFAB_BUTTON = "assets/prefabs/deployable/playerioents/button/button.prefab";
- private const string PREFAB_FLASHERLIGHT = null;
- private const string PREFAB_SIRENLIGHT = null;
- private const string PREFAB_RADIO = "assets/prefabs/voiceaudio/boombox/boombox.static.prefab";
- private const string PREFAB_SEDAN = "assets/content/vehicles/sedan_a/sedantest.entity.prefab";
- private const string PREFAB_MINICOPTER = "assets/content/vehicles/minicopter/minicopter.entity.prefab";
- private const string PREFAB_TRANSPORTHELI = "assets/content/vehicles/scrap heli carrier/scraptransporthelicopter.prefab";
- private const string PREFAB_RHIB = "assets/content/vehicles/boats/rhib/rhib.prefab";
- private const string PREFAB_ROWBOAT = "assets/content/vehicles/boats/rowboat/rowboat.prefab";
- private const string PREFAB_WORKCART = "assets/content/vehicles/workcart/workcart.entity.prefab";
- private const string PREFAB_WORKCART_ABOVEGROUND = "assets/content/vehicles/workcart/workcart_aboveground.entity.prefab";
- private const string PREFAB_MAGNETCRANE = "assets/content/vehicles/crane_magnet/magnetcrane.entity.prefab";
- private const string PREFAB_HORSE = "assets/rust.ai/nextai/testridablehorse.prefab";
- private const string KEY_MODULAR_CAR = "MODULAR_CAR";
- private const string DATAPATH_RADIO = "carradio/";
- // Preconfigured carradio
- private static readonly Radio SIREN_DEFAULT = new Radio("Car-Radio",
- new Dictionary<string, Attachment[]>
- {
- [PREFAB_COCKPIT] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.05f, 1.7f, 0.78f), new Vector3(210f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(-0.00f, 1.0f, -0.9f), new Vector3(180f, 180f, 180f))
- },
- [PREFAB_COCKPIT_ARMORED] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.05f, 1.7f, 0.78f), new Vector3(210f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(-0.00f, 1.0f, -0.9f), new Vector3(180f, 180f, 180f))
- },
- [PREFAB_COCKPIT_WITH_ENGINE] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.05f, 1.7f, 0.78f), new Vector3(210f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(-0.00f, 1.0f, -0.9f), new Vector3(180f, 180f, 180f))
- }
- },
- new Dictionary<string, Attachment[]>
- {
- [PREFAB_SEDAN] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.0f, 2.05f, 1.9f), new Vector3(210f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 0.55f, 1.7f), new Vector3(0f, 180f, 0f))
- },
- [PREFAB_MINICOPTER] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(-0.2f, 2.0f, 0.91f), new Vector3(180f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 0.700f, -0.1f), new Vector3(0f, 0f, 0f))
- },
- [PREFAB_TRANSPORTHELI] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(-0.1f, 2.68f, 3.865f), new Vector3(205f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 0.55f, 3.6f), new Vector3(0f, 180f, 0f))
- },
- [PREFAB_RHIB] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(-0.0f, 3.4f, 0.60f), new Vector3(180f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 2.83f, 0.62f), new Vector3(0f, 180f, 0f))
- },
- [PREFAB_ROWBOAT] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(-1.7f, 0.5f, -1.8f), new Vector3(270f, 270f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 0.8f, 2.18f), new Vector3(0f, 180f, 0f))
- },
- [PREFAB_WORKCART] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.19f, 3.13f, 4.95f), new Vector3(235f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.49f, 1.53f, 3.95f), new Vector3(0f, 180f, 0f))
- },
- [PREFAB_WORKCART_ABOVEGROUND] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.19f, 3.13f, 4.95f), new Vector3(235f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.49f, 1.53f, 3.95f), new Vector3(0f, 180f, 0f))
- },
- [PREFAB_MAGNETCRANE] = new Attachment[] {
- new Attachment(PREFAB_FLASHERLIGHT, new Vector3(-0.95f, 4.25f, 0.5f))
- }
- }, new Tone(Notes.A, NoteType.Regular, 4, 1f), new Tone(Notes.D, NoteType.Regular, 5, 1f));
- private static readonly Radio SIREN_SILENT = new Radio("test-radio",
- new Dictionary<string, Attachment[]>
- {
- [PREFAB_COCKPIT] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.05f, 1.7f, 0.78f), new Vector3(210f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(-0.00f, 1.0f, -0.9f), new Vector3(180f, 180f, 180f))
- },
- [PREFAB_COCKPIT_ARMORED] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.05f, 1.7f, 0.78f), new Vector3(210f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(-0.00f, 1.0f, -0.9f), new Vector3(180f, 180f, 180f))
- },
- [PREFAB_COCKPIT_WITH_ENGINE] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.05f, 1.7f, 0.78f), new Vector3(210f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(-0.00f, 1.0f, -0.9f), new Vector3(180f, 180f, 180f))
- }
- },
- new Dictionary<string, Attachment[]>
- {
- [PREFAB_SEDAN] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.0f, 2.05f, 1.9f), new Vector3(210f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 0.55f, 3.6f), new Vector3(0f, 180f, 0f))
- },
- [PREFAB_MINICOPTER] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(-0.1f, 2.0f, 1.0f), new Vector3(180f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 0.700f, -0.1f), new Vector3(0f, 0f, 0f))
- },
- [PREFAB_TRANSPORTHELI] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(-0.1f, 2.68f, 3.865f), new Vector3(205f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 0.55f, 3.6f), new Vector3(0f, 180f, 0f))
- },
- [PREFAB_RHIB] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(-0.0f, 3.4f, 0.60f), new Vector3(180f, 0f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 2.83f, 0.62f), new Vector3(0f, 180f, 0f))
- },
- [PREFAB_ROWBOAT] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(-1.7f, 0.5f, -1.8f), new Vector3(270f, 270f, 0f)),
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 0.8f, 2.18f), new Vector3(0f, 180f, 0f))
- },
- [PREFAB_WORKCART] = new Attachment[] {
- new Attachment(PREFAB_BUTTON, new Vector3(0.19f, 3.13f, 4.95f), new Vector3(235f, 0f, 0f))
- },
- [PREFAB_MAGNETCRANE] = new Attachment[] {
- new Attachment(PREFAB_FLASHERLIGHT, new Vector3(-0.95f, 4.25f, 0.5f))
- },
- [PREFAB_HORSE] = new Attachment[] {
- new Attachment(PREFAB_RADIO, new Vector3(0.0f, 1.7f, 1.2f), new Vector3(25f, 0f, 0f), "head")
- }
- });
- #endregion variables
- #region data
- private class DataContainer
- {
- // Map BaseVehicle.net.ID -> RadioInfos
- public Dictionary<uint, VehicleContainer> VehicleRadioMap = new Dictionary<uint, VehicleContainer>();
- }
- private class VehicleContainer
- {
- public string RadioName = SIREN_DEFAULT.Name;
- public RadioController.States State = RadioController.States.OFF;
- public HashSet<uint> NetIDs = new HashSet<uint>();
- public VehicleContainer()
- {
- }
- public VehicleContainer(string aRadioName, RadioController.States aState, IEnumerable<uint> someNetIDs)
- {
- RadioName = aRadioName;
- State = aState;
- NetIDs.UnionWith(someNetIDs);
- }
- }
- #endregion data
- #region configuration
- private Configuration config;
- private IDictionary<string, Radio> RadioDictionary { get; } = new Dictionary<string, Radio>();
- private class Configuration
- {
- [JsonProperty("MountNeeded")]
- public bool MountNeeded = true;
- [JsonProperty("SoundEnabled")]
- public bool SoundEnabled = true;
- [JsonProperty("RadioSpawnProbability")]
- public Dictionary<string, float> RadioSpawnProbability = new Dictionary<string, float>
- {
- [KEY_MODULAR_CAR] = 0f,
- [PREFAB_HORSE] = 0f,
- [PREFAB_MINICOPTER] = 0f,
- [PREFAB_SEDAN] = 0f,
- [PREFAB_TRANSPORTHELI] = 0f
- };
- [JsonConverter(typeof(StringEnumConverter))]
- [JsonProperty("DefaultState")]
- public RadioController.States DefaultState = RadioController.States.OFF;
- public string ToJson() => JsonConvert.SerializeObject(this);
- public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
- }
- private class Tone
- {
- public Tone(Notes aNote = Notes.A, NoteType aNoteType = NoteType.Regular, int anOctave = 4, float aDuration = 1f)
- {
- Note = aNote;
- NoteType = aNoteType;
- Octave = anOctave;
- Duration = aDuration;
- }
- [JsonConverter(typeof(StringEnumConverter))]
- [JsonProperty("Note")]
- public Notes Note;
- [JsonConverter(typeof(StringEnumConverter))]
- [JsonProperty("NoteType")]
- public NoteType NoteType;
- [JsonProperty("Octave")]
- public int Octave;
- [JsonProperty("Duration")]
- public float Duration;
- public string ToJson() => JsonConvert.SerializeObject(this);
- public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
- }
- private class Radio
- {
- public Radio(string aName, Dictionary<string, Attachment[]> someModules, Dictionary<string, Attachment[]> someVehicles, params Tone[] someTones)
- {
- Name = aName;
- Modules = someModules;
- Vehicles = someVehicles;
- Tones = someTones;
- }
- [JsonProperty("Name")]
- public string Name;
- [JsonProperty("Tones")]
- public Tone[] Tones;
- [JsonProperty("Modules")]
- public Dictionary<string, Attachment[]> Modules;
- [JsonProperty("Vehicles")]
- public Dictionary<string, Attachment[]> Vehicles;
- public string ToJson() => JsonConvert.SerializeObject(this);
- public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
- }
- private class Attachment
- {
- public Attachment(string aPrefab, Vector3 aPosition, Vector3 anAngle = new Vector3(), string aBone = null)
- {
- Prefab = aPrefab;
- Position = aPosition;
- Angle = anAngle;
- Bone = aBone;
- }
- [JsonProperty("Prefab")]
- public string Prefab;
- [JsonProperty("Position")]
- public Vector3 Position;
- [JsonProperty("Angle")]
- public Vector3 Angle;
- [JsonProperty("Bone")]
- public string Bone;
- public string ToJson() => JsonConvert.SerializeObject(this);
- public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
- }
- protected override void LoadDefaultConfig()
- {
- config = new Configuration();
- RadioDictionary.Clear();
- RadioDictionary.Add(SIREN_DEFAULT.Name, SIREN_DEFAULT);
- RadioDictionary.Add(SIREN_SILENT.Name, SIREN_SILENT);
- }
- protected override void LoadConfig()
- {
- base.LoadConfig();
- try
- {
- config = Config.ReadObject<Configuration>();
- if (config == null)
- {
- throw new JsonException();
- }
- try
- {
- foreach (string eachRadioFile in Interface.Oxide.DataFileSystem.GetFiles(DATAPATH_RADIO, "*.json"))
- {
- string theFilename = eachRadioFile.Basename(".json");
- try
- {
- Radio theRadio = Interface.Oxide.DataFileSystem.ReadObject<Radio>(DATAPATH_RADIO + theFilename);
- RadioDictionary.Add(theRadio.Name, theRadio);
- }
- catch
- {
- PrintWarning($"Radio file {theFilename}.json is invalid; ignoring");
- }
- }
- }
- catch
- {
- }
- Puts("Loaded carradio: " + string.Join(", ", RadioDictionary.Keys));
- if (RadioDictionary.IsEmpty())
- {
- PrintWarning("Configuration appears to be missing carradio; using defaults");
- RadioDictionary.Add(SIREN_DEFAULT.Name, SIREN_DEFAULT);
- RadioDictionary.Add(SIREN_SILENT.Name, SIREN_SILENT);
- SaveConfig();
- }
- if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys))
- {
- PrintWarning("Configuration appears to be outdated; updating and saving");
- SaveConfig();
- }
- }
- catch
- {
- PrintWarning($"Configuration file {Name}.json is invalid; using defaults");
- LoadDefaultConfig();
- }
- }
- protected override void SaveConfig()
- {
- PrintWarning($"Configuration changes saved to {Name}.json");
- Config.WriteObject(config, true);
- foreach (Radio eachRadio in RadioDictionary.Values)
- {
- Interface.Oxide.DataFileSystem.WriteObject(DATAPATH_RADIO + eachRadio.Name, eachRadio);
- }
- }
- #endregion configuration
- #region localization
- protected override void LoadDefaultMessages()
- {
- lang.RegisterMessages(new Dictionary<string, string>
- {
- [I18N_MISSING_SIREN] = "No radio was found for the given name (using {0} instead)",
- [I18N_COULD_NOT_ATTACH] = "Could not attach '{0}'",
- [I18N_ATTACHED] = "Attached radio '{0}'",
- [I18N_ATTACHED_GLOBAL] = "Attached radio '{0}' to all existing cars",
- [I18N_DETACHED] = "Detached radio",
- [I18N_DETACHED_GLOBAL] = "Detached all existing carradio",
- [I18N_NOT_A_VEHICLE] = "This entity is not a (supported) vehicle",
- [I18N_RADIO] = "Available carradio: {0}",
- [I18N_PLAYERS_ONLY] = "Command '{0}' can only be used by a player",
- [I18N_NOT_SUPPORTED] = "The radio '{0}' has no configuration for '{1}'"
- }, this);
- }
- #endregion localization
- #region commands
- [Command("attachradio"), Permission(PERMISSION_ATTACHRADIO)]
- private void AttachCarRadios(IPlayer aPlayer, string aCommand, string[] someArgs)
- {
- if (aPlayer.IsServer)
- {
- Message(aPlayer, I18N_PLAYERS_ONLY, aCommand);
- return;
- }
- //BaseVehicle theVehicle = RaycastVehicle(aPlayer);
- BasePlayer thePlayer = aPlayer.Object as BasePlayer;
- BaseVehicle theVehicle = thePlayer?.GetMountedVehicle();
- if (theVehicle)
- {
- Radio theRadio = someArgs.Length > 0 ? FindRadioForName(someArgs[0], aPlayer) : RadioDictionary.Values.First();
- AttachRadios(theVehicle, theRadio, config.DefaultState, aPlayer);
- Message(aPlayer, I18N_ATTACHED, theRadio.Name);
- }
- }
- [Command("removeradio"), Permission(PERMISSION_DETACHRADIO)]
- private void DetachCarRadios(IPlayer aPlayer, string aCommand, string[] someArgs)
- {
- if (aPlayer.IsServer)
- {
- Message(aPlayer, I18N_PLAYERS_ONLY, aCommand);
- return;
- }
- BaseVehicle theVehicle = RaycastVehicle(aPlayer);
- if (theVehicle && DetachRadios(theVehicle))
- {
- Message(aPlayer, I18N_DETACHED);
- }
- }
- [Command("attachallcarradio"), Permission(PERMISSION_ATTACHRADIO_GLOBAL)]
- private void AttachAllCarRadios(IPlayer aPlayer, string aCommand, string[] someArgs)
- {
- Radio theRadio = someArgs.Length > 0 ? FindRadioForName(someArgs[0], aPlayer) : RadioDictionary.Values.First();
- foreach (BaseVehicle eachVehicle in BaseNetworkable.serverEntities.OfType<BaseVehicle>())
- {
- AttachRadios(eachVehicle, theRadio, config.DefaultState, aPlayer);
- }
- Message(aPlayer, I18N_ATTACHED_GLOBAL, theRadio.Name);
- }
- [Command("detachallcarradio"), Permission(PERMISSION_DETACHRADIO_GLOBAL)]
- private void DetachAllCarRadios(IPlayer aPlayer, string aCommand, string[] someArgs)
- {
- foreach (BaseVehicle eachVehicle in BaseNetworkable.serverEntities.OfType<BaseVehicle>())
- {
- DetachRadios(eachVehicle);
- }
- Message(aPlayer, I18N_DETACHED_GLOBAL);
- }
- [Command("togglecarradio")]
- private void ToggleRadios(IPlayer aPlayer, string aCommand, string[] someArgs)
- {
- if (aPlayer.IsServer)
- {
- Message(aPlayer, I18N_PLAYERS_ONLY, aCommand);
- return;
- }
- BasePlayer thePlayer = aPlayer.Object as BasePlayer;
- BaseVehicle theVehicle = thePlayer?.GetMountedVehicle();
- if (theVehicle)
- {
- theVehicle.GetComponent<RadioController>()?.ChangeState();
- }
- else if (!config.MountNeeded)
- {
- RaycastVehicle(aPlayer)?.GetComponent<RadioController>()?.ChangeState(); ;
- }
- }
- #endregion commands
- #region hooks
- private void Unload()
- {
- OnServerSave();
- foreach (BaseVehicle eachVehicle in BaseNetworkable.serverEntities.OfType<BaseVehicle>())
- {
- DetachRadios(eachVehicle);
- }
- }
- private void OnServerSave()
- {
- DataContainer thePersistentData = new DataContainer();
- foreach (BaseVehicle eachCar in BaseNetworkable.serverEntities.OfType<BaseVehicle>())
- {
- RadioController theController = eachCar.GetComponent<RadioController>();
- thePersistentData.VehicleRadioMap.Add(eachCar.net.ID, theController ? new VehicleContainer(theController.Radio.Name, theController.State, theController.NetIDs) : null);
- }
- Interface.Oxide.DataFileSystem.WriteObject(Name, thePersistentData);
- }
- private void OnServerInitialized(bool anInitialFlag)
- {
- bool theSpawnRandomlyFlag = config.RadioSpawnProbability.Any(entry => entry.Value > 0f);
- if (!theSpawnRandomlyFlag)
- {
- Unsubscribe("OnEntitySpawned");
- }
- // Reattach on server restart
- DataContainer thePersistentData = Interface.Oxide.DataFileSystem.ReadObject<DataContainer>(Name);
- foreach (BaseVehicle eachVehicle in BaseNetworkable.serverEntities.OfType<BaseVehicle>())
- {
- VehicleContainer theContainer;
- if (thePersistentData.VehicleRadioMap.TryGetValue(eachVehicle.net.ID, out theContainer))
- {
- if (theContainer != null)
- {
- Radio theRadio;
- if (RadioDictionary.TryGetValue(theContainer.RadioName, out theRadio))
- {
- CreateRadioController(eachVehicle, theRadio, theContainer.NetIDs);
- AttachRadios(eachVehicle, theRadio, theContainer.State);
- }
- else
- {
- CreateRadioController(eachVehicle, null, theContainer.NetIDs);
- DetachRadios(eachVehicle);
- PrintWarning($"Missing radio for name \"{theContainer.RadioName}\". Ignoring...");
- }
- }
- }
- else if (theSpawnRandomlyFlag)
- {
- RadioController theController = eachVehicle.GetComponent<RadioController>();
- if (!theController)
- {
- float theProbability;
- if (config.RadioSpawnProbability.TryGetValue(eachVehicle is ModularCar ? KEY_MODULAR_CAR : eachVehicle.PrefabName, out theProbability) && Core.Random.Range(0f, 1f) < theProbability)
- {
- AttachRadios(eachVehicle, RadioDictionary.Values.First(), config.DefaultState);
- }
- }
- }
- }
- }
- private object OnButtonPress(PressButton aButton, BasePlayer aPlayer)
- {
- BaseVehicle theVehicle = aButton.GetComponentInParent<BaseVehicle>()?.VehicleParent();
- // theVehicle = theVehicle ? theVehicle : aButton.GetComponentInParent<BaseVehicle>();
- theVehicle = aPlayer?.GetMountedVehicle();
- if (theVehicle)
- {
- RadioController theController = theVehicle.GetComponent<RadioController>();
- if (theController)
- {
- if ((config.MountNeeded && aPlayer.GetMountedVehicle() != theVehicle) || !theController.NetIDs.Contains(aButton.net.ID))
- {
- return false;
- }
- theController.ChangeState();
- }
- }
- return null;
- }
- private void OnEntitySpawned(BaseVehicle aVehicle)
- {
- RadioController theController = aVehicle.GetComponent<RadioController>();
- if (!theController)
- {
- float theProbability;
- if (config.RadioSpawnProbability.TryGetValue(aVehicle is ModularCar ? KEY_MODULAR_CAR : aVehicle.PrefabName, out theProbability) && Core.Random.Range(0f, 1f) < theProbability)
- {
- AttachRadios(aVehicle, RadioDictionary.Values.First(), config.DefaultState);
- }
- }
- }
- #endregion hooks
- #region methods
- /// <summary>
- /// Tries to attach the given radio to the vehicle, replacing any existing radio.
- /// </summary>
- /// <param name="aVehicle">The vehicle.</param>
- /// <param name="aRadio">The radio.</param>
- /// <param name="anInitialState">The initial radio state.</param>
- /// <param name="aPlayer">The calling player.</param>
- private void AttachRadios(BaseVehicle aVehicle, Radio aRadio, RadioController.States anInitialState, IPlayer aPlayer = null)
- {
- DetachRadios(aVehicle);
- RadioController theController = CreateRadioController(aVehicle, aRadio);
- if (aVehicle as ModularCar)
- {
- if (aRadio.Modules == null)
- {
- Message(aPlayer, I18N_NOT_SUPPORTED, aRadio.Name, KEY_MODULAR_CAR);
- DetachRadios(aVehicle);
- return;
- }
- foreach (BaseVehicleModule eachModule in aVehicle.GetComponentsInChildren<BaseVehicleModule>())
- {
- SpawnAttachments(aRadio.Modules, aPlayer, theController, eachModule);
- }
- }
- else if (!SpawnAttachments(aRadio.Vehicles, aPlayer, theController, aVehicle))
- {
- Message(aPlayer, I18N_NOT_SUPPORTED, aRadio.Name, aVehicle.PrefabName);
- DetachRadios(aVehicle);
- return;
- }
- theController.SetState(anInitialState);
- }
- /// <summary>
- /// Spawns the attachments for the given dictionary for the given parent entity.
- /// </summary>
- /// <param name="someAttachments">The dictionary.</param>
- /// <param name="aPlayer">The calling player.</param>
- /// <param name="theController">The RadioController of the Parent.</param>
- /// <param name="aParent">The Parent.</param>
- /// <returns>True, if the parent has an entry in the dictionary with at least one Attachment.</returns>
- private bool SpawnAttachments(IDictionary<string, Attachment[]> someAttachments, IPlayer aPlayer, RadioController theController, BaseEntity aParent)
- {
- if (someAttachments == null)
- {
- return false;
- }
- Attachment[] theAttachments;
- if (someAttachments.TryGetValue(aParent.PrefabName, out theAttachments))
- {
- foreach (Attachment eachAttachment in theAttachments)
- {
- BaseEntity theNewEntity = AttachEntity(aParent, eachAttachment.Prefab, eachAttachment.Position, eachAttachment.Angle, eachAttachment.Bone);
- if (theNewEntity)
- {
- theController.NetIDs.Add(theNewEntity.net.ID);
- }
- else if (aPlayer != null)
- {
- Message(aPlayer, I18N_COULD_NOT_ATTACH, eachAttachment.Prefab);
- }
- }
- return !theAttachments.IsEmpty();
- }
- return false;
- }
- /// <summary>
- /// Creates or replaces the RadioController of the given vehicle.
- /// </summary>
- /// <param name="aVehicle">The vehicle.</param>
- /// <param name="aRadio">The Radio.</param>
- /// <param name="someNetIDs">Already existing radio entities.</param>
- /// <returns>The newly created RadioController.</returns>
- private RadioController CreateRadioController(BaseVehicle aVehicle, Radio aRadio, IEnumerable<uint> someNetIDs = null)
- {
- RadioController theController = aVehicle.GetComponent<RadioController>();
- if (theController)
- {
- UnityEngine.Object.DestroyImmediate(theController);
- }
- theController = aVehicle.gameObject.AddComponent<RadioController>();
- theController.Config = config;
- theController.Radio = aRadio;
- if (someNetIDs != null)
- {
- theController.NetIDs.UnionWith(someNetIDs);
- }
- return theController;
- }
- /// <summary>
- /// Detaches the radio from a vehicle and removes all corresponding entities.
- /// </summary>
- /// <param name="aVehicle"> The vehicle.</param>
- /// <returns>True, if a radio was removed.</returns>
- private bool DetachRadios(BaseVehicle aVehicle)
- {
- RadioController theController = aVehicle.GetComponent<RadioController>();
- if (theController)
- {
- foreach (BaseEntity eachEntity in aVehicle.GetComponentsInChildren<BaseEntity>())
- {
- if (theController.NetIDs.Contains(eachEntity.net.ID))
- {
- Destroy(eachEntity);
- }
- }
- UnityEngine.Object.DestroyImmediate(theController);
- return true;
- }
- return false;
- }
- /// <summary>
- /// Destroys the entity.
- /// </summary>
- /// <param name="anEntity">The entity.</param>
- private static void Destroy(BaseEntity anEntity)
- {
- if (!anEntity.IsDestroyed)
- {
- anEntity.Kill();
- }
- }
- /// <summary>
- /// Attaches the prefab entity at the given local position and angles to the parent.
- /// </summary>
- /// <param name="aParent">The parent.</param>
- /// <param name="aPrefab">The prefab for the new entity.</param>
- /// <param name="aPosition">The local position.</param>
- /// <param name="anAngle">The local angles.</param>
- /// <returns></returns>
- private BaseEntity AttachEntity(BaseEntity aParent, string aPrefab, Vector3 aPosition, Vector3 anAngle = new Vector3(), string aBone = null)
- {
- BaseEntity theNewEntity = GameManager.server.CreateEntity(aPrefab, aParent.transform.position);
- Puts($"Attaching {aPrefab} at loction {aPosition}");
- if (!theNewEntity)
- {
- return null;
- }
- theNewEntity.Spawn();
- Transform theBone = aParent.FindBone(aBone);
- if (theBone == null && aBone != null)
- {
- PrintWarning($"No bone found for name '{aBone}'");
- PrintWarning("Valid bone names: " + string.Join(", ", aParent.GetBones().Select(eachBone => eachBone.name)));
- }
- if (theBone != null && theBone != aParent.transform)
- {
- theNewEntity.SetParent(aParent, theBone.name);
- theNewEntity.transform.localPosition = theBone.InverseTransformPoint(aParent.transform.TransformPoint(aPosition));
- theNewEntity.transform.localRotation = Quaternion.Inverse(theBone.rotation) * (aParent.transform.rotation * Quaternion.Euler(anAngle));
- }
- else
- {
- theNewEntity.transform.localPosition = aPosition;
- theNewEntity.transform.localEulerAngles = anAngle;
- theNewEntity.SetParent(aParent);
- }
- //Puts(theNewEntity.ShortPrefabName + ": (" + theNewEntity.GetComponents<Component>().Length + ") " + string.Join(", ", theNewEntity.GetComponents<Component>().Select(eachComp => eachComp.GetType().Name)));
- UnityEngine.Object.DestroyImmediate(theNewEntity.GetComponent<DestroyOnGroundMissing>());
- UnityEngine.Object.DestroyImmediate(theNewEntity.GetComponent<GroundWatch>());
- UnityEngine.Object.DestroyImmediate(theNewEntity.GetComponent<BoxCollider>());
- UnityEngine.Object.DestroyImmediate(theNewEntity.GetComponent<InstrumentKeyController>());
- theNewEntity.OwnerID = 0;
- BaseCombatEntity theCombatEntity = theNewEntity as BaseCombatEntity;
- if (theCombatEntity)
- {
- theCombatEntity.pickup.enabled = false;
- }
- PressButton theButton = theNewEntity as PressButton;
- if (theButton)
- {
- theButton.pressDuration = 0.2f;
- }
- theNewEntity.EnableSaving(true);
- theNewEntity.SendNetworkUpdateImmediate();
- return theNewEntity;
- }
- /// <summary>
- /// Toggles the IOEntity.
- /// </summary>
- /// <param name="anIOEntity">The IOEntity.</param>
- /// <param name="theEnabledFlag">The new state.</param>
- private static void ToogleRadios(IOEntity anIOEntity, bool theEnabledFlag)
- {
- anIOEntity.UpdateHasPower(theEnabledFlag ? anIOEntity.ConsumptionAmount() : 0, 0);
- anIOEntity.SetFlag(BaseEntity.Flags.On, theEnabledFlag);
- }
- #endregion methods
- #region helpers
- private BaseVehicle RaycastVehicle(IPlayer aPlayer)
- {
- RaycastHit theHit;
- if (!Physics.Raycast((aPlayer.Object as BasePlayer).eyes.HeadRay(), out theHit, 5f))
- {
- return null;
- }
- BaseVehicle theVehicle = theHit.GetEntity()?.GetComponentInParent<BaseVehicle>();
- if (!theVehicle)
- {
- Message(aPlayer, I18N_NOT_A_VEHICLE);
- }
- return theVehicle;
- }
- private Radio FindRadioForName(string aName, IPlayer aPlayer)
- {
- Radio theRadio;
- if (!RadioDictionary.TryGetValue(aName, out theRadio))
- {
- theRadio = RadioDictionary.Values.First();
- Message(aPlayer, I18N_MISSING_SIREN, theRadio.Name);
- }
- return theRadio;
- }
- private string GetText(string aKey, string aPlayerId = null, params object[] someArgs) => string.Format(lang.GetMessage(aKey, this, aPlayerId), someArgs);
- private void Message(IPlayer aPlayer, string anI18nKey, params object[] someArgs)
- {
- if (aPlayer.IsConnected)
- {
- string theText = GetText(anI18nKey, aPlayer.Id, someArgs);
- aPlayer.Reply(theText != anI18nKey ? theText : anI18nKey);
- }
- }
- private void Message(BasePlayer aPlayer, string anI18nKey, params object[] someArgs)
- {
- if (aPlayer.IsConnected)
- {
- string theText = GetText(anI18nKey, aPlayer.UserIDString, someArgs);
- aPlayer.ChatMessage(theText != anI18nKey ? theText : anI18nKey);
- }
- }
- #endregion helpers
- #region controllers
- private class RadioController : FacepunchBehaviour
- {
- public enum States
- {
- OFF,
- ON,
- LIGHTS_ONLY
- }
- private BaseVehicle vehicle;
- private InstrumentTool trumpet;
- public Configuration Config { get; set; }
- public States State { get; private set; }
- public Radio Radio { get; set; }
- public ISet<uint> NetIDs { get; } = new HashSet<uint>();
- public States ChangeState()
- {
- SetState(State >= States.LIGHTS_ONLY ? States.OFF : State + 1);
- return State;
- }
- public void SetState(States aState)
- {
- State = aState;
- if ((!Config.SoundEnabled || Radio?.Tones?.Length < 1 || !GetTrumpet()) && State == States.ON)
- {
- State++;
- }
- RefreshRadioState();
- }
- public void RefreshRadioState()
- {
- if (State == States.ON)
- {
- PlayTone(0);
- }
- bool theLightsOnFlag = State > States.OFF;
- foreach (IOEntity eachEntity in GetVehicle().GetComponentsInChildren<IOEntity>())
- {
- if (NetIDs.Contains(eachEntity.net.ID) && !(eachEntity is PressButton))
- {
- ToogleRadios(eachEntity, theLightsOnFlag);
- }
- }
- }
- private InstrumentTool GetTrumpet()
- {
- if (trumpet == null || trumpet.IsDestroyed)
- {
- trumpet = GetVehicle().GetComponentInChildren<InstrumentTool>();
- }
- return trumpet;
- }
- private BaseVehicle GetVehicle()
- {
- if (vehicle == null)
- {
- vehicle = GetComponentInParent<BaseVehicle>();
- }
- return vehicle;
- }
- private void PlayTone(int anIndex)
- {
- if (State != States.ON || !GetTrumpet())
- {
- return;
- }
- if (anIndex >= Radio.Tones.Length)
- {
- anIndex = 0;
- }
- Tone theTone = Radio.Tones[anIndex];
- GetTrumpet().ClientRPC(null, "Client_PlayNote", (int)theTone.Note, (int)theTone.NoteType, theTone.Octave, 1f);
- Invoke(() => GetTrumpet().ClientRPC(null, "Client_StopNote", (int)theTone.Note, (int)theTone.NoteType, theTone.Octave), theTone.Duration);
- Invoke(() => PlayTone(++anIndex), theTone.Duration);
- }
- }
- #endregion controllers
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement