Decompiled source of TrainTunes v0.2.1

BepInEx/plugins/TrainTunes/TrainTunes.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using Blackforge;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace TrainTunes;

[BepInPlugin("local.traintunes", "Train Tunes", "0.2.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class TrainTunesPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "local.traintunes";

	private ConfigEntry<bool> _enabled;

	private ConfigEntry<float> _volume;

	private ConfigEntry<float> _minDistance;

	private ConfigEntry<float> _maxDistance;

	private ConfigEntry<float> _speedThreshold;

	private float _nextScan;

	private AudioClip[] _clips = (AudioClip[])(object)new AudioClip[0];

	internal int TrackCount => _clips.Length;

	internal bool Enabled => _enabled.Value;

	internal float Volume => Mathf.Clamp01(_volume.Value);

	internal float MinDistance => Mathf.Max(0.1f, _minDistance.Value);

	internal float MaxDistance => Mathf.Max(MinDistance + 1f, _maxDistance.Value);

	internal float SpeedThreshold => Mathf.Max(0f, _speedThreshold.Value);

	internal AudioClip GetTrack(int index)
	{
		return _clips[index];
	}

	private void Awake()
	{
		_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable train-mounted music.");
		_volume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Volume", 0.6f, "Volume from 0.0 to 1.0.");
		_minDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MinDistance", 8f, "Distance in meters at which music is full volume.");
		_maxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MaxDistance", 75f, "Distance in meters at which music is inaudible.");
		_speedThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SpeedThreshold", 0.1f, "Absolute Railroads locomotive speed (m/s) above which music plays.");
		string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
		string text = Path.Combine(directoryName, "Music");
		Directory.CreateDirectory(text);
		((MonoBehaviour)this).StartCoroutine(LoadPlaylist(text));
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Train Tunes v0.2.0 loaded: train-mounted shuffled playlists (local audio only).");
	}

	private IEnumerator LoadPlaylist(string folder)
	{
		List<string> paths = new List<string>();
		string[] files = Directory.GetFiles(folder, "*", SearchOption.TopDirectoryOnly);
		foreach (string text in files)
		{
			string extension = Path.GetExtension(text);
			if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".ogg", StringComparison.OrdinalIgnoreCase))
			{
				paths.Add(text);
			}
		}
		paths.Sort(StringComparer.OrdinalIgnoreCase);
		if (paths.Count == 0)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Train Tunes: no MP3 or OGG files found in " + folder));
			yield break;
		}
		List<AudioClip> loaded = new List<AudioClip>();
		foreach (string path in paths)
		{
			string ext = Path.GetExtension(path);
			AudioType type = (AudioType)(string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase) ? 13 : 14);
			string uri = new Uri(Path.GetFullPath(path)).AbsoluteUri;
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(uri, type);
			try
			{
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Train Tunes: skipping " + Path.GetFileName(path) + ": " + request.error));
					continue;
				}
				AudioClip clip = DownloadHandlerAudioClip.GetContent(request);
				if ((Object)(object)clip == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Train Tunes: Unity could not load " + Path.GetFileName(path)));
					continue;
				}
				((Object)clip).name = Path.GetFileNameWithoutExtension(path);
				loaded.Add(clip);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Train Tunes: loaded " + Path.GetFileName(path)));
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}
		_clips = loaded.ToArray();
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Train Tunes: ready with " + _clips.Length + " song(s)."));
	}

	private void Update()
	{
		if (Time.unscaledTime < _nextScan)
		{
			return;
		}
		_nextScan = Time.unscaledTime + 1f;
		RailLocomotive[] array = Object.FindObjectsOfType<RailLocomotive>();
		foreach (RailLocomotive val in array)
		{
			if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy)
			{
				TrainTunesEmitter component = ((Component)val).GetComponent<TrainTunesEmitter>();
				if ((Object)(object)component == (Object)null)
				{
					component = ((Component)val).gameObject.AddComponent<TrainTunesEmitter>();
					component.Initialize(this);
				}
			}
		}
	}

	private void OnDestroy()
	{
		AudioClip[] clips = _clips;
		foreach (AudioClip val in clips)
		{
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)val);
			}
		}
	}
}
internal sealed class TrainTunesEmitter : MonoBehaviour
{
	private TrainTunesPlugin _plugin;

	private ZNetView _networkView;

	private AudioSource _source;

	private readonly List<int> _shuffleBag = new List<int>();

	private int _nextInBag;

	private int _lastTrack = -1;

	private bool _trackStarted;

	private void Awake()
	{
		_networkView = ((Component)this).GetComponent<ZNetView>();
		_source = ((Component)this).gameObject.AddComponent<AudioSource>();
		_source.playOnAwake = false;
		_source.loop = false;
		_source.spatialBlend = 1f;
		_source.rolloffMode = (AudioRolloffMode)1;
		_source.dopplerLevel = 0f;
	}

	internal void Initialize(TrainTunesPlugin plugin)
	{
		_plugin = plugin;
	}

	private void Update()
	{
		if ((Object)(object)_plugin == (Object)null || !_plugin.Enabled || _plugin.TrackCount == 0 || (Object)(object)_networkView == (Object)null || !_networkView.IsValid())
		{
			StopMusic();
			return;
		}
		_source.volume = _plugin.Volume;
		_source.minDistance = _plugin.MinDistance;
		_source.maxDistance = _plugin.MaxDistance;
		ZDO zDO = _networkView.GetZDO();
		if (zDO == null)
		{
			StopMusic();
			return;
		}
		float num = Mathf.Abs(zDO.GetFloat("bf_speed", 0f));
		if (num <= _plugin.SpeedThreshold)
		{
			StopMusic();
		}
		else if (!_trackStarted || !_source.isPlaying)
		{
			PlayNextTrack();
		}
	}

	private void PlayNextTrack()
	{
		int trackCount = _plugin.TrackCount;
		if (trackCount >= 1)
		{
			int index = DrawTrack(trackCount);
			_source.Stop();
			_source.clip = _plugin.GetTrack(index);
			_source.loop = trackCount == 1;
			_source.Play();
			_trackStarted = true;
		}
	}

	private int DrawTrack(int count)
	{
		if (_shuffleBag.Count != count || _nextInBag >= _shuffleBag.Count)
		{
			_shuffleBag.Clear();
			for (int i = 0; i < count; i++)
			{
				_shuffleBag.Add(i);
			}
			for (int num = count - 1; num > 0; num--)
			{
				int index = Random.Range(0, num + 1);
				int value = _shuffleBag[num];
				_shuffleBag[num] = _shuffleBag[index];
				_shuffleBag[index] = value;
			}
			if (count > 1 && _shuffleBag[0] == _lastTrack)
			{
				int index2 = Random.Range(1, count);
				int value2 = _shuffleBag[0];
				_shuffleBag[0] = _shuffleBag[index2];
				_shuffleBag[index2] = value2;
			}
			_nextInBag = 0;
		}
		return _lastTrack = _shuffleBag[_nextInBag++];
	}

	private void StopMusic()
	{
		if ((Object)(object)_source != (Object)null && _source.isPlaying)
		{
			_source.Stop();
		}
		_trackStarted = false;
	}

	private void OnDisable()
	{
		StopMusic();
	}
}