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 KingsAndGodsAdditions v1.6.8
KingsAndGodsAdditions.dll
Decompiled 4 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using Steamworks; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.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 KingAndGodsAdditional { internal static class BossEnvironments { internal static readonly string[] Names = new string[8] { "Eikthyr", "GDKing", "Bonemass", "Moder", "GoblinKing", "Queen", "Fader", "DN_Bossroom" }; private static bool registered; private static readonly MethodInfo GetEnv = AccessTools.Method(typeof(EnvMan), "GetEnv", (Type[])null, (Type[])null); internal static string Prefab(string name) { return "KAG_Environment_" + name; } internal static void Install(Harmony harmony) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_00a3: 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_00bc: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown PrefabManager.OnVanillaPrefabsAvailable += Register; harmony.Patch((MethodBase)AccessTools.Method(typeof(EnvMan), "GetEnvironmentOverride", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(BossEnvironments), "Environment", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(AccessTools.TypeByName("Localization"), "Localize", new Type[2] { typeof(string), typeof(string[]) }, (Type[])null), new HarmonyMethod(typeof(BossEnvironments), "NewDay", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(ItemDrop), "Interact", (Type[])null, (Type[])null), new HarmonyMethod(typeof(BossEnvironments), "NoPickup", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void Register() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown if (registered) { return; } string[] names = Names; foreach (string text in names) { string text2 = Prefab(text); ItemConfig val = new ItemConfig(); val.Name = "Environment " + text; val.Description = "Persistent boss environment: " + text + ". Radius: 200 metres. Place with spawn " + Prefab(text) + ". Remove with an admin world-edit tool."; val.StackSize = 1; CustomItem val2 = new CustomItem(text2, "Stone", val); GameObject itemPrefab = val2.ItemPrefab; ItemDrop itemDrop = val2.ItemDrop; itemDrop.m_autoPickup = false; itemDrop.m_autoDestroy = false; Rigidbody component = itemPrefab.GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.isKinematic = true; component.useGravity = false; } ZNetView component2 = itemPrefab.GetComponent<ZNetView>(); component2.m_persistent = true; component2.m_distant = true; itemPrefab.AddComponent<BossEnvironmentMarker>().EnvironmentName = text; if (!ItemManager.Instance.AddItem(val2)) { throw new InvalidOperationException("Cannot register " + Prefab(text)); } } registered = true; } private static bool NewDay(string __0, ref string __result) { if (__0 != "$msg_newday") { return true; } __result = "A new day has dawned"; return false; } private static bool NoPickup(ItemDrop __instance, ref bool __result) { if ((Object)(object)((Component)__instance).GetComponent<BossEnvironmentMarker>() == (Object)null) { return true; } __result = false; return false; } private static void Environment(EnvMan __instance, ref string __result) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_006e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null || !string.IsNullOrEmpty(__instance.m_debugEnv)) { return; } Vector3 position = ((Component)Player.m_localPlayer).transform.position; BossEnvironmentMarker bossEnvironmentMarker = null; float num = 40000f; foreach (BossEnvironmentMarker item in BossEnvironmentMarker.Active) { if (!((Object)(object)item == (Object)null) && item.Live) { Vector3 val = ((Component)item).transform.position - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude > num) && GetEnv.Invoke(__instance, new object[1] { item.EnvironmentName }) != null) { bossEnvironmentMarker = item; num = sqrMagnitude; } } } if ((Object)(object)bossEnvironmentMarker != (Object)null) { __result = bossEnvironmentMarker.EnvironmentName; } } } public sealed class BossEnvironmentMarker : MonoBehaviour { public const float Radius = 200f; public string EnvironmentName; internal static readonly HashSet<BossEnvironmentMarker> Active = new HashSet<BossEnvironmentMarker>(); private ZNetView view; internal bool Live { get { if ((Object)(object)view != (Object)null) { return view.IsValid(); } return false; } } private void Awake() { view = ((Component)this).GetComponent<ZNetView>(); } private void OnEnable() { Active.Add(this); } private void OnDisable() { Active.Remove(this); } private void OnDestroy() { Active.Remove(this); } } public sealed class ConfigAuthority { private readonly Dictionary<string, ConfigEntryBase> entries = new Dictionary<string, ConfigEntryBase>(); private readonly Dictionary<ConfigEntryBase, string> originals = new Dictionary<ConfigEntryBase, string>(); private readonly Dictionary<ConfigEntryBase, string> locked = new Dictionary<ConfigEntryBase, string>(); private readonly Dictionary<ConfigFile, bool> saveFlags = new Dictionary<ConfigFile, bool>(); private readonly List<ConfigFile> files = new List<ConfigFile>(); private readonly Dictionary<ConfigFile, DateTime> stamps = new Dictionary<ConfigFile, DateTime>(); private bool applying; private bool active; public bool Received { get; private set; } public void Discover(BaseUnityPlugin owner) { AddFile("kag", owner.Config); if (Chainloader.PluginInfos.TryGetValue("com.nandor.racesofvalheim", out var value)) { BaseUnityPlugin instance = value.Instance; if ((Object)(object)instance != (Object)null) { AddFile("races", instance.Config); } } } private static string Key(string group, string section, string key) { return group + "\t" + Convert.ToBase64String(Encoding.UTF8.GetBytes(section)) + "\t" + Convert.ToBase64String(Encoding.UTF8.GetBytes(key)); } private void AddFile(string group, ConfigFile file) { if (!files.Contains(file)) { files.Add(file); file.SettingChanged += Changed; } foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in file) { entries[Key(group, item.Key.Section, item.Key.Key)] = item.Value; } } public bool Manages(ConfigFile file) { return files.Contains(file); } public void ReloadServerFiles(bool force) { foreach (ConfigFile file in files) { DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(file.ConfigFilePath); if (force || !stamps.TryGetValue(file, out var value) || !(value == lastWriteTimeUtc)) { file.Reload(); stamps[file] = File.GetLastWriteTimeUtc(file.ConfigFilePath); } } } public void SetServerValue(string group, string section, string key, string value) { if (!entries.TryGetValue(Key(group, section, key), out var value2)) { throw new FormatException("Unknown configuration entry"); } TomlTypeConverter.ConvertToValue(value, value2.SettingType); value2.SetSerializedValue(value); value2.ConfigFile.Save(); } public string Snapshot() { StringBuilder stringBuilder = new StringBuilder("KAGCFG2\n"); foreach (KeyValuePair<string, ConfigEntryBase> item in entries.OrderBy<KeyValuePair<string, ConfigEntryBase>, string>((KeyValuePair<string, ConfigEntryBase> p) => p.Key, StringComparer.Ordinal)) { stringBuilder.Append(item.Key).Append('\t').Append(Convert.ToBase64String(Encoding.UTF8.GetBytes(item.Value.GetSerializedValue()))) .Append('\n'); } string text = stringBuilder.ToString(); if (text.Length > 1048576) { throw new InvalidOperationException("Server configuration exceeds 1 MiB"); } return text; } public static Dictionary<string, string> Decode(string text) { if (text == null || text.Length > 1048576 || !text.StartsWith("KAGCFG2\n", StringComparison.Ordinal)) { throw new FormatException("Invalid configuration packet"); } Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); string[] array = text.Substring(8).Split('\n'); foreach (string text2 in array) { if (text2.Length != 0) { string[] array2 = text2.Split('\t'); if (array2.Length != 4 || (array2[0] != "kag" && array2[0] != "races")) { throw new FormatException("Invalid config row"); } Encoding.UTF8.GetString(Convert.FromBase64String(array2[1])); Encoding.UTF8.GetString(Convert.FromBase64String(array2[2])); string key = array2[0] + "\t" + array2[1] + "\t" + array2[2]; if (dictionary.ContainsKey(key)) { throw new FormatException("Duplicate configuration key"); } dictionary.Add(key, Encoding.UTF8.GetString(Convert.FromBase64String(array2[3]))); } } return dictionary; } public void Apply(string text) { Dictionary<string, string> values = Decode(text); if (values.Count != entries.Count || entries.Keys.Any((string k) => !values.ContainsKey(k))) { throw new InvalidOperationException("Server/client configuration schema differs. Install matching RacesOfValheim and KAG versions."); } foreach (KeyValuePair<string, string> item in values) { TomlTypeConverter.ConvertToValue(item.Value, entries[item.Key].SettingType); } applying = true; try { foreach (ConfigFile file in files) { if (!saveFlags.ContainsKey(file)) { saveFlags[file] = file.SaveOnConfigSet; } file.SaveOnConfigSet = false; } foreach (KeyValuePair<string, string> item2 in values) { ConfigEntryBase val = entries[item2.Key]; if (!originals.ContainsKey(val)) { originals[val] = val.GetSerializedValue(); } val.SetSerializedValue(item2.Value); locked[val] = val.GetSerializedValue(); } active = true; Received = true; } finally { applying = false; } } private void Changed(object sender, SettingChangedEventArgs args) { if (!active || applying || !locked.TryGetValue(args.ChangedSetting, out var value) || args.ChangedSetting.GetSerializedValue() == value) { return; } applying = true; try { args.ChangedSetting.SetSerializedValue(value); } finally { applying = false; } } public void Enforce() { if (!active) { return; } applying = true; try { foreach (ConfigFile file in files) { file.SaveOnConfigSet = false; } foreach (KeyValuePair<ConfigEntryBase, string> item in locked) { if (item.Key.GetSerializedValue() != item.Value) { item.Key.SetSerializedValue(item.Value); } } } finally { applying = false; } } public void Restore() { active = false; Received = false; applying = true; try { foreach (KeyValuePair<ConfigEntryBase, string> original in originals) { original.Key.SetSerializedValue(original.Value); } foreach (KeyValuePair<ConfigFile, bool> saveFlag in saveFlags) { saveFlag.Key.SaveOnConfigSet = saveFlag.Value; } originals.Clear(); locked.Clear(); saveFlags.Clear(); } finally { applying = false; } } } internal static class DayNightCycle { private static ConfigEntry<int> day; private static ConfigEntry<int> night; internal static long CycleSeconds => (long)(day.Value + night.Value) * 60L; internal static double Dawn => (double)night.Value / (2.0 * (double)(day.Value + night.Value)); internal static void Install(Harmony harmony) { Install(harmony, "FixedUpdate", "SetCycle"); Install(harmony, "RescaleDayFraction", "RescaleTime"); Install(harmony, "GetMorningStartSec", "Morning"); Install(harmony, "SkipToMorning", "Sleep"); } private static void Install(Harmony harmony, string target, string prefix) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(EnvMan), target, (Type[])null, (Type[])null); if (methodInfo == null) { throw new MissingMethodException(typeof(EnvMan).FullName, target); } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DayNightCycle), prefix, (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); if (patchInfo == null || !patchInfo.Prefixes.Any((Patch p) => p.owner == "kingsandgods.additional" && p.PatchMethod.Name == prefix)) { throw new InvalidOperationException("Time patch was not installed: " + target); } } internal static void Bind(ConfigFile config) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown day = config.Bind<int>("Time", "DayDurationMinutes", 21, new ConfigDescription("Real minutes from dawn to dusk. Server authoritative. Change before starting the world; changing cycle length changes the displayed day number.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1440), Array.Empty<object>())); night = config.Bind<int>("Time", "NightDurationMinutes", 9, new ConfigDescription("Real minutes from dusk to dawn. Server authoritative. Sleeping still skips the night. Change before starting the world.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1440), Array.Empty<object>())); } internal static float Rescale(float fraction, double dawn) { if ((double)fraction < dawn) { return (float)((double)fraction / dawn * 0.25); } if ((double)fraction <= 1.0 - dawn) { return (float)(0.25 + ((double)fraction - dawn) / (1.0 - 2.0 * dawn) * 0.5); } return (float)(0.75 + ((double)fraction - (1.0 - dawn)) / dawn * 0.25); } private static void SetCycle(ref long ___m_dayLengthSec) { ___m_dayLengthSec = CycleSeconds; } private static bool RescaleTime(float __0, ref float __result) { __result = Rescale(__0, Dawn); return false; } private static bool Morning(int __0, ref double __result) { __result = (double)__0 * (double)CycleSeconds + (double)night.Value * 30.0; return false; } private static bool Sleep(ref bool ___m_skipTime, ref double ___m_skipToTime, ref double ___m_timeSkipSpeed) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return false; } double timeSeconds = ZNet.instance.GetTimeSeconds(); double num = (double)night.Value * 30.0; double num2 = (Math.Floor((timeSeconds - num) / (double)CycleSeconds) + 1.0) * (double)CycleSeconds + num; ___m_skipTime = true; ___m_skipToTime = num2; ___m_timeSkipSpeed = (num2 - timeSeconds) / 12.0; return false; } } internal static class DeathRules { private static ConfigEntry<bool> keep; [ThreadStatic] private static int dying; private static bool Enabled { get { if (keep != null) { return keep.Value; } return false; } } internal static void Bind(ConfigFile config) { keep = config.Bind<bool>("Death", "KeepInventoryOnDeath", true, "Server setting: keep all carried inventory on death, prevent new tombstones and death map markers. Existing graves and pins are not deleted. Skill/food death penalties are unchanged."); } internal static void Install(Harmony h) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_005b: Expected O, but got Unknown h.Patch((MethodBase)AccessTools.Method(typeof(Player), "OnDeath", (Type[])null, (Type[])null), new HarmonyMethod(typeof(DeathRules), "Begin", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(DeathRules), "End", (Type[])null) { priority = 0 }, (HarmonyMethod)null); Patch(h, AccessTools.Method(typeof(Player), "CreateTombStone", (Type[])null, (Type[])null), "NoGrave"); Patch(h, AccessTools.Method(typeof(PlayerProfile), "SetDeathPoint", (Type[])null, (Type[])null), "NoDeathPoint"); Patch(h, AccessTools.Method(typeof(PlayerProfile), "HaveDeathPoint", (Type[])null, (Type[])null), "NoSkull"); Patch(h, AccessTools.Method(typeof(Minimap), "AddPin", (Type[])null, (Type[])null), "NoPin"); Patch(h, AccessTools.Method(typeof(ZoneSystem), "GetGlobalKey", new Type[1] { typeof(GlobalKeys) }, (Type[])null), "KeepKey"); Type type = AccessTools.TypeByName("PassiveTree.Permadeath"); if (type != null) { Patch(h, AccessTools.Method(type, "DestroyItems", (Type[])null, (Type[])null), "NoGrave"); } } private static void Patch(Harmony h, MethodInfo method, string prefix) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown if (method == null) { throw new MissingMethodException("Death rule target: " + prefix); } h.Patch((MethodBase)method, new HarmonyMethod(typeof(DeathRules), prefix, (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void Begin(out int __state) { __state = dying; if (Enabled) { dying++; } } private static void End(int __state) { dying = __state; } private static bool NoGrave() { return !Enabled; } private static bool NoDeathPoint() { if (Enabled) { return dying == 0; } return true; } private static bool NoSkull(ref bool __result) { if (!Enabled) { return true; } __result = false; return false; } private static bool NoPin(PinType __1, ref PinData __result) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 if (!Enabled || dying == 0 || (int)__1 != 4) { return true; } __result = null; return false; } private static bool KeepKey(GlobalKeys __0, ref bool __result) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 if (!Enabled) { return true; } if ((int)__0 == 23) { __result = true; return false; } if ((int)__0 == 20 || (int)__0 == 21) { __result = false; return false; } return true; } } internal static class DemigodRunes { private static Type ui; private static Type demigod; private static Type configs; private static Action<string> log; private static readonly Dictionary<string, string> classes = new Dictionary<string, string>(StringComparer.Ordinal); private static ItemData usedRune; private static string selectedClass; private static bool opening; private static bool registered; private static IList Defaults => (IList)AccessTools.Property(demigod, "DemigodDefaults").GetValue(null, null); private static string Name(object entry) { return (string)AccessTools.Property(entry.GetType(), "Name").GetValue(entry, null); } private static bool Hidden(object entry) { return (bool)AccessTools.Property(entry.GetType(), "Hidden").GetValue(entry, null); } internal static string PrefabName(string name) { return "KAG_Rune_" + name; } private static int Index(string name) { IList defaults = Defaults; for (int i = 0; i < defaults.Count; i++) { if (Name(defaults[i]) == name && !Hidden(defaults[i])) { return i; } } return -1; } internal static void Install(Harmony harmony, Action<string> logger) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown ui = AccessTools.TypeByName("NorseDemigods.CustomUI"); if (!(ui == null)) { log = logger; demigod = AccessTools.TypeByName("NorseDemigods.Demigod"); configs = AccessTools.TypeByName("NorseDemigods.Configs"); MethodInfo methodInfo = AccessTools.Method(AccessTools.Inner(AccessTools.TypeByName("NorseDemigods.NorseDemigods"), "Player_OnSpawned_Patch"), "Postfix", (Type[])null, (Type[])null); if (methodInfo == null) { throw new MissingMethodException("NorseDemigods starter runestone hook"); } harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(DemigodRunes), "NoStarterRune", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); log("NorseDemigods automatic starter runestone disabled; pickup and crafting preserved."); Hook(harmony, AccessTools.TypeByName("NorseDemigods.NorseDemigods"), "AddCustomItems", null, "Register"); Hook(harmony, ui, "RunestoneMenuOpen", "BeforeOpen", "AfterOpen"); Hook(harmony, ui, "BuildRunestoneMenu", null, "HideDropdown"); Hook(harmony, ui, "RunestoneMenuUpdatePage", "LockPage", null); Hook(harmony, ui, "RunestoneMenuChooseDemigod", "ValidChoice", null); Hook(harmony, ui, "RunestoneMenuConfirmChoice", "ValidChoice", null); Hook(harmony, ui, "RunestoneDemigodChosen", "ConsumeRune", null); Hook(harmony, typeof(Humanoid), "UseItem", "UseRune", null); } } private static void Hook(Harmony harmony, Type type, string name, string pre, string post) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_005a: Unknown result type (might be due to invalid IL or missing references) MethodInfo methodInfo = AccessTools.Method(type, name, (Type[])null, (Type[])null); if (methodInfo == null) { throw new MissingMethodException(type.FullName, name); } harmony.Patch((MethodBase)methodInfo, (pre == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(DemigodRunes), pre, (Type[])null) { priority = 800 }, (post == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(DemigodRunes), post, (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static IEnumerable<CodeInstruction> NoStarterRune(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; for (int i = 0; i + 1 < list.Count; i++) { FieldInfo fieldInfo = list[i].operand as FieldInfo; MethodInfo methodInfo = list[i + 1].operand as MethodInfo; if (!(list[i].opcode != OpCodes.Ldsfld) && !(fieldInfo == null) && !(fieldInfo.DeclaringType.FullName != "NorseDemigods.Configs") && !(fieldInfo.Name != "RunestoneSpawnAtStart") && !(methodInfo == null) && !(methodInfo.Name != "get_Value") && !(methodInfo.ReturnType != typeof(bool))) { list[i].opcode = OpCodes.Ldc_I4_0; list[i].operand = null; list[i + 1].opcode = OpCodes.Nop; list[i + 1].operand = null; num++; } } if (num != 1) { throw new InvalidOperationException("Unsupported NorseDemigods starter-rune branch: " + num); } return list; } private static void Register() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown if (registered) { return; } if (ItemManager.Instance.GetItem("DemigodRunestone") == null) { throw new InvalidOperationException("DemigodRunestone is not registered."); } foreach (object @default in Defaults) { if (!Hidden(@default)) { string text = Name(@default); string text2 = PrefabName(text); ItemConfig val = new ItemConfig(); val.Name = "Rune " + text; val.Description = "Use to read about " + text + " and choose this demigod."; val.Amount = 1; val.Requirements = (RequirementConfig[])(object)new RequirementConfig[2] { new RequirementConfig("Stone", 1, 0, true), new RequirementConfig("Resin", 1, 0, true) }; CustomItem val2 = new CustomItem(text2, "DemigodRunestone", val); if (!ItemManager.Instance.AddItem(val2)) { throw new InvalidOperationException("Cannot register " + text2); } classes.Add(text2, text); log("Registered Rune " + text + ": " + text2); } } registered = true; } private static bool UseRune(Humanoid __instance, ItemData item) { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null || !classes.TryGetValue(((Object)item.m_dropPrefab).name, out var value)) { return true; } if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !__instance.GetInventory().ContainsItem(item)) { return false; } if (Index(value) < 0) { return false; } usedRune = item; selectedClass = value; opening = true; try { AccessTools.Method(ui, "RunestoneMenuOpen", (Type[])null, (Type[])null).Invoke(null, null); } finally { opening = false; } return false; } private static void BeforeOpen() { if (opening) { return; } usedRune = null; selectedClass = null; foreach (object @default in Defaults) { if (!Hidden(@default)) { selectedClass = Name(@default); break; } } if ((Object)(object)Player.m_localPlayer != (Object)null) { usedRune = ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems().Find((ItemData i) => (Object)(object)i.m_dropPrefab != (Object)null && ((Object)i.m_dropPrefab).name == "DemigodRunestone"); } } private static void AfterOpen() { AccessTools.Property(ui, "Owner").SetValue(null, Player.m_localPlayer, null); int num = Index(selectedClass); if (num >= 0) { AccessTools.Method(ui, "RunestoneMenuUpdatePage", (Type[])null, (Type[])null).Invoke(null, new object[1] { num }); } HideDropdown(); } private static void HideDropdown() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown GameObject val = (GameObject)AccessTools.Field(ui, "RunestoneMenuPanel").GetValue(null); if (!((Object)(object)val == (Object)null)) { Dropdown[] componentsInChildren = val.GetComponentsInChildren<Dropdown>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Component)componentsInChildren[i]).gameObject.SetActive(false); } } } private static void LockPage(ref int __0) { int num = Index(selectedClass); if (num >= 0) { __0 = num; } } private static bool ValidChoice() { Player localPlayer = Player.m_localPlayer; int num = Index(selectedClass); if ((Object)(object)localPlayer == (Object)null || usedRune == null || !((Humanoid)localPlayer).GetInventory().ContainsItem(usedRune) || num < 0) { return false; } object obj = Defaults[num]; if ((bool)AccessTools.Method(demigod, "IsDemigodDisabled", (Type[])null, (Type[])null).Invoke(null, new object[1] { obj })) { return false; } AccessTools.Field(ui, "RunestoneMenuPage").SetValue(null, num); return true; } private static bool ConsumeRune() { if (selectedClass == null) { return true; } object value = AccessTools.Field(configs, "RunestoneConsumable").GetValue(null); if ((bool)AccessTools.Property(value.GetType(), "Value").GetValue(value, null) && (Object)(object)Player.m_localPlayer != (Object)null && usedRune != null && ((Humanoid)Player.m_localPlayer).GetInventory().ContainsItem(usedRune)) { ((Humanoid)Player.m_localPlayer).GetInventory().RemoveItem(usedRune, 1); } usedRune = null; selectedClass = null; return false; } } internal static class GearInterface { private static FieldInfo foldTab; private static FieldInfo settingsButton; private static FieldInfo settings; internal static void Install(Harmony harmony) { //IL_007f: 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_0098: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected O, but got Unknown Type type = AccessTools.TypeByName("PassiveTree.Gear.Sheet"); Type type2 = AccessTools.TypeByName("PassiveTree.Gear.Module"); if (type == null || type2 == null) { throw new MissingMemberException("PathOfValheiman equipment interface"); } foldTab = Field(type, "foldTab"); settingsButton = Field(type, "settingsButton"); settings = Field(type, "settings"); harmony.Patch((MethodBase)Method(type2, "get_Compact"), new HarmonyMethod(typeof(GearInterface), "Compact", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); string[] array = new string[2] { "SyncFold", "Tick" }; foreach (string name in array) { harmony.Patch((MethodBase)Method(type, name), (HarmonyMethod)null, new HarmonyMethod(typeof(GearInterface), "HideControls", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } harmony.Patch((MethodBase)Method(type, "ToggleSettings"), new HarmonyMethod(typeof(GearInterface), "BlockSettings", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static FieldInfo Field(Type type, string name) { return AccessTools.Field(type, name) ?? throw new MissingFieldException(type.FullName, name); } private static MethodInfo Method(Type type, string name) { return AccessTools.Method(type, name, (Type[])null, (Type[])null) ?? throw new MissingMethodException(type.FullName, name); } private static bool Compact(ref bool __result) { __result = true; return false; } private static bool BlockSettings() { return false; } private static void HideControls(object __instance) { Hide(foldTab.GetValue(__instance)); Hide(settingsButton.GetValue(__instance)); Hide(settings.GetValue(__instance)); } private static void Hide(object value) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val == (Object)null && value is Component) { val = ((Component)value).gameObject; } if ((Object)(object)val != (Object)null && val.activeSelf) { val.SetActive(false); } } } public sealed class InventoryStatsLayout : MonoBehaviour { private InventoryGui gui; private Type trashType; private FieldInfo trashRect; private FieldInfo[] sortButtons; private RectTransform shieldIcon; private Vector2 shieldHome; internal static void Install(Harmony harmony) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown harmony.Patch((MethodBase)AccessTools.Method(typeof(InventoryGui), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(InventoryStatsLayout), "Attach", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void Attach(InventoryGui __instance) { if ((Object)(object)((Component)__instance).GetComponent<InventoryStatsLayout>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<InventoryStatsLayout>(); } } private void Awake() { gui = ((Component)this).GetComponent<InventoryGui>(); trashType = AccessTools.TypeByName("QuickStackStore.TrashModule+TrashButton"); if (trashType != null) { trashRect = AccessTools.Field(trashType, "rectTransform"); } Type type = AccessTools.TypeByName("QuickStackStore.ButtonRenderer"); if (type != null) { sortButtons = new FieldInfo[4] { AccessTools.Field(type, "favoritingTogglingButton"), AccessTools.Field(type, "sortInventoryButton"), AccessTools.Field(type, "restockAreaButton"), AccessTools.Field(type, "quickStackAreaButton") }; } } private static bool Visible(RectTransform rect) { if ((Object)(object)rect != (Object)null) { return ((Component)rect).gameObject.activeInHierarchy; } return false; } private static Bounds VisualBounds(RectTransform space, RectTransform root) { //IL_0009: 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) //IL_00f9: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[4]; Bounds result = default(Bounds); bool flag = false; Graphic[] componentsInChildren = ((Component)root).GetComponentsInChildren<Graphic>(false); foreach (Graphic val in componentsInChildren) { if (!((Behaviour)val).enabled || val.color.a <= 0.001f) { continue; } val.rectTransform.GetWorldCorners(array); Vector3[] array2 = array; foreach (Vector3 val2 in array2) { Vector3 val3 = ((Transform)space).InverseTransformPoint(val2); if (!flag) { ((Bounds)(ref result))..ctor(val3, Vector3.zero); flag = true; } else { ((Bounds)(ref result)).Encapsulate(val3); } } } if (!flag) { root.GetWorldCorners(array); ((Bounds)(ref result))..ctor(((Transform)space).InverseTransformPoint(array[0]), Vector3.zero); Vector3[] array2 = array; foreach (Vector3 val4 in array2) { ((Bounds)(ref result)).Encapsulate(((Transform)space).InverseTransformPoint(val4)); } } return result; } private void LateUpdate() { //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gui == (Object)null || (Object)(object)gui.m_player == (Object)null || !((Component)gui.m_player).gameObject.activeInHierarchy) { return; } RectTransform player = gui.m_player; AdjustShieldAndButtons(player); Transform obj = ((Transform)player).Find("CoinPocketUI"); RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null); if (!Visible(val)) { return; } Transform obj2 = ((Transform)player).Find("Trash"); RectTransform val2 = (RectTransform)(object)((obj2 is RectTransform) ? obj2 : null); if (!Visible(val2) && trashType != null && trashRect != null) { Component componentInChildren = ((Component)gui).GetComponentInChildren(trashType, true); if ((Object)(object)componentInChildren != (Object)null) { object? value = trashRect.GetValue(componentInChildren); val2 = (RectTransform)((value is RectTransform) ? value : null); } } if (!Visible(val2)) { RectTransform[] componentsInChildren = ((Component)gui).GetComponentsInChildren<RectTransform>(false); foreach (RectTransform val3 in componentsInChildren) { if (((Object)val3).name.Equals("Trash", StringComparison.OrdinalIgnoreCase) || ((Object)val3).name.Equals("TrashButton", StringComparison.OrdinalIgnoreCase)) { val2 = val3; break; } } } if (Visible(val2)) { Bounds val4 = VisualBounds(player, val2); Bounds val5 = VisualBounds(player, val); Vector3 val6 = default(Vector3); ((Vector3)(ref val6))..ctor(((Bounds)(ref val4)).max.x + 12f - ((Bounds)(ref val5)).min.x, ((Bounds)(ref val4)).center.y - ((Bounds)(ref val5)).center.y, 0f); ((Transform)val).position = ((Transform)val).position + ((Transform)player).TransformVector(val6); } } private void AdjustShieldAndButtons(RectTransform space) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) Transform obj = ((Transform)space).Find("Armor"); RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null); if (Visible(val)) { Transform obj2 = ((Transform)val).Find("armor_icon"); RectTransform val2 = (RectTransform)(object)((obj2 is RectTransform) ? obj2 : null); if ((Object)(object)val2 != (Object)null) { if ((Object)(object)shieldIcon != (Object)(object)val2) { shieldIcon = val2; shieldHome = val2.anchoredPosition; } val2.anchoredPosition = shieldHome + new Vector2(0f, -14f); } } Transform obj3 = ((Transform)space).Find("Weight"); RectTransform val3 = (RectTransform)(object)((obj3 is RectTransform) ? obj3 : null); if (!Visible(val3) || sortButtons == null) { return; } Bounds val4 = VisualBounds(space, val3); float num = ((Bounds)(ref val4)).min.x; FieldInfo[] array = sortButtons; Vector3 val8 = default(Vector3); foreach (FieldInfo fieldInfo in array) { Component val5 = (Component)((fieldInfo == null) ? null : /*isinst with value type is only supported in some contexts*/); RectTransform val6 = (RectTransform)(((Object)(object)val5 == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/); if (Visible(val6)) { Bounds val7 = VisualBounds(space, val6); ((Vector3)(ref val8))..ctor(num - ((Bounds)(ref val7)).min.x, ((Bounds)(ref val4)).min.y - 10f - ((Bounds)(ref val7)).max.y, 0f); ((Transform)val6).position = ((Transform)val6).position + ((Transform)space).TransformVector(val8); num += ((Bounds)(ref val7)).size.x + 10f; } } } } internal static class MenuTheme { private static ConfigEntry<bool> enabled; internal static void Bind(ConfigFile config) { enabled = config.Bind<bool>("Interface", "BlueMenuTheme", true, "Use a Moder-inspired cold blue lighting/fog palette in the main-menu scene. Replaces the old EikthyrMenuTheme option. Does not change weather in the world. Restart after changing."); } internal static void Install(Harmony harmony) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown harmony.Patch((MethodBase)AccessTools.Method(typeof(MenuScene), "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(MenuTheme), "Apply", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void Apply(ref Color ___m_sunFogColor, ref Color ___m_fogColor, ref Color ___m_ambientLightColor, ref float ___m_fogDensity, ref float ___m_windIntensity, Light ___m_dirLight) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) if (enabled.Value) { ___m_sunFogColor = new Color(0.12f, 0.3f, 0.55f, 1f); ___m_fogColor = new Color(0.055f, 0.12f, 0.24f, 1f); ___m_ambientLightColor = new Color(0.14f, 0.2f, 0.3f, 1f); ___m_fogDensity = 0.008f; ___m_windIntensity = 0.7f; if ((Object)(object)___m_dirLight != (Object)null) { ___m_dirLight.color = new Color(0.4f, 0.65f, 1f, 1f); ___m_dirLight.intensity = 0.65f; } } } } [BepInPlugin("kingsandgods.additional", "KingsAndGodsAdditions", "1.6.8")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__85_0; internal void <DiscordPostfix>b__85_0() { Application.OpenURL("https://discord.gg/PMPDpuPTND"); } } public const string Guid = "kingsandgods.additional"; public const string Version = "1.6.8"; private const string NetworkVersion = "1.6.8"; private const string HelloRpc = "KAGAdditional_Hello_v1"; private const string AssignRpc = "KAGAdditional_Assign_v1"; private const string ConfigRpc = "KAGAdditional_Config_v2"; private const string AdminRpc = "KAGAdditional_Admin_v2"; private const string ReplyRpc = "KAGAdditional_Reply_v2"; private const string ConfigAckRpc = "KAGAdditional_ConfigAck_v2"; private const string RecipesRpc = "KAGAdditional_Recipes_v3"; private const string RecipesAckRpc = "KAGAdditional_RecipesAck_v3"; private const string Discord = "https://discord.gg/PMPDpuPTND"; internal static Plugin One; private Harmony harmony; private Type raceType; private object raceInstance; private ZRoutedRpc registered; private ZNet session; private float nextTick; private float nextRequest; private float nextApply; private string assigned; private bool applying; private Player lastPlayer; private string assignmentFile; private DateTime fileStamp; private RaceAssignments assignments = new RaceAssignments(); private readonly Dictionary<long, float> firstSeen = new Dictionary<long, float>(); private readonly HashSet<long> verified = new HashSet<long>(); private ConfigEntry<bool> requireClients; private ConfigEntry<int> graceSeconds; private ConfigEntry<float> logoOffset; private readonly Dictionary<RectTransform, Vector2> logoPositions = new Dictionary<RectTransform, Vector2>(); private Sprite logo; private Texture2D logoTexture; private bool ready; private readonly ConfigAuthority authority = new ConfigAuthority(); private readonly Dictionary<long, string> sentConfig = new Dictionary<long, string>(); private bool clientAdmin; private string configSnapshot; private readonly HashSet<long> configConfirmed = new HashSet<long>(); private RecipeAuthority recipes; private readonly Dictionary<long, string> sentRecipes = new Dictionary<long, string>(); private readonly HashSet<long> recipesConfirmed = new HashSet<long>(); private string recipeAck; private static readonly MethodInfo ServerPeerMethod = AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null); private long ServerPeerId { get { if (registered != null) { return (long)ServerPeerMethod.Invoke(registered, null); } return 0L; } } private void Awake() { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown One = this; DayNightCycle.Bind(((BaseUnityPlugin)this).Config); DeathRules.Bind(((BaseUnityPlugin)this).Config); MenuTheme.Bind(((BaseUnityPlugin)this).Config); logoOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Interface", "LogoOffsetDown", 60f, "Move the main-menu logo down in UI units. Positive = lower. Restart the game after editing."); requireClients = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "RequireClientMod", true, "Disconnect peers that do not complete the KingsAndGodsAdditions version handshake. Server setting only."); graceSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Server", "HandshakeTimeoutSeconds", 60, new ConfigDescription("Seconds allowed after a peer joins. Server setting only.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(20, 300), Array.Empty<object>())); assignmentFile = Path.Combine(Paths.ConfigPath, "KingAndGodsAdditional.races.yml"); if (!File.Exists(assignmentFile)) { File.WriteAllText(assignmentFile, RaceAssignments.Template()); } recipes = new RecipeAuthority(Path.Combine(Paths.ConfigPath, "KingAndGodsAdditional.recipes.yml"), delegate(string text) { ((BaseUnityPlugin)this).Logger.LogInfo((object)text); }); harmony = new Harmony("kingsandgods.additional"); InventoryStatsLayout.Install(harmony); BossEnvironments.Install(harmony); DeathRules.Install(harmony); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type type = assembly.GetType("Vapok.Common.Managers.Splash.ModSplashManager", throwOnError: false); if (!(type == null)) { Patch(type, "CheckAndQueueStartupSplashes", "Block", null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Vapok automatic startup splash disabled: " + assembly.GetName().Name)); } } MenuTheme.Install(harmony); Patch(typeof(Game), "ShowIntro", "SkipTextIntro", null); DemigodRunes.Install(harmony, delegate(string text) { ((BaseUnityPlugin)this).Logger.LogInfo((object)text); }); Type type2 = AccessTools.TypeByName("Guilds.GuildUI"); if (type2 != null) { Patch(type2, "BuildDiscordLink", "Block", null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Guilds: Northarun Discord link hidden."); } DayNightCycle.Install(harmony); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Day/night hooks installed and verified. Config: [Time] DayDurationMinutes / NightDurationMinutes."); raceType = AccessTools.TypeByName("RacesOfValheim.RacesOfValheim"); if (raceType == null) { throw new InvalidOperationException("RacesOfValheim 1.6.6 is required."); } Patch(raceType, "ShowRaceSelectionMenu", "Block", null); Patch(raceType, "ResetRace", "SelectionGuard", null); string[] names = RaceAssignments.Names; foreach (string race in names) { Patch(raceType, "Select" + RaceAssignments.Canonical(race), "SelectionGuard", null); } Patch(NeedType("RacesOfValheim.RaceMenuWard"), "TryPlaceAtSpawn", "Block", null); Patch(NeedType("RacesOfValheim.RaceMenuWardUI"), "Show", "Block", null); Type type3 = AccessTools.TypeByName("PassiveTree.UI.GameLogo"); if (type3 != null) { GearInterface.Install(harmony); SkillsButton.Install(harmony); Patch(type3, "Ours", "LogoPrefix", null); Patch(type3, "Apply", null, "LogoPositionPostfix"); Patch(NeedType("PassiveTree.UI.MenuDiscord"), "Add", null, "DiscordPostfix"); Patch(NeedType("PassiveTree.UI.TreeWindow"), "BuildTopBar", null, "TreePostfix"); Type type4 = NeedType("PassiveTree.UI.SetupWizard"); Patch(type4, "MaybeShow", "WizardGuard", null); Patch(type4, "Build", "Block", null); Patch(type4, "OpenForTest", "Block", null); Type type5 = NeedType("PassiveTree.DifficultyAdmin"); Patch(type5, "SenderCanEdit", "PathAdminGuard", null); Patch(type5, "get_CanEdit", "PathCanEdit", null); Patch(NeedType("PassiveTree.ConfigSync"), "OnApply", "PathServerMessage", null); Patch(type5, "ReceiveRole", "PathServerMessage", null); Patch(type5, "ReceiveState", "PathServerMessage", null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"PathOfValheiman hooks enabled: logo, Discord, tree Settings and BuildsManager buttons."); } authority.Discover((BaseUnityPlugin)(object)this); Patch(typeof(ConfigFile), "Save", "ConfigSaveGuard", null); RegisterCommands(); ready = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"KingsAndGodsAdditions 1.6.8 loaded. Race selection and automatic starter altar disabled."); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Server assignment file: " + assignmentFile)); } private static Type NeedType(string name) { return AccessTools.TypeByName(name) ?? throw new MissingMemberException(name); } private void Patch(Type type, string method, string prefix, string postfix) { //IL_002f: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null); if (methodInfo == null) { throw new MissingMethodException(type.FullName, method); } HarmonyMethod val = ((prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Plugin), prefix, (Type[])null) { priority = 800 }); HarmonyMethod val2 = ((postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Plugin), postfix, (Type[])null) { priority = 0 }); harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Bound " + type.FullName + "." + method)); } private static bool Block() { return false; } private static bool SkipTextIntro(Game __instance) { AccessTools.Method(typeof(Game), "SkipIntro", (Type[])null, (Type[])null).Invoke(__instance, null); return false; } private static bool SelectionGuard() { if ((Object)(object)One != (Object)null) { return One.applying; } return false; } private static bool ConfigSaveGuard(ConfigFile __instance) { if (!((Object)(object)One == (Object)null) && !((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer()) { return !One.authority.Manages(__instance); } return true; } private static bool WizardGuard(ref bool __result) { __result = false; return false; } private static bool PathAdminGuard(long __0, ref bool __result) { __result = (Object)(object)One != (Object)null && One.IsServerAdmin(__0); return false; } private static bool PathCanEdit(ref bool __result) { __result = (Object)(object)ZNet.instance != (Object)null && (ZNet.instance.IsServer() || ((Object)(object)One != (Object)null && One.clientAdmin)); return false; } private static bool PathServerMessage(long __0) { if ((Object)(object)One != (Object)null && (Object)(object)ZNet.instance != (Object)null) { return RaceAssignments.TrustedServer(ZNet.instance.IsServer(), __0, One.ServerPeerId); } return false; } private void Update() { if (!ready || Time.realtimeSinceStartup < nextTick) { return; } nextTick = Time.realtimeSinceStartup + 1f; try { Tick(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("KAG update: " + ex)); } } private void Tick() { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { authority.Restore(); recipes.Reset(); recipeAck = null; sentRecipes.Clear(); recipesConfirmed.Clear(); clientAdmin = false; sentConfig.Clear(); configConfirmed.Clear(); configSnapshot = null; session = null; registered = null; assigned = null; lastPlayer = null; verified.Clear(); firstSeen.Clear(); return; } if ((Object)(object)session != (Object)(object)instance) { authority.Restore(); recipes.Reset(); recipeAck = null; sentRecipes.Clear(); recipesConfirmed.Clear(); clientAdmin = false; sentConfig.Clear(); configConfirmed.Clear(); configSnapshot = null; session = instance; registered = null; assigned = null; lastPlayer = null; verified.Clear(); firstSeen.Clear(); nextRequest = 0f; nextApply = 0f; if (instance.IsServer()) { ReloadAssignments(force: true); ReloadServerConfig(force: true); } } if (ZRoutedRpc.instance != null && registered != ZRoutedRpc.instance) { registered = ZRoutedRpc.instance; registered.Register<string>("KAGAdditional_Hello_v1", (Action<long, string>)ReceiveHello); registered.Register<string>("KAGAdditional_Assign_v1", (Action<long, string>)ReceiveAssignment); registered.Register<string>("KAGAdditional_Config_v2", (Action<long, string>)ReceiveConfig); registered.Register<string>("KAGAdditional_Admin_v2", (Action<long, string>)ReceiveAdmin); registered.Register<string>("KAGAdditional_Reply_v2", (Action<long, string>)ReceiveReply); registered.Register<string>("KAGAdditional_ConfigAck_v2", (Action<long, string>)ReceiveConfigAck); registered.Register<string>("KAGAdditional_Recipes_v3", (Action<long, string>)ReceiveRecipes); registered.Register<string>("KAGAdditional_RecipesAck_v3", (Action<long, string>)ReceiveRecipesAck); } if (instance.IsServer()) { ReloadAssignments(force: false); ReloadServerConfig(force: false); configSnapshot = authority.Snapshot(); recipes.ServerTick(); ServerPeers(); if (!instance.IsDedicated()) { assigned = assignments.ForPlayer(LocalSteamId()); } } else if (registered != null && Time.realtimeSinceStartup >= nextRequest && ServerPeerId != 0L) { nextRequest = Time.realtimeSinceStartup + 3f; registered.InvokeRoutedRPC(ServerPeerId, "KAGAdditional_Hello_v1", new object[1] { "1.6.8" }); } if (!instance.IsServer()) { authority.Enforce(); recipes.Tick(); if (recipes.Received && recipeAck != recipes.Payload && registered != null && ServerPeerId != 0L) { registered.InvokeRoutedRPC(ServerPeerId, "KAGAdditional_RecipesAck_v3", new object[1] { "1.6.8" }); recipeAck = recipes.Payload; } } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { lastPlayer = null; } else if (assigned != null && (instance.IsServer() || authority.Received)) { localPlayer.m_customData.TryGetValue("Race", out var value); if (((Object)(object)lastPlayer != (Object)(object)localPlayer || value != assigned) && Time.realtimeSinceStartup >= nextApply) { nextApply = Time.realtimeSinceStartup + 3f; ApplyRace(localPlayer, assigned); lastPlayer = localPlayer; } } } private void ReloadAssignments(bool force) { DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(assignmentFile); if (!force && lastWriteTimeUtc == fileStamp) { return; } fileStamp = lastWriteTimeUtc; try { RaceAssignments raceAssignments = (assignments = RaceAssignments.Parse(File.ReadAllText(assignmentFile))); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded server race assignments: " + raceAssignments.Count + " SteamID64 entries. Unlisted players: Human.")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Invalid race file; keeping last valid assignments. " + ex.Message)); } } private static string LocalSteamId() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { return RaceAssignments.FromSocketName(((object)SteamUser.GetSteamID()/*cast due to .constrained prefix*/).ToString()); } catch { return null; } } private void ReceiveHello(long sender, string version) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || version != "1.6.8" || registered == null) { return; } ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer != null && peer.m_socket != null) { string text = RaceAssignments.FromSocketName(peer.m_socket.GetHostName()); if (text == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Cannot authenticate SteamID64 for peer " + sender + ". Use Steam networking; crossplay IDs are not Steam IDs.")); return; } verified.Add(sender); SendConfig(sender); SendRecipes(sender); registered.InvokeRoutedRPC(sender, "KAGAdditional_Assign_v1", new object[1] { assignments.ForPlayer(text) }); } } private void ReceiveAssignment(long sender, string race) { if ((Object)(object)ZNet.instance == (Object)null || registered == null || !RaceAssignments.TrustedServer(ZNet.instance.IsServer(), sender, ServerPeerId)) { return; } string text = RaceAssignments.Canonical(race); if (text != null) { if (assigned != text) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Server assigned race: " + text)); } assigned = text; } } private void ServerPeers() { if (registered == null) { return; } List<ZNetPeer> list = new List<ZNetPeer>(ZNet.instance.GetPeers()); HashSet<long> hashSet = new HashSet<long>(); foreach (ZNetPeer item in list) { if (item.m_uid == 0L || item.m_server || item.m_socket == null) { continue; } long uid = item.m_uid; hashSet.Add(uid); if (!firstSeen.ContainsKey(uid)) { firstSeen[uid] = Time.realtimeSinceStartup; } if (verified.Contains(uid)) { SendConfig(uid); SendRecipes(uid); string text = RaceAssignments.FromSocketName(item.m_socket.GetHostName()); if (text != null) { registered.InvokeRoutedRPC(uid, "KAGAdditional_Assign_v1", new object[1] { assignments.ForPlayer(text) }); } } if (requireClients.Value && (!verified.Contains(uid) || !configConfirmed.Contains(uid) || !recipesConfirmed.Contains(uid)) && Time.realtimeSinceStartup - firstSeen[uid] > (float)graceSeconds.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Disconnecting " + item.m_playerName + ": KingsAndGodsAdditions 1.6.8 handshake/configuration sync missing or no authenticated SteamID64. Install matching mods on the client and use Steam networking.")); AccessTools.Method(typeof(ZNet), "Disconnect", new Type[1] { typeof(ZNetPeer) }, (Type[])null).Invoke(ZNet.instance, new object[1] { item }); firstSeen.Remove(uid); } } long[] array = firstSeen.Keys.ToArray(); foreach (long num in array) { if (!hashSet.Contains(num)) { firstSeen.Remove(num); verified.Remove(num); sentConfig.Remove(num); configConfirmed.Remove(num); sentRecipes.Remove(num); recipesConfirmed.Remove(num); } } } private void SendRecipes(long peer) { string payload = recipes.Payload; if (!sentRecipes.TryGetValue(peer, out var value) || !(value == payload)) { recipesConfirmed.Remove(peer); firstSeen[peer] = Time.realtimeSinceStartup; registered.InvokeRoutedRPC(peer, "KAGAdditional_Recipes_v3", new object[1] { payload }); sentRecipes[peer] = payload; } } private void ReceiveRecipes(long sender, string text) { if (!PathServerMessage(sender)) { return; } try { recipes.Accept(text); recipeAck = null; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Server recipes rejected: " + ex.Message)); } } private void ReceiveRecipesAck(long sender, string version) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && version == "1.6.8" && verified.Contains(sender)) { recipesConfirmed.Add(sender); } } private void ReloadServerConfig(bool force) { authority.ReloadServerFiles(force); } private void SendConfig(long peer) { if (configSnapshot == null) { configSnapshot = authority.Snapshot(); } string text = (IsServerAdmin(peer) ? "1\n" : "0\n") + configSnapshot; if (!sentConfig.TryGetValue(peer, out var value) || !(value == text)) { configConfirmed.Remove(peer); firstSeen[peer] = Time.realtimeSinceStartup; registered.InvokeRoutedRPC(peer, "KAGAdditional_Config_v2", new object[1] { text }); sentConfig[peer] = text; } } private void ReceiveConfig(long sender, string payload) { if (!PathServerMessage(sender) || payload == null || payload.Length < 10 || payload.Length > 1048580 || (!payload.StartsWith("0\n", StringComparison.Ordinal) && !payload.StartsWith("1\n", StringComparison.Ordinal))) { return; } try { authority.Apply(payload.Substring(2)); clientAdmin = payload[0] == '1'; registered.InvokeRoutedRPC(ServerPeerId, "KAGAdditional_ConfigAck_v2", new object[1] { "1.6.8" }); LogoPositionPostfix(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Server configuration applied and locked. Server admin: " + clientAdmin)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Server configuration rejected: " + ex.Message)); } } private void ReceiveConfigAck(long sender, string version) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && version == "1.6.8" && verified.Contains(sender)) { configConfirmed.Add(sender); } } private bool IsServerAdmin(long sender) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !verified.Contains(sender)) { return false; } ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null || peer.m_socket == null) { return false; } return (bool)AccessTools.Method(typeof(ZNet), "IsAdmin", new Type[1] { typeof(string) }, (Type[])null).Invoke(ZNet.instance, new object[1] { peer.m_socket.GetHostName() }); } private void RegisterCommands() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand("kag_setrace", "kag_setrace <SteamID64> <race> - server/admin only", (ConsoleEvent)delegate(ConsoleEventArgs args) { if (args.Args.Length != 3) { Print("Usage: kag_setrace <SteamID64> <race>"); } else { SubmitAdmin("race\t" + args.Args[1] + "\t" + args.Args[2]); } }, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); new ConsoleCommand("kag_reload", "Reload server race and addon configuration (server/admin only)", (ConsoleEvent)delegate { SubmitAdmin("reload"); }, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); new ConsoleCommand("kag_setconfig", "kag_setconfig <kag|races> <section>|<key>|<value> - server/admin only", (ConsoleEvent)delegate(ConsoleEventArgs args) { if (args.Args.Length < 3) { Print("Usage: kag_setconfig kag Interface|LogoOffsetDown|60"); } else { string[] array = string.Join(" ", args.Args.Skip(2)).Split(new char[1] { '|' }, 3); if (array.Length != 3) { Print("Expected section|key|value"); } else { SubmitAdmin("config\t" + args.Args[1] + "\t" + array[0] + "\t" + array[1] + "\t" + array[2]); } } }, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private void SubmitAdmin(string payload) { if ((Object)(object)ZNet.instance == (Object)null || registered == null) { Print("Not connected to a world."); return; } if (ZNet.instance.IsServer()) { Print(ExecuteAdmin(payload)); return; } registered.InvokeRoutedRPC(ServerPeerId, "KAGAdditional_Admin_v2", new object[1] { payload }); } private void ReceiveAdmin(long sender, string payload) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && registered != null && payload != null && payload.Length <= 8192) { string text = (IsServerAdmin(sender) ? ExecuteAdmin(payload) : "Denied: only a server admin may change races/settings."); registered.InvokeRoutedRPC(sender, "KAGAdditional_Reply_v2", new object[1] { text }); } } private string ExecuteAdmin(string payload) { try { if (payload == "reload") { ReloadAssignments(force: true); ReloadServerConfig(force: true); recipes.ServerTick(force: true); configSnapshot = authority.Snapshot(); sentConfig.Clear(); return "Server configuration reloaded."; } string[] array = payload.Split('\t'); if (array.Length == 5 && array[0] == "config") { authority.SetServerValue(array[1], array[2], array[3], array[4]); configSnapshot = authority.Snapshot(); sentConfig.Clear(); return "Server setting saved: " + array[1] + " / " + array[2] + " / " + array[3]; } if (array.Length != 3 || array[0] != "race") { return "Invalid admin command."; } string text = assignments.WithPlayer(array[1], array[2]); RaceAssignments raceAssignments = RaceAssignments.Parse(text); File.Copy(assignmentFile, assignmentFile + ".bak", overwrite: true); File.WriteAllText(assignmentFile, text); assignments = raceAssignments; fileStamp = File.GetLastWriteTimeUtc(assignmentFile); return "Assigned " + RaceAssignments.Canonical(array[2]) + " to " + array[1] + ". Saved on server."; } catch (Exception ex) { return "Admin command failed: " + ex.Message; } } private void ReceiveReply(long sender, string text) { if (PathServerMessage(sender) && text != null && text.Length < 2048) { Print(text); } } private void Print(string text) { ((BaseUnityPlugin)this).Logger.LogInfo((object)text); if ((Object)(object)Console.instance != (Object)null) { Console.instance.Print(text); } } private void ApplyRace(Player player, string race) { if (raceInstance == null) { raceInstance = AccessTools.Field(raceType, "Instance").GetValue(null); } if (raceInstance == null) { return; } applying = true; try { AccessTools.Method(raceType, "ResetRace", (Type[])null, (Type[])null).Invoke(raceInstance, null); AccessTools.Method(raceType, "Select" + race, (Type[])null, (Type[])null).Invoke(raceInstance, null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied server race " + race + " to local character.")); } finally { applying = false; } } private Sprite GetLogo() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)logo != (Object)null) { return logo; } using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("KingAndGodsAdditional.KAGlogo.png")) { if (stream == null) { throw new FileNotFoundException("Embedded KAG logo missing"); } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); logoTexture = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(logoTexture, memoryStream.ToArray(), true)) { throw new InvalidDataException("Cannot decode KAG logo"); } } ((Object)logoTexture).name = "KingsAndGodsLogo"; logo = Sprite.Create(logoTexture, new Rect(0f, 0f, (float)((Texture)logoTexture).width, (float)((Texture)logoTexture).height), new Vector2(0.5f, 0.5f), 100f); ((Object)logo).name = "KingsAndGodsLogo"; return logo; } private static bool LogoPrefix(ref Sprite __result) { __result = One.GetLogo(); return false; } private static void LogoPositionPostfix() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)One == (Object)null || (Object)(object)Object.FindFirstObjectByType<FejdStartup>() == (Object)null) { return; } Image[] array = Resources.FindObjectsOfTypeAll<Image>(); Scene scene; foreach (Image val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val.sprite == (Object)(object)One.logo) { scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { One.MoveLogo(((Graphic)val).rectTransform); } } } RawImage[] array2 = Resources.FindObjectsOfTypeAll<RawImage>(); foreach (RawImage val2 in array2) { if ((Object)(object)val2 != (Object)null && (Object)(object)One.logoTexture != (Object)null && (Object)(object)val2.texture == (Object)(object)One.logoTexture) { scene = ((Component)val2).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { One.MoveLogo(((Graphic)val2).rectTransform); } } } } private void MoveLogo(RectTransform rect) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //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_001e: Unknown result type (might be due to invalid IL or missing references) if (!logoPositions.TryGetValue(rect, out var value)) { value = rect.anchoredPosition; logoPositions.Add(rect, value); } rect.anchoredPosition = value + new Vector2(0f, 0f - logoOffset.Value); } private static void DiscordPostfix(FejdStartup __0) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown if (!(AccessTools.Field(typeof(FejdStartup), "m_menuButtons").GetValue(__0) is Button[] array)) { return; } Button[] array2 = array; foreach (Button val in array2) { if ((Object)(object)val == (Object)null || ((Object)val).name != "PT_Discord") { continue; } val.onClick = new ButtonClickedEvent(); ButtonClickedEvent onClick = val.onClick; object obj = <>c.<>9__85_0; if (obj == null) { UnityAction val2 = delegate { Application.OpenURL("https://discord.gg/PMPDpuPTND"); }; <>c.<>9__85_0 = val2; obj = (object)val2; } ((UnityEvent)onClick).AddListener((UnityAction)obj); } } private static void TreePostfix(object __instance) { object? value = AccessTools.Field(__instance.GetType(), "root").GetValue(__instance); GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val == (Object)null) { return; } string[] array = new string[2] { "Settings", "BuildsManager" }; foreach (string text in array) { Transform val2 = val.transform.Find(text); if ((Object)(object)val2 != (Object)null) { ((Component)val2).gameObject.SetActive(false); } } } private void OnDestroy() { authority.Restore(); if (recipes != null) { recipes.Reset(); } if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)logo != (Object)null) { Object.Destroy((Object)(object)logo); } if ((Object)(object)logoTexture != (Object)null) { Object.Destroy((Object)(object)logoTexture); } if ((Object)(object)One == (Object)(object)this) { One = null; } } } public sealed class RaceAssignments { public static readonly string[] Names = new string[12] { "human", "fenrir", "skadi", "skeleton", "aswid", "furling", "trol", "draugh", "dvergar", "trenta", "sverm", "alfar" }; private readonly Dictionary<string, string> players = new Dictionary<string, string>(StringComparer.Ordinal); public int Count => players.Count; public static string Canonical(string race) { if (race == null) { return null; } race = race.Trim().ToLowerInvariant(); if (race == "dvergr" || race == "dverger") { race = "dvergar"; } if (race == "troll") { race = "trol"; } if (race == "draugr") { race = "draugh"; } string[] names = Names; foreach (string text in names) { if (race == text) { return char.ToUpperInvariant(text[0]) + text.Substring(1); } } return null; } public string ForPlayer(string steamId) { if (steamId == null || !players.TryGetValue(steamId, out var value)) { return "Human"; } return value; } public string WithPlayer(string steamId, string race) { string text = Canonical(race); if (!IsSteamId(steamId) || text == null) { throw new FormatException("Expected SteamID64 and a known race"); } Dictionary<string, string> dictionary = new Dictionary<string, string>(players, StringComparer.Ordinal); dictionary[steamId] = text; StringBuilder stringBuilder = new StringBuilder("# KingAndGodsAdditional - server-owned assignments\n"); string[] names = Names; foreach (string text2 in names) { stringBuilder.AppendLine().AppendLine(text2 + ":"); foreach (KeyValuePair<string, string> item in dictionary) { if (item.Value == Canonical(text2)) { stringBuilder.AppendLine(" - " + item.Key); } } } return stringBuilder.ToString(); } public static bool IsSteamId(string value) { if (value != null && Regex.IsMatch(value, "^\\d{17}$") && ulong.TryParse(value, out var result)) { return result != 0; } return false; } public static string FromSocketName(string value) { if (value == null) { return null; } if (value.StartsWith("Steam_", StringComparison.OrdinalIgnoreCase)) { value = value.Substring(6); } if (!IsSteamId(value)) { return null; } return value; } public static bool TrustedServer(bool runningServer, long sender, long serverPeer) { if (!runningServer && serverPeer != 0L) { return sender == serverPeer; } return false; } public static RaceAssignments Parse(string text) { RaceAssignments raceAssignments = new RaceAssignments(); string text2 = null; HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); int num = 0; string[] array = text.Replace("\r", "").Split('\n'); foreach (string obj in array) { num++; string text3 = obj.Split('#')[0].Trim(); if (text3.Length == 0) { continue; } if (text3.EndsWith(":")) { text2 = Canonical(text3.Substring(0, text3.Length - 1)); if (text2 == null) { throw new FormatException("Unknown race on line " + num); } if (!hashSet.Add(text2)) { throw new FormatException("Duplicate race section on line " + num); } continue; } if (text2 == null) { throw new FormatException("SteamID outside a race section on line " + num); } if (text3.StartsWith("-")) { text3 = text3.Substring(1).Trim(); } text3 = text3.Trim('"', '\''); if (!IsSteamId(text3)) { throw new FormatException("Expected a 17-digit SteamID64 on line " + num); } if (raceAssignments.players.ContainsKey(text3)) { throw new FormatException("SteamID appears more than once: " + text3); } raceAssignments.players.Add(text3, text2); } return raceAssignments; } public static string Template() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# KingAndGodsAdditional - server-owned race assignments"); stringBuilder.AppendLine("# Edit ONLY on the server (or on the host for a hosted game)."); stringBuilder.AppendLine("# Unlisted players become Human. One SteamID64 in exactly one section."); stringBuilder.AppendLine("# Use real 17-digit SteamID64 values, NOT character IDs, names or Steam friend codes."); stringBuilder.AppendLine("# Reloads automatically. Invalid edits keep the last valid configuration."); stringBuilder.AppendLine("# Example: add a line such as ' - 76561198000000000' under skadi:"); string[] names = Names; foreach (string text in names) { stringBuilder.AppendLine(); stringBuilder.AppendLine(text + ":"); } return stringBuilder.ToString(); } } public sealed class RecipeAuthority { private sealed class Original { public Requirement[] Resources; public bool OneIngredient; } private readonly string file; private readonly Action<string> log; private DateTime stamp = DateTime.MinValue; private ObjectDB database; private List<RecipeRule> active = new List<RecipeRule>(); private List<RecipeRule> pending; private readonly Dictionary<Recipe, Original> originals = new Dictionary<Recipe, Original>(); private readonly Dictionary<Recipe, Requirement[]> imposed = new Dictionary<Recipe, Requirement[]>(); private readonly List<Recipe> created = new List<Recipe>(); private readonly Dictionary<Piece, Requirement[]> originalPieces = new Dictionary<Piece, Requirement[]>(); private readonly Dictionary<Piece, Requirement[]> imposedPieces = new Dictionary<Piece, Requirement[]>(); private string lastError; private int itemCount = -1; private int recipeCount = -1; public string Payload { get; private set; } = "recipes:\n"; public bool Received { get; private set; } public RecipeAuthority(string path, Action<string> logger) { file = path; log = logger; if (!File.Exists(file)) { File.WriteAllText(file, RecipeRules.Template()); } } public void ServerTick(bool force = false) { DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(file); if (force || lastWriteTimeUtc != stamp) { stamp = lastWriteTimeUtc; try { pending = RecipeRules.Parse(File.ReadAllText(file)); lastError = null; } catch (Exception ex) { Report("Invalid recipes YAML; keeping previous recipes: " + ex.Message); } } Tick(); } public void Accept(string text) { pending = RecipeRules.Parse(text); Received = false; Tick(); } public void Tick() { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || instance.m_items.Count == 0) { return; } if ((Object)(object)database != (Object)(object)instance) { RestoreEdits(); database = instance; if (pending == null) { pending = active; } } bool flag = itemCount != instance.m_items.Count || recipeCount != instance.m_recipes.Count; if (pending == null && flag) { pending = active; } if (pending != null) { try { Validate(instance, pending); List<RecipeRule> list = pending; RestoreEdits(); database = instance; foreach (RecipeRule item in list) { ApplyRule(instance, item); } active = list; pending = null; Payload = RecipeRules.Serialize(active); Received = true; lastError = null; log("Applied recipe overrides: " + active.Count + " (item recipes: " + imposed.Count + ", building pieces: " + imposedPieces.Count + ")"); } catch (Exception ex) { Report("Recipe overrides pending; previous valid recipes retained: " + ex.Message); } } foreach (KeyValuePair<Recipe, Requirement[]> item2 in imposed) { if ((Object)(object)item2.Key != (Object)null) { item2.Key.m_resources = item2.Value; item2.Key.m_requireOnlyOneIngredient = false; } } foreach (KeyValuePair<Piece, Requirement[]> imposedPiece in imposedPieces) { if ((Object)(object)imposedPiece.Key != (Object)null) { imposedPiece.Key.m_resources = imposedPiece.Value; } } itemCount = instance.m_items.Count; recipeCount = instance.m_recipes.Count; } private static void Validate(ObjectDB db, List<RecipeRule> rules) { foreach (RecipeRule rule in rules) { GameObject itemPrefab = db.GetItemPrefab(rule.Prefab); if ((!((Object)(object)itemPrefab != (Object)null) || !((Object)(object)itemPrefab.GetComponent<ItemDrop>() != (Object)null)) && (Object)(object)FindPiece(db, rule.Prefab) == (Object)null) { throw new InvalidOperationException("Unknown item or building Piece prefab: " + rule.Prefab); } foreach (RecipeIngredient ingredient in rule.Ingredients) { GetItem(db, ingredient.Prefab); } } } private static Piece FindPiece(ObjectDB db, string name) { if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab(name); if ((Object)(object)prefab != (Object)null) { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { return component; } } } foreach (GameObject item in db.m_items) { ItemDrop val = (((Object)(object)item == (Object)null) ? null : item.GetComponent<ItemDrop>()); PieceTable val2 = (((Object)(object)val == (Object)null) ? null : val.m_itemData.m_shared.m_buildPieces); if ((Object)(object)val2 == (Object)null) { continue; } foreach (GameObject piece in val2.m_pieces) { if ((Object)(object)piece != (Object)null && ((Object)piece).name == name) { Piece component2 = piece.GetComponent<Piece>(); if ((Object)(object)component2 != (Object)null) { return component2; } } } } return null; } private static ItemDrop GetItem(ObjectDB db, string name) { GameObject itemPrefab = db.GetItemPrefab(name); ItemDrop obj = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>()); if ((Object)(object)obj == (Object)null) { throw new InvalidOperationException("Unknown ItemDrop prefab: " + name); } return obj; } private void ApplyRule(ObjectDB db, RecipeRule rule) { GameObject itemPrefab = db.GetItemPrefab(rule.Prefab); if ((Object)(object)itemPrefab == (Object)null || (Object)(object)itemPrefab.GetComponent<ItemDrop>() == (Object)null) { Piece val = FindPiece(db, rule.Prefab); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("Building prefab unavailable: " + rule.Prefab); } Requirement[] array = (Requirement[])(((object)val.m_resources) ?? ((object)new Requirement[0])); originalPieces[val] = array; val.m_resources = BuildResources(db, rule, array); imposedPieces[val] = val.m_resources; return; } ItemDrop item = GetItem(db, rule.Prefab); List<Recipe> list = db.m_recipes.Where((Recipe r) => (Object)(object)r != (Object)null && (Object)(object)r.m_item != (Object)null && ((Object)((Component)r.m_item).gameObject).name == rule.Prefab).ToList(); if (list.Count == 0) { Recipe val2 = ScriptableObject.CreateInstance<Recipe>(); ((Object)val2).name = "KAGRecipe_" + rule.Prefab; val2.m_item = item; val2.m_amount = 1; val2.m_enabled = true; val2.m_minStationLevel = 1; val2.m_craftingStation = null; db.m_recipes.Add(val2); created.Add(val2); list.Add(val2); } foreach (Recipe item2 in list) { Requirement[] array2 = (Requirement[])(((object)item2.m_resources) ?? ((object)new Requirement[0])); originals[item2] = new Original { Resources = array2, OneIngredient = item2.m_requireOnlyOneIngredient }; item2.m_resources = BuildResources(db, rule, array2); item2.m_requireOnlyOneIngredient = false; imposed[item2] = item2.m_resources; } } private static Requirement[] BuildResources(ObjectDB db, RecipeRule rule, Requirement[] before) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown List<Requirement> list = new List<Requirement>(); IEnumerable<string> upgradeMaterials = from r in before where r != null && (Object)(object)r.m_resItem != (Object)null && r.m_amountPerLevel > 0 select ((Object)((Component)r.m_resItem).gameObject).name; foreach (RecipeIngredient ingredient in RecipeRules.BaseWithUpgradeOnly(rule, upgradeMaterials)) { Requirement val = ((IEnumerable<Requirement>)before).FirstOrDefault((Func<Requirement, bool>)((Requirement r) => r != null && (Object)(object)r.m_resItem != (Object)null && ((Object)((Component)r.m_resItem).gameObject).name == ingredient.Prefab)); Requirement val2 = new Requirement(); val2.m_resItem = GetItem(db, ingredient.Prefab); val2.m_amount = ingredient.Amount; val2.m_amountPerLevel = val?.m_amountPerLevel ?? 0; val2.m_recover = val?.m_recover ?? true; val2.m_upgraderResource = val?.m_upgraderResource ?? false; val2.m_extraAmountOnlyOneIngredient = val?.m_extraAmountOnlyOneIngredient ?? 0; list.Add(val2); } return list.ToArray(); } private void Report(string error) { if (!(lastError == error)) { lastError = error; log(error); } } private void RestoreEdits() { foreach (KeyValuePair<Recipe, Original> original in originals) { if ((Object)(object)original.Key != (Object)null) { original.Key.m_resources = original.Value.Resources; original.Key.m_requireOnlyOneIngredient = original.Value.OneIngredient; } } foreach (KeyValuePair<Piece, Requirement[]> originalPiece in originalPieces) { if ((Object)(object)originalPiece.Key != (Object)null) { originalPiece.Key.m_resources = originalPiece.Value; } } if ((Object)(object)database != (Object)null) { foreach (Recipe item in created) { database.m_recipes.Remove(item); if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)item); } } } originals.Clear(); imposed.Clear(); created.Clear(); originalPieces.Clear(); imposedPieces.Clear(); } public void Reset() { RestoreEdits(); database = null; active = new List<RecipeRule>(); pending = null; Payload = "recipes:\n"; Received = false; stamp = DateTime.MinValue; itemCount = -1; recipeCount = -1; lastError = null; } } public sealed class RecipeIngredient { public string Prefab; public int Amount; public RecipeIngredient(string prefab, int amount) { Prefab = prefab; Amount = amount; } } public sealed class RecipeRule { public string Prefab; public readonly List<RecipeIngredient> Ingredients = new List<RecipeIngredient>(); } public static class RecipeRules { public static List<RecipeRule> Parse(string text) { if (text == null || text.Length > 524288) { throw new FormatException("Recipe file exceeds 512 KiB"); } List<RecipeRule> list = new List<RecipeRule>(); HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); int num = 0; string[] array = text.Replace("\r", "").Split('\n'); foreach (string obj in array) { num++; string text2 = obj.Split('#')[0].Trim(); if (text2.Length == 0 || text2 == "recipes:" || text2 == "recipes: []") { continue; } if (text2.StartsWith("- ", StringComparison.Ordinal)) { text2 = text2.Substring(2).Trim(); } if (text2.StartsWith("\"", StringComparison.Ordinal) && text2.EndsWith("\"", StringComparison.Ordinal)) { text2 = text2.Substring(1, text2.Length - 2); } else if (text2.StartsWith("'", StringComparison.Ordinal) && text2.EndsWith("'", StringComparison.Ordinal)) { text2 = text2.Substring(1, text2.Length - 2); } string[] array2 = (from p in text2.Split(',') select p.Trim()).ToArray(); if (array2.Length < 3 || array2.Length % 2 != 1) { throw new FormatException("Line " + num + ": expected Prefab, Material, Amount, ..."); } if (!NameValid(array2[0]) || !hashSet.Add(array2[0])) { throw new FormatException("Line " + num + ": invalid or duplicate output prefab"); } RecipeRule recipeRule = new RecipeRule { Prefab = array2[0] }; HashSet<string> hashSet2 = new HashSet<string>(StringComparer.Ordinal); for (int num2 = 1; num2 < array2.Length; num2 += 2) { if (!NameValid(array2[num2]) || !hashSet2.Add(array2[num2])) { throw new FormatException("Line " + num + ": invalid or duplicate material"); } if (array2[num2] == array2[0]) { throw new FormatException("Line " + num + ": item cannot require itself"); } if (!int.TryParse(array2[num2 + 1], NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result < 1 || result > 1000000) { throw new FormatException("Line " + num + ": amount must be 1..1000000"); } recipeRule.Ingredients.Add(new RecipeIngredient(array2[num2], result)); } list.Add(recipeRule); } if (list.Count > 2000) { throw new FormatException("At most 2000 recipe overrides are supported"); } return list; } private static bool NameValid(string name) { if (!string.IsNullOrWhiteSpace(name) && name.Length <= 160) { return name.IndexOfAny(new char[11] { '\t', '\n', '\r', '"', '\'', '\\', ',', '#', ':', '[', ']' }) < 0; } return false; } public static string Serialize(IEnumerable<RecipeRule> rules) { StringBuilder stringBuilder = new StringBuilder("recipes:\n"); foreach (RecipeRule rule in rules) { stringBuilder.Append(" - \"").Append(rule.Prefab); foreach (RecipeIngredient ingredient in rule.Ingredients) { stringBuilder.Append(", ").Append(ingredient.Prefab).Append(", ") .Append(ingredient.Amount.ToString(CultureInfo.InvariantCulture)); } stringBuilder.AppendLine("\""); } return stringBuilder.ToString(); } public static List<RecipeIngredient> BaseWithUpgradeOnly(RecipeRule rule, IEnumerable<string> upgradeMaterials) { List<RecipeIngredient> list = rule.Ingredients.Select((RecipeIngredient i) => new RecipeIngredient(i.Prefab, i.Amount)).ToList(); foreach (string prefab in upgradeMaterials.Distinct<string>(StringComparer.Ordinal)) { if (!list.Any((RecipeIngredient i) => i.Prefab == prefab)) { list.Add(new RecipeIngredient(prefab, 0)); } } return list; } public static string Template() { return "# KingAndGodsAdditional - crafting recipes (SERVER FILE)\n# Format: ItemPrefab, MaterialPrefab, Amount, MaterialPrefab, Amount, ...\n# Use internal prefab names, case-sensitive. One item per line.\n# Existing crafting station/output amount and upgrade costs are preserved.\n# A registered item without a recipe gets a new hand-crafting recipe, output 1.\n# Server changes reload automatically. Client edits are ignored online.\n# Uncomment the example below to enable it. Empty file = no changes.\nrecipes:\n # - \"Hammer, Tin, 20, Copper, 15, Stone, 10, Wood, 10, Resin, 4\"\n"; } } internal static class SkillsButton { private static MethodInfo ensure; private static MethodInfo open; private static MethodInfo skillMode; private static FieldInfo instance; internal static void Install(Harmony harmony) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown Type type = AccessTools.TypeByName("PassiveTree.UI.TreeWindow"); ensure = AccessTools.Method(type, "Ensure", (Type[])null, (Type[])null); open = AccessTools.Method(type, "Open", (Type[])null, (Type[])null); skillMode = AccessTools.Method(type, "SetCraftMode", (Type[])null, (Type[])null); instance = AccessTools.Field(type, "Instance"); if (ensure == null || open == null || skillMode == null || instance == null) { throw new MissingMemberException("PathOfValheiman skill tree API"); } harmony.Patch((MethodBase)AccessTools.Method(typeof(InventoryGui), "OnOpenSkills", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SkillsButton), "OpenTree", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static bool OpenTree() { if ((Object)(object)Player.m_localPlayer == (Object)null) { return false; } ensure.Invoke(null, null); object value = instance.GetValue(null); if (value == null) { return true; } open.Invoke(value, null); skillMode.Invoke(value, new object[1] { false }); return false; } } }