using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using BoneLib;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow.Pool;
using LabFusion.Network;
using LabFusion.Network.Serialization;
using LabFusion.Safety;
using MelonLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Video;
using YoutubeVideoPlayer;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonOptionalDependencies(new string[] { "LabFusion" })]
[assembly: MelonInfo(typeof(Core), "YoutubeVideoPlayer", "1.1.2", "larkos", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("YoutubeVideoPlayer")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("YoutubeVideoPlayer")]
[assembly: AssemblyTitle("YoutubeVideoPlayer")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 YoutubeVideoPlayer
{
public class UrlResolver
{
private static readonly string YtDlpPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UserData", "YoutubeVideoPlayer", "yt-dlp.exe");
public static bool NeedsResolution(string url)
{
if (string.IsNullOrEmpty(url))
{
return false;
}
return url.Contains("youtube.com") || url.Contains("youtu.be") || url.Contains("twitch.tv") || url.Contains("vimeo.com");
}
public string Resolve(string url)
{
if (!NeedsResolution(url))
{
return url;
}
if (!File.Exists(YtDlpPath))
{
MelonLogger.Msg("[YoutubeVideoPlayer] yt-dlp.exe is not found, please download at Github and place it in UserData/YoutubeVideoPlayer.");
}
if (!File.Exists(YtDlpPath))
{
MelonLogger.Error("[YoutubeVideoPlayer] yt-dlp.exe is not found, please download at Github and place it in UserData/YoutubeVideoPlayer.");
return null;
}
try
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = YtDlpPath,
Arguments = "-g -f \"best[ext=mp4][vcodec^=avc1]/best[ext=mp4]/best\" \"" + url + "\"",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
using Process process = Process.Start(startInfo);
string text = process.StandardOutput.ReadToEnd();
process.WaitForExit();
string text2 = text.Split('\n')[0].Trim();
if (string.IsNullOrEmpty(text2))
{
MelonLogger.Error("[YoutubeVideoPlayer] yt-dlp returned empty output.");
return null;
}
return text2;
}
catch (Exception ex)
{
MelonLogger.Error("[YoutubeVideoPlayer] Exception: " + ex.Message);
return null;
}
}
}
public class YoutubeSyncMessage : NativeMessageHandler
{
public override byte Tag => 225;
public static void BroadcastLink(string link)
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
if (string.IsNullOrEmpty(link))
{
return;
}
MelonLogger.Msg("[YoutubeVideoPlayer] Broadcasting video to clients...");
if (NetworkInfo.HasServer)
{
NetWriter val = NetWriter.Create();
try
{
val.Write(link);
RelayType val2 = (RelayType)((!NetworkInfo.IsHost) ? 1 : 3);
NetMessage val3 = NetMessage.Create((byte)225, val, new MessageRoute(val2, (NetworkChannel)0), (byte?)null);
try
{
if (NetworkInfo.IsHost)
{
MessageSender.BroadcastMessageExceptSelf((NetworkChannel)0, val3);
}
else
{
MessageSender.SendToServer((NetworkChannel)0, val3);
}
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
ProcessLink(link);
}
protected override void OnHandleMessage(ReceivedMessage received)
{
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
string text = string.Empty;
try
{
NetReader val = NetReader.Create(((ReceivedMessage)(ref received)).Bytes);
try
{
text = val.ReadString();
}
finally
{
((IDisposable)val)?.Dispose();
}
}
catch (Exception ex)
{
MelonLogger.Error("[YoutubeVideoPlayer] Failed to read network message: " + ex.Message);
return;
}
if (string.IsNullOrEmpty(text))
{
return;
}
MelonLogger.Msg("[YoutubeVideoPlayer] Network received link: " + text);
if (NetworkInfo.IsHost)
{
NetWriter val2 = NetWriter.Create();
try
{
val2.Write(text);
NetMessage val3 = NetMessage.Create((byte)225, val2, new MessageRoute((RelayType)3, (NetworkChannel)0), (byte?)null);
try
{
MessageSender.BroadcastMessageExcept(((ReceivedMessage)(ref received)).Sender.GetValueOrDefault(), (NetworkChannel)0, val3, false);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
ProcessLink(text);
}
private static void ProcessLink(string originalUrl)
{
Task.Run(delegate
{
string resolved = VideoManager.ResolveUrl(originalUrl);
Core.MainThreadQueue.Enqueue(delegate
{
VideoManager.ScanScene();
MelonLogger.Msg($"[YoutubeVideoPlayer] ProcessLink firing, {VideoManager._players.Count} players registered.");
foreach (VideoPlayer player in VideoManager._players)
{
if ((Object)(object)player != (Object)null && !string.IsNullOrEmpty(resolved))
{
MelonLogger.Msg("[YoutubeVideoPlayer] Applying MP4 to player...");
VideoPlayerEarlyPatch.IsRPCProcessing = true;
player.url = resolved;
player.Play();
VideoPlayerEarlyPatch.IsRPCProcessing = false;
}
}
});
});
}
}
[HarmonyPatch(typeof(URLWhitelistManager), "IsURLWhitelisted")]
public static class WhitelistBypassPatch
{
private static bool Prefix(string url, ref bool __result)
{
if (!string.IsNullOrEmpty(url) && url.Contains("googlevideo.com"))
{
__result = true;
return false;
}
return true;
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPriority(800)]
public static class VideoPlayerEarlyPatch
{
public static bool IsRPCProcessing;
public static string GuardedUrl;
private static string _lastTriggeredUrl;
private static float _lastTriggerTime;
private const float DebounceSeconds = 1f;
private static bool Prefix(VideoPlayer __instance, ref string value)
{
if (IsRPCProcessing)
{
GuardedUrl = value;
return true;
}
string text = value;
string systemCopyBuffer = GUIUtility.systemCopyBuffer;
if (!UrlResolver.NeedsResolution(text) && UrlResolver.NeedsResolution(systemCopyBuffer))
{
text = systemCopyBuffer;
}
if (UrlResolver.NeedsResolution(text))
{
float realtimeSinceStartup = Time.realtimeSinceStartup;
if (text == _lastTriggeredUrl && realtimeSinceStartup - _lastTriggerTime < 1f)
{
return false;
}
_lastTriggeredUrl = text;
_lastTriggerTime = realtimeSinceStartup;
MelonLogger.Msg("[YoutubeVideoPlayer] Link found: " + text);
YoutubeSyncMessage.BroadcastLink(text);
return false;
}
return true;
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
[HarmonyPriority(0)]
public static class VideoPlayerLatePatch
{
private static void Prefix(ref string value)
{
if (VideoPlayerEarlyPatch.IsRPCProcessing && VideoPlayerEarlyPatch.GuardedUrl != null && value != VideoPlayerEarlyPatch.GuardedUrl)
{
MelonLogger.Msg("[YoutubeVideoPlayer] Restoring guarded URL.");
value = VideoPlayerEarlyPatch.GuardedUrl;
}
}
}
[HarmonyPatch(typeof(VideoPlayer), "Prepare")]
public static class VideoPlayerPreparePatch
{
private static bool Prefix(VideoPlayer __instance)
{
return !string.IsNullOrEmpty(__instance.url);
}
}
[HarmonyPatch(typeof(VideoPlayer), "Play")]
public static class VideoPlayerPlayPatch
{
private static bool Prefix(VideoPlayer __instance)
{
return !string.IsNullOrEmpty(__instance.url);
}
}
public static class VideoManager
{
public static readonly List<VideoPlayer> _players = new List<VideoPlayer>();
public static void ScanScene()
{
_players.Clear();
Il2CppArrayBase<VideoPlayer> val = Object.FindObjectsOfType<VideoPlayer>();
foreach (VideoPlayer item in val)
{
RegisterVideoPlayer(item);
}
MelonLogger.Msg($"[YoutubeVideoPlayer] Found {_players.Count} VideoPlayer(s) in scene.");
}
public static void RegisterVideoPlayer(VideoPlayer vp)
{
if (!((Object)(object)vp == (Object)null) && !_players.Contains(vp))
{
_players.Add(vp);
SetupVideoPlayer(vp);
MelonLogger.Msg("[YoutubeVideoPlayer] Registered: " + ((Object)((Component)vp).gameObject).name);
}
}
private static void SetupVideoPlayer(VideoPlayer vp)
{
MeshRenderer component = ((Component)vp).gameObject.GetComponent<MeshRenderer>();
if ((Object)(object)component != (Object)null && (Object)(object)((Renderer)component).material != (Object)null)
{
vp.renderMode = (VideoRenderMode)3;
vp.targetMaterialRenderer = (Renderer)(object)component;
if (((Renderer)component).material.HasProperty("_BaseMap"))
{
vp.targetMaterialProperty = "_BaseMap";
}
else if (((Renderer)component).material.HasProperty("_MainTex"))
{
vp.targetMaterialProperty = "_MainTex";
}
}
}
public static string ResolveUrl(string url)
{
if (string.IsNullOrEmpty(url))
{
return url;
}
return new UrlResolver().Resolve(url);
}
}
public class Core : MelonMod
{
public static readonly ConcurrentQueue<Action> MainThreadQueue = new ConcurrentQueue<Action>();
public static Core Instance { get; private set; }
public override void OnInitializeMelon()
{
Instance = this;
Hooking.OnLevelLoaded += OnLevelLoaded;
((MelonBase)this).HarmonyInstance.PatchAll();
if (MelonTypeBase<MelonMod>.RegisteredMelons.Any((MelonMod m) => ((MelonBase)m).Info.Name == "LabFusion"))
{
NativeMessageHandler.RegisterHandler<YoutubeSyncMessage>();
}
}
public override void OnUpdate()
{
Action result;
while (MainThreadQueue.TryDequeue(out result))
{
result?.Invoke();
}
}
private void OnLevelLoaded(LevelInfo levelInfo)
{
VideoManager.ScanScene();
}
}
[HarmonyPatch(typeof(Poolee), "OnSpawn")]
public static class PooleeOnSpawnPatch
{
[HarmonyPostfix]
public static void Postfix(Poolee __instance)
{
GameObject gameObject = ((Component)__instance).gameObject;
if (!((Object)(object)gameObject == (Object)null))
{
VideoPlayer componentInChildren = gameObject.GetComponentInChildren<VideoPlayer>();
if ((Object)(object)componentInChildren != (Object)null)
{
VideoManager.RegisterVideoPlayer(componentInChildren);
}
}
}
}
}