using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using TVSync.Networking;
using TVSync.Patches;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Video;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TVSync")]
[assembly: AssemblyDescription("Synchronized YouTube TV playback for Lethal Company multiplayer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCompany("TVSync")]
[assembly: AssemblyProduct("TVSync")]
[assembly: AssemblyCopyright("Copyright 2025")]
[assembly: ComVisible(false)]
[assembly: Guid("ad955809-1ecb-4d74-a640-73a1179c4823")]
[assembly: AssemblyInformationalVersion("2.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.0")]
[module: UnverifiableCode]
[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 TVSync
{
public static class ChatHelper
{
private static string _lastMessage = "";
public static void ShowMessage(HUDManager hud, string message, string senderName)
{
if (!((Object)(object)hud == (Object)null) && !string.IsNullOrEmpty(message) && !(_lastMessage == message))
{
_lastMessage = message;
hud.PingHUDElement(hud.Chat, 4f, 1f, 0.2f);
if (hud.ChatMessageHistory.Count >= 4)
{
hud.ChatMessageHistory.RemoveAt(0);
}
string item = (string.IsNullOrEmpty(senderName) ? ("" + message + "") : ("" + senderName + ": " + message + ""));
hud.ChatMessageHistory.Add(item);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < hud.ChatMessageHistory.Count; i++)
{
stringBuilder.Append("\n");
stringBuilder.Append(hud.ChatMessageHistory[i]);
}
((TMP_Text)hud.chatText).text = stringBuilder.ToString();
}
}
public static void ResetDedup()
{
_lastMessage = "";
}
}
public class TVSyncConfig
{
public ConfigEntry Language { get; private set; }
public ConfigEntry DriftThresholdMs { get; private set; }
public ConfigEntry SyncIntervalSec { get; private set; }
public ConfigEntry ReadyTimeoutSec { get; private set; }
public ConfigEntry MaxSeekThresholdMs { get; private set; }
public Lang LangData { get; private set; }
public void Init()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "TVSync.cfg"), true);
Language = val.Bind("General", "Language", "en", "en = English, ru = Русский");
DriftThresholdMs = val.Bind("Sync", "DriftThresholdMs", 150f, "Maximum drift in ms before correction is applied");
SyncIntervalSec = val.Bind("Sync", "SyncIntervalSec", 3f, "How often the host broadcasts sync data (seconds)");
ReadyTimeoutSec = val.Bind("Sync", "ReadyTimeoutSec", 30f, "Maximum time to wait for all clients to be ready (seconds)");
MaxSeekThresholdMs = val.Bind("Sync", "MaxSeekThresholdMs", 500f, "Drift above this threshold causes a hard seek instead of speed adjustment");
LangData = new Lang();
if (Language.Value.ToLower() == "ru")
{
LangData.InitRU();
}
else
{
LangData.InitEN();
}
}
}
public class Lang
{
public ConfigEntry LibLoading;
public ConfigEntry TVTooltip;
public ConfigEntry LibReady;
public ConfigEntry VideoLoading;
public ConfigEntry HelpText;
public ConfigEntry InvalidUrl;
public ConfigEntry PleaseWait;
public ConfigEntry VideoReady;
public ConfigEntry VolumeChanged;
public ConfigEntry InvalidVolume;
public ConfigEntry LinkInvalid;
public ConfigEntry TimeChanged;
public ConfigEntry MemoryToggle;
public ConfigEntry WaitingForPlayers;
public ConfigEntry AllPlayersReady;
public ConfigEntry SyncStarting;
public ConfigEntry PlayerTimedOut;
public ConfigEntry HostOnly;
public ConfigEntry Paused;
public ConfigEntry Resumed;
public ConfigEntry Stopped;
public void InitEN()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
ConfigFile val = new ConfigFile("TVSync\\lang\\television_en.cfg", true);
LibLoading = val.Bind("General", "Main_1", "Please wait, downloading libraries...", (ConfigDescription)null);
TVTooltip = val.Bind("General", "Main_2", "Toggle TV : [E]\n@2 - @3\n@1 volume\nVol Up [PG UP]\nVol Down [PG DN]", (ConfigDescription)null);
LibReady = val.Bind("General", "Main_3", "Libraries loaded.", (ConfigDescription)null);
VideoLoading = val.Bind("General", "Main_4", "Video is loading!", (ConfigDescription)null);
HelpText = val.Bind("General", "Main_5", "/tplay [LINK] - Play video\n/ttime [TIME] - Seek to time\n/treset - Restart\n/tpause - Pause\n/tresume - Resume\n/tstop - Stop\n/tvolume [0-100] - Volume\n/tposition [BOOL] - Remember position", (ConfigDescription)null);
InvalidUrl = val.Bind("General", "Main_6", "Invalid URL!", (ConfigDescription)null);
PleaseWait = val.Bind("General", "Main_7", "Please wait...", (ConfigDescription)null);
VideoReady = val.Bind("General", "Main_8", "Video loaded.", (ConfigDescription)null);
VolumeChanged = val.Bind("General", "Main_9", "@1 set volume to @2", (ConfigDescription)null);
InvalidVolume = val.Bind("General", "Main_10", "Invalid Volume!", (ConfigDescription)null);
LinkInvalid = val.Bind("General", "Main_11", "Link is invalid!", (ConfigDescription)null);
TimeChanged = val.Bind("General", "Main_12", "Time: @1", (ConfigDescription)null);
MemoryToggle = val.Bind("General", "Main_13", "Memory: @1", (ConfigDescription)null);
WaitingForPlayers = val.Bind("General", "Main_14", "Waiting for all players to be ready...", (ConfigDescription)null);
AllPlayersReady = val.Bind("General", "Main_15", "All players ready! Starting playback.", (ConfigDescription)null);
SyncStarting = val.Bind("General", "Main_16", "Synchronized playback starting...", (ConfigDescription)null);
PlayerTimedOut = val.Bind("General", "Main_17", "Timed out waiting for players. Starting anyway.", (ConfigDescription)null);
HostOnly = val.Bind("General", "Main_18", "Only the host can use this command.", (ConfigDescription)null);
Paused = val.Bind("General", "Main_19", "Playback paused.", (ConfigDescription)null);
Resumed = val.Bind("General", "Main_20", "Playback resumed.", (ConfigDescription)null);
Stopped = val.Bind("General", "Main_21", "Playback stopped.", (ConfigDescription)null);
}
public void InitRU()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
ConfigFile val = new ConfigFile("TVSync\\lang\\television_ru.cfg", true);
LibLoading = val.Bind("General", "Main_1", "Пожалуйста, подождите, загружаются библиотеки...", (ConfigDescription)null);
TVTooltip = val.Bind("General", "Main_2", "Вкл/Выкл ТВ : [E]\n@2 - @3\n@1 громкость\nГромче [PG UP]\nТише [PG DN]", (ConfigDescription)null);
LibReady = val.Bind("General", "Main_3", "Библиотеки загружены.", (ConfigDescription)null);
VideoLoading = val.Bind("General", "Main_4", "Видео загружается!", (ConfigDescription)null);
HelpText = val.Bind("General", "Main_5", "/tplay [ССЫЛКА] - Проиграть\n/ttime [ВРЕМЯ] - Перемотать\n/treset - Сброс\n/tpause - Пауза\n/tresume - Продолжить\n/tstop - Остановить\n/tvolume [0-100] - Громкость\n/tposition [BOOL] - Запомнить позицию", (ConfigDescription)null);
InvalidUrl = val.Bind("General", "Main_6", "Неверный URL!", (ConfigDescription)null);
PleaseWait = val.Bind("General", "Main_7", "Пожалуйста подождите...", (ConfigDescription)null);
VideoReady = val.Bind("General", "Main_8", "Видео готово.", (ConfigDescription)null);
VolumeChanged = val.Bind("General", "Main_9", "@1 изменил громкость @2", (ConfigDescription)null);
InvalidVolume = val.Bind("General", "Main_10", "Неверная громкость!", (ConfigDescription)null);
LinkInvalid = val.Bind("General", "Main_11", "Ссылка недействительная!", (ConfigDescription)null);
TimeChanged = val.Bind("General", "Main_12", "Позиция: @1", (ConfigDescription)null);
MemoryToggle = val.Bind("General", "Main_13", "Запоминание: @1", (ConfigDescription)null);
WaitingForPlayers = val.Bind("General", "Main_14", "Ожидание готовности всех игроков...", (ConfigDescription)null);
AllPlayersReady = val.Bind("General", "Main_15", "Все игроки готовы! Начинаем воспроизведение.", (ConfigDescription)null);
SyncStarting = val.Bind("General", "Main_16", "Синхронное воспроизведение начинается...", (ConfigDescription)null);
PlayerTimedOut = val.Bind("General", "Main_17", "Время ожидания игроков истекло. Начинаем.", (ConfigDescription)null);
HostOnly = val.Bind("General", "Main_18", "Только хост может использовать эту команду.", (ConfigDescription)null);
Paused = val.Bind("General", "Main_19", "Воспроизведение приостановлено.", (ConfigDescription)null);
Resumed = val.Bind("General", "Main_20", "Воспроизведение продолжено.", (ConfigDescription)null);
Stopped = val.Bind("General", "Main_21", "Воспроизведение остановлено.", (ConfigDescription)null);
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "TVSync.SynchronizedTV";
public const string PLUGIN_NAME = "TVSync";
public const string PLUGIN_VERSION = "2.0.0";
}
[BepInPlugin("TVSync.SynchronizedTV", "TVSync", "2.0.0")]
public class Plugin : BaseUnityPlugin
{
private Harmony _harmony;
public static readonly string DataDir = Path.Combine("TVSync");
public static readonly string LangDir = Path.Combine(DataDir, "lang");
public static readonly string OtherDir = Path.Combine(DataDir, "other");
public static readonly string YtDlpPath = Path.Combine(OtherDir, "yt-dlp.exe");
public static readonly string CachePath = Path.Combine(DataDir, "cache");
public static readonly string VersionPath = Path.Combine(OtherDir, "yt-dlp.version");
public static readonly string VideoPath = Path.Combine(OtherDir, "test.mp4");
public static Plugin Instance { get; private set; }
internal static ManualLogSource Log { get; private set; }
internal static TVSyncConfig SyncConfig { get; private set; }
public static bool YtDlpReady { get; private set; }
private void Awake()
{
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Expected O, but got Unknown
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
SyncConfig = new TVSyncConfig();
SyncConfig.Init();
EnsureDirectories();
CleanTempFiles();
((BaseUnityPlugin)this).Logger.LogInfo((object)"TVSync v2.0.0 loaded!");
Thread thread = new Thread(UpdateYtDlp);
thread.IsBackground = true;
thread.Start();
_harmony = new Harmony("TVSync.SynchronizedTV");
_harmony.PatchAll(typeof(TVPatches));
_harmony.PatchAll(typeof(HUDPatches));
_harmony.PatchAll(typeof(NetworkPatches));
}
private void EnsureDirectories()
{
if (!Directory.Exists(LangDir))
{
Directory.CreateDirectory(LangDir);
}
if (!Directory.Exists(OtherDir))
{
Directory.CreateDirectory(OtherDir);
}
}
private void CleanTempFiles()
{
TryDeleteFile(VideoPath);
TryDeleteFile(VideoPath + ".part");
if (!File.Exists(CachePath))
{
File.WriteAllText(CachePath, "");
}
}
private static void TryDeleteFile(string path)
{
try
{
if (File.Exists(path))
{
File.Delete(path);
}
}
catch (Exception ex)
{
Log.LogWarning((object)("Could not delete " + path + ": " + ex.Message));
}
}
private void UpdateYtDlp()
{
try
{
string latestYtDlpTag = GetLatestYtDlpTag();
if (string.IsNullOrEmpty(latestYtDlpTag))
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"TVSync: Could not determine latest yt-dlp version. Skipping update.");
YtDlpReady = File.Exists(YtDlpPath);
return;
}
bool flag = true;
if (File.Exists(YtDlpPath) && File.Exists(VersionPath) && File.ReadAllText(VersionPath).Trim() == latestYtDlpTag)
{
flag = false;
}
if (flag)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)("TVSync: Downloading yt-dlp version " + latestYtDlpTag + "..."));
DownloadFileSync(new Uri("https://github.com/yt-dlp/yt-dlp/releases/download/" + latestYtDlpTag + "/yt-dlp.exe"), YtDlpPath);
if (File.Exists(YtDlpPath))
{
File.WriteAllText(VersionPath, latestYtDlpTag);
}
}
YtDlpReady = File.Exists(YtDlpPath);
((BaseUnityPlugin)this).Logger.LogInfo((object)"TVSync: yt-dlp ready.");
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogError((object)("TVSync: yt-dlp update failed: " + ex.Message));
YtDlpReady = File.Exists(YtDlpPath);
}
}
private string GetLatestYtDlpTag()
{
try
{
HttpWebRequest obj = (HttpWebRequest)WebRequest.Create("https://github.com/yt-dlp/yt-dlp/releases/latest");
obj.Method = "HEAD";
obj.AllowAutoRedirect = false;
obj.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)";
obj.Timeout = 10000;
using WebResponse webResponse = obj.GetResponse();
string text = webResponse.Headers["Location"];
if (!string.IsNullOrEmpty(text))
{
return text.Substring(text.LastIndexOf('/') + 1);
}
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("TVSync: Failed to fetch latest yt-dlp tag: " + ex.Message));
}
return null;
}
public static void DownloadFileSync(Uri uri, string filename)
{
try
{
TryDeleteFile(filename);
using WebClient webClient = new WebClient();
webClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
webClient.DownloadFile(uri, filename);
}
catch (Exception ex)
{
Log.LogError((object)$"TVSync: Download failed for {uri}: {ex.Message}");
throw;
}
}
}
public class TVController : MonoBehaviour
{
private bool _isDownloading;
private bool _isWaitingForReady;
private bool _isPlaying;
private bool _isPaused;
private double _scheduledStartNetworkTime;
private string _currentUrl = "";
private double _hostPlaybackTime;
private float _lastSyncTime;
private float _syncInterval;
private float _driftThresholdSec;
private float _maxSeekThresholdSec;
private float _readyTimeoutSec;
public static TVController Instance { get; private set; }
public TVScript TV { get; private set; }
public bool PositionMemory { get; set; }
public double SavedPosition { get; set; }
public float Volume
{
get
{
if (!((Object)(object)TV != (Object)null))
{
return 0.5f;
}
return TV.tvSFX.volume;
}
set
{
if ((Object)(object)TV != (Object)null)
{
TV.tvSFX.volume = Mathf.Clamp01(value);
}
SaveVolume(value);
}
}
public double CurrentTime
{
get
{
if (!((Object)(object)TV != (Object)null) || !((Object)(object)TV.video != (Object)null))
{
return 0.0;
}
return TV.video.time;
}
}
public double TotalTime
{
get
{
if (!((Object)(object)TV != (Object)null) || !((Object)(object)TV.video != (Object)null))
{
return 0.0;
}
return TV.video.length;
}
}
public bool IsPlaying => _isPlaying;
public bool IsPaused => _isPaused;
private void Awake()
{
Instance = this;
}
private void OnDestroy()
{
if ((Object)(object)Instance == (Object)(object)this)
{
Instance = null;
}
}
public void Init(TVScript tvScript)
{
TV = tvScript;
TVSyncConfig syncConfig = Plugin.SyncConfig;
_syncInterval = syncConfig.SyncIntervalSec.Value;
_driftThresholdSec = syncConfig.DriftThresholdMs.Value / 1000f;
_maxSeekThresholdSec = syncConfig.MaxSeekThresholdMs.Value / 1000f;
_readyTimeoutSec = syncConfig.ReadyTimeoutSec.Value;
LoadVolume();
}
private void Update()
{
if (!((Object)(object)TV == (Object)null) && !((Object)(object)TV.video == (Object)null))
{
if (NetworkSync.IsHost && _isPlaying && !_isPaused && Time.time - _lastSyncTime >= _syncInterval)
{
_lastSyncTime = Time.time;
BroadcastSyncState();
}
if (_isWaitingForReady && _scheduledStartNetworkTime > 0.0 && GetNetworkTime() >= _scheduledStartNetworkTime)
{
_isWaitingForReady = false;
BeginPlaybackNow();
}
}
}
public void HostPlayVideo(string url, HUDManager hud, string playerName)
{
if (_isDownloading)
{
ShowChat(Plugin.SyncConfig.LangData.VideoLoading.Value);
return;
}
_currentUrl = url;
NetworkSync.SendPlayVideo(url);
ShowChat(Plugin.SyncConfig.LangData.PleaseWait.Value);
}
public void HostPause()
{
if (NetworkSync.IsHost && _isPlaying && !_isPaused)
{
NetworkSync.SendPause(TV.video.time);
}
}
public void HostResume()
{
if (NetworkSync.IsHost && _isPaused)
{
double time = TV.video.time;
double networkTime = GetNetworkTime() + 0.5;
NetworkSync.SendResume(time, networkTime);
}
}
public void HostSeek(double seekTime)
{
if (NetworkSync.IsHost)
{
NetworkSync.SendSeek(seekTime);
}
}
public void HostStop()
{
if (NetworkSync.IsHost)
{
NetworkSync.SendStop();
}
}
public void HostRestart()
{
if (NetworkSync.IsHost)
{
NetworkSync.SendSeek(0.0);
}
}
public void OnPlayVideoReceived(string url)
{
_currentUrl = url;
_isPlaying = false;
_isPaused = false;
((MonoBehaviour)this).StartCoroutine(DownloadAndPrepareCoroutine(url));
}
public void OnSyncStateReceived(PlaybackState state)
{
if (!NetworkSync.IsHost && _isPlaying && _isPaused == state.IsPaused)
{
ApplyDriftCorrection(state);
}
}
public void OnPauseReceived(double pauseTime)
{
if (!((Object)(object)TV == (Object)null) && !((Object)(object)TV.video == (Object)null))
{
_isPaused = true;
TV.video.Pause();
TV.tvSFX.Pause();
TV.video.time = pauseTime;
}
}
public void OnResumeReceived(double resumeTime, double scheduledNetworkTime)
{
if (!((Object)(object)TV == (Object)null) && !((Object)(object)TV.video == (Object)null))
{
TV.video.time = resumeTime;
_scheduledStartNetworkTime = scheduledNetworkTime;
_isPaused = false;
_isWaitingForReady = true;
}
}
public void OnSeekReceived(double seekTime)
{
if (!((Object)(object)TV == (Object)null) && !((Object)(object)TV.video == (Object)null))
{
TV.video.time = seekTime;
_hostPlaybackTime = seekTime;
}
}
public void OnStopReceived()
{
if (!((Object)(object)TV == (Object)null))
{
_isPlaying = false;
_isPaused = false;
_isWaitingForReady = false;
if (TV.tvOn)
{
TV.tvOn = false;
SetTVScreenMaterial(on: false);
TV.tvSFX.Stop();
TV.video.Stop();
}
}
}
public void OnChatReceived(string message)
{
ShowChat(message);
}
public void SendCurrentStateToClient(ulong clientId)
{
if (NetworkSync.IsHost)
{
PlaybackState state = new PlaybackState
{
PlaybackTime = (((Object)(object)TV != (Object)null) ? TV.video.time : 0.0),
NetworkTime = GetNetworkTime(),
PlaybackSpeed = 1f,
IsPaused = _isPaused,
IsPlaying = _isPlaying,
VideoUrl = _currentUrl
};
NetworkSync.SendSyncStateToClient(clientId, state);
}
}
private IEnumerator DownloadAndPrepareCoroutine(string url)
{
_isDownloading = true;
try
{
if (!Directory.Exists(Plugin.OtherDir))
{
Directory.CreateDirectory(Plugin.OtherDir);
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("TVSync: Could not create directory: " + ex.Message));
}
if (TV.tvOn)
{
TV.video.Stop();
TV.tvSFX.Stop();
}
string videoPath = Path.GetFullPath(Plugin.VideoPath);
try
{
if (File.Exists(videoPath))
{
File.Delete(videoPath);
}
string path = videoPath + ".part";
if (File.Exists(path))
{
File.Delete(path);
}
}
catch (Exception ex2)
{
Plugin.Log.LogWarning((object)("TVSync: Could not clean old video: " + ex2.Message));
}
ShowChat(Plugin.SyncConfig.LangData.PleaseWait.Value);
float waitStart = Time.time;
while (!Plugin.YtDlpReady && Time.time - waitStart < 60f)
{
yield return (object)new WaitForSeconds(1f);
}
if (!Plugin.YtDlpReady)
{
Plugin.Log.LogError((object)"TVSync: yt-dlp not ready after 60s");
_isDownloading = false;
ShowChat(Plugin.SyncConfig.LangData.LinkInvalid.Value);
yield break;
}
string ytDlpFullPath = Path.GetFullPath(Plugin.YtDlpPath);
string workDir = Path.GetFullPath(Plugin.OtherDir);
string text = Path.Combine(workDir, "cookies.txt");
string text2 = (File.Exists(text) ? ("--cookies \"" + text + "\" ") : "");
string arguments = text2 + "-f \"b[height<=360][ext=mp4]/b[ext=mp4]/b\" --force-ipv4 -N 4 \"" + url + "\" -o test.mp4";
Plugin.Log.LogInfo((object)("TVSync: Starting download: " + ytDlpFullPath + " " + arguments));
Plugin.Log.LogInfo((object)("TVSync: Working directory: " + workDir));
bool downloadComplete = false;
bool downloadFailed = false;
string errorMsg = "";
Thread downloadThread = new Thread((ThreadStart)delegate
{
try
{
Process process = new Process();
process.StartInfo.FileName = ytDlpFullPath;
process.StartInfo.UseShellExecute = false;
process.StartInfo.Arguments = arguments;
process.StartInfo.WorkingDirectory = workDir;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
string text4 = process.StandardOutput.ReadToEnd();
string text5 = process.StandardError.ReadToEnd();
process.WaitForExit(120000);
if (!process.HasExited)
{
process.Kill();
downloadFailed = true;
errorMsg = "yt-dlp timed out after 2 minutes";
}
else
{
if (!string.IsNullOrEmpty(text5))
{
Plugin.Log.LogWarning((object)("TVSync: yt-dlp stderr: " + text5));
}
if (!string.IsNullOrEmpty(text4))
{
Plugin.Log.LogInfo((object)("TVSync: yt-dlp stdout: " + text4));
}
Plugin.Log.LogInfo((object)$"TVSync: yt-dlp exit code: {process.ExitCode}");
for (int i = 0; i < 30; i++)
{
if (File.Exists(videoPath))
{
downloadComplete = true;
return;
}
Thread.Sleep(500);
}
downloadFailed = true;
errorMsg = "Video file not found at: " + videoPath;
}
}
catch (Exception ex3)
{
downloadFailed = true;
errorMsg = ex3.ToString();
}
})
{
IsBackground = true
};
downloadThread.Start();
while (downloadThread.IsAlive)
{
yield return (object)new WaitForSeconds(0.5f);
}
if (downloadFailed || !downloadComplete)
{
Plugin.Log.LogError((object)("TVSync: Download failed: " + errorMsg));
_isDownloading = false;
ShowChat(Plugin.SyncConfig.LangData.LinkInvalid.Value);
yield break;
}
string text3 = "file:///" + videoPath.Replace('\\', '/');
Plugin.Log.LogInfo((object)("TVSync: Loading video from: " + text3));
TV.video.source = (VideoSource)1;
TV.video.url = text3;
TV.video.controlledAudioTrackCount = 1;
TV.video.audioOutputMode = (VideoAudioOutputMode)1;
TV.video.SetTargetAudioSource((ushort)0, TV.tvSFX);
TV.video.playbackSpeed = 1f;
TV.video.Prepare();
float prepStart = Time.time;
while (!TV.video.isPrepared && Time.time - prepStart < 30f)
{
yield return (object)new WaitForSeconds(0.1f);
}
_isDownloading = false;
if (!TV.video.isPrepared)
{
Plugin.Log.LogError((object)"TVSync: VideoPlayer failed to prepare");
ShowChat(Plugin.SyncConfig.LangData.LinkInvalid.Value);
yield break;
}
Plugin.Log.LogInfo((object)"TVSync: Video prepared. Reporting ready.");
ShowChat(Plugin.SyncConfig.LangData.VideoReady.Value);
NetworkSync.SendClientReady();
if (NetworkSync.IsHost)
{
((MonoBehaviour)this).StartCoroutine(WaitForReadyAndStart());
}
}
private IEnumerator WaitForReadyAndStart()
{
int count = NetworkManager.Singleton.ConnectedClientsIds.Count;
_isWaitingForReady = true;
ShowChat(Plugin.SyncConfig.LangData.WaitingForPlayers.Value);
NetworkSync.BeginWaitForReady(count, delegate
{
Plugin.Log.LogInfo((object)"TVSync: All clients ready!");
});
float waitStart = Time.time;
while (NetworkSync.ReadyCount < NetworkSync.ExpectedCount)
{
if (Time.time - waitStart > _readyTimeoutSec)
{
Plugin.Log.LogWarning((object)$"TVSync: Timeout waiting for clients ({NetworkSync.ReadyCount}/{NetworkSync.ExpectedCount})");
ShowChat(Plugin.SyncConfig.LangData.PlayerTimedOut.Value);
NetworkSync.ForceAllReady();
break;
}
yield return (object)new WaitForSeconds(0.25f);
}
ShowChat(Plugin.SyncConfig.LangData.AllPlayersReady.Value);
NetworkSync.SendResume(0.0, _scheduledStartNetworkTime = GetNetworkTime() + 1.0);
}
private void BeginPlaybackNow()
{
if (!((Object)(object)TV == (Object)null) && !((Object)(object)TV.video == (Object)null))
{
Plugin.Log.LogInfo((object)"TVSync: Beginning synchronized playback!");
TV.tvOn = true;
SetTVScreenMaterial(on: true);
TV.video.Play();
TV.tvSFX.Play();
TV.tvSFX.PlayOneShot(TV.switchTVOn);
WalkieTalkie.TransmitOneShotAudio(TV.tvSFX, TV.switchTVOn, 1f);
_isPlaying = true;
_isPaused = false;
_lastSyncTime = Time.time;
}
}
private void BroadcastSyncState()
{
if (!((Object)(object)TV == (Object)null) && !((Object)(object)TV.video == (Object)null))
{
NetworkSync.SendSyncState(new PlaybackState
{
PlaybackTime = TV.video.time,
NetworkTime = GetNetworkTime(),
PlaybackSpeed = TV.video.playbackSpeed,
IsPaused = _isPaused,
IsPlaying = _isPlaying,
VideoUrl = _currentUrl
});
}
}
private void ApplyDriftCorrection(PlaybackState hostState)
{
if (!((Object)(object)TV == (Object)null) && !((Object)(object)TV.video == (Object)null) && TV.video.isPlaying)
{
double num = GetNetworkTime() - hostState.NetworkTime;
double num2 = hostState.PlaybackTime + num * (double)hostState.PlaybackSpeed;
double time = TV.video.time;
double num3 = num2 - time;
double num4 = Math.Abs(num3);
if (num4 < (double)_driftThresholdSec)
{
TV.video.playbackSpeed = 1f;
}
else if (num4 > (double)_maxSeekThresholdSec)
{
Plugin.Log.LogInfo((object)$"TVSync: Large drift {num3:F3}s — seeking to {num2:F2}");
TV.video.time = num2;
TV.video.playbackSpeed = 1f;
}
else
{
float playbackSpeed = ((num3 > 0.0) ? 1.03f : 0.97f);
TV.video.playbackSpeed = playbackSpeed;
}
}
}
public void HandleLateJoin()
{
if (!NetworkSync.IsHost)
{
Plugin.Log.LogInfo((object)"TVSync: Requesting current state (late join)...");
NetworkSync.SendRequestState();
}
}
public void HandleFullStateSync(PlaybackState state)
{
if (!string.IsNullOrEmpty(state.VideoUrl) && state.IsPlaying)
{
_currentUrl = state.VideoUrl;
((MonoBehaviour)this).StartCoroutine(LateJoinCoroutine(state));
}
}
private IEnumerator LateJoinCoroutine(PlaybackState state)
{
yield return DownloadAndPrepareCoroutine(state.VideoUrl);
if (TV.video.isPrepared)
{
double num = GetNetworkTime() - state.NetworkTime;
double val = state.PlaybackTime + num * (double)state.PlaybackSpeed;
TV.video.time = Math.Max(0.0, val);
if (state.IsPaused)
{
TV.video.time = state.PlaybackTime;
_isPaused = true;
}
else
{
BeginPlaybackNow();
}
}
}
public void SetTVScreenMaterial(bool on)
{
if (!((Object)(object)TV == (Object)null) && !((Object)(object)TV.tvMesh == (Object)null))
{
Material[] sharedMaterials = ((Renderer)TV.tvMesh).sharedMaterials;
if (sharedMaterials.Length > 1)
{
sharedMaterials[1] = (on ? TV.tvOnMaterial : TV.tvOffMaterial);
((Renderer)TV.tvMesh).sharedMaterials = sharedMaterials;
}
if ((Object)(object)TV.tvLight != (Object)null)
{
((Behaviour)TV.tvLight).enabled = on;
}
}
}
public void HandleTVToggle(bool on)
{
if (on)
{
if (PositionMemory)
{
TV.video.time = SavedPosition;
}
SetTVScreenMaterial(on: true);
TV.video.Play();
TV.tvSFX.Play();
TV.tvSFX.PlayOneShot(TV.switchTVOn);
WalkieTalkie.TransmitOneShotAudio(TV.tvSFX, TV.switchTVOn, 1f);
}
else
{
if (PositionMemory)
{
SavedPosition = TV.video.time;
}
SetTVScreenMaterial(on: false);
TV.tvSFX.Stop();
TV.video.Stop();
TV.tvSFX.PlayOneShot(TV.switchTVOff);
WalkieTalkie.TransmitOneShotAudio(TV.tvSFX, TV.switchTVOff, 1f);
}
}
private void LoadVolume()
{
try
{
if (File.Exists(Plugin.CachePath))
{
string text = File.ReadAllText(Plugin.CachePath).Trim();
if (!string.IsNullOrEmpty(text) && float.TryParse(text, out var result))
{
if ((Object)(object)TV != (Object)null)
{
TV.tvSFX.volume = Mathf.Clamp01(result);
}
}
else if ((Object)(object)TV != (Object)null)
{
TV.tvSFX.volume = 0.5f;
}
}
else if ((Object)(object)TV != (Object)null)
{
TV.tvSFX.volume = 0.5f;
}
}
catch
{
if ((Object)(object)TV != (Object)null)
{
TV.tvSFX.volume = 0.5f;
}
}
}
private void SaveVolume(float vol)
{
try
{
File.WriteAllText(Plugin.CachePath, vol.ToString("F2"));
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("TVSync: Could not save volume: " + ex.Message));
}
}
public void ShowChat(string message)
{
HUDManager instance = HUDManager.Instance;
if (!((Object)(object)instance == (Object)null))
{
ChatHelper.ShowMessage(instance, message, "TVSync");
}
}
private static double GetNetworkTime()
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsConnectedClient)
{
NetworkTime serverTime = NetworkManager.Singleton.ServerTime;
return ((NetworkTime)(ref serverTime)).Time;
}
return Time.timeAsDouble;
}
}
}
namespace TVSync.Patches
{
public static class TVPatches
{
[HarmonyPatch(typeof(TVScript), "OnEnable")]
[HarmonyPrefix]
public static bool OnEnable_Prefix(TVScript __instance)
{
TVController tVController = ((Component)__instance).GetComponent();
if ((Object)(object)tVController == (Object)null)
{
tVController = ((Component)__instance).gameObject.AddComponent();
}
tVController.Init(__instance);
__instance.video.clip = null;
__instance.tvSFX.clip = null;
__instance.video.Stop();
__instance.tvSFX.Stop();
return false;
}
[HarmonyPatch(typeof(TVScript), "TurnTVOnOff")]
[HarmonyPrefix]
public static bool TurnTVOnOff_Prefix(TVScript __instance, bool on)
{
__instance.tvOn = on;
TVController instance = TVController.Instance;
if ((Object)(object)instance != (Object)null)
{
instance.HandleTVToggle(on);
}
return false;
}
[HarmonyPatch(typeof(TVScript), "TVFinishedClip")]
[HarmonyPrefix]
public static bool TVFinishedClip_Prefix()
{
return false;
}
[HarmonyPatch(typeof(TVScript), "Update")]
[HarmonyPrefix]
public static bool Update_Prefix()
{
return false;
}
}
public static class HUDPatches
{
private static readonly Regex UrlRegex = new Regex("^https?:\\/\\/(?:www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b(?:[-a-zA-Z0-9()@:%_\\+.~#?&\\/=]*)$", RegexOptions.Compiled);
[HarmonyPatch(typeof(PlayerControllerB), "SetHoverTipAndCurrentInteractTrigger")]
[HarmonyPostfix]
public static void SetHoverTipAndCurrentInteractTrigger_Postfix(PlayerControllerB __instance)
{
InteractTrigger hoveringOverTrigger = __instance.hoveringOverTrigger;
if ((Object)(object)hoveringOverTrigger == (Object)null || !hoveringOverTrigger.interactable || !((Object)(object)((Component)hoveringOverTrigger).transform.parent != (Object)null) || (!((Object)((Component)hoveringOverTrigger).transform.parent).name.Contains("Television") && !hoveringOverTrigger.hoverTip.Contains("Switch TV")))
{
return;
}
TVController instance = TVController.Instance;
if ((Object)(object)instance == (Object)null || (Object)(object)instance.TV == (Object)null)
{
return;
}
if (!Plugin.YtDlpReady)
{
hoveringOverTrigger.hoverTip = Plugin.SyncConfig.LangData.LibLoading.Value;
return;
}
double currentTime = instance.CurrentTime;
double totalTime = instance.TotalTime;
string newValue = FormatTime(currentTime);
string newValue2 = FormatTime(totalTime);
float volume = instance.Volume;
hoveringOverTrigger.hoverTip = Plugin.SyncConfig.LangData.TVTooltip.Value.Replace("@1", $"{Mathf.RoundToInt(volume * 100f)}%").Replace("@2", newValue).Replace("@3", newValue2);
if (((ButtonControl)Keyboard.current.pageDownKey).wasPressedThisFrame && volume > 0f)
{
instance.Volume = Mathf.Max(0f, volume - 0.1f);
}
if (((ButtonControl)Keyboard.current.pageUpKey).wasPressedThisFrame && volume < 1f)
{
instance.Volume = Mathf.Min(1f, volume + 0.1f);
}
}
[HarmonyPatch(typeof(HUDManager), "Start")]
[HarmonyPostfix]
public static void HUDStart_Postfix(HUDManager __instance)
{
__instance.chatTextField.characterLimit = 200;
}
[HarmonyPatch(typeof(HUDManager), "AddPlayerChatMessageServerRpc")]
[HarmonyPostfix]
public static void AddPlayerChatMessageServerRpc_Postfix(HUDManager __instance, string chatMessage, int playerId)
{
if (chatMessage.Length > 50)
{
typeof(HUDManager).GetMethod("AddPlayerChatMessageClientRpc", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(__instance, new object[2] { chatMessage, playerId });
}
}
[HarmonyPatch(typeof(HUDManager), "AddChatMessage")]
[HarmonyPrefix]
public static bool AddChatMessage_Prefix(HUDManager __instance, string chatMessage, string nameOfUserWhoTyped)
{
if (__instance.lastChatMessage != chatMessage)
{
__instance.lastChatMessage = chatMessage;
__instance.PingHUDElement(__instance.Chat, 4f, 1f, 0.2f);
if (__instance.ChatMessageHistory.Count >= 4)
{
__instance.ChatMessageHistory.RemoveAt(0);
}
StringBuilder stringBuilder = new StringBuilder(chatMessage);
for (int i = 0; i < Math.Min(4, StartOfRound.Instance.allPlayerScripts.Length); i++)
{
stringBuilder.Replace($"[playerNum{i}]", StartOfRound.Instance.allPlayerScripts[i].playerUsername);
}
chatMessage = stringBuilder.ToString();
string item = (string.IsNullOrEmpty(nameOfUserWhoTyped) ? ("" + chatMessage + "") : ("" + nameOfUserWhoTyped + ": '" + chatMessage + "'"));
__instance.ChatMessageHistory.Add(item);
StringBuilder stringBuilder2 = new StringBuilder();
for (int j = 0; j < __instance.ChatMessageHistory.Count; j++)
{
stringBuilder2.Append("\n");
stringBuilder2.Append(__instance.ChatMessageHistory[j]);
}
((TMP_Text)__instance.chatText).text = stringBuilder2.ToString();
ProcessCommand(__instance, chatMessage, nameOfUserWhoTyped);
}
return false;
}
[HarmonyPatch(typeof(HUDManager), "SubmitChat_performed")]
[HarmonyPrefix]
public static bool SubmitChat_performed_Prefix(HUDManager __instance, ref CallbackContext context)
{
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
if (!((CallbackContext)(ref context)).performed)
{
return false;
}
__instance.localPlayer = GameNetworkManager.Instance.localPlayerController;
if ((Object)(object)__instance.localPlayer == (Object)null)
{
return false;
}
if (!__instance.localPlayer.isTypingChat)
{
return false;
}
if ((!((NetworkBehaviour)__instance.localPlayer).IsOwner || (((NetworkBehaviour)__instance).IsServer && !__instance.localPlayer.isHostPlayerObject)) && !__instance.localPlayer.isTestingPlayer)
{
return false;
}
if (__instance.localPlayer.isPlayerDead)
{
return false;
}
if (!string.IsNullOrEmpty(__instance.chatTextField.text) && __instance.chatTextField.text.Length < 200)
{
__instance.AddTextToChatOnServer(__instance.chatTextField.text, (int)__instance.localPlayer.playerClientId);
}
for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++)
{
if (StartOfRound.Instance.allPlayerScripts[i].isPlayerControlled && Vector3.Distance(((Component)GameNetworkManager.Instance.localPlayerController).transform.position, ((Component)StartOfRound.Instance.allPlayerScripts[i]).transform.position) > 24.4f && (!GameNetworkManager.Instance.localPlayerController.holdingWalkieTalkie || !StartOfRound.Instance.allPlayerScripts[i].holdingWalkieTalkie))
{
__instance.playerCouldRecieveTextChatAnimator.SetTrigger("ping");
break;
}
}
__instance.localPlayer.isTypingChat = false;
__instance.chatTextField.text = "";
EventSystem.current.SetSelectedGameObject((GameObject)null);
__instance.PingHUDElement(__instance.Chat, 2f, 1f, 0.2f);
((Behaviour)__instance.typingIndicator).enabled = false;
return false;
}
[HarmonyPatch(typeof(HUDManager), "Update")]
[HarmonyPrefix]
public static void HUDUpdate_Prefix(HUDManager __instance)
{
}
private static void ProcessCommand(HUDManager hud, string chatMessage, string senderName)
{
if (string.IsNullOrEmpty(chatMessage))
{
return;
}
string[] array = chatMessage.Split(' ');
string text = array[0].Replace("/", "").ToLower();
Lang langData = Plugin.SyncConfig.LangData;
TVController instance = TVController.Instance;
if (text == null)
{
return;
}
switch (text.Length)
{
case 5:
switch (text[1])
{
case 'h':
if (text == "thelp")
{
ChatHelper.ResetDedup();
ChatHelper.ShowMessage(hud, langData.HelpText.Value, "TVSync");
}
break;
case 'p':
{
if (!(text == "tplay") || !NetworkSync.IsHost)
{
break;
}
if (array.Length < 2)
{
ChatHelper.ShowMessage(hud, langData.InvalidUrl.Value, "TVSync");
break;
}
if (!UrlRegex.IsMatch(array[1]))
{
ChatHelper.ShowMessage(hud, langData.InvalidUrl.Value, "TVSync");
break;
}
string text2 = (array[1].Contains("://") ? array[1].Split(new string[1] { "://" }, StringSplitOptions.None)[1] : array[1]);
if (!text2.Contains("youtube.com") && !text2.Contains("youtu.be"))
{
ChatHelper.ShowMessage(hud, langData.InvalidUrl.Value, "TVSync");
}
else if (array[1].Contains("list"))
{
ChatHelper.ShowMessage(hud, langData.InvalidUrl.Value, "TVSync");
}
else if ((Object)(object)instance != (Object)null)
{
instance.HostPlayVideo(array[1], hud, senderName);
}
break;
}
case 't':
if (text == "ttime" && NetworkSync.IsHost && array.Length >= 2 && !((Object)(object)instance == (Object)null))
{
double num = ParseTimeString(array[1]);
if (num >= 0.0)
{
instance.HostSeek(num);
ChatHelper.ResetDedup();
ChatHelper.ShowMessage(hud, langData.TimeChanged.Value.Replace("@1", FormatTime(num)), "TVSync");
}
}
break;
case 's':
if (text == "tstop" && NetworkSync.IsHost && !((Object)(object)instance == (Object)null))
{
instance.HostStop();
ChatHelper.ResetDedup();
ChatHelper.ShowMessage(hud, langData.Stopped.Value, "TVSync");
}
break;
}
break;
case 6:
switch (text[1])
{
case 'r':
if (text == "treset" && NetworkSync.IsHost && !((Object)(object)instance == (Object)null))
{
instance.HostRestart();
ChatHelper.ResetDedup();
ChatHelper.ShowMessage(hud, langData.TimeChanged.Value.Replace("@1", "00:00:00"), "TVSync");
}
break;
case 'p':
if (text == "tpause" && NetworkSync.IsHost && !((Object)(object)instance == (Object)null))
{
instance.HostPause();
ChatHelper.ResetDedup();
ChatHelper.ShowMessage(hud, langData.Paused.Value, "TVSync");
}
break;
}
break;
case 7:
switch (text[1])
{
case 'r':
if (text == "tresume" && NetworkSync.IsHost && !((Object)(object)instance == (Object)null))
{
instance.HostResume();
ChatHelper.ResetDedup();
ChatHelper.ShowMessage(hud, langData.Resumed.Value, "TVSync");
}
break;
case 'v':
{
if (!(text == "tvolume") || array.Length < 2 || !(senderName == GameNetworkManager.Instance.localPlayerController.playerUsername))
{
break;
}
if (int.TryParse(array[1], out var result))
{
float volume = Mathf.Clamp01((float)result / 100f);
if ((Object)(object)instance != (Object)null)
{
instance.Volume = volume;
ChatHelper.ResetDedup();
ChatHelper.ShowMessage(hud, langData.VolumeChanged.Value.Replace("@1", senderName ?? "").Replace("@2", array[1] + "%"), "TVSync");
}
}
else
{
ChatHelper.ShowMessage(hud, langData.InvalidVolume.Value, "TVSync");
}
break;
}
}
break;
case 9:
if (text == "tposition" && array.Length >= 2 && !((Object)(object)instance == (Object)null))
{
if (array[1].ToLower() == "true")
{
instance.PositionMemory = true;
}
else if (array[1].ToLower() == "false")
{
instance.PositionMemory = false;
}
string newValue = (instance.PositionMemory ? "enabled" : "disabled");
ChatHelper.ResetDedup();
ChatHelper.ShowMessage(hud, langData.MemoryToggle.Value.Replace("@1", newValue), "TVSync");
}
break;
case 8:
break;
}
}
private static double ParseTimeString(string timeStr)
{
string[] array = timeStr.Split(':');
try
{
return array.Length switch
{
1 => Convert.ToDouble(array[0]),
2 => Convert.ToInt32(array[0]) * 60 + Convert.ToInt32(array[1]),
3 => Convert.ToInt32(array[0]) * 3600 + Convert.ToInt32(array[1]) * 60 + Convert.ToInt32(array[2]),
_ => -1.0,
};
}
catch
{
return -1.0;
}
}
public static string FormatTime(double seconds)
{
int num = (int)seconds;
int num2 = num / 3600;
int num3 = num % 3600 / 60;
int num4 = num % 60;
return $"{num2:00}:{num3:00}:{num4:00}";
}
}
public static class NetworkPatches
{
[HarmonyPatch(typeof(GameNetworkManager), "StartDisconnect")]
[HarmonyPostfix]
public static void StartDisconnect_Postfix()
{
NetworkSync.Unregister();
}
[HarmonyPatch(typeof(StartOfRound), "Start")]
[HarmonyPostfix]
public static void StartOfRound_Start_Postfix()
{
NetworkSync.Register();
if (!NetworkSync.IsHost && (Object)(object)TVController.Instance != (Object)null)
{
TVController.Instance.HandleLateJoin();
}
}
[HarmonyPatch(typeof(StartOfRound), "OnPlayerConnectedClientRpc")]
[HarmonyPostfix]
public static void OnPlayerConnected_Postfix(ulong clientId)
{
if (NetworkSync.IsHost)
{
Plugin.Log.LogInfo((object)$"TVSync: Client {clientId} connected. Will send state on request.");
}
}
}
}
namespace TVSync.Networking
{
public static class NetworkSync
{
[CompilerGenerated]
private static class <>O
{
public static HandleNamedMessageDelegate <0>__OnReceivePlayVideo;
public static HandleNamedMessageDelegate <1>__OnReceiveSyncState;
public static HandleNamedMessageDelegate <2>__OnReceiveClientReady;
public static HandleNamedMessageDelegate <3>__OnReceivePause;
public static HandleNamedMessageDelegate <4>__OnReceiveResume;
public static HandleNamedMessageDelegate <5>__OnReceiveSeek;
public static HandleNamedMessageDelegate <6>__OnReceiveStop;
public static HandleNamedMessageDelegate <7>__OnReceiveChat;
public static HandleNamedMessageDelegate <8>__OnReceiveRequestState;
}
private const string MSG_PLAY_VIDEO = "TVSync_PlayVideo";
private const string MSG_SYNC_STATE = "TVSync_SyncState";
private const string MSG_CLIENT_READY = "TVSync_ClientReady";
private const string MSG_PAUSE = "TVSync_Pause";
private const string MSG_RESUME = "TVSync_Resume";
private const string MSG_SEEK = "TVSync_Seek";
private const string MSG_STOP = "TVSync_Stop";
private const string MSG_CHAT = "TVSync_Chat";
private const string MSG_REQUEST_STATE = "TVSync_RequestState";
private static HashSet _readyClients = new HashSet();
private static int _expectedReadyCount = 0;
private static Action _onAllReady;
public static bool IsRegistered { get; private set; }
public static bool IsHost
{
get
{
if ((Object)(object)NetworkManager.Singleton != (Object)null)
{
return NetworkManager.Singleton.IsHost;
}
return false;
}
}
public static bool IsConnected
{
get
{
if ((Object)(object)NetworkManager.Singleton != (Object)null)
{
return NetworkManager.Singleton.IsConnectedClient;
}
return false;
}
}
public static int ReadyCount => _readyClients.Count;
public static int ExpectedCount => _expectedReadyCount;
public static void Register()
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Expected O, but got Unknown
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Expected O, but got Unknown
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Expected O, but got Unknown
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Expected O, but got Unknown
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Expected O, but got Unknown
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Expected O, but got Unknown
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Expected O, but got Unknown
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Expected O, but got Unknown
if (IsRegistered)
{
return;
}
NetworkManager singleton = NetworkManager.Singleton;
CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null);
if (val != null)
{
object obj = <>O.<0>__OnReceivePlayVideo;
if (obj == null)
{
HandleNamedMessageDelegate val2 = OnReceivePlayVideo;
<>O.<0>__OnReceivePlayVideo = val2;
obj = (object)val2;
}
val.RegisterNamedMessageHandler("TVSync_PlayVideo", (HandleNamedMessageDelegate)obj);
object obj2 = <>O.<1>__OnReceiveSyncState;
if (obj2 == null)
{
HandleNamedMessageDelegate val3 = OnReceiveSyncState;
<>O.<1>__OnReceiveSyncState = val3;
obj2 = (object)val3;
}
val.RegisterNamedMessageHandler("TVSync_SyncState", (HandleNamedMessageDelegate)obj2);
object obj3 = <>O.<2>__OnReceiveClientReady;
if (obj3 == null)
{
HandleNamedMessageDelegate val4 = OnReceiveClientReady;
<>O.<2>__OnReceiveClientReady = val4;
obj3 = (object)val4;
}
val.RegisterNamedMessageHandler("TVSync_ClientReady", (HandleNamedMessageDelegate)obj3);
object obj4 = <>O.<3>__OnReceivePause;
if (obj4 == null)
{
HandleNamedMessageDelegate val5 = OnReceivePause;
<>O.<3>__OnReceivePause = val5;
obj4 = (object)val5;
}
val.RegisterNamedMessageHandler("TVSync_Pause", (HandleNamedMessageDelegate)obj4);
object obj5 = <>O.<4>__OnReceiveResume;
if (obj5 == null)
{
HandleNamedMessageDelegate val6 = OnReceiveResume;
<>O.<4>__OnReceiveResume = val6;
obj5 = (object)val6;
}
val.RegisterNamedMessageHandler("TVSync_Resume", (HandleNamedMessageDelegate)obj5);
object obj6 = <>O.<5>__OnReceiveSeek;
if (obj6 == null)
{
HandleNamedMessageDelegate val7 = OnReceiveSeek;
<>O.<5>__OnReceiveSeek = val7;
obj6 = (object)val7;
}
val.RegisterNamedMessageHandler("TVSync_Seek", (HandleNamedMessageDelegate)obj6);
object obj7 = <>O.<6>__OnReceiveStop;
if (obj7 == null)
{
HandleNamedMessageDelegate val8 = OnReceiveStop;
<>O.<6>__OnReceiveStop = val8;
obj7 = (object)val8;
}
val.RegisterNamedMessageHandler("TVSync_Stop", (HandleNamedMessageDelegate)obj7);
object obj8 = <>O.<7>__OnReceiveChat;
if (obj8 == null)
{
HandleNamedMessageDelegate val9 = OnReceiveChat;
<>O.<7>__OnReceiveChat = val9;
obj8 = (object)val9;
}
val.RegisterNamedMessageHandler("TVSync_Chat", (HandleNamedMessageDelegate)obj8);
object obj9 = <>O.<8>__OnReceiveRequestState;
if (obj9 == null)
{
HandleNamedMessageDelegate val10 = OnReceiveRequestState;
<>O.<8>__OnReceiveRequestState = val10;
obj9 = (object)val10;
}
val.RegisterNamedMessageHandler("TVSync_RequestState", (HandleNamedMessageDelegate)obj9);
IsRegistered = true;
Plugin.Log.LogInfo((object)"TVSync: Network message handlers registered.");
}
}
public static void Unregister()
{
if (IsRegistered)
{
NetworkManager singleton = NetworkManager.Singleton;
CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null);
if (val != null)
{
val.UnregisterNamedMessageHandler("TVSync_PlayVideo");
val.UnregisterNamedMessageHandler("TVSync_SyncState");
val.UnregisterNamedMessageHandler("TVSync_ClientReady");
val.UnregisterNamedMessageHandler("TVSync_Pause");
val.UnregisterNamedMessageHandler("TVSync_Resume");
val.UnregisterNamedMessageHandler("TVSync_Seek");
val.UnregisterNamedMessageHandler("TVSync_Stop");
val.UnregisterNamedMessageHandler("TVSync_Chat");
val.UnregisterNamedMessageHandler("TVSync_RequestState");
IsRegistered = false;
_readyClients.Clear();
}
}
}
public static void SendPlayVideo(string url)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
if (IsHost)
{
FastBufferWriter writer = BeginMessage();
WriteString(writer, url);
SendToAllClients("TVSync_PlayVideo", writer);
((FastBufferWriter)(ref writer)).Dispose();
TVController.Instance?.OnPlayVideoReceived(url);
}
}
public static void SendSyncState(PlaybackState state)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: 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_001b: Unknown result type (might be due to invalid IL or missing references)
if (IsHost)
{
FastBufferWriter writer = BeginMessage();
state.Serialize(writer);
SendToAllClients("TVSync_SyncState", writer);
((FastBufferWriter)(ref writer)).Dispose();
}
}
public static void SendPause(double pauseTime)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
if (IsHost)
{
FastBufferWriter writer = BeginMessage();
((FastBufferWriter)(ref writer)).WriteValueSafe(ref pauseTime, default(ForPrimitives));
SendToAllClients("TVSync_Pause", writer);
((FastBufferWriter)(ref writer)).Dispose();
TVController.Instance?.OnPauseReceived(pauseTime);
}
}
public static void SendResume(double resumeTime, double networkTime)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: 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_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
if (IsHost)
{
FastBufferWriter writer = BeginMessage();
((FastBufferWriter)(ref writer)).WriteValueSafe(ref resumeTime, default(ForPrimitives));
((FastBufferWriter)(ref writer)).WriteValueSafe(ref networkTime, default(ForPrimitives));
SendToAllClients("TVSync_Resume", writer);
((FastBufferWriter)(ref writer)).Dispose();
TVController.Instance?.OnResumeReceived(resumeTime, networkTime);
}
}
public static void SendSeek(double seekTime)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
if (IsHost)
{
FastBufferWriter writer = BeginMessage();
((FastBufferWriter)(ref writer)).WriteValueSafe(ref seekTime, default(ForPrimitives));
SendToAllClients("TVSync_Seek", writer);
((FastBufferWriter)(ref writer)).Dispose();
TVController.Instance?.OnSeekReceived(seekTime);
}
}
public static void SendStop()
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
if (IsHost)
{
FastBufferWriter writer = BeginMessage();
byte b = 0;
((FastBufferWriter)(ref writer)).WriteValueSafe(ref b, default(ForPrimitives));
SendToAllClients("TVSync_Stop", writer);
((FastBufferWriter)(ref writer)).Dispose();
TVController.Instance?.OnStopReceived();
}
}
public static void SendChat(string message)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
if (IsHost)
{
FastBufferWriter writer = BeginMessage();
WriteString(writer, message);
SendToAllClients("TVSync_Chat", writer);
((FastBufferWriter)(ref writer)).Dispose();
}
}
public static void SendClientReady()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
if (IsHost)
{
OnClientReady(NetworkManager.Singleton.LocalClientId);
return;
}
FastBufferWriter writer = BeginMessage();
ulong localClientId = NetworkManager.Singleton.LocalClientId;
((FastBufferWriter)(ref writer)).WriteValueSafe(ref localClientId, default(ForPrimitives));
SendToServer("TVSync_ClientReady", writer);
((FastBufferWriter)(ref writer)).Dispose();
}
public static void SendRequestState()
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
if (!IsHost)
{
FastBufferWriter writer = BeginMessage();
ulong localClientId = NetworkManager.Singleton.LocalClientId;
((FastBufferWriter)(ref writer)).WriteValueSafe(ref localClientId, default(ForPrimitives));
SendToServer("TVSync_RequestState", writer);
((FastBufferWriter)(ref writer)).Dispose();
}
}
public static void BeginWaitForReady(int expectedCount, Action onAllReady)
{
_readyClients.Clear();
_expectedReadyCount = expectedCount;
_onAllReady = onAllReady;
}
private static void OnClientReady(ulong clientId)
{
_readyClients.Add(clientId);
Plugin.Log.LogInfo((object)$"TVSync: Client {clientId} ready ({_readyClients.Count}/{_expectedReadyCount})");
if (_readyClients.Count >= _expectedReadyCount)
{
_onAllReady?.Invoke();
_onAllReady = null;
}
}
public static void ForceAllReady()
{
_onAllReady?.Invoke();
_onAllReady = null;
}
private static void OnReceivePlayVideo(ulong senderClientId, FastBufferReader reader)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
string text = ReadString(reader);
Plugin.Log.LogInfo((object)("TVSync: Received PlayVideo: " + text));
TVController.Instance?.OnPlayVideoReceived(text);
}
private static void OnReceiveSyncState(ulong senderClientId, FastBufferReader reader)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
PlaybackState state = PlaybackState.Deserialize(reader);
TVController.Instance?.OnSyncStateReceived(state);
}
private static void OnReceiveClientReady(ulong senderClientId, FastBufferReader reader)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
ulong clientId = default(ulong);
((FastBufferReader)(ref reader)).ReadValueSafe(ref clientId, default(ForPrimitives));
if (IsHost)
{
OnClientReady(clientId);
}
}
private static void OnReceivePause(ulong senderClientId, FastBufferReader reader)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
double pauseTime = default(double);
((FastBufferReader)(ref reader)).ReadValueSafe(ref pauseTime, default(ForPrimitives));
TVController.Instance?.OnPauseReceived(pauseTime);
}
private static void OnReceiveResume(ulong senderClientId, FastBufferReader reader)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
double resumeTime = default(double);
((FastBufferReader)(ref reader)).ReadValueSafe(ref resumeTime, default(ForPrimitives));
double scheduledNetworkTime = default(double);
((FastBufferReader)(ref reader)).ReadValueSafe(ref scheduledNetworkTime, default(ForPrimitives));
TVController.Instance?.OnResumeReceived(resumeTime, scheduledNetworkTime);
}
private static void OnReceiveSeek(ulong senderClientId, FastBufferReader reader)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
double seekTime = default(double);
((FastBufferReader)(ref reader)).ReadValueSafe(ref seekTime, default(ForPrimitives));
TVController.Instance?.OnSeekReceived(seekTime);
}
private static void OnReceiveStop(ulong senderClientId, FastBufferReader reader)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
byte b = default(byte);
((FastBufferReader)(ref reader)).ReadValueSafe(ref b, default(ForPrimitives));
TVController.Instance?.OnStopReceived();
}
private static void OnReceiveChat(ulong senderClientId, FastBufferReader reader)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
string message = ReadString(reader);
TVController.Instance?.OnChatReceived(message);
}
private static void OnReceiveRequestState(ulong senderClientId, FastBufferReader reader)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
ulong clientId = default(ulong);
((FastBufferReader)(ref reader)).ReadValueSafe(ref clientId, default(ForPrimitives));
if (IsHost)
{
TVController.Instance?.SendCurrentStateToClient(clientId);
}
}
private static FastBufferWriter BeginMessage()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
return new FastBufferWriter(4096, (Allocator)2, -1);
}
private static void SendToAllClients(string msgName, FastBufferWriter writer)
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
NetworkManager singleton = NetworkManager.Singleton;
CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null);
if (val == null)
{
return;
}
foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds)
{
if (connectedClientsId != NetworkManager.Singleton.LocalClientId)
{
val.SendNamedMessage(msgName, connectedClientsId, writer, (NetworkDelivery)3);
}
}
}
private static void SendToServer(string msgName, FastBufferWriter writer)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
NetworkManager singleton = NetworkManager.Singleton;
CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null);
if (val != null)
{
val.SendNamedMessage(msgName, 0uL, writer, (NetworkDelivery)3);
}
}
public static void SendSyncStateToClient(ulong clientId, PlaybackState state)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: 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)
NetworkManager singleton = NetworkManager.Singleton;
CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null);
if (val != null)
{
FastBufferWriter val2 = BeginMessage();
state.Serialize(val2);
val.SendNamedMessage("TVSync_SyncState", clientId, val2, (NetworkDelivery)3);
((FastBufferWriter)(ref val2)).Dispose();
}
}
private static void WriteString(FastBufferWriter writer, string value)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
byte[] bytes = Encoding.UTF8.GetBytes(value ?? "");
int num = bytes.Length;
((FastBufferWriter)(ref writer)).WriteValueSafe(ref num, default(ForPrimitives));
if (bytes.Length != 0)
{
((FastBufferWriter)(ref writer)).WriteBytesSafe(bytes, -1, 0);
}
}
private static string ReadString(FastBufferReader reader)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
int num = default(int);
((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives));
if (num <= 0)
{
return "";
}
byte[] bytes = new byte[num];
((FastBufferReader)(ref reader)).ReadBytesSafe(ref bytes, num, 0);
return Encoding.UTF8.GetString(bytes);
}
}
public struct PlaybackState
{
public double PlaybackTime;
public double NetworkTime;
public float PlaybackSpeed;
public bool IsPaused;
public bool IsPlaying;
public string VideoUrl;
public void Serialize(FastBufferWriter writer)
{
//IL_000a: 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_0020: 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_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: 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_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
((FastBufferWriter)(ref writer)).WriteValueSafe(ref PlaybackTime, default(ForPrimitives));
((FastBufferWriter)(ref writer)).WriteValueSafe(ref NetworkTime, default(ForPrimitives));
((FastBufferWriter)(ref writer)).WriteValueSafe(ref PlaybackSpeed, default(ForPrimitives));
((FastBufferWriter)(ref writer)).WriteValueSafe(ref IsPaused, default(ForPrimitives));
((FastBufferWriter)(ref writer)).WriteValueSafe(ref IsPlaying, default(ForPrimitives));
byte[] bytes = Encoding.UTF8.GetBytes(VideoUrl ?? "");
int num = bytes.Length;
((FastBufferWriter)(ref writer)).WriteValueSafe(ref num, default(ForPrimitives));
if (bytes.Length != 0)
{
((FastBufferWriter)(ref writer)).WriteBytesSafe(bytes, -1, 0);
}
}
public static PlaybackState Deserialize(FastBufferReader reader)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
PlaybackState result = default(PlaybackState);
((FastBufferReader)(ref reader)).ReadValueSafe(ref result.PlaybackTime, default(ForPrimitives));
((FastBufferReader)(ref reader)).ReadValueSafe(ref result.NetworkTime, default(ForPrimitives));
((FastBufferReader)(ref reader)).ReadValueSafe(ref result.PlaybackSpeed, default(ForPrimitives));
((FastBufferReader)(ref reader)).ReadValueSafe(ref result.IsPaused, default(ForPrimitives));
((FastBufferReader)(ref reader)).ReadValueSafe(ref result.IsPlaying, default(ForPrimitives));
int num = default(int);
((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives));
if (num > 0)
{
byte[] bytes = new byte[num];
((FastBufferReader)(ref reader)).ReadBytesSafe(ref bytes, num, 0);
result.VideoUrl = Encoding.UTF8.GetString(bytes);
}
else
{
result.VideoUrl = "";
}
return result;
}
}
}