Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SleepThroughDay v1.0.1
SleepThroughDay.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("SleepThroughDay")] [assembly: AssemblyDescription("Adds a day bed to Valheim. Napping in it during the day skips time to nightfall")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: InternalsVisibleTo("SleepCheck")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.1.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 SleepThroughDay { internal static class BedActions { private static readonly Func<Bed, Player, bool> CheckEnemies = Check("CheckEnemies"); private static readonly Func<Bed, Player, bool> CheckExposure = Check("CheckExposure"); private static readonly Func<Bed, Player, bool> CheckFire = Check("CheckFire"); private static readonly Func<Bed, Player, bool> CheckWet = Check("CheckWet"); private static readonly Func<Bed, long> GetOwner = AccessTools.MethodDelegate<Func<Bed, long>>(AccessTools.Method(typeof(Bed), "GetOwner", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<Bed, bool> IsMine = AccessTools.MethodDelegate<Func<Bed, bool>>(AccessTools.Method(typeof(Bed), "IsMine", (Type[])null, (Type[])null), (object)null, true); private static Func<Bed, Player, bool> Check(string name) { return AccessTools.MethodDelegate<Func<Bed, Player, bool>>(AccessTools.Method(typeof(Bed), name, new Type[1] { typeof(Player) }, (Type[])null), (object)null, true); } internal static bool PassesChecks(Bed bed, Player player) { if (CheckEnemies(bed, player) && CheckExposure(bed, player) && CheckFire(bed, player)) { return CheckWet(bed, player); } return false; } internal static void LieDown(Bed bed, Player player) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) ((Character)player).AttachStart(bed.m_spawnPoint, ((Component)bed).gameObject, true, true, false, "attach_bed", new Vector3(0f, 0.5f, 0f), (Transform)null); } internal static bool OwnedByOther(Bed bed) { if (GetOwner(bed) != 0L) { return !IsMine(bed); } return false; } } public class DayBed : Bed, Interactable, Hoverable { public bool Interact(Humanoid human, bool repeat, bool alt) { if (!repeat) { Player val = (Player)(object)((human is Player) ? human : null); if (val != null) { if (!Plugin.Enabled.Value) { ((Character)val).Message((MessageType)2, "$msg_sleepthroughday_off", 0, (Sprite)null, false); return false; } if (!DayTime.IsNapTime()) { ((Character)val).Message((MessageType)2, Plugin.FunnyRefusals.Value ? Refusals.DayBed.Next() : "$msg_sleepthroughday_night", 0, (Sprite)null, false); return false; } if (!BedActions.PassesChecks((Bed)(object)this, val)) { return false; } BedActions.LieDown((Bed)(object)this, val); SleepPatches.SetInDayBed(val, value: true); return false; } } return false; } public string GetHoverText() { string text = ((!Plugin.Enabled.Value) ? "$msg_sleepthroughday_off" : (DayTime.IsNapTime() ? "[<color=yellow><b>$KEY_Use</b></color>] $piece_sleepthroughday_nap" : "$piece_sleepthroughday_dayonly")); return Localization.instance.Localize("$piece_sleepthroughday_daybed\n" + text); } public string GetHoverName() { return Localization.instance.Localize("$piece_sleepthroughday_daybed"); } } internal static class DayTime { internal const float MorningEnd = 0.25f; internal static float FromRaw(float raw) { if (raw >= 0.15f && raw <= 0.85f) { return 0.25f + (raw - 0.15f) / 0.7f * 0.5f; } if (raw < 0.5f) { return raw / 0.15f * 0.25f; } return 0.75f + (raw - 0.85f) / 0.15f * 0.25f; } internal static double ToRaw(float shown) { return 0.15 + ((double)shown - 0.25) / 0.5 * 0.7; } internal static float At(double seconds, long dayLength) { return FromRaw((float)((long)seconds % dayLength) / (float)dayLength); } internal static double NightTarget(double seconds, long dayLength, float nightStart) { return Math.Floor(seconds / (double)dayLength) * (double)dayLength + (double)dayLength * ToRaw(nightStart); } internal static float Now() { EnvMan instance = EnvMan.instance; if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)ZNet.instance)) { return -1f; } return At(ZNet.instance.GetTimeSeconds(), instance.m_dayLengthSec); } internal static bool IsNapTime() { float num = Now(); if (num >= 0.25f) { return num < Plugin.NightStart.Value; } return false; } internal static bool IsMorning() { float num = Now(); if (num >= 0.25f) { return num < 0.5f; } return false; } } [BepInPlugin("onononoki.SleepThroughDay", "SleepThroughDay", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string ModGuid = "onononoki.SleepThroughDay"; public const string ModName = "SleepThroughDay"; public const string ModVersion = "1.0.1"; internal const string PrefabName = "SleepThroughDay_DayBed"; internal const string DefaultRecipe = "BjornHide:5,DeerHide:5,LeatherScraps:5,LoxPelt:5"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> NightStart; internal static ConfigEntry<bool> FunnyRefusals; internal static ConfigEntry<bool> IgnoreEnemies; internal static ConfigEntry<bool> IgnoreRoof; internal static ConfigEntry<bool> IgnoreFire; internal static ConfigEntry<bool> IgnoreWet; internal static ConfigEntry<bool> SleepWithoutSpawn; internal static ConfigEntry<bool> SleepInOthersBeds; private static ConfigEntry<string> _recipe; private static ConfigEntry<bool> _savePreview; private static CustomPiece _piece; private static readonly Color32 DarkwoodTone = new Color32((byte)74, (byte)50, (byte)36, byte.MaxValue); private static readonly Color32 StrawTone = new Color32((byte)128, (byte)44, (byte)38, byte.MaxValue); private static readonly Dictionary<Material, Material> RecoloredMaterials = new Dictionary<Material, Material>(); private static readonly Dictionary<Texture, Texture2D> RecoloredTextures = new Dictionary<Texture, Texture2D>(); private void Awake() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Expected O, but got Unknown //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Expected O, but got Unknown //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Expected O, but got Unknown //IL_0286: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true }; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, new ConfigDescription("Day beds can be napped in. Off leaves them as furniture that cannot be used.", (AcceptableValueBase)null, new object[1] { val })); NightStart = ((BaseUnityPlugin)this).Config.Bind<float>("General", "NightStart", 0.75f, new ConfigDescription("Time of day a nap skips to, as a fraction of the day. 0.75 is nightfall, 0.5 is noon. Day beds work from morning (0.25) until this time.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 0.75f), new object[1] { val })); FunnyRefusals = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "FunnyRefusals", true, "Show a random joke when a bed refuses, the Day bed at night and normal beds in the morning. Off shows the plain messages. Only affects your own game."); _recipe = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Recipe", "BjornHide:5,DeerHide:5,LeatherScraps:5,LoxPelt:5", new ConfigDescription("Building cost of the day bed, as item prefab names and amounts separated by commas.", (AcceptableValueBase)null, new object[1] { val })); IgnoreEnemies = ((BaseUnityPlugin)this).Config.Bind<bool>("Beds", "IgnoreEnemies", true, new ConfigDescription("Every bed can be slept in with enemies nearby, for passive creatures that hear you through floors and walls.", (AcceptableValueBase)null, new object[1] { val })); IgnoreRoof = ((BaseUnityPlugin)this).Config.Bind<bool>("Beds", "IgnoreRoof", false, new ConfigDescription("Every bed can be slept in without a roof.", (AcceptableValueBase)null, new object[1] { val })); IgnoreFire = ((BaseUnityPlugin)this).Config.Bind<bool>("Beds", "IgnoreFire", false, new ConfigDescription("Every bed can be slept in without a fire nearby.", (AcceptableValueBase)null, new object[1] { val })); IgnoreWet = ((BaseUnityPlugin)this).Config.Bind<bool>("Beds", "IgnoreWet", false, new ConfigDescription("Every bed can be slept in while wet.", (AcceptableValueBase)null, new object[1] { val })); SleepWithoutSpawn = ((BaseUnityPlugin)this).Config.Bind<bool>("Beds", "SleepWithoutSpawn", false, new ConfigDescription("Hold the alt key (Left Shift by default) while using a normal bed to sleep in it without claiming it or moving your spawn point.", (AcceptableValueBase)null, new object[1] { val })); SleepInOthersBeds = ((BaseUnityPlugin)this).Config.Bind<bool>("Beds", "SleepInOthersBeds", false, new ConfigDescription("Beds owned by other players can be slept in. They stay theirs and your spawn point does not move.", (AcceptableValueBase)null, new object[1] { val })); _savePreview = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "SavePreview", false, "Save a picture of the day bed next to this config and log its material names on start. Only for checking the look."); AddLocalization(); PrefabManager.OnVanillaPrefabsAvailable += AddPiece; SynchronizationManager.OnConfigurationSynchronized += delegate { ApplyRecipe(); }; _recipe.SettingChanged += delegate { ApplyRecipe(); }; new Harmony("onononoki.SleepThroughDay").PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SleepThroughDay 1.0.1 loaded"); } internal static bool SkipsCheck(string check) { return check switch { "CheckEnemies" => IgnoreEnemies.Value, "CheckExposure" => IgnoreRoof.Value, "CheckFire" => IgnoreFire.Value, "CheckWet" => IgnoreWet.Value, _ => false, }; } private void AddPiece() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown PrefabManager.OnVanillaPrefabsAvailable -= AddPiece; GameObject val = PrefabManager.Instance.CreateClonedPrefab("SleepThroughDay_DayBed", "bed"); if (!Object.op_Implicit((Object)(object)val)) { Log.LogError((object)"vanilla bed not found, the day bed is not added"); return; } Bed component = val.GetComponent<Bed>(); DayBed dayBed = val.AddComponent<DayBed>(); ((Bed)dayBed).m_spawnPoint = component.m_spawnPoint; ((Bed)dayBed).m_monsterCheckRadius = component.m_monsterCheckRadius; ((Bed)dayBed).m_hoverOffset = component.m_hoverOffset; Object.DestroyImmediate((Object)(object)component); Recolor(val); PieceConfig val2 = new PieceConfig { Name = "$piece_sleepthroughday_daybed", Description = "$piece_sleepthroughday_daybed_desc", PieceTable = "Hammer", Category = "Furniture", CraftingStation = "piece_workbench", Requirements = ((IEnumerable<KeyValuePair<string, int>>)Requirements(_recipe.Value)).Select((Func<KeyValuePair<string, int>, RequirementConfig>)((KeyValuePair<string, int> r) => new RequirementConfig(r.Key, r.Value, 0, true))).ToArray() }; Sprite val3 = Render(val, 128); if (Object.op_Implicit((Object)(object)val3)) { val2.Icon = val3; } _piece = new CustomPiece(val, false, val2); PieceManager.Instance.AddPiece(_piece); if (_savePreview.Value) { SavePreview(val); } } private static void Recolor(GameObject prefab) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { Material[] sharedMaterials = val.sharedMaterials; bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { if (Object.op_Implicit((Object)(object)sharedMaterials[j]) && ((Object)sharedMaterials[j]).name.StartsWith("BedSimple")) { if (!RecoloredMaterials.TryGetValue(sharedMaterials[j], out var value)) { Texture2D val2 = RecolorTexture(sharedMaterials[j].mainTexture); value = (Material)((!Object.op_Implicit((Object)(object)val2)) ? ((object)sharedMaterials[j]) : ((object)new Material(sharedMaterials[j]) { name = ((Object)sharedMaterials[j]).name + "_daybed", mainTexture = (Texture)(object)val2 })); RecoloredMaterials[sharedMaterials[j]] = value; } if (!((Object)(object)value == (Object)(object)sharedMaterials[j])) { sharedMaterials[j] = value; flag = true; } } } if (flag) { val.sharedMaterials = sharedMaterials; } } } private static Texture2D RecolorTexture(Texture source) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)source)) { return null; } if (RecoloredTextures.TryGetValue(source, out var value)) { return value; } RenderTexture temporary = RenderTexture.GetTemporary(source.width, source.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); RenderTexture active = RenderTexture.active; Graphics.Blit(source, temporary); RenderTexture.active = temporary; Texture2D val = new Texture2D(source.width, source.height, (TextureFormat)4, true, false) { name = ((Object)source).name + "_daybed", wrapMode = source.wrapMode, filterMode = source.filterMode, anisoLevel = source.anisoLevel }; val.ReadPixels(new Rect(0f, 0f, (float)source.width, (float)source.height), 0, 0); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); if (_savePreview.Value) { SavePng(val, "SleepThroughDay_" + ((Object)source).name + "_original.png"); } Color32[] pixels = val.GetPixels32(); int width = ((Texture)val).width; int height = ((Texture)val).height; double num = 0.0; double num2 = 0.0; int num3 = 0; int num4 = 0; for (int i = 0; i < pixels.Length; i++) { if (pixels[i].a >= 8) { if (InStraw(i % width, i / width, width, height)) { num2 += (double)Luminance(pixels[i]); num4++; } else { num += (double)Luminance(pixels[i]); num3++; } } } float num5 = (float)(num / (double)Math.Max(1, num3)); float num6 = (float)(num2 / (double)Math.Max(1, num4)); for (int j = 0; j < pixels.Length; j++) { bool flag = InStraw(j % width, j / width, width, height); pixels[j] = Stain(pixels[j], flag ? num6 : num5, flag ? StrawTone : DarkwoodTone); } val.SetPixels32(pixels); val.Apply(true); if (_savePreview.Value) { SavePng(val, "SleepThroughDay_" + ((Object)source).name + "_recolored.png"); } RecoloredTextures[source] = val; return val; } internal static bool InStraw(int x, int y, int width, int height) { if ((float)x >= (float)width * 0.375f) { return (float)y >= (float)height * 0.625f; } return false; } internal static Color32 Stain(Color32 pixel, float areaMean, Color32 tone) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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) float num = ((areaMean > 0f) ? (Luminance(pixel) / areaMean) : 1f); return new Color32(Channel((float)(int)tone.r * num), Channel((float)(int)tone.g * num), Channel((float)(int)tone.b * num), pixel.a); } internal static float Luminance(Color32 c) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) return 0.299f * (float)(int)c.r + 0.587f * (float)(int)c.g + 0.114f * (float)(int)c.b; } private static byte Channel(float value) { return (byte)Math.Max(0, Math.Min(255, (int)Math.Round(value))); } private static Sprite Render(GameObject prefab, int size) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown return RenderManager.Instance.Render(new RenderRequest(prefab) { Width = size, Height = size, Rotation = RenderManager.IsometricRotation, UseCache = false }); } private static void SavePreview(GameObject prefab) { IEnumerable<string> values = prefab.GetComponentsInChildren<Renderer>(true).SelectMany((Renderer r) => from m in r.sharedMaterials where Object.op_Implicit((Object)(object)m) select ((Object)r).name + "/" + ((Object)m).name); Log.LogInfo((object)("day bed parts: " + string.Join(", ", values))); Sprite val = Render(prefab, 512); if (Object.op_Implicit((Object)(object)val)) { SavePng(val.texture, "SleepThroughDay_preview.png"); } } private static void SavePng(Texture2D texture, string file) { try { File.WriteAllBytes(Path.Combine(Paths.ConfigPath, file), ImageConversion.EncodeToPNG(texture)); } catch (Exception ex) { Log.LogWarning((object)("could not save " + file + ": " + ex.Message)); } } private static void ApplyRecipe() { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown if (_piece == null || !Object.op_Implicit((Object)(object)_piece.Piece) || !Object.op_Implicit((Object)(object)ObjectDB.instance)) { return; } List<Requirement> list = new List<Requirement>(); foreach (KeyValuePair<string, int> item in Requirements(_recipe.Value)) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.Key); ItemDrop val = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null); if (!Object.op_Implicit((Object)(object)val)) { Log.LogWarning((object)("unknown item " + item.Key + " in Recipe, skipped")); continue; } list.Add(new Requirement { m_resItem = val, m_amount = item.Value, m_recover = true }); } if (list.Count > 0) { _piece.Piece.m_resources = list.ToArray(); } } internal static List<KeyValuePair<string, int>> Requirements(string value) { List<KeyValuePair<string, int>> list = ParseRecipe(value); if (list.Count > 0) { return list; } ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"Recipe has no valid entries, using the default"); } return ParseRecipe("BjornHide:5,DeerHide:5,LeatherScraps:5,LoxPelt:5"); } internal static List<KeyValuePair<string, int>> ParseRecipe(string value) { List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>(); string[] array = (value ?? "").Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ':' }); if (array2.Length == 2 && array2[0].Trim().Length > 0 && int.TryParse(array2[1].Trim(), out var result) && result > 0) { list.Add(new KeyValuePair<string, int>(array2[0].Trim(), result)); } } return list; } private static void AddLocalization() { string text = "English"; Dictionary<string, string> dictionary = new Dictionary<string, string> { ["piece_sleepthroughday_daybed"] = "Day bed", ["piece_sleepthroughday_daybed_desc"] = "A bed for daytime naps. When everyone naps in one, time skips to nightfall.", ["piece_sleepthroughday_nap"] = "Nap until night", ["piece_sleepthroughday_dayonly"] = "Only for naps during the day", ["msg_sleepthroughday_night"] = "Too late for a nap. Use a normal bed at night", ["msg_sleepthroughday_off"] = "Day beds are turned off", ["msg_sleepthroughday_goodevening"] = "Good evening", ["piece_sleepthroughday_sleephere"] = "Sleep here (spawn point stays)" }; JokeDeck[] all = Refusals.All; foreach (JokeDeck jokeDeck in all) { for (int j = 0; j < jokeDeck.Lines.Length; j++) { dictionary[jokeDeck.Token(j)] = jokeDeck.Lines[j]; } } LocalizationManager.Instance.GetLocalization().AddTranslation(ref text, dictionary); } } internal static class Refusals { internal static readonly JokeDeck DayBed = new JokeDeck("msg_sleepthroughday_night", new string[30] { "The bed refuses. It has seen what you do at night.", "Hugin landed on the pillow. He is not moving.", "A Greydwarf is already in there. He paid rent.", "You lie down. The bed stands up and walks away.", "Night naps cost extra. Haldor wants 999 coins.", "The pillow has filed a complaint with Odin.", "The Lox pelt blanket went out grazing.", "The Bear Hide wants its bear back.", "Closed. Opening hours are sunrise to sunset.", "The moon called dibs.", "Too dark. You cannot tell which end is the pillow.", "The bed is busy dreaming about the sun.", "Error 404. Sun not found.", "A Fuling is reading the bed a bedtime story. Please wait.", "Night naps are for Trolls only. You are not tall enough.", "The blanket went to fight the Queen. Back by morning.", "The bed whispers. Go to your real bed.", "Deathsquitos are holding a meeting in the sheets.", "The bed pretends it does not know you.", "Hildir borrowed the pillow. No return date given.", "It is already night. Skipping to night again would break the sky.", "The Bog Witch cursed this bed. It only works in sunlight.", "The bed is on strike until sunrise.", "You try to nap. The bed bites.", "A Neck is guarding the bed. It looks very serious.", "A day bed at night? Bold. Wrong, but bold.", "Even Eikthyr does not nap at night. He just stares.", "Bonemass booked this bed for the night shift.", "Your nap is in another biome.", "Yagluth is using the bed to grumble. Try tomorrow." }); internal static readonly JokeDeck NormalBed = new JokeDeck("msg_sleepthroughday_day", new string[50] { "You are not tired. You just want to skip chores.", "The sun is out. The bed is on its lunch break.", "Odin did not bring you to Valheim to nap at breakfast.", "The bed checks the sky. Too bright. Request denied.", "Sleeping now? The Greydwarfs will tell everyone.", "This bed only works in the dark. It is scared of the sun.", "The pillow is still warm from last night. Let it rest.", "Haldor sells many things. Daytime naps are not one of them.", "It is daytime. Even the Draugr are awake.", "Munin saw that. He will tell Odin.", "The bed says come back after sunset. It has standards.", "You cannot sleep with the sun staring at you like that.", "Too early. The mead has not even kicked in.", "The Trolls are working. You can work too.", "Your bed went outside to enjoy the weather.", "The bed rolls over and ignores you.", "Sleeping in the daytime is how Eikthyr got so lazy.", "The chickens would never allow this.", "No sleep for you. The Elder is watching from his stump.", "The bed has decided you have not earned it yet.", "The sun is up. So are you. That is the rule.", "Daytime naps are a Plains thing. Ask a Fuling.", "Sleep now and Bonemass wins.", "A Viking does not sleep before noon. Probably.", "The bed is not open yet. Please take a number.", "The blanket is drying in the sun.", "Your bed is still recovering from last night.", "The bed looked at your stamina bar and laughed.", "You lie down. The sun pokes you in the eye.", "Nap request sent to Odin. He said no.", "The Bog Witch says beauty sleep starts after dark.", "Somewhere a Greydwarf is doing your chores. Just kidding. Go.", "The bed is busy. It is sunbathing.", "The bed refuses to sleep while the sun is watching.", "Wrong bed. Daytime naps need a Day bed.", "You count sheep. There are no sheep in Valheim.", "Too bright. Even your eyelids refuse.", "Hugin says sleeping at noon is not very Viking of you.", "The bed is a night owl. You are not.", "Get up. The Boars need feeding.", "Your crops are watching you. They look disappointed.", "The bed checked the time. Then it checked you. Then it said no.", "The sun is a deadline. Your bed respects deadlines.", "Yagluth slept in once. Look how that turned out.", "The bed only accepts tired Vikings. You look fine.", "Daylight detected. Bed powers disabled.", "Moder is flying around up there. Do you really want to nap now?", "Your portal is still glowing. So are you. Go explore.", "Sleeping now would make the night jealous.", "The bed is closed for daily maintenance. Try again tonight." }); internal static readonly JokeDeck[] All = new JokeDeck[2] { DayBed, NormalBed }; } internal sealed class JokeDeck { internal readonly string[] Lines; private readonly string _prefix; private readonly List<int> _deck = new List<int>(); private readonly Random _rng = new Random(); private int _last = -1; internal JokeDeck(string prefix, string[] lines) { _prefix = prefix; Lines = lines; } internal string Token(int index) { return $"{_prefix}_{index + 1:00}"; } internal string Next() { return "$" + Token(Draw()); } internal int Draw() { if (_deck.Count == 0) { Refill(); } _last = _deck[_deck.Count - 1]; _deck.RemoveAt(_deck.Count - 1); return _last; } private void Refill() { for (int i = 0; i < Lines.Length; i++) { _deck.Add(i); } for (int num = _deck.Count - 1; num > 0; num--) { int num2 = _rng.Next(num + 1); List<int> deck = _deck; int index = num; List<int> deck2 = _deck; int index2 = num2; int value = _deck[num2]; int value2 = _deck[num]; deck[index] = value; deck2[index2] = value2; } if (_deck[_deck.Count - 1] == _last) { List<int> deck3 = _deck; List<int> deck = _deck; int index2 = _deck.Count - 1; int index = _deck[_deck.Count - 1]; int value2 = _deck[0]; deck3[0] = index; deck[index2] = value2; } } } public static class SleepPatches { [HarmonyPatch(typeof(Game), "EverybodyIsTryingToSleep")] private static class BlockMorningSkip { private static void Postfix(ref bool __result) { if (__result && AnyInDayBed()) { __result = false; } } } [HarmonyPatch(typeof(Game), "UpdateSleeping")] private static class SkipToNight { private static void Postfix(Game __instance) { if (!Plugin.Enabled.Value || !Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer()) { return; } EnvMan instance = EnvMan.instance; if (!Object.op_Implicit((Object)(object)instance) || GameSleeping.Invoke(__instance) || instance.IsTimeSkipping() || !DayTime.IsNapTime()) { return; } double timeSeconds = ZNet.instance.GetTimeSeconds(); if (!(timeSeconds - LastSleepTime.Invoke(__instance) < 10.0) && EverybodyInDayBed()) { double num = DayTime.NightTarget(timeSeconds, instance.m_dayLengthSec, Plugin.NightStart.Value); if (!(num - timeSeconds < 1.0)) { StartSkipToNight(instance, timeSeconds, num); GameSleeping.Invoke(__instance) = true; ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SleepStart", Array.Empty<object>()); } } } } [HarmonyPatch(typeof(Player), "AttachStop")] private static class ClearFlag { private static void Postfix(Player __instance) { ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.IsOwner()) { ZDO zDO = component.GetZDO(); if (zDO.GetBool(InDayBedKey, false) && !zDO.GetBool(ZDOVars.s_inBed, false)) { zDO.Set(InDayBedKey, false); } } } } [HarmonyPatch(typeof(Player), "Message")] private static class EveningMessage { private static void Prefix(Player __instance, ref string msg) { if (msg == "$msg_goodmorning" && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && InDayBed(__instance)) { msg = "$msg_sleepthroughday_goodevening"; } } } [HarmonyPatch(typeof(Player), "Message")] private static class MorningJoke { private static void Prefix(Player __instance, ref string msg) { if (msg == "$msg_cantsleep" && Plugin.FunnyRefusals.Value && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && DayTime.IsMorning()) { msg = Refusals.NormalBed.Next(); } } } [HarmonyPatch] private static class SkipBedChecks { private static IEnumerable<MethodBase> TargetMethods() { return ((IEnumerable<string>)new string[4] { "CheckEnemies", "CheckExposure", "CheckFire", "CheckWet" }).Select((Func<string, MethodBase>)((string name) => AccessTools.Method(typeof(Bed), name, (Type[])null, (Type[])null))); } private static bool Prefix(MethodBase __originalMethod, ref bool __result) { if (!Plugin.SkipsCheck(__originalMethod.Name)) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Bed), "Interact")] private static class SleepWithoutClaim { private static bool Prefix(Bed __instance, Humanoid human, bool repeat, bool alt, ref bool __result) { if (!repeat) { Player val = (Player)(object)((human is Player) ? human : null); if (val != null) { bool num = alt && Plugin.SleepWithoutSpawn.Value; bool flag = Plugin.SleepInOthersBeds.Value && BedActions.OwnedByOther(__instance); if (!num && !flag) { return true; } __result = false; if (!EnvMan.CanSleep()) { ((Character)val).Message((MessageType)2, "$msg_cantsleep", 0, (Sprite)null, false); return false; } if (BedActions.PassesChecks(__instance, val)) { BedActions.LieDown(__instance, val); } return false; } } return true; } } [HarmonyPatch(typeof(Bed), "GetHoverText")] private static class BedHints { private static void Postfix(Bed __instance, ref string __result) { if (Plugin.SleepInOthersBeds.Value && BedActions.OwnedByOther(__instance)) { __result += Localization.instance.Localize("\n[<color=yellow><b>$KEY_Use</b></color>] $piece_sleepthroughday_sleephere"); } else if (Plugin.SleepWithoutSpawn.Value) { __result += Localization.instance.Localize("\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] $piece_sleepthroughday_sleephere"); } } } internal static readonly int InDayBedKey = StringExtensionMethods.GetStableHashCode("onononoki.SleepThroughDay.inDayBed"); private const double SleepPause = 10.0; private const double FadeSeconds = 12.0; private static readonly FieldRef<Game, bool> GameSleeping = AccessTools.FieldRefAccess<Game, bool>("m_sleeping"); private static readonly FieldRef<Game, double> LastSleepTime = AccessTools.FieldRefAccess<Game, double>("m_lastSleepTime"); private static readonly FieldRef<EnvMan, bool> SkipTime = AccessTools.FieldRefAccess<EnvMan, bool>("m_skipTime"); private static readonly FieldRef<EnvMan, double> SkipToTime = AccessTools.FieldRefAccess<EnvMan, double>("m_skipToTime"); private static readonly FieldRef<EnvMan, double> TimeSkipSpeed = AccessTools.FieldRefAccess<EnvMan, double>("m_timeSkipSpeed"); internal static void SetInDayBed(Player player, bool value) { ZNetView val = (Object.op_Implicit((Object)(object)player) ? ((Component)player).GetComponent<ZNetView>() : null); if (Object.op_Implicit((Object)(object)val) && val.IsValid() && val.IsOwner()) { val.GetZDO().Set(InDayBedKey, value); } } internal static bool InDayBed(Player player) { ZNetView val = (Object.op_Implicit((Object)(object)player) ? ((Component)player).GetComponent<ZNetView>() : null); if (Object.op_Implicit((Object)(object)val) && val.IsValid()) { return val.GetZDO().GetBool(InDayBedKey, false); } return false; } private static void StartSkipToNight(EnvMan env, double now, double target) { SkipTime.Invoke(env) = true; SkipToTime.Invoke(env) = target; TimeSkipSpeed.Invoke(env) = (target - now) / 12.0; Plugin.Log.LogInfo((object)$"everyone is napping, skipping to nightfall ({now:0} to {target:0})"); } private static bool EverybodyInDayBed() { List<ZDO> allCharacterZDOS = ZNet.instance.GetAllCharacterZDOS(); if (allCharacterZDOS.Count == 0) { return false; } foreach (ZDO item in allCharacterZDOS) { if (!item.GetBool(ZDOVars.s_inBed, false) || !item.GetBool(InDayBedKey, false)) { return false; } } return true; } private static bool AnyInDayBed() { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } foreach (ZDO allCharacterZDO in ZNet.instance.GetAllCharacterZDOS()) { if (allCharacterZDO.GetBool(InDayBedKey, false)) { return true; } } return false; } } }