using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using SpongePEAK.Core.Logging; using UnityEngine; [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("sponge")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) sponge")] [assembly: AssemblyDescription("Pure library tier: logging, config, reflection and patching helpers. Registers no BepInEx plugin.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+ddcbf023fcb4c2065ad9b038910633cd4a3a93b0")] [assembly: AssemblyProduct("SpongePEAKCore")] [assembly: AssemblyTitle("com.sponge.peakcore")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.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 SpongePEAK.Core.Reflection { public static class ReflectionCache { private const BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags AllStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static readonly Dictionary<(Type, string), FieldInfo> Fields = new Dictionary<(Type, string), FieldInfo>(); private static readonly Dictionary<(Type, string), PropertyInfo> Properties = new Dictionary<(Type, string), PropertyInfo>(); private static readonly Dictionary<(Type, string), MethodInfo> Methods = new Dictionary<(Type, string), MethodInfo>(); public static FieldInfo Field(Type type, string name) { if (type == null || string.IsNullOrEmpty(name)) { return null; } (Type, string) key = (type, name); if (Fields.TryGetValue(key, out var value)) { return value; } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); Fields[key] = field; return field; } public static PropertyInfo Property(Type type, string name) { if (type == null || string.IsNullOrEmpty(name)) { return null; } (Type, string) key = (type, name); if (Properties.TryGetValue(key, out var value)) { return value; } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); Properties[key] = property; return property; } public static MethodInfo Method(Type type, string name) { if (type == null || string.IsNullOrEmpty(name)) { return null; } (Type, string) key = (type, name); if (Methods.TryGetValue(key, out var value)) { return value; } MethodInfo methodInfo; try { methodInfo = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch (AmbiguousMatchException) { methodInfo = null; } Methods[key] = methodInfo; return methodInfo; } public static T GetField(object instance, string name, T fallback = default(T)) { if (instance == null) { return fallback; } FieldInfo fieldInfo = Field(instance.GetType(), name); if (fieldInfo == null) { return fallback; } try { return (fieldInfo.GetValue(instance) is T val) ? val : fallback; } catch { return fallback; } } public static bool SetField(object instance, string name, object value) { if (instance == null) { return false; } FieldInfo fieldInfo = Field(instance.GetType(), name); if (fieldInfo == null) { return false; } try { fieldInfo.SetValue(instance, value); return true; } catch { return false; } } public static void Clear() { Fields.Clear(); Properties.Clear(); Methods.Clear(); } } } namespace SpongePEAK.Core.Patching { public sealed class PatchHost : IDisposable { private readonly ModLog _log; private Harmony _harmony; public string Id { get; } public int FailureCount { get; private set; } public Harmony Harmony { get { //IL_0011: 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_0018: Expected O, but got Unknown //IL_001d: Expected O, but got Unknown Harmony obj = _harmony; if (obj == null) { Harmony val = new Harmony(Id); Harmony val2 = val; _harmony = val; obj = val2; } return obj; } } public PatchHost(string id, ModLog log) { if (string.IsNullOrEmpty(id)) { throw new ArgumentException("Patch host id must not be empty.", "id"); } Id = id; _log = log; } public bool PatchAll(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException("assembly"); } try { Harmony.PatchAll(assembly); _log?.Debug("Applied patches from " + assembly.GetName().Name + "."); return true; } catch (Exception ex) { FailureCount++; _log?.Exception("Failed to apply patches from " + assembly.GetName().Name, ex); return false; } } public bool PatchMethod(MethodBase target, MethodInfo prefix = null, MethodInfo postfix = null, MethodInfo transpiler = null, MethodInfo finalizer = null) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (target == null) { FailureCount++; _log?.Warning("Cannot patch a null method."); return false; } try { _harmony.Patch(target, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix), (transpiler == null) ? ((HarmonyMethod)null) : new HarmonyMethod(transpiler), (finalizer == null) ? ((HarmonyMethod)null) : new HarmonyMethod(finalizer), (HarmonyMethod)null); _log?.Debug("Patched " + target.DeclaringType?.Name + "." + target.Name + "."); return true; } catch (Exception ex) { FailureCount++; _log?.Exception("Failed to patch " + target.DeclaringType?.Name + "." + target.Name, ex); return false; } } public bool PatchType(Type type) { if (type == null) { throw new ArgumentNullException("type"); } try { Harmony.CreateClassProcessor(type).Patch(); _log?.Debug("Applied patches from " + type.Name + "."); return true; } catch (Exception ex) { FailureCount++; _log?.Exception("Failed to apply patches from " + type.Name, ex); return false; } } public void UnpatchAll() { if (_harmony == null) { return; } try { _harmony.UnpatchSelf(); _log?.Debug("Removed all patches."); } catch (Exception ex) { _log?.Exception("Failed to unpatch", ex); } } public void Dispose() { UnpatchAll(); } } } namespace SpongePEAK.Core.Logging { public sealed class ModLog { private readonly string _prefix; private ManualLogSource _sink; public bool IsAttached => _sink != null; public ModLog(string prefix) { _prefix = (string.IsNullOrEmpty(prefix) ? "SpongePEAK" : prefix); } public void Attach(ManualLogSource sink) { _sink = sink; } public void Debug(object message) { Write((LogLevel)32, message); } public void Info(object message) { Write((LogLevel)16, message); } public void Message(object message) { Write((LogLevel)8, message); } public void Warning(object message) { Write((LogLevel)4, message); } public void Error(object message) { Write((LogLevel)2, message); } public void Fatal(object message) { Write((LogLevel)1, message); } public void Exception(string context, Exception ex) { Write((LogLevel)2, $"{context}: {ex}"); } private void Write(LogLevel level, object message) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) ManualLogSource sink = _sink; if (sink == null) { return; } try { sink.Log(level, (object)$"[{_prefix}] {message}"); } catch { } } } } namespace SpongePEAK.Core.Game { public static class GameState { public static Character LocalCharacter => Character.localCharacter; public static bool InRun => (Object)(object)Character.localCharacter != (Object)null; public static List AllCharacters => Character.AllCharacters ?? new List(); public static List AllBots => Character.AllBotCharacters ?? new List(); public static int PlayerCount { get { List allCharacters = Character.AllCharacters; if (allCharacters == null) { return 0; } int num = 0; for (int i = 0; i < allCharacters.Count; i++) { Character val = allCharacters[i]; if ((Object)(object)val != (Object)null && !val.isBot) { num++; } } return num; } } public static List AllPlayers() { List list = new List(); List allCharacters = Character.AllCharacters; if (allCharacters == null) { return list; } for (int i = 0; i < allCharacters.Count; i++) { Character val = allCharacters[i]; if ((Object)(object)val != (Object)null && !val.isBot) { list.Add(val); } } return list; } } } namespace SpongePEAK.Core.Config { public sealed class FeatureToggle { private readonly ConfigEntry _entry; public string Name { get; } public bool Enabled => _entry?.Value ?? false; public bool Applied { get; private set; } public event Action Changed { add { if (_entry != null) { _entry.SettingChanged += delegate { value(_entry.Value); }; } } remove { } } public void MarkApplied(bool applied) { Applied = applied; } public FeatureToggle(ConfigFile config, string section, string name, bool defaultValue, string description) { if (config == null) { throw new ArgumentNullException("config"); } if (string.IsNullOrEmpty(name)) { throw new ArgumentException("Feature name must not be empty.", "name"); } Name = name; _entry = config.Bind(section, name, defaultValue, description); } public override string ToString() { return Name + "=" + (Enabled ? "on" : "off"); } } }