Decompiled source of FunnyProjector v1.0.6

FunnyProjector.dll

Decompiled 8 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using FunnyProjector.RPCs;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MyceliumNetworking;
using Steamworks;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("FunnyProjector")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Show whatever you want on the greenscreen")]
[assembly: AssemblyFileVersion("1.0.6.0")]
[assembly: AssemblyInformationalVersion("1.0.6+b8cdccd89e6f21243a71705de378811be5a6dfbc")]
[assembly: AssemblyProduct("FunnyProjector")]
[assembly: AssemblyTitle("FunnyProjector")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.6.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 FunnyProjector
{
	[BepInPlugin("FunnyProjector", "FunnyProjector", "1.0.6")]
	public class Plugin : BaseUnityPlugin
	{
		private static readonly UrlsRPC _urlsRPC = new UrlsRPC(1398770954u);

		public const uint PLUGIN_ID = 1398770954u;

		public static Texture2D? FallbackTexture;

		public static UrlsManager? Urls;

		public static Texture[] Textures = Array.Empty<Texture>();

		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_0073: Unknown result type (might be due to invalid IL or missing references)
			PluginConfig config = new PluginConfig(((BaseUnityPlugin)this).Config, Paths.ConfigPath);
			Urls = new UrlsManager(_urlsRPC, config);
			using Stream stream = ((object)this).GetType().Assembly.GetManifestResourceStream("fallback.png");
			using MemoryStream memoryStream = new MemoryStream(2048);
			stream.CopyTo(memoryStream);
			FallbackTexture = new Texture2D(800, 600);
			ImageConversion.LoadImage(FallbackTexture, memoryStream.ToArray());
			new Harmony("FunnyProjector").PatchAll();
		}

		private void Start()
		{
			_urlsRPC.Register();
		}
	}
	public enum Group
	{
		Host,
		Friends,
		Everyone
	}
	public class PluginConfig
	{
		[CompilerGenerated]
		private string <configDir>P;

		private const string SECTION = "Textures";

		public readonly ConfigEntry<bool> KeepVanilla;

		public readonly ConfigEntry<Group> AllowedFrom;

		public IEnumerable<string> Urls
		{
			get
			{
				string path = Path.Join((ReadOnlySpan<char>)<configDir>P, (ReadOnlySpan<char>)"FunnyProjector.Backgrounds.txt");
				if (File.Exists(path))
				{
					return (from url in File.ReadAllLines(path).AsEnumerable()
						select url.Trim() into url
						where !string.IsNullOrWhiteSpace(url)
						select url).ToArray();
				}
				File.Create(path).Close();
				return Array.Empty<string>();
			}
		}

		public PluginConfig(ConfigFile config, string configDir)
		{
			<configDir>P = configDir;
			KeepVanilla = config.Bind<bool>("Textures", "Keep vanilla", true, (ConfigDescription)null);
			AllowedFrom = config.Bind<Group>("Textures", "Allowed from", Group.Friends, (ConfigDescription)null);
			base..ctor();
		}
	}
	public static class TextureLoader
	{
		private static readonly HttpClient _httpClient = new HttpClient();

		public static Task<Texture2D[]> LoadTexturesAsync(IEnumerable<string> urls)
		{
			return Task.WhenAll(urls.Select((Func<string, Task<Texture2D>>)async delegate(string url)
			{
				_ = 1;
				try
				{
					if (!url.StartsWith("https://"))
					{
						throw new Exception("Only https:// is supported");
					}
					HttpResponseMessage obj = await _httpClient.GetAsync(url);
					Texture2D texture = new Texture2D(1, 1);
					Texture2D val = texture;
					ImageConversion.LoadImage(val, await obj.Content.ReadAsByteArrayAsync());
					return texture;
				}
				catch (Exception ex)
				{
					Debug.LogError((object)ex);
					return Plugin.FallbackTexture;
				}
			}));
		}
	}
	public class UrlsManager
	{
		private readonly Dictionary<CSteamID, IEnumerable<string>> _suggestedUrls = new Dictionary<CSteamID, IEnumerable<string>>();

		private readonly PluginConfig _config;

		private readonly UrlsRPC _rpc;

		public Action<IEnumerable<string>, bool>? OnResultUrls;

		private IEnumerable<IEnumerable<string>> _allowedUrls => from pair in _suggestedUrls
			where IsAllowed(pair.Key)
			select pair.Value;

		public IEnumerable<string> Urls => _suggestedUrls.Count switch
		{
			0 => Array.Empty<string>(), 
			1 => _allowedUrls.First(), 
			_ => _allowedUrls.Aggregate((IEnumerable<string> a, IEnumerable<string> b) => a.Concat(b)), 
		};

		private static CSteamID CurrentUser => SteamUser.GetSteamID();

		public UrlsManager(UrlsRPC rpc, PluginConfig config)
		{
			_rpc = rpc;
			_config = config;
			MyceliumNetwork.PlayerLeft += delegate(CSteamID steamID)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				_suggestedUrls.Remove(steamID);
			};
			MyceliumNetwork.LobbyEntered += delegate
			{
				_suggestedUrls.Clear();
				_rpc.SuggestUrls(_config.Urls);
			};
			rpc.OnSuggestUrls = (Action<CSteamID, IEnumerable<string>>)Delegate.Combine(rpc.OnSuggestUrls, (Action<CSteamID, IEnumerable<string>>)delegate(CSteamID steamID, IEnumerable<string> urls)
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				if (!MyceliumNetwork.IsHost)
				{
					throw new Exception("Not a host");
				}
				_suggestedUrls.Add(steamID, urls);
				SendResultUrls();
			});
			rpc.OnResultUrls = (Action<IEnumerable<string>, bool>)Delegate.Combine(rpc.OnResultUrls, (Action<IEnumerable<string>, bool>)delegate(IEnumerable<string> urls, bool keepVanilla)
			{
				OnResultUrls?.Invoke(urls, keepVanilla);
			});
			ResendOnConfigChange<bool>(_config.KeepVanilla);
			ResendOnConfigChange<Group>(_config.AllowedFrom);
			SceneManager.activeSceneChanged += delegate
			{
				OnResultUrls = null;
			};
		}

		public void SendResultUrls()
		{
			_rpc.SendResultUrls(Urls, _config.KeepVanilla.Value);
		}

		private bool IsAllowed(CSteamID steamID)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			return _config.AllowedFrom.Value switch
			{
				Group.Friends => (int)SteamFriends.GetFriendRelationship(steamID) == 3 || steamID == CurrentUser, 
				Group.Host => steamID == CurrentUser, 
				Group.Everyone => true, 
				_ => throw new NotImplementedException(), 
			};
		}

		private void ResendOnConfigChange<T>(ConfigEntry<T> entry)
		{
			entry.SettingChanged += delegate
			{
				SendResultUrls();
			};
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "FunnyProjector";

		public const string PLUGIN_NAME = "FunnyProjector";

		public const string PLUGIN_VERSION = "1.0.6";
	}
}
namespace FunnyProjector.RPCs
{
	public class UrlsRPC
	{
		[CompilerGenerated]
		private uint <modId>P;

