using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet;
using FishNet.Broadcast;
using FishNet.Managing.Client;
using FishNet.Managing.Server;
using FishNet.Serializing;
using FishNet.Transporting;
using HTF.Shared;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
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("HTFCustomRadio")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.0.0")]
[assembly: AssemblyInformationalVersion("1.3.0")]
[assembly: AssemblyProduct("HTFCustomRadio")]
[assembly: AssemblyTitle("HTFCustomRadio")]
[assembly: AssemblyVersion("1.3.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace HTF.Shared
{
internal static class AudioLoading
{
internal static readonly string[] SupportedExtensions = new string[3] { ".ogg", ".wav", ".mp3" };
internal static bool IsSupported(string path)
{
string ext = Path.GetExtension(path);
return Array.Exists(SupportedExtensions, (string e) => string.Equals(e, ext, StringComparison.OrdinalIgnoreCase));
}
internal static AudioType TypeOf(string path)
{
return (AudioType)(Path.GetExtension(path)?.ToLowerInvariant() switch
{
".ogg" => 14,
".wav" => 20,
".mp3" => 13,
_ => 0,
});
}
internal static IEnumerator Load(string source, bool stream, Action<AudioClip> onLoaded, Action<string> onError)
{
bool isRemote = source.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || source.StartsWith("https://", StringComparison.OrdinalIgnoreCase);
string text;
if (isRemote)
{
text = source;
}
else
{
if (!File.Exists(source))
{
onError?.Invoke("No existe el archivo: " + source);
yield break;
}
text = new Uri(Path.GetFullPath(source)).AbsoluteUri;
}
AudioType val = TypeOf(source);
if ((int)val == 0)
{
onError?.Invoke("Formato no soportado: " + source);
yield break;
}
UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(text, val);
try
{
DownloadHandler downloadHandler = request.downloadHandler;
DownloadHandlerAudioClip val2 = (DownloadHandlerAudioClip)(object)((downloadHandler is DownloadHandlerAudioClip) ? downloadHandler : null);
if (val2 != null)
{
val2.streamAudio = stream || isRemote;
val2.compressed = false;
}
yield return request.SendWebRequest();
if ((int)request.result != 1)
{
onError?.Invoke(request.error + " (" + source + ")");
yield break;
}
AudioClip content;
try
{
content = DownloadHandlerAudioClip.GetContent(request);
}
catch (Exception ex)
{
onError?.Invoke(ex.Message + " (" + source + ")");
yield break;
}
if ((Object)(object)content == (Object)null || (int)content.loadState == 3)
{
onError?.Invoke("Unity no pudo descodificar " + Path.GetFileName(source) + ". Si es un MP3 con etiquetas raras, reexpórtalo a OGG.");
yield break;
}
((Object)content).name = (isRemote ? source : Path.GetFileNameWithoutExtension(source));
onLoaded?.Invoke(content);
}
finally
{
((IDisposable)request)?.Dispose();
}
}
}
}
namespace HTFCustomRadio
{
internal class Station
{
public string Name;
public List<string> Tracks = new List<string>();
public bool IsStream;
public AudioSource Source;
public float Frequency;
public int Index;
public bool Loading;
public float LastStart = -99f;
public float ExpectedEnd;
public int RecentAdvances;
public float WindowStart;
public bool Paused;
public AudioClip OwnedClip;
public string CurrentTrack
{
get
{
if (Tracks.Count != 0)
{
return Path.GetFileNameWithoutExtension(Tracks[Index % Tracks.Count]);
}
return "(vacía)";
}
}
}
[BepInPlugin("com.hatsuneexo.htfcustomradio", "HTF Custom Radio", "1.3.0")]
[BepInProcess("How to Fish.exe")]
public class Plugin : BaseUnityPlugin
{
public const string Guid = "com.hatsuneexo.htfcustomradio";
internal static ManualLogSource Log;
internal static Plugin Instance;
internal static ConfigEntry<bool> Shuffle;
internal static ConfigEntry<int> KeepOriginalStations;
internal static ConfigEntry<string> StreamStations;
internal static ConfigEntry<bool> AnnounceTrack;
internal static ConfigEntry<string> MusicFolders;
internal static ConfigEntry<bool> SplitSubfolders;
internal static ConfigEntry<bool> UseMyMusicFolder;
internal static ConfigEntry<Key> ReloadKey;
internal static ConfigEntry<Key> SkipKey;
private readonly List<Station> _stations = new List<Station>();
private readonly List<Station> _live = new List<Station>();
private object _lastRadio;
private static readonly Random Rng = new Random();
private const float MinSecondsBetweenTracks = 1f;
private const int MaxAdvancesPerMinute = 30;
private const float ResyncToleranceSeconds = 2.5f;
private const float BroadcastInterval = 8f;
private float _nextBroadcast;
private readonly HashSet<string> _missingTracks = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private void Awake()
{
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Expected O, but got Unknown
//IL_0198: Unknown result type (might be due to invalid IL or missing references)
//IL_019e: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Instance = this;
Shuffle = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Shuffle", true, "Reproduce las pistas de cada emisora en orden aleatorio.");
KeepOriginalStations = ((BaseUnityPlugin)this).Config.Bind<int>("General", "KeepOriginalStations", 0, new ConfigDescription("Cuántas emisoras originales del juego dejar intactas antes de empezar a sustituir.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 8), Array.Empty<object>()));
AnnounceTrack = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AnnounceTrack", true, "Escribe en el log qué pista empieza a sonar en cada emisora.");
UseMyMusicFolder = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UseMyMusicFolder", true, "Usa tu carpeta de música de Windows como origen de emisoras, sin configurar nada. Cada subcarpeta suya se convierte en una emisora.");
MusicFolders = ((BaseUnityPlugin)this).Config.Bind<string>("General", "MusicFolders", "", "Carpetas de tu disco que quieres usar como emisoras, separadas por ';'. Ejemplo: C:\\Users\\Usuario\\Music;D:\\Descargas\\Lofi No hace falta copiar ni mover nada: el mod lee de donde estén.");
SplitSubfolders = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SplitSubfolders", true, "Si una carpeta de MusicFolders tiene subcarpetas, cada subcarpeta se convierte en una emisora distinta. Si lo apagas, toda la carpeta es una sola emisora.");
SkipKey = ((BaseUnityPlugin)this).Config.Bind<Key>("General", "SkipKey", (Key)103, "Salta a la siguiente canción de la emisora que estés escuchando en ese momento.");
ReloadKey = ((BaseUnityPlugin)this).Config.Bind<Key>("General", "ReloadKey", (Key)102, "Vuelve a leer las carpetas sin cerrar el juego. Útil mientras montas tus emisoras.");
StreamStations = ((BaseUnityPlugin)this).Config.Bind<string>("Streaming", "StreamStations", "", "Emisoras de internet, formato Nombre=URL separadas por ';'. La URL debe apuntar a un flujo de audio directo (.mp3/.ogg), no a una página web. Ejemplo: Lofi=https://ejemplo.com/stream.mp3;Jazz=https://otro.com/jazz.ogg");
Sync.Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Multijugador", "SyncWithHost", false, "EXPERIMENTAL. El anfitrión decide qué canción suena y todos la oyen a la vez. Requiere que TODOS tengáis el mod y los mismos archivos de música: por la red solo viaja el nombre de la canción, no el audio. Desactivado por defecto porque no ha podido probarse en una partida real con varios jugadores.");
Sync.EnsureSerializers();
DiscoverStations();
if (_stations.Count == 0)
{
Log.LogInfo((object)"Ninguna emisora configurada. Crea una carpeta por emisora en BepInEx/plugins/HTFCustomRadio/Stations/ y mete ahí tus .ogg o .mp3");
}
Harmony val = new Harmony("com.hatsuneexo.htfcustomradio");
val.PatchAll(Assembly.GetExecutingAssembly());
Log.LogInfo((object)(val.GetPatchedMethods().Any() ? "Enganchado a Radio.OnStartClient: coge una radio en la partida." : "AVISO: no encuentro Radio.OnStartClient. El mod no hará nada."));
}
private void DiscoverStations()
{
string pluginPath = Paths.PluginPath;
if (Directory.Exists(pluginPath))
{
foreach (string item in Directory.GetDirectories(pluginPath, "Stations", SearchOption.AllDirectories).SelectMany(Directory.GetDirectories).OrderBy<string, string>((string d) => Path.GetFileName(d), StringComparer.OrdinalIgnoreCase))
{
List<string> list = Directory.GetFiles(item, "*.*", SearchOption.AllDirectories).Where(AudioLoading.IsSupported).OrderBy<string, string>((string f) => Path.GetFileName(f), StringComparer.OrdinalIgnoreCase)
.ToList();
if (list.Count == 0)
{
Log.LogWarning((object)("Emisora '" + Path.GetFileName(item) + "' sin pistas soportadas (.ogg/.wav/.mp3)."));
continue;
}
_stations.Add(new Station
{
Name = Path.GetFileName(item),
Tracks = list
});
}
}
foreach (string item2 in FoldersToScan())
{
List<string> list2 = (SplitSubfolders.Value ? Directory.GetDirectories(item2).OrderBy<string, string>((string d) => d, StringComparer.OrdinalIgnoreCase).ToList() : new List<string>());
foreach (string item3 in (list2.Count > 0) ? list2 : new List<string> { item2 })
{
List<string> list3 = SafeFiles(item3);
if (list3.Count != 0)
{
_stations.Add(new Station
{
Name = Path.GetFileName(item3.TrimEnd(new char[1] { Path.DirectorySeparatorChar })),
Tracks = list3
});
}
}
}
string[] array = StreamStations.Value.Split(new char[1] { ';' });
for (int num = 0; num < array.Length; num++)
{
string[] array2 = array[num].Split(new char[1] { '=' }, 2);
if (array2.Length == 2)
{
string text = array2[0].Trim();
string text2 = array2[1].Trim();
if (text.Length != 0 && text2.Length != 0)
{
_stations.Add(new Station
{
Name = text,
IsStream = true,
Tracks = new List<string> { text2 }
});
}
}
}
if (_stations.Count > 0)
{
Log.LogInfo((object)string.Format("{0} emisora(s): {1}", _stations.Count, string.Join(", ", _stations.Select((Station s) => s.Name))));
}
}
private List<string> FoldersToScan()
{
List<string> result = new List<string>();
HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (UseMyMusicFolder.Value)
{
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);
if (!string.IsNullOrEmpty(folderPath) && Directory.Exists(folderPath))
{
Add(folderPath, warnIfMissing: false);
Log.LogInfo((object)("Usando tu carpeta de música: " + folderPath));
}
}
string[] array = MusicFolders.Value.Split(new char[1] { ';' });
for (int i = 0; i < array.Length; i++)
{
Add(array[i], warnIfMissing: true);
}
return result;
void Add(string path, bool warnIfMissing)
{
if (!string.IsNullOrEmpty(path))
{
string fullPath;
try
{
fullPath = Path.GetFullPath(path.Trim().Trim(new char[1] { '"' }));
}
catch
{
Log.LogWarning((object)("Ruta inválida: " + path));
return;
}
if (!Directory.Exists(fullPath))
{
if (warnIfMissing)
{
Log.LogWarning((object)("No existe la carpeta: " + fullPath));
}
}
else if (seen.Add(fullPath))
{
result.Add(fullPath);
}
}
}
}
private List<string> SafeFiles(string dir)
{
try
{
return Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories).Where(AudioLoading.IsSupported).OrderBy<string, string>((string f) => Path.GetFileName(f), StringComparer.OrdinalIgnoreCase)
.ToList();
}
catch (Exception ex)
{
Log.LogWarning((object)("No pude leer " + dir + ": " + ex.Message));
return new List<string>();
}
}
private void HandleSkipKey()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
Keyboard current = Keyboard.current;
if (current == null)
{
return;
}
KeyControl val = current[SkipKey.Value];
if (val == null || !((ButtonControl)val).wasPressedThisFrame)
{
return;
}
if (_live.Count == 0)
{
Log.LogInfo((object)"No hay ninguna emisora activa. Coge una radio primero.");
return;
}
Station station = null;
float num = 0.01f;
foreach (Station item in _live)
{
if (!((Object)(object)item.Source == (Object)null) && !(item.Source.volume <= num))
{
num = item.Source.volume;
station = item;
}
}
if (station == null)
{
Log.LogInfo((object)"No estás sintonizado en ninguna emisora; gira el dial.");
}
else if (station.IsStream)
{
Log.LogInfo((object)("[" + station.Name + "] es una emisora de internet: no hay pistas que saltar."));
}
else if (!station.Loading)
{
if (station.Tracks.Count < 2)
{
Log.LogInfo((object)("[" + station.Name + "] solo tiene una canción; añade más a la carpeta."));
return;
}
Advance(station);
station.ExpectedEnd = 0f;
station.RecentAdvances = 0;
station.Paused = false;
((MonoBehaviour)this).StartCoroutine(PlayCurrent(station));
}
}
private void HandleReloadKey()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
Keyboard current = Keyboard.current;
if (current == null)
{
return;
}
KeyControl val = current[ReloadKey.Value];
if (val != null && ((ButtonControl)val).wasPressedThisFrame)
{
((MonoBehaviour)this).StopAllCoroutines();
_live.Clear();
_stations.Clear();
DiscoverStations();
if (_lastRadio != null)
{
TakeOverRadio(_lastRadio);
Log.LogInfo((object)"Emisoras recargadas.");
}
else
{
Log.LogInfo((object)"Emisoras recargadas. Coge una radio para oírlas.");
}
}
}
internal void TakeOverRadio(object radio)
{
_lastRadio = radio;
if (_stations.Count == 0)
{
return;
}
((MonoBehaviour)this).StopAllCoroutines();
foreach (Station station2 in _stations)
{
station2.Loading = false;
station2.Paused = false;
station2.RecentAdvances = 0;
}
if (AccessTools.Field(radio.GetType(), "_channels")?.GetValue(radio) is Array { Length: not 0 } array)
{
Log.LogInfo((object)$"Radio encontrada con {array.Length} canal(es).");
_live.Clear();
int num = Mathf.Clamp(KeepOriginalStations.Value, 0, array.Length);
for (int i = num; i < array.Length; i++)
{
int num2 = i - num;
if (num2 < _stations.Count)
{
object value = array.GetValue(i);
object? obj = AccessTools.Field(value.GetType(), "_channelSource")?.GetValue(value);
AudioSource val = (AudioSource)((obj is AudioSource) ? obj : null);
if ((Object)(object)val == (Object)null)
{
Log.LogWarning((object)$"Canal {i} sin AudioSource, lo dejo como está.");
continue;
}
object obj2 = AccessTools.Field(value.GetType(), "_frequency")?.GetValue(value);
Station station = _stations[num2];
station.Source = val;
station.Frequency = ((obj2 is float num3) ? num3 : 0f);
station.Index = (Shuffle.Value ? Rng.Next(station.Tracks.Count) : 0);
_live.Add(station);
Log.LogInfo((object)$" {station.Frequency:0.0} -> {station.Name} ({station.Tracks.Count} pista(s))");
((MonoBehaviour)this).StartCoroutine(PlayCurrent(station));
continue;
}
break;
}
}
else
{
Log.LogWarning((object)"La radio no expone canales; ¿cambió el juego?");
}
}
private IEnumerator PlayCurrent(Station station, float startAt = 0f)
{
if (station.Loading || (Object)(object)station.Source == (Object)null)
{
yield break;
}
station.Loading = true;
string path = station.Tracks[station.Index % station.Tracks.Count];
yield return AudioLoading.Load(path, station.IsStream, delegate(AudioClip clip)
{
if (!((Object)(object)station.Source == (Object)null))
{
if ((Object)(object)station.OwnedClip != (Object)null && (Object)(object)station.OwnedClip != (Object)(object)clip)
{
Object.Destroy((Object)(object)station.OwnedClip);
}
station.OwnedClip = clip;
station.Source.clip = clip;
station.Source.loop = station.IsStream;
station.Source.time = Mathf.Clamp(startAt, 0f, Mathf.Max(0f, clip.length - 0.1f));
station.Source.Play();
station.LastStart = Time.unscaledTime;
station.ExpectedEnd = Time.unscaledTime + Mathf.Max(1f, clip.length - station.Source.time);
if (AnnounceTrack.Value)
{
Log.LogInfo((object)("[" + station.Name + "] suena '" + ((Object)clip).name + "'"));
}
Sync.Announce(station.Name, path, station.Source.time);
}
}, delegate(string msg)
{
Log.LogWarning((object)("[" + station.Name + "] " + msg));
Advance(station);
});
station.Loading = false;
}
private bool AllowAdvance(Station station)
{
if (station.Paused)
{
return false;
}
float unscaledTime = Time.unscaledTime;
if (unscaledTime - station.WindowStart > 60f)
{
station.WindowStart = unscaledTime;
station.RecentAdvances = 0;
}
station.RecentAdvances++;
if (station.RecentAdvances <= 30)
{
return true;
}
station.Paused = true;
Log.LogError((object)($"[{station.Name}] ha cambiado de pista {station.RecentAdvances} veces en un " + "minuto, lo cual no es normal. Emisora detenida para no agotar la memoria. Pulsa la tecla de recarga para reactivarla."));
return false;
}
internal void ApplySync(string stationName, string trackName, float position)
{
Station station = _live.FirstOrDefault((Station s) => string.Equals(s.Name, stationName, StringComparison.OrdinalIgnoreCase));
if (station == null || station.IsStream)
{
return;
}
int num = station.Tracks.FindIndex((string t) => string.Equals(Path.GetFileNameWithoutExtension(t), trackName, StringComparison.OrdinalIgnoreCase));
if (num < 0)
{
if (_missingTracks.Add(trackName))
{
Log.LogWarning((object)("[" + stationName + "] el anfitrión puso '" + trackName + "' y tú no la tienes. Para oír lo mismo necesitáis los mismos archivos."));
}
}
else
{
AudioSource source = station.Source;
if (station.Index != num || !((Object)(object)source != (Object)null) || !source.isPlaying || !(Mathf.Abs(source.time - position) < 2.5f))
{
station.Index = num;
station.Paused = false;
station.RecentAdvances = 0;
((MonoBehaviour)this).StartCoroutine(PlayCurrent(station, position));
}
}
}
private void BroadcastState()
{
if (!Sync.IsHost || Time.unscaledTime < _nextBroadcast)
{
return;
}
_nextBroadcast = Time.unscaledTime + 8f;
foreach (Station item in _live)
{
if (!item.IsStream && !((Object)(object)item.Source == (Object)null) && !((Object)(object)item.Source.clip == (Object)null) && item.Source.isPlaying)
{
Sync.Announce(item.Name, item.Tracks[item.Index % item.Tracks.Count], item.Source.time);
}
}
}
private void Advance(Station station)
{
if (station.Tracks.Count != 0)
{
station.Index = ((Shuffle.Value && station.Tracks.Count > 1) ? NextRandomDifferent(station) : ((station.Index + 1) % station.Tracks.Count));
}
}
private static int NextRandomDifferent(Station station)
{
int num = Rng.Next(station.Tracks.Count - 1);
if (num < station.Index)
{
return num;
}
return num + 1;
}
private void Update()
{
HandleReloadKey();
HandleSkipKey();
Sync.TryRegisterClient();
BroadcastState();
if (Sync.FollowingHost)
{
return;
}
foreach (Station item in _live)
{
if (!item.Loading && !item.IsStream)
{
AudioSource source = item.Source;
if (!((Object)(object)source == (Object)null) && !((Object)(object)source.clip == (Object)null) && ((Behaviour)source).isActiveAndEnabled && !source.isPlaying && !(Time.unscaledTime < item.ExpectedEnd - 0.25f) && AllowAdvance(item))
{
Advance(item);
((MonoBehaviour)this).StartCoroutine(PlayCurrent(item));
}
}
}
}
}
[HarmonyPatch]
internal static class RadioPatch
{
private static MethodBase TargetMethod()
{
Type type = AccessTools.TypeByName("Radio");
if (!(type == null))
{
return AccessTools.Method(type, "OnStartClient", (Type[])null, (Type[])null);
}
return null;
}
private static bool Prepare()
{
return TargetMethod() != null;
}
private static void Postfix(object __instance)
{
try
{
Plugin.Instance?.TakeOverRadio(__instance);
}
catch (Exception arg)
{
Plugin.Log.LogError((object)$"No pude tomar la radio: {arg}");
}
}
}
public struct RadioSyncBroadcast : IBroadcast
{
public string Station;
public string Track;
public float Position;
}
internal static class Sync
{
internal static ConfigEntry<bool> Enabled;
private static bool _serializersReady;
private static bool _clientRegistered;
private static bool _broken;
internal static bool IsHost => InstanceFinder.IsServerStarted;
internal static bool FollowingHost
{
get
{
if (Enabled != null && Enabled.Value && _clientRegistered)
{
return !IsHost;
}
return false;
}
}
internal static void EnsureSerializers()
{
if (_serializersReady || _broken)
{
return;
}
try
{
GenericWriter<RadioSyncBroadcast>.SetWrite((Action<Writer, RadioSyncBroadcast>)delegate(Writer writer, RadioSyncBroadcast value)
{
writer.WriteRadioSync(value);
});
GenericReader<RadioSyncBroadcast>.SetRead((Func<Reader, RadioSyncBroadcast>)((Reader reader) => reader.ReadRadioSync()));
_serializersReady = true;
}
catch (Exception ex)
{
_broken = true;
Plugin.Log.LogWarning((object)("No pude registrar el serializador de red: " + ex.Message + ". La sincronización queda desactivada; la radio sigue funcionando en local."));
}
}
internal static void TryRegisterClient()
{
if (_clientRegistered || _broken || Enabled == null || !Enabled.Value)
{
return;
}
ClientManager clientManager = InstanceFinder.ClientManager;
if ((Object)(object)clientManager == (Object)null)
{
return;
}
try
{
clientManager.RegisterBroadcast<RadioSyncBroadcast>((Action<RadioSyncBroadcast, Channel>)OnReceived);
_clientRegistered = true;
Plugin.Log.LogInfo((object)"Sincronización activa: escuchando al anfitrión.");
}
catch (Exception ex)
{
_broken = true;
Plugin.Log.LogWarning((object)("No pude activar la sincronización: " + ex.Message + ". La radio sigue funcionando en local."));
}
}
internal static void Unregister()
{
if (!_clientRegistered)
{
return;
}
try
{
ClientManager clientManager = InstanceFinder.ClientManager;
if (clientManager != null)
{
clientManager.UnregisterBroadcast<RadioSyncBroadcast>((Action<RadioSyncBroadcast, Channel>)OnReceived);
}
}
catch
{
}
_clientRegistered = false;
}
internal static void Announce(string station, string trackPath, float position)
{
if (_broken || Enabled == null || !Enabled.Value || !IsHost)
{
return;
}
ServerManager serverManager = InstanceFinder.ServerManager;
if ((Object)(object)serverManager == (Object)null)
{
return;
}
try
{
serverManager.Broadcast<RadioSyncBroadcast>(new RadioSyncBroadcast
{
Station = station,
Track = Path.GetFileNameWithoutExtension(trackPath),
Position = position
}, true, (Channel)0);
}
catch (Exception ex)
{
_broken = true;
Plugin.Log.LogWarning((object)("Fallo enviando la sincronización: " + ex.Message + ". Cada uno oirá su propia música."));
}
}
private static void OnReceived(RadioSyncBroadcast message, Channel channel)
{
if (IsHost)
{
return;
}
try
{
Plugin.Instance?.ApplySync(message.Station, message.Track, message.Position);
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("No pude aplicar la sincronización: " + ex.Message));
}
}
}
public static class RadioSyncSerializer
{
public static void WriteRadioSync(this Writer writer, RadioSyncBroadcast value)
{
if (writer != null)
{
writer.WriteString(value.Station);
writer.WriteString(value.Track);
writer.WriteSingle(value.Position);
}
}
public static RadioSyncBroadcast ReadRadioSync(this Reader reader)
{
return new RadioSyncBroadcast
{
Station = reader.ReadString(),
Track = reader.ReadString(),
Position = reader.ReadSingle()
};
}
}
}