using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using FishNet;
using FishNet.Broadcast;
using FishNet.Connection;
using FishNet.Managing.Object;
using FishNet.Object;
using FishNet.Serializing;
using FishNet.Transporting;
using UnityEngine;
using UnityEngine.Networking;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("HowToFishCustomRadio")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("HowToFishCustomRadio")]
[assembly: AssemblyTitle("HowToFishCustomRadio")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace CustomRadioFramework;
public struct MusicChunkBroadcast : IBroadcast
{
public int trackId;
public int chunkIndex;
public int totalChunks;
public byte[] data;
}
public struct MusicControlBroadcast : IBroadcast
{
public bool isPaused;
public float timePosition;
}
public struct MusicVolumeBroadcast : IBroadcast
{
public float volume;
}
public static class CustomSerializers
{
public static void WriteMusicChunkBroadcast(this Writer writer, MusicChunkBroadcast msg)
{
writer.Write<int>(msg.trackId);
writer.Write<int>(msg.chunkIndex);
writer.Write<int>(msg.totalChunks);
writer.Write<byte[]>(msg.data);
}
public static MusicChunkBroadcast ReadMusicChunkBroadcast(this Reader reader)
{
return new MusicChunkBroadcast
{
trackId = reader.Read<int>(),
chunkIndex = reader.Read<int>(),
totalChunks = reader.Read<int>(),
data = reader.Read<byte[]>()
};
}
public static void WriteMusicControlBroadcast(this Writer writer, MusicControlBroadcast msg)
{
writer.Write<bool>(msg.isPaused);
writer.Write<float>(msg.timePosition);
}
public static MusicControlBroadcast ReadMusicControlBroadcast(this Reader reader)
{
return new MusicControlBroadcast
{
isPaused = reader.Read<bool>(),
timePosition = reader.Read<float>()
};
}
public static void WriteMusicVolumeBroadcast(this Writer writer, MusicVolumeBroadcast msg)
{
writer.Write<float>(msg.volume);
}
public static MusicVolumeBroadcast ReadMusicVolumeBroadcast(this Reader reader)
{
return new MusicVolumeBroadcast
{
volume = reader.Read<float>()
};
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class OpenFileName
{
public int structSize;
public IntPtr hwndOwner = IntPtr.Zero;
public IntPtr hInstance = IntPtr.Zero;
public string filter;
public string customFilter;
public int maxCustFilter;
public int filterIndex;
public string file;
public int maxFile;
public string fileTitle;
public int maxFileTitle;
public string initialDir;
public string title;
public int flags;
public short fileOffset;
public short fileExtension;
public string defExt;
public IntPtr custData = IntPtr.Zero;
public IntPtr hook = IntPtr.Zero;
public string templateName;
public IntPtr reservedPtr = IntPtr.Zero;
public int reservedInt;
public int flagsEx;
}
public class LocalDialog
{
[DllImport("Comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true, ThrowOnUnmappableChar = true)]
public static extern bool GetOpenFileName([In][Out] OpenFileName ofn);
}
[BepInPlugin("com.customradio.howtofish", "Custom Radio Framework", "0.1.2")]
public class Plugin : BaseUnityPlugin
{
public static ManualLogSource Log;
public static float LocalIgnoreNetworkTime;
private CustomRadioNetworkService networkService;
private CustomRadioAudioController audioController;
private CustomRadioUI uiManager;
private void Awake()
{
Log = ((BaseUnityPlugin)this).Logger;
Log.LogInfo((object)"Custom Radio v0.1.2 (Standard) загружен. Защита Steamworks включена.");
CleanupOldTempFiles();
audioController = new CustomRadioAudioController(this);
networkService = new CustomRadioNetworkService(this, audioController);
uiManager = new CustomRadioUI(this, networkService, audioController);
((MonoBehaviour)this).StartCoroutine(WaitForNetwork());
}
private IEnumerator WaitForNetwork()
{
while ((Object)(object)InstanceFinder.NetworkManager == (Object)null || (Object)(object)InstanceFinder.ClientManager == (Object)null)
{
yield return null;
}
networkService.RegisterCallbacks();
}
private void Update()
{
uiManager.HandleInput();
networkService.ProcessTimeouts();
}
private void OnGUI()
{
uiManager.DrawUI();
}
private void OnDestroy()
{
networkService?.UnregisterCallbacks();
audioController?.Dispose();
CleanupOldTempFiles();
}
private void CleanupOldTempFiles()
{
try
{
string[] files = Directory.GetFiles(Application.temporaryCachePath, "radio_sync_*.mp3");
for (int i = 0; i < files.Length; i++)
{
File.Delete(files[i]);
}
}
catch
{
}
}
}
public class CustomRadioAudioController : IDisposable
{
private Plugin plugin;
public AudioSource Source { get; private set; }
public bool IsPaused { get; private set; }
public float CurrentVolume { get; set; } = 1f;
public CustomRadioAudioController(Plugin plugin)
{
this.plugin = plugin;
}
public void EnsureRadioExists()
{
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)Source != (Object)null)
{
return;
}
GameObject val = null;
GameObject val2 = GameObject.Find("LocalPlayer");
float num = float.MaxValue;
if ((Object)(object)InstanceFinder.ClientManager != (Object)null)
{
foreach (NetworkObject value in ((ManagedObjects)InstanceFinder.ClientManager.Objects).Spawned.Values)
{
if (((Object)((Component)value).gameObject).name.IndexOf("Radio", StringComparison.OrdinalIgnoreCase) >= 0)
{
if (!((Object)(object)val2 != (Object)null))
{
val = ((Component)value).gameObject;
break;
}
float num2 = Vector3.Distance(val2.transform.position, ((Component)value).transform.position);
if (num2 < num)
{
num = num2;
val = ((Component)value).gameObject;
}
}
}
}
if ((Object)(object)val == (Object)null && (Object)(object)val2 != (Object)null)
{
val = val2;
}
if ((Object)(object)val != (Object)null)
{
Transform val3 = val.transform.Find("CustomRadioSource");
GameObject val4 = (GameObject)(((Object)(object)val3 != (Object)null) ? ((object)((Component)val3).gameObject) : ((object)new GameObject("CustomRadioSource")));
val4.transform.SetParent(val.transform);
val4.transform.localPosition = Vector3.zero;
Source = val4.GetComponent<AudioSource>() ?? val4.AddComponent<AudioSource>();
Source.spatialBlend = 1f;
Source.minDistance = 3f;
Source.maxDistance = 40f;
Source.rolloffMode = (AudioRolloffMode)1;
Source.volume = CurrentVolume;
}
}
public void PlayLocalFile(string path)
{
((MonoBehaviour)plugin).StartCoroutine(LoadAndPlayAudio("file:///" + path.Replace("\\", "/")));
}
private IEnumerator LoadAndPlayAudio(string url)
{
UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, (AudioType)13);
try
{
yield return www.SendWebRequest();
if ((Object)(object)Source == (Object)null)
{
yield break;
}
if ((int)www.result == 1)
{
AudioClip content = DownloadHandlerAudioClip.GetContent(www);
if ((Object)(object)Source.clip != (Object)null)
{
Object.Destroy((Object)(object)Source.clip);
}
Source.clip = content;
IsPaused = false;
Source.Play();
}
}
finally
{
((IDisposable)www)?.Dispose();
}
}
public void ApplyControlState(bool pauseState, float timePosition)
{
if (!((Object)(object)Source == (Object)null))
{
IsPaused = pauseState;
Source.time = timePosition;
if (IsPaused)
{
Source.Pause();
}
else
{
Source.Play();
}
}
}
public void ApplyVolume(float vol)
{
CurrentVolume = vol;
if ((Object)(object)Source != (Object)null)
{
Source.volume = CurrentVolume;
}
}
public void Dispose()
{
if ((Object)(object)Source != (Object)null && (Object)(object)Source.clip != (Object)null)
{
Object.Destroy((Object)(object)Source.clip);
}
}
}
public class CustomRadioNetworkService
{
private class DownloadContext
{
public FileStream Stream;
public int ExpectedChunks;
public HashSet<int> ReceivedChunks;
public float LastActivityTime;
public string TempPath;
}
public const int CHUNK_SIZE = 8192;
private const int MAX_FILE_SIZE = 15728640;
private const float DOWNLOAD_TIMEOUT = 120f;
private Plugin plugin;
private CustomRadioAudioController audio;
private bool isRegistered;
private Dictionary<int, DownloadContext> activeDownloads = new Dictionary<int, DownloadContext>();
public CustomRadioNetworkService(Plugin plugin, CustomRadioAudioController audio)
{
this.plugin = plugin;
this.audio = audio;
}
public void RegisterCallbacks()
{
if (!isRegistered)
{
GenericWriter<MusicChunkBroadcast>.SetWrite((Action<Writer, MusicChunkBroadcast>)CustomSerializers.WriteMusicChunkBroadcast);
GenericReader<MusicChunkBroadcast>.SetRead((Func<Reader, MusicChunkBroadcast>)CustomSerializers.ReadMusicChunkBroadcast);
GenericWriter<MusicControlBroadcast>.SetWrite((Action<Writer, MusicControlBroadcast>)CustomSerializers.WriteMusicControlBroadcast);
GenericReader<MusicControlBroadcast>.SetRead((Func<Reader, MusicControlBroadcast>)CustomSerializers.ReadMusicControlBroadcast);
GenericWriter<MusicVolumeBroadcast>.SetWrite((Action<Writer, MusicVolumeBroadcast>)CustomSerializers.WriteMusicVolumeBroadcast);
GenericReader<MusicVolumeBroadcast>.SetRead((Func<Reader, MusicVolumeBroadcast>)CustomSerializers.ReadMusicVolumeBroadcast);
InstanceFinder.ClientManager.RegisterBroadcast<MusicChunkBroadcast>((Action<MusicChunkBroadcast, Channel>)OnClientReceiveChunk);
InstanceFinder.ServerManager.RegisterBroadcast<MusicChunkBroadcast>((Action<NetworkConnection, MusicChunkBroadcast, Channel>)OnServerReceiveChunk, true);
InstanceFinder.ClientManager.RegisterBroadcast<MusicControlBroadcast>((Action<MusicControlBroadcast, Channel>)OnClientReceiveControl);
InstanceFinder.ServerManager.RegisterBroadcast<MusicControlBroadcast>((Action<NetworkConnection, MusicControlBroadcast, Channel>)OnServerReceiveControl, true);
InstanceFinder.ClientManager.RegisterBroadcast<MusicVolumeBroadcast>((Action<MusicVolumeBroadcast, Channel>)OnClientReceiveVolume);
InstanceFinder.ServerManager.RegisterBroadcast<MusicVolumeBroadcast>((Action<NetworkConnection, MusicVolumeBroadcast, Channel>)OnServerReceiveVolume, true);
isRegistered = true;
}
}
public void UnregisterCallbacks()
{
if (!isRegistered)
{
return;
}
if ((Object)(object)InstanceFinder.ClientManager != (Object)null)
{
InstanceFinder.ClientManager.UnregisterBroadcast<MusicChunkBroadcast>((Action<MusicChunkBroadcast, Channel>)OnClientReceiveChunk);
InstanceFinder.ClientManager.UnregisterBroadcast<MusicControlBroadcast>((Action<MusicControlBroadcast, Channel>)OnClientReceiveControl);
InstanceFinder.ClientManager.UnregisterBroadcast<MusicVolumeBroadcast>((Action<MusicVolumeBroadcast, Channel>)OnClientReceiveVolume);
}
if ((Object)(object)InstanceFinder.ServerManager != (Object)null)
{
InstanceFinder.ServerManager.UnregisterBroadcast<MusicChunkBroadcast>((Action<NetworkConnection, MusicChunkBroadcast, Channel>)OnServerReceiveChunk);
InstanceFinder.ServerManager.UnregisterBroadcast<MusicControlBroadcast>((Action<NetworkConnection, MusicControlBroadcast, Channel>)OnServerReceiveControl);
InstanceFinder.ServerManager.UnregisterBroadcast<MusicVolumeBroadcast>((Action<NetworkConnection, MusicVolumeBroadcast, Channel>)OnServerReceiveVolume);
}
foreach (DownloadContext value in activeDownloads.Values)
{
value.Stream.Dispose();
if (File.Exists(value.TempPath))
{
File.Delete(value.TempPath);
}
}
activeDownloads.Clear();
}
public void SendFile(string path)
{
((MonoBehaviour)plugin).StartCoroutine(StreamFileCoroutine(path));
}
private IEnumerator StreamFileCoroutine(string path)
{
if ((Object)(object)InstanceFinder.ClientManager == (Object)null)
{
yield break;
}
FileInfo fileInfo = new FileInfo(path);
if (fileInfo.Length > 15728640)
{
yield break;
}
int trackId = Random.Range(1000, 999999);
int totalChunks = Mathf.CeilToInt((float)fileInfo.Length / 8192f);
using FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[8192];
int chunkIndex = 0;
int num;
while ((num = fs.Read(buffer, 0, buffer.Length)) > 0)
{
byte[] array;
if (num < 8192)
{
array = new byte[num];
Buffer.BlockCopy(buffer, 0, array, 0, num);
}
else
{
array = buffer;
}
InstanceFinder.ClientManager.Broadcast<MusicChunkBroadcast>(new MusicChunkBroadcast
{
trackId = trackId,
chunkIndex = chunkIndex,
totalChunks = totalChunks,
data = array
}, (Channel)0);
chunkIndex++;
yield return (object)new WaitForSeconds(0.03f);
}
}
public void SendControl(bool isPaused, float time)
{
if ((Object)(object)InstanceFinder.ClientManager != (Object)null)
{
InstanceFinder.ClientManager.Broadcast<MusicControlBroadcast>(new MusicControlBroadcast
{
isPaused = isPaused,
timePosition = time
}, (Channel)0);
}
}
public void SendVolume(float vol)
{
if ((Object)(object)InstanceFinder.ClientManager != (Object)null)
{
InstanceFinder.ClientManager.Broadcast<MusicVolumeBroadcast>(new MusicVolumeBroadcast
{
volume = vol
}, (Channel)0);
}
}
private void OnServerReceiveChunk(NetworkConnection conn, MusicChunkBroadcast msg, Channel channel)
{
if (msg.data != null && msg.data.Length <= 9216)
{
InstanceFinder.ServerManager.Broadcast<MusicChunkBroadcast>(msg, true, (Channel)0);
}
}
private void OnServerReceiveControl(NetworkConnection conn, MusicControlBroadcast msg, Channel channel)
{
InstanceFinder.ServerManager.Broadcast<MusicControlBroadcast>(msg, true, (Channel)0);
}
private void OnServerReceiveVolume(NetworkConnection conn, MusicVolumeBroadcast msg, Channel channel)
{
InstanceFinder.ServerManager.Broadcast<MusicVolumeBroadcast>(msg, true, (Channel)0);
}
private void OnClientReceiveChunk(MusicChunkBroadcast msg, Channel channel)
{
if (!activeDownloads.TryGetValue(msg.trackId, out var value))
{
string text = Path.Combine(Application.temporaryCachePath, $"radio_sync_{msg.trackId}.mp3");
value = new DownloadContext
{
TempPath = text,
Stream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None),
ExpectedChunks = msg.totalChunks,
ReceivedChunks = new HashSet<int>(),
LastActivityTime = Time.realtimeSinceStartup
};
activeDownloads[msg.trackId] = value;
}
value.Stream.Seek((long)msg.chunkIndex * 8192L, SeekOrigin.Begin);
value.Stream.Write(msg.data, 0, msg.data.Length);
value.ReceivedChunks.Add(msg.chunkIndex);
value.LastActivityTime = Time.realtimeSinceStartup;
if (value.ReceivedChunks.Count >= value.ExpectedChunks)
{
value.Stream.Dispose();
activeDownloads.Remove(msg.trackId);
audio.PlayLocalFile(value.TempPath);
}
}
private void OnClientReceiveControl(MusicControlBroadcast msg, Channel channel)
{
if (!(Time.realtimeSinceStartup - Plugin.LocalIgnoreNetworkTime < 0.8f))
{
audio.ApplyControlState(msg.isPaused, msg.timePosition);
}
}
private void OnClientReceiveVolume(MusicVolumeBroadcast msg, Channel channel)
{
if (!(Time.realtimeSinceStartup - Plugin.LocalIgnoreNetworkTime < 0.8f))
{
audio.ApplyVolume(msg.volume);
}
}
public void ProcessTimeouts()
{
if (activeDownloads.Count == 0)
{
return;
}
List<int> list = null;
float realtimeSinceStartup = Time.realtimeSinceStartup;
foreach (KeyValuePair<int, DownloadContext> activeDownload in activeDownloads)
{
if (realtimeSinceStartup - activeDownload.Value.LastActivityTime > 120f)
{
if (list == null)
{
list = new List<int>();
}
list.Add(activeDownload.Key);
}
}
if (list == null)
{
return;
}
foreach (int item in list)
{
DownloadContext downloadContext = activeDownloads[item];
downloadContext.Stream.Dispose();
if (File.Exists(downloadContext.TempPath))
{
File.Delete(downloadContext.TempPath);
}
activeDownloads.Remove(item);
}
}
}
public class CustomRadioUI
{
private Plugin plugin;
private CustomRadioNetworkService network;
private CustomRadioAudioController audio;
private bool showUI;
private bool isDialogOpen;
private ConcurrentQueue<string> pendingFiles = new ConcurrentQueue<string>();
private float lastSeekSendTime;
private float lastVolumeSendTime;
private GUIStyle windowStyle;
private GUIStyle btnStyle;
private GUIStyle labelStyle;
private GUIStyle sliderTrackStyle;
private GUIStyle sliderThumbStyle;
private bool stylesInitialized;
public CustomRadioUI(Plugin plugin, CustomRadioNetworkService network, CustomRadioAudioController audio)
{
this.plugin = plugin;
this.network = network;
this.audio = audio;
}
private void InitStyles()
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Expected O, but got Unknown
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_0167: Expected O, but got Unknown
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
//IL_01be: Expected O, but got Unknown
//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
//IL_020a: Unknown result type (might be due to invalid IL or missing references)
//IL_0214: Expected O, but got Unknown
//IL_0236: Unknown result type (might be due to invalid IL or missing references)
//IL_0253: Unknown result type (might be due to invalid IL or missing references)
if (!stylesInitialized)
{
windowStyle = new GUIStyle(GUI.skin.box);
windowStyle.normal.background = MakeTex(2, 2, new Color(0.08f, 0.08f, 0.08f, 0.95f));
windowStyle.normal.textColor = Color.white;
windowStyle.alignment = (TextAnchor)1;
windowStyle.fontStyle = (FontStyle)1;
windowStyle.fontSize = 14;
btnStyle = new GUIStyle(GUI.skin.button);
btnStyle.normal.background = MakeTex(2, 2, new Color(0.18f, 0.18f, 0.18f, 1f));
btnStyle.hover.background = MakeTex(2, 2, new Color(0.35f, 0.35f, 0.35f, 1f));
btnStyle.active.background = MakeTex(2, 2, new Color(0.5f, 0.5f, 0.5f, 1f));
btnStyle.normal.textColor = Color.white;
btnStyle.fontStyle = (FontStyle)1;
labelStyle = new GUIStyle(GUI.skin.label);
labelStyle.normal.textColor = new Color(0.85f, 0.85f, 0.85f, 1f);
labelStyle.alignment = (TextAnchor)4;
labelStyle.fontSize = 13;
sliderTrackStyle = new GUIStyle(GUI.skin.horizontalSlider);
sliderTrackStyle.normal.background = MakeTex(2, 2, new Color(0.2f, 0.2f, 0.2f, 1f));
sliderTrackStyle.fixedHeight = 6f;
sliderThumbStyle = new GUIStyle(GUI.skin.horizontalSliderThumb);
sliderThumbStyle.normal.background = MakeTex(2, 2, new Color(0.8f, 0.8f, 0.8f, 1f));
sliderThumbStyle.hover.background = MakeTex(2, 2, Color.white);
sliderThumbStyle.fixedWidth = 14f;
sliderThumbStyle.fixedHeight = 14f;
stylesInitialized = true;
}
}
private Texture2D MakeTex(int width, int height, Color col)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
Color[] array = (Color[])(object)new Color[width * height];
for (int i = 0; i < array.Length; i++)
{
array[i] = col;
}
Texture2D val = new Texture2D(width, height);
val.SetPixels(array);
val.Apply();
return val;
}
public void HandleInput()
{
if (Input.GetKeyDown((KeyCode)121))
{
showUI = !showUI;
audio.EnsureRadioExists();
}
if (pendingFiles.TryDequeue(out var result))
{
network.SendFile(result);
}
}
public void DrawUI()
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
//IL_020e: Unknown result type (might be due to invalid IL or missing references)
//IL_0275: Unknown result type (might be due to invalid IL or missing references)
//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
//IL_0337: Unknown result type (might be due to invalid IL or missing references)
if (!showUI)
{
return;
}
InitStyles();
GUI.Box(new Rect(20f, 20f, 320f, 200f), "\nC U S T O M R A D I O", windowStyle);
if (GUI.Button(new Rect(40f, 55f, 280f, 25f), "Загрузить MP3", btnStyle))
{
OpenWindowsExplorerSafe();
}
AudioSource source = audio.Source;
if (!((Object)(object)source != (Object)null) || !((Object)(object)source.clip != (Object)null))
{
return;
}
string text = FormatTime(source.time) + " / " + FormatTime(source.clip.length);
GUI.Label(new Rect(40f, 85f, 280f, 20f), text, labelStyle);
GUI.changed = false;
float time = GUI.HorizontalSlider(new Rect(40f, 105f, 280f, 15f), source.time, 0f, source.clip.length, sliderTrackStyle, sliderThumbStyle);
if (GUI.changed)
{
source.time = time;
Plugin.LocalIgnoreNetworkTime = Time.realtimeSinceStartup;
if (Time.realtimeSinceStartup - lastSeekSendTime > 0.1f)
{
lastSeekSendTime = Time.realtimeSinceStartup;
network.SendControl(audio.IsPaused, time);
}
}
if (GUI.Button(new Rect(100f, 130f, 45f, 25f), "<<", btnStyle))
{
float time2 = (source.time = Mathf.Max(0f, source.time - 15f));
Plugin.LocalIgnoreNetworkTime = Time.realtimeSinceStartup;
network.SendControl(audio.IsPaused, time2);
}
string text2 = (audio.IsPaused ? "Play" : "Pause");
if (GUI.Button(new Rect(155f, 130f, 50f, 25f), text2, btnStyle))
{
bool flag = !audio.IsPaused;
audio.ApplyControlState(flag, source.time);
Plugin.LocalIgnoreNetworkTime = Time.realtimeSinceStartup;
network.SendControl(flag, source.time);
}
if (GUI.Button(new Rect(215f, 130f, 45f, 25f), ">>", btnStyle))
{
float time3 = (source.time = Mathf.Min(source.clip.length, source.time + 15f));
Plugin.LocalIgnoreNetworkTime = Time.realtimeSinceStartup;
network.SendControl(audio.IsPaused, time3);
}
GUI.Label(new Rect(40f, 165f, 70f, 20f), $"Vol: {Mathf.RoundToInt(audio.CurrentVolume * 100f)}%", labelStyle);
GUI.changed = false;
float vol = GUI.HorizontalSlider(new Rect(110f, 170f, 210f, 15f), audio.CurrentVolume, 0f, 1f, sliderTrackStyle, sliderThumbStyle);
if (GUI.changed)
{
audio.ApplyVolume(vol);
Plugin.LocalIgnoreNetworkTime = Time.realtimeSinceStartup;
if (Time.realtimeSinceStartup - lastVolumeSendTime > 0.1f)
{
lastVolumeSendTime = Time.realtimeSinceStartup;
network.SendVolume(vol);
}
}
}
private string FormatTime(float timeInSeconds)
{
int num = Mathf.FloorToInt(timeInSeconds / 60f);
int num2 = Mathf.FloorToInt(timeInSeconds % 60f);
return $"{num:00}:{num2:00}";
}
private void OpenWindowsExplorerSafe()
{
if (isDialogOpen)
{
return;
}
isDialogOpen = true;
new Thread((ThreadStart)delegate
{
OpenFileName openFileName = new OpenFileName();
openFileName.structSize = Marshal.SizeOf(openFileName);
openFileName.filter = "MP3 Files (*.mp3)\0*.mp3\0";
openFileName.file = new string(new char[1024]);
openFileName.maxFile = openFileName.file.Length;
openFileName.title = "Выберите песню для радио";
openFileName.flags = 528392;
if (LocalDialog.GetOpenFileName(openFileName))
{
pendingFiles.Enqueue(openFileName.file.TrimEnd(new char[1]));
}
isDialogOpen = false;
}).Start();
}
}