Decompiled source of JBLSpeakerMod v1.1.0

JBLSpeaker.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using JBLSpeaker.Valuables;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using REPOLib;
using REPOLib.Modules;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Brian Hepp")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+06647606a89ba302cb63e404e399123082d3f024")]
[assembly: AssemblyProduct("JBLSpeaker")]
[assembly: AssemblyTitle("JBLSpeaker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace JBLSpeaker
{
	[BepInPlugin("drb.jblspeaker", "JBLSpeaker", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugins : BaseUnityPlugin
	{
		private void Awake()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"JBLSpeaker Plugin Awake");
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			string text = Path.Combine(directoryName, "jblspeaker.bundle");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("BundlePath = " + text.ToString()));
			BundleLoader.LoadBundle(text, (Action<AssetBundle>)delegate(AssetBundle assetBundle)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"BundleLoader callback fired");
				if ((Object)(object)assetBundle == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)"AssetBundle is NULL");
				}
				else
				{
					GameObject val = assetBundle.LoadAsset<GameObject>("jblspeaker");
					if ((Object)(object)val == (Object)null)
					{
						((BaseUnityPlugin)this).Logger.LogError((object)"JBLSpeaker prefab NOT found in bundle");
					}
					else
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)("Prefab found: " + ((Object)val).name));
						JBLSpeaker.Valuables.JBLSpeaker jBLSpeaker = default(JBLSpeaker.Valuables.JBLSpeaker);
						if (!val.TryGetComponent<JBLSpeaker.Valuables.JBLSpeaker>(ref jBLSpeaker))
						{
							((BaseUnityPlugin)this).Logger.LogInfo((object)"JBLSpeaker component NOT found on prefab — adding");
							jBLSpeaker = val.AddComponent<JBLSpeaker.Valuables.JBLSpeaker>();
							jBLSpeaker.tracks = new List<AudioSource>(val.GetComponentsInChildren<AudioSource>(true));
							jBLSpeaker.particles = new List<ParticleSystem>(val.GetComponentsInChildren<ParticleSystem>(true));
						}
						else
						{
							((BaseUnityPlugin)this).Logger.LogInfo((object)"JBLSpeaker component already exists on prefab");
						}
						((BaseUnityPlugin)this).Logger.LogInfo((object)"Registering JBLSpeaker valuable");
						Valuables.RegisterValuable(val);
					}
				}
			}, false);
		}
	}
}
namespace JBLSpeaker.Valuables
{
	public class JBLSpeaker : MonoBehaviourPun
	{
		[Serializable]
		public class TrackLyrics
		{
			public AudioSource track;

			public List<AudioClip> lyrics;
		}

		private PhysGrabObject grab;

		private bool wasGrabbed;

		public List<AudioSource> tracks;

		[Header("Audio")]
		public List<ParticleSystem> particles;

		private int musicIndex = -1;

		[Header("Behavior")]
		public float slamVelocityThreshold = 6f;

		public int maxSkipsBeforeOff = 6;

		private int skipCount;

		private bool isActive;

		[Header("Drop Audio")]
		public float droppedVolume = 0.25f;

		public float heldVolume = 0.8f;

		private float[] audioSamples = new float[256];

		private float headBobStrength = 0.03f;

		[SerializeField]
		private AudioSource voiceSource;

		[SerializeField]
		private AudioSource connectedSource;

		[SerializeField]
		private AudioSource skipSource;

		[SerializeField]
		private List<AudioSource> musicTracks;

		[SerializeField]
		private List<AudioClip> lyricClips;

		[Header("Lyrics")]
		public List<TrackLyrics> trackLyrics;

		public float lyricInterval = 3f;

		private float lyricTimer;

		private AudioSource currentMusic;

		[Header("Voice")]
		[SerializeField]
		private float voiceCooldown = 1.5f;

		private float lastVoiceTime;

