Decompiled source of One Player Sleep v1.0.0

plugins/OnePlayerSleep.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("BenjSammy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("One player in bed is enough to skip the night on a Valheim server.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("One Player Sleep by BenjSammy")]
[assembly: AssemblyTitle("OnePlayerSleep")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 BenjSammy.OnePlayerSleep
{
	[BepInPlugin("benjsammy.oneplayersleep", "One Player Sleep by BenjSammy", "1.0.0")]
	public sealed class OnePlayerSleepPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "benjsammy.oneplayersleep";

		public const string PluginName = "One Player Sleep by BenjSammy";

		public const string PluginVersion = "1.0.0";

		private Harmony _harmony;

		private ConfigEntry<bool> _enabled;

		private void Awake()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Un seul joueur dans son lit suffit pour passer la nuit. Effet sur le serveur ou l'hôte seulement.");
			_harmony = new Harmony("benjsammy.oneplayersleep");
			try
			{
				SleepApi api = new SleepApi(SleepApi.RequireType("ZNet"), SleepApi.RequireType("ZDO"), SleepApi.FindType("ZDOVars"));
				SleepPatch.Install(_harmony, SleepApi.RequireType("Game"), api, () => _enabled.Value, delegate(Exception exception)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("One Player Sleep: API error; normal sleep rule retained. " + exception));
				});
				((BaseUnityPlugin)this).Logger.LogInfo((object)"One Player Sleep 1.0.0 by BenjSammy active. One player in bed is enough. Install on the server/host; clients do not need this mod.");
			}
			catch (Exception ex)
			{
				_harmony.UnpatchSelf();
				SleepPatch.Reset();
				((BaseUnityPlugin)this).Logger.LogError((object)("One Player Sleep could not start: incompatible Valheim API. " + ex));
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			SleepPatch.Reset();
		}
	}
	internal interface ISleepApi
	{
		bool AnyPlayerInBedOnServer();
	}
	internal sealed class SleepApi : ISleepApi
	{
		private const BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private readonly MemberInfo _netInstance;

		private readonly MethodInfo _isServer;

		private readonly MethodInfo _characters;

		private readonly MethodInfo _getInBed;

		private readonly object[] _inBedArguments;

		private readonly Type _zdoType;

		internal SleepApi(Type netType, Type zdoType, Type varsType)
		{
			if (netType == null || zdoType == null)
			{
				throw new TypeLoadException("ZNet or ZDO was not found.");
			}
			_zdoType = zdoType;
			_netInstance = FindMember(netType, "instance") ?? throw new MissingMemberException(netType.FullName, "instance");
			_isServer = netType.GetMethod("IsServer", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (_isServer == null || _isServer.ReturnType != typeof(bool))
			{
				throw new MissingMethodException(netType.FullName, "IsServer()");
			}
			_characters = netType.GetMethod("GetAllCharacterZDOS", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (_characters == null || !typeof(IEnumerable).IsAssignableFrom(_characters.ReturnType))
			{
				throw new MissingMethodException(netType.FullName, "GetAllCharacterZDOS()");
			}
			MemberInfo memberInfo = ((varsType == null) ? null : FindMember(varsType, "s_inBed"));
			object obj = ((memberInfo == null) ? null : Read(memberInfo, null));
			MethodInfo method = zdoType.GetMethod("GetBool", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
			{
				typeof(int),
				typeof(bool)
			}, null);
			if (obj is int && method != null && method.ReturnType == typeof(bool))
			{
				_getInBed = method;
				_inBedArguments = new object[2] { obj, false };
				return;
			}
			_getInBed = zdoType.GetMethod("GetBool", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
			{
				typeof(string),
				typeof(bool)
			}, null);
			if (_getInBed == null || _getInBed.ReturnType != typeof(bool))
			{
				throw new MissingMethodException(zdoType.FullName, "GetBool(inBed, false)");
			}
			_inBedArguments = new object[2] { "inBed", false };
		}

		public bool AnyPlayerInBedOnServer()
		{
			object obj = Read(_netInstance, null);
			if (obj == null || !(bool)_isServer.Invoke(obj, null))
			{
				return false;
			}
			if (!(_characters.Invoke(obj, null) is IEnumerable enumerable))
			{
				return false;
			}
			foreach (object item in enumerable)
			{
				if (item != null && _zdoType.IsInstanceOfType(item) && (bool)_getInBed.Invoke(item, _inBedArguments))
				{
					return true;
				}
			}
			return false;
		}

		internal static Type FindType(string name)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType(name, throwOnError: false);
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}

		internal static Type RequireType(string name)
		{
			return FindType(name) ?? throw new TypeLoadException("Valheim type was not found: " + name);
		}

		private static MemberInfo FindMember(Type type, string name)
		{
			return (MemberInfo)(((object)type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) ?? ((object)type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)));
		}

		private static object Read(MemberInfo member, object instance)
		{
			FieldInfo fieldInfo = member as FieldInfo;
			if (!(fieldInfo != null))
			{
				return ((PropertyInfo)member).GetValue(instance, null);
			}
			return fieldInfo.GetValue(instance);
		}
	}
	internal static class SleepPatch
	{
		private static ISleepApi _api;

		private static Func<bool> _enabled;

		private static Action<Exception> _error;

		private static bool _reported;

		internal static void Install(Harmony harmony, Type gameType, ISleepApi api, Func<bool> enabled, Action<Exception> error)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			if (gameType == null)
			{
				throw new TypeLoadException("Game was not found.");
			}
			MethodInfo method = gameType.GetMethod("EverybodyIsTryingToSleep", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (method == null || method.ReturnType != typeof(bool))
			{
				throw new MissingMethodException(gameType.FullName, "EverybodyIsTryingToSleep()");
			}
			_api = api ?? throw new ArgumentNullException("api");
			_enabled = enabled ?? throw new ArgumentNullException("enabled");
			_error = error;
			_reported = false;
			harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(SleepPatch).GetMethod("AfterSleepCheck", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void AfterSleepCheck(ref bool __result)
		{
			if (__result || _api == null || _enabled == null)
			{
				return;
			}
			try
			{
				if (_enabled() && _api.AnyPlayerInBedOnServer())
				{
					__result = true;
				}
			}
			catch (Exception obj)
			{
				if (!_reported)
				{
					_reported = true;
					_error?.Invoke(obj);
				}
			}
		}

		internal static void Reset()
		{
			_api = null;
			_enabled = null;
			_error = null;
			_reported = false;
		}
	}
}