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)
{
}
}
}