		private void Awake()
		{
			grab = ((Component)this).GetComponent<PhysGrabObject>();
			particles = new List<ParticleSystem>(((Component)this).GetComponentsInChildren<ParticleSystem>(true));
			AudioSource[] componentsInChildren = ((Component)this).GetComponentsInChildren<AudioSource>(true);
			AudioSource[] array = componentsInChildren;
			foreach (AudioSource val in array)
			{
				if (((Object)((Component)val).gameObject).name == "ConnectedSource")
				{
					connectedSource = val;
				}
				else if (((Object)((Component)val).gameObject).name == "SkipSource")
				{
					skipSource = val;
				}
				else if (((Object)((Component)val).gameObject).name.StartsWith("Music"))
				{
					musicTracks.Add(val);
				}
				else if (((Object)((Component)val).gameObject).name == "VoiceSource")
				{
					voiceSource = val;
				}
			}
			if (musicTracks.Count == 0)
			{
				Debug.LogError((object)"JBLSpeaker: musicTracks is empty!");
			}
			if (!Object.op_Implicit((Object)(object)skipSource))
			{
				Debug.LogError((object)"JBLSpeaker: SkipSource not assigned");
			}
			ShuffleMusic();
		}

		private void Update()
		{
			if (!Object.op_Implicit((Object)(object)grab))
			{
				return;
			}
			if (grab.grabbed && !wasGrabbed)
			{
				OnPickup();
			}
			if (!grab.grabbed && wasGrabbed)
			{
				OnDrop();
			}
			wasGrabbed = grab.grabbed;
			if (grab.grabbedLocal && Input.GetKeyDown((KeyCode)101))
			{
				SkipTrack();
			}
			foreach (AudioSource musicTrack in musicTracks)
			{
				if (musicTrack.isPlaying)
				{
					ApplyHeadBob(musicTrack);
					break;
				}
			}
			if (grab.grabbed && Object.op_Implicit((Object)(object)currentMusic) && currentMusic.isPlaying)
			{
				lyricTimer += Time.deltaTime;
				if (lyricTimer >= lyricInterval)
				{
					TrySpeakLyricForCurrentTrack();
					lyricTimer = 0f;
				}
			}
		}

		private void OnPickup()
		{
			isActive = true;
			skipCount = 0;
			RestoreMusicVolume();
			if (!IsAnyMusicPlaying() && Object.op_Implicit((Object)(object)connectedSource) && Object.op_Implicit((Object)(object)connectedSource.clip))
			{
				musicIndex = -1;
				connectedSource.Play();
			}
		}

		private void OnDrop()
		{
			SetMusicVolume(droppedVolume);
			StopParticles();
		}

		private void ShuffleMusic()
		{
			for (int num = musicTracks.Count - 1; num > 0; num--)
			{
				int num2 = Random.Range(0, num + 1);
				List<AudioSource> list = musicTracks;
				int index = num;
				List<AudioSource> list2 = musicTracks;
				int index2 = num2;
				AudioSource value = musicTracks[num2];
				AudioSource value2 = musicTracks[num];
				list[index] = value;
				list2[index2] = value2;
			}
		}

		private void SkipTrack()
		{
			if (!isActive)
			{
				return;
			}
			skipCount++;
			if (skipCount >= maxSkipsBeforeOff)
			{
				PowerOff();
				return;
			}
			PlaySkipThenMusic();
			if (((MonoBehaviourPun)this).photonView.IsMine)
			{
				((MonoBehaviourPun)this).photonView.RPC("RPC_SkipTrack", (RpcTarget)1, Array.Empty<object>());
			}
		}

		private void PlaySkipThenMusic()
		{
			if (!Object.op_Implicit((Object)(object)skipSource))
			{
				Debug.LogError((object)"JBLSpeaker: SkipSource not assigned");
				return;
			}
			if (musicTracks == null || musicTracks.Count == 0)
			{
				Debug.LogError((object)"JBLSpeaker: No music tracks assigned");
				return;
			}
			StopMusicOnly();
			if (Object.op_Implicit((Object)(object)skipSource.clip))
			{
				skipSource.Play();
			}
			musicIndex++;
			if (musicIndex >= musicTracks.Count)
			{
				ShuffleMusic();
				musicIndex = 0;
			}
			float num = (Object.op_Implicit((Object)(object)skipSource.clip) ? skipSource.clip.length : 0f);
			((MonoBehaviour)this).Invoke("PlayCurrentMusic", num);
		}

		private void PlayCurrentMusic()
		{
			if (!isActive || musicTracks.Count == 0)
			{
				return;
			}
			currentMusic = musicTracks[musicIndex];
			currentMusic.volume = (grab.grabbed ? heldVolume : droppedVolume);
			currentMusic.Play();
			foreach (ParticleSystem particle in particles)
			{
				particle.Play();
			}
		}

		private void PowerOff()
		{
			isActive = false;
			StopMusicOnly();
			StopParticles(clear: true);
		}

		private void StopMusicOnly()
		{
			foreach (AudioSource musicTrack in musicTracks)
			{
				musicTrack.Stop();
			}
		}

		private void StopParticles(bool clear = false)
		{
			foreach (ParticleSystem particle in particles)
			{
				if (clear)
				{
					particle.Stop(true, (ParticleSystemStopBehavior)0);
				}
				else
				{
					particle.Stop(true, (ParticleSystemStopBehavior)1);
				}
			}
		}

		private void OnCollisionEnter(Collision collision)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)grab) && grab.grabbed)
			{
				Vector3 relativeVelocity = collision.relativeVelocity;
				if (((Vector3)(ref relativeVelocity)).magnitude >= slamVelocityThreshold)
				{
					SkipTrack();
				}
			}
		}

		private void ApplyHeadBob(AudioSource src)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)src) || !src.isPlaying)
			{
				return;
			}
			src.GetOutputData(audioSamples, 0);
			float num = 0f;
			for (int i = 0; i < audioSamples.Length; i++)
			{
				num += Mathf.Abs(audioSamples[i]);
			}
			float num2 = num / (float)audioSamples.Length;
			float num3 = num2 * headBobStrength;
			foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
			{
				if ((Object)(object)player == (Object)null)
				{
					continue;
				}
				float num4 = Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position);
				if (!(num4 > 8f))
				{
					if (player.isLocal)
					{
						CameraAim.Instance.AdditiveAimY(num3);
					}
					else
					{
						player.playerAvatarVisuals.HeadTiltOverride(num3);
					}
				}
			}
		}

		private void TrySpeakLyricForCurrentTrack()
		{
			if ((Object)(object)currentMusic == (Object)null || trackLyrics == null)
			{
				return;
			}
			foreach (TrackLyrics trackLyric in trackLyrics)
			{
				if (trackLyric == null || (Object)(object)trackLyric.track == (Object)null || trackLyric.lyrics == null || !((Object)(object)trackLyric.track == (Object)(object)currentMusic) || trackLyric.lyrics.Count <= 0)
				{
					continue;
				}
				AudioClip clip = trackLyric.lyrics[Random.Range(0, trackLyric.lyrics.Count)];
				Speak(clip);
				break;
			}
		}

		private bool IsAnyMusicPlaying()
		{
			foreach (AudioSource musicTrack in musicTracks)
			{
				if (Object.op_Implicit((Object)(object)musicTrack) && musicTrack.isPlaying)
				{
					return true;
				}
			}
			return false;
		}

		private void SetMusicVolume(float volume)
		{
			foreach (AudioSource musicTrack in musicTracks)
			{
				if (Object.op_Implicit((Object)(object)musicTrack) && musicTrack.isPlaying)
				{
					musicTrack.volume = volume;
				}
			}
		}

		private void RestoreMusicVolume()
		{
			SetMusicVolume(heldVolume);
		}

		private void Speak(AudioClip clip)
		{
			if (Object.op_Implicit((Object)(object)clip) && Object.op_Implicit((Object)(object)voiceSource) && !voiceSource.isPlaying && !(Time.time - lastVoiceTime < voiceCooldown))
			{
				voiceSource.clip = clip;
				voiceSource.Play();
				lastVoiceTime = Time.time;
			}
		}

		[PunRPC]
		private void RPC_SkipTrack()
		{
			SkipTrack();
		}
	}
}