		public Action<CSteamID, IEnumerable<string>>? OnSuggestUrls;

		public Action<IEnumerable<string>, bool>? OnResultUrls;

		public UrlsRPC(uint modId)
		{
			<modId>P = modId;
			base..ctor();
		}

		public void Register()
		{
			MyceliumNetwork.RegisterNetworkObject((object)this, <modId>P, 0);
		}

		private static IEnumerable<string> SplitUrls(string urls)
		{
			return (from url in urls.Split("\n")
				select url.Trim()).ToArray();
		}

		private static string JoinUrls(IEnumerable<string> urls)
		{
			return string.Join("\n", urls);
		}

		[CustomRPC]
		private void AcceptSuggestUrls(string data, RPCInfo info)
		{
			//IL_000b: 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)
			OnSuggestUrls?.Invoke(info.SenderSteamID, SplitUrls(data));
		}

		[CustomRPC]
		private void AcceptResultUrls(string data, bool keepVanilla, RPCInfo info)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (info.SenderSteamID != MyceliumNetwork.LobbyHost)
			{
				throw new Exception("Only host can send ResultUrls requests");
			}
			OnResultUrls?.Invoke(SplitUrls(data), keepVanilla);
		}

		public void SuggestUrls(IEnumerable<string> urls)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			MyceliumNetwork.RPCTarget(<modId>P, "AcceptSuggestUrls", MyceliumNetwork.LobbyHost, (ReliableType)1, new object[1] { JoinUrls(urls) });
		}

		public void SendResultUrls(IEnumerable<string> urls, bool keepVanilla)
		{
			MyceliumNetwork.RPC(<modId>P, "AcceptResultUrls", (ReliableType)1, new object[2]
			{
				JoinUrls(urls),
				keepVanilla
			});
		}
	}
}
namespace FunnyProjector.Patches
{
	[HarmonyPatch(typeof(ProjectorMachine), "Start")]
	public class LogImages
	{
		private static void Postfix(ProjectorMachine __instance)
		{
			ProjectorMachine proj = __instance;
			UrlsManager? urls2 = Plugin.Urls;
			urls2.OnResultUrls = (Action<IEnumerable<string>, bool>)Delegate.Combine(urls2.OnResultUrls, (Action<IEnumerable<string>, bool>)delegate(IEnumerable<string> urls, bool keepVanilla)
			{
				TextureLoader.LoadTexturesAsync(urls).ContinueWith(delegate(Task<Texture2D[]> loaded)
				{
					IEnumerable<Texture2D> enumerable;
					if (!keepVanilla)
					{
						enumerable = proj.textures.Take(1);
					}
					else
					{
						IEnumerable<Texture2D> textures = proj.textures;
						enumerable = textures;
					}
					IEnumerable<Texture2D> collection = enumerable;
					List<Texture> list = new List<Texture>();
					list.AddRange((IEnumerable<Texture>)collection);
					list.AddRange((IEnumerable<Texture>)(object)loaded.Result);
					Plugin.Textures = list.ToArray();
				});
			});
			if (MyceliumNetwork.IsHost)
			{
				Plugin.Urls.SendResultUrls();
			}
		}
	}
	[HarmonyPatch(typeof(ProjectorMachine), "RPCA_Press")]
	public class ReplaceTextures
	{
		private static readonly CodeMatch[] origTextureLoad = (CodeMatch[])(object)new CodeMatch[1]
		{
			new CodeMatch((OpCode?)OpCodes.Ldfld, (object)typeof(ProjectorMachine).GetField("textures"), (string)null)
		};

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> codes)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return new CodeMatcher(codes, (ILGenerator)null).MatchForward(true, origTextureLoad).Repeat((Action<CodeMatcher>)delegate(CodeMatcher match)
			{
				match.Set(OpCodes.Ldfld, (object)typeof(Plugin).GetField("Textures"));
			}, (Action<string>)null).InstructionEnumeration();
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}