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 RestlessCook v0.1.9
RestlessCook.dll
Decompiled a day 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.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("RestlessCook")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.9.0")] [assembly: AssemblyInformationalVersion("0.1.9+ad4a593175051de8fe6db4b8cd706e4428a6234b")] [assembly: AssemblyProduct("RestlessCook")] [assembly: AssemblyTitle("RestlessCook")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.9.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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 RestlessCook { internal static class CookIcons { private static readonly Dictionary<string, Sprite> Cache = new Dictionary<string, Sprite>(); private static MethodInfo? _loadImage; private static bool _searched; public static Sprite? Sprite(string id) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) string text = id.Replace('_', '-'); if (Cache.TryGetValue(text, out Sprite value) && (Object)(object)value != (Object)null) { return value; } Texture2D val = Texture(text); if ((Object)(object)val == (Object)null) { return null; } value = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0); ((Object)value).name = text; Cache[text] = value; return value; } private static Texture2D? Texture(string key) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown Stream manifestResourceStream = typeof(CookIcons).Assembly.GetManifestResourceStream("RestlessCook.Assets." + key + ".png"); if (manifestResourceStream == null) { Plugin.Log.LogWarning((object)("cook icon missing " + key)); return null; } using (manifestResourceStream) { byte[] array = new byte[manifestResourceStream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = manifestResourceStream.Read(array, i, array.Length - i); if (num <= 0) { break; } } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); MethodInfo methodInfo = LoadImage(); if (methodInfo == null || !(bool)methodInfo.Invoke(null, new object[2] { val, array })) { Object.Destroy((Object)(object)val); Plugin.Log.LogWarning((object)("cook icon decode failed " + key)); return null; } ((Object)val).name = key; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; return val; } } private static MethodInfo? LoadImage() { if (_searched) { return _loadImage; } _searched = true; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("UnityEngine.ImageConversion"); if (!(type == null)) { _loadImage = type.GetMethod("LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }); if (_loadImage != null) { return _loadImage; } } } return null; } } internal static class CookMesh { private static readonly Dictionary<string, Mesh> Meshes = new Dictionary<string, Mesh>(); private static readonly Dictionary<string, Texture2D> Albedos = new Dictionary<string, Texture2D>(); private static string? _folder; private static MethodInfo? _loadImage; private static bool _searched; public static string Folder() { if (_folder != null) { return _folder; } string[] array = PluginRoots(); string[] array2 = array; foreach (string text in array2) { string dir = Path.Combine(text, "mesh"); if (HasRcm(dir)) { return Remember(dir); } if (HasRcm(text)) { return Remember(text); } } _folder = Path.Combine((array.Length != 0) ? array[0] : ".", "mesh"); Plugin.Log.LogWarning((object)("cook mesh folder missing, looking in " + _folder)); return _folder; } private static string[] PluginRoots() { List<string> list = new List<string>(); Plugin instance = Plugin.Instance; object obj; if (instance == null) { obj = null; } else { PluginInfo info = ((BaseUnityPlugin)instance).Info; obj = ((info != null) ? info.Location : null); } string text = (string)obj; if (!string.IsNullOrEmpty(text)) { AddRoot(list, Path.GetDirectoryName(text)); } string location = typeof(CookMesh).Assembly.Location; if (!string.IsNullOrEmpty(location)) { AddRoot(list, Path.GetDirectoryName(location)); } return list.ToArray(); } private static void AddRoot(List<string> roots, string? root) { if (string.IsNullOrEmpty(root)) { return; } foreach (string root2 in roots) { if (string.Equals(root2, root, StringComparison.OrdinalIgnoreCase)) { return; } } roots.Add(root); } private static string Remember(string dir) { _folder = dir; Plugin.Log.LogInfo((object)("cook mesh folder " + dir)); return dir; } private static bool HasRcm(string dir) { if (Directory.Exists(dir)) { return Directory.GetFiles(dir, "*.rcm").Length != 0; } return false; } public static Mesh? Mesh(string id) { string text = id.Replace('_', '-'); if (Meshes.TryGetValue(text, out Mesh value) && (Object)(object)value != (Object)null) { return value; } string path = Path.Combine(Folder(), text + ".rcm"); if (!File.Exists(path)) { Plugin.Log.LogWarning((object)("cook mesh missing " + text)); return null; } value = ReadRcm(File.ReadAllBytes(path), text); if ((Object)(object)value != (Object)null) { Meshes[text] = value; } return value; } public static Texture2D? Albedo(string id) { string text = id.Replace('_', '-'); if (Albedos.TryGetValue(text, out Texture2D value) && (Object)(object)value != (Object)null) { return value; } string path = Path.Combine(Folder(), text + ".png"); if (!File.Exists(path)) { Plugin.Log.LogWarning((object)("cook albedo missing " + text)); return null; } value = DecodePng(File.ReadAllBytes(path), text); if ((Object)(object)value != (Object)null) { Albedos[text] = value; } return value; } private static Mesh? ReadRcm(byte[] data, string name) { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: 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_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Expected O, but got Unknown if (data.Length < 12 || data[0] != 82 || data[1] != 67 || data[2] != 77 || (data[3] != 49 && data[3] != 50)) { Plugin.Log.LogWarning((object)("cook mesh bad header " + name)); return null; } bool flag = data[3] == 49; int num = 4; int num2 = BitConverter.ToInt32(data, num); num += 4; int num3 = BitConverter.ToInt32(data, num); num += 4; if (num2 <= 0 || num3 <= 0 || num + num2 * 32 + num3 * 4 > data.Length) { Plugin.Log.LogWarning((object)("cook mesh truncated " + name)); return null; } Vector3[] array = (Vector3[])(object)new Vector3[num2]; Vector3[] array2 = (Vector3[])(object)new Vector3[num2]; Vector2[] array3 = (Vector2[])(object)new Vector2[num2]; for (int i = 0; i < num2; i++) { array[i] = new Vector3(BitConverter.ToSingle(data, num), BitConverter.ToSingle(data, num + 4), BitConverter.ToSingle(data, num + 8)); array2[i] = new Vector3(BitConverter.ToSingle(data, num + 12), BitConverter.ToSingle(data, num + 16), BitConverter.ToSingle(data, num + 20)); float num4 = BitConverter.ToSingle(data, num + 28); array3[i] = new Vector2(BitConverter.ToSingle(data, num + 24), flag ? (1f - num4) : num4); num += 32; } int[] array4 = new int[num3]; for (int j = 0; j < num3; j++) { array4[j] = BitConverter.ToInt32(data, num); num += 4; } Mesh val = new Mesh { name = name, indexFormat = (IndexFormat)(num2 > 65000) }; val.SetVertices(array); val.SetNormals(array2); val.SetUVs(0, array3); val.SetTriangles(array4, 0); val.RecalculateBounds(); return val; } private static Texture2D? DecodePng(byte[] bytes, string name) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true); MethodInfo methodInfo = LoadImage(); if (methodInfo == null || !(bool)methodInfo.Invoke(null, new object[2] { val, bytes })) { Object.Destroy((Object)(object)val); Plugin.Log.LogWarning((object)("cook albedo decode failed " + name)); return null; } ((Object)val).name = name; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).anisoLevel = 4; val.Apply(true, false); return val; } private static MethodInfo? LoadImage() { if (_searched) { return _loadImage; } _searched = true; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("UnityEngine.ImageConversion"); if (!(type == null)) { _loadImage = type.GetMethod("LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }); if (_loadImage != null) { return _loadImage; } } } return null; } } public sealed class CookUse { public string Item { get; set; } = ""; public int Amount { get; set; } } public sealed class CookRow { public string Id { get; set; } = ""; public string Name { get; set; } = ""; public string Kind { get; set; } = ""; public string Source { get; set; } = ""; public string Operation { get; set; } = ""; public string Tier { get; set; } = ""; public string Prefab { get; set; } = ""; public string RecipeId { get; set; } = ""; public string CloneFrom { get; set; } = ""; public int Food { get; set; } public int FoodStamina { get; set; } public int FoodEitr { get; set; } public float FoodRegen { get; set; } public int FoodMinutes { get; set; } public List<string> Feeds { get; } = new List<string>(); public List<CookUse> Uses { get; } = new List<CookUse>(); public int OutputAmount { get; set; } = 1; public string Station { get; set; } = ""; public int StationLevel { get; set; } = 1; public bool IsAdd => Operation == "add"; public bool IsRewrite => Operation == "rewrite"; public bool IsReference => Operation == "reference"; public bool IsMeal => Kind == "meal"; public bool IsFeast => Kind == "feast"; public bool IsSideboard => Kind == "sideboard"; public bool IsStation => Kind == "station"; public bool IsTool => Kind == "tool"; } public sealed class CookBook { public List<CookRow> Items { get; } = new List<CookRow>(); public List<CookRow> Kit { get; } = new List<CookRow>(); } internal static class CookVisual { private const string ChildName = "RestlessCookMesh"; private const float FeastMeshScale = 3f; private static readonly Vector3 ModelScale = Vector3.one * 2.5f; public static void Apply(CustomItem item, CookRow row) { if ((Object)(object)((item != null) ? item.ItemPrefab : null) != (Object)null) { Apply(item.ItemPrefab, row); } } public static void Apply(GameObject prefab, CookRow row) { if (!((Object)(object)prefab == (Object)null)) { Mesh val = CookMesh.Mesh(row.Id); Texture2D albedo = CookMesh.Albedo(row.Id); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("RestlessCook: no custom model for '" + row.Id + "', using vanilla appearance.")); return; } GameObject val2 = FindOrCreate(prefab); (val2.GetComponent<MeshFilter>() ?? val2.AddComponent<MeshFilter>()).sharedMesh = val; MeshRenderer obj = val2.GetComponent<MeshRenderer>() ?? val2.AddComponent<MeshRenderer>(); ((Renderer)obj).enabled = true; Paint((Renderer)(object)obj, albedo, prefab); KeepPlate(prefab); } } public static void KeepPlate(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return; } Transform obj = prefab.transform.Find("RestlessCookMesh"); Renderer val = ((obj != null) ? ((Component)obj).GetComponent<Renderer>() : null); if ((Object)(object)val == (Object)null) { return; } val.enabled = true; ((Component)val).gameObject.SetActive(true); Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val) && (val2 is MeshRenderer || val2 is SkinnedMeshRenderer)) { val2.enabled = false; } } EnsureHit(prefab); } public static void EnsureHit(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return; } Transform val = prefab.transform.Find("RestlessCookMesh"); if ((Object)(object)val == (Object)null) { return; } if ((Object)(object)prefab.GetComponent<Feast>() == (Object)null) { Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true); foreach (Collider obj in componentsInChildren) { MeshCollider val2 = (MeshCollider)(object)((obj is MeshCollider) ? obj : null); if (val2 != null) { Object.DestroyImmediate((Object)(object)val2); } } if ((Object)(object)prefab.GetComponentInChildren<Collider>(true) == (Object)null) { SitOnGround(val); } } else { DressFeast(prefab, val); } } private static void DressFeast(GameObject prefab, Transform keep) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) keep.localScale = Vector3.one * 3f; keep.localPosition = new Vector3(0f, 0.02f, 0f); Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).transform == (Object)(object)keep) && !((Component)val).transform.IsChildOf(keep)) { val.enabled = false; } } Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { component.m_clipGround = true; component.m_noInWater = true; component.m_cultivatedGroundOnly = false; component.m_groundOnly = false; } MeshFilter component2 = ((Component)keep).GetComponent<MeshFilter>(); if (!((Object)(object)((component2 != null) ? component2.sharedMesh : null) == (Object)null)) { MeshCollider obj = ((Component)keep).GetComponent<MeshCollider>() ?? ((Component)keep).gameObject.AddComponent<MeshCollider>(); obj.sharedMesh = component2.sharedMesh; obj.convex = true; ((Collider)obj).enabled = true; } } private static void SitOnGround(Transform keep) { //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_0040: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) MeshFilter component = ((Component)keep).GetComponent<MeshFilter>(); if (!((Object)(object)((component != null) ? component.sharedMesh : null) == (Object)null)) { BoxCollider obj = ((Component)keep).GetComponent<BoxCollider>() ?? ((Component)keep).gameObject.AddComponent<BoxCollider>(); Bounds bounds = component.sharedMesh.bounds; obj.center = ((Bounds)(ref bounds)).center; obj.size = Vector3.Max(((Bounds)(ref bounds)).size, new Vector3(0.08f, 0.04f, 0.08f)); ((Collider)obj).enabled = true; } } private static GameObject FindOrCreate(GameObject prefab) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00c5: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) Transform val = prefab.transform.Find("RestlessCookMesh"); if ((Object)(object)val != (Object)null) { val.SetParent(prefab.transform, false); val.localPosition = Vector3.zero; val.localRotation = Quaternion.identity; val.localScale = ModelScale; ((Component)val).gameObject.layer = prefab.layer; ((Component)val).gameObject.SetActive(true); return ((Component)val).gameObject; } GameObject val2 = new GameObject("RestlessCookMesh") { layer = prefab.layer }; val2.transform.SetParent(prefab.transform, false); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = ModelScale; return val2; } private static void Paint(Renderer renderer, Texture2D? albedo, GameObject prefab) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) Material val = CopyLit(prefab); if ((Object)(object)val == (Object)null) { return; } val.color = Color.white; SetColor(val, "_Color", Color.white); SetColor(val, "_BaseColor", Color.white); SetColor(val, "_Tint", Color.white); SetFloat(val, "_Metallic", 0f); SetFloat(val, "_Glossiness", 0.12f); SetFloat(val, "_Smoothness", 0.12f); SetFloat(val, "_GlossMapScale", 0.12f); MuteGlow(val); if ((Object)(object)albedo != (Object)null) { if (val.HasProperty("_MainTex")) { val.SetTexture("_MainTex", (Texture)(object)albedo); } if (val.HasProperty("_BaseMap")) { val.SetTexture("_BaseMap", (Texture)(object)albedo); } if (val.HasProperty("_Diffuse")) { val.SetTexture("_Diffuse", (Texture)(object)albedo); } } renderer.sharedMaterial = val; } private static Material? CopyLit(GameObject prefab) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown Material val = QuietMat(prefab) ?? QuietFeast(); if ((Object)(object)val != (Object)null) { return new Material(val); } Shader val2 = Shader.Find("Standard") ?? Shader.Find("Diffuse") ?? Shader.Find("Legacy Shaders/Diffuse"); if (!((Object)(object)val2 != (Object)null)) { return null; } return new Material(val2); } private static Material? QuietFeast() { string[] array = new string[2] { "FeastMeadows", "FeastBlackforest" }; foreach (string text in array) { PrefabManager instance = PrefabManager.Instance; Material val = QuietMat((instance != null) ? instance.GetPrefab(text) : null); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static Material? QuietMat(GameObject? prefab) { if ((Object)(object)prefab == (Object)null) { return null; } Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !(((Object)((Component)val).transform).name == "RestlessCookMesh") && val is MeshRenderer && !Garnish(((Component)val).transform)) { Material sharedMaterial = val.sharedMaterial; if (!((Object)(object)((sharedMaterial != null) ? sharedMaterial.shader : null) == (Object)null) && !Glows(sharedMaterial)) { return sharedMaterial; } } } return null; } private static bool Garnish(Transform node) { Transform val = node; while ((Object)(object)val != (Object)null) { string name = ((Object)val).name; if (Has(name, "thistle") || Has(name, "spice") || Has(name, "eitr") || Has(name, "glow") || Has(name, "garnish") || Has(name, "magecap") || Has(name, "jotun") || Has(name, "wisp") || Has(name, "mist")) { return true; } val = val.parent; } return false; } private static bool Glows(Material mat) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) string text = ((Object)mat).name + " " + ((Object)mat.shader).name; if (Has(text, "thistle") || Has(text, "spice") || Has(text, "eitr") || Has(text, "glow")) { return true; } if (mat.IsKeywordEnabled("_EMISSION") || mat.IsKeywordEnabled("EMISSION")) { return true; } if (mat.HasProperty("_EmissionMap") && (Object)(object)mat.GetTexture("_EmissionMap") != (Object)null) { return true; } if (mat.HasProperty("_EmissionColorMap") && (Object)(object)mat.GetTexture("_EmissionColorMap") != (Object)null) { return true; } Color color; if (mat.HasProperty("_EmissionColor")) { color = mat.GetColor("_EmissionColor"); if (((Color)(ref color)).maxColorComponent > 0.02f) { return true; } } if (mat.HasProperty("_EmissiveColor")) { color = mat.GetColor("_EmissiveColor"); if (((Color)(ref color)).maxColorComponent > 0.02f) { return true; } } if (mat.HasProperty("_EnableEmission") && mat.GetFloat("_EnableEmission") > 0.5f) { return true; } return false; } private static void MuteGlow(Material mat) { //IL_0006: 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_0026: Unknown result type (might be due to invalid IL or missing references) SetColor(mat, "_EmissionColor", Color.black); SetColor(mat, "_EmissiveColor", Color.black); SetColor(mat, "_GlowColor", Color.black); SetFloat(mat, "_EnableEmission", 0f); SetFloat(mat, "_EmissionIntensity", 0f); if (mat.HasProperty("_EmissionMap")) { mat.SetTexture("_EmissionMap", (Texture)null); } if (mat.HasProperty("_EmissionColorMap")) { mat.SetTexture("_EmissionColorMap", (Texture)null); } mat.DisableKeyword("_EMISSION"); mat.DisableKeyword("EMISSION"); } private static bool Has(string text, string token) { return text.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0; } private static void SetColor(Material mat, string prop, Color color) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (mat.HasProperty(prop)) { mat.SetColor(prop, color); } } private static void SetFloat(Material mat, string prop, float value) { if (mat.HasProperty(prop)) { mat.SetFloat(prop, value); } } } public static class CookYaml { public static CookBook LoadEmbedded() { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("RestlessCook.cook.yaml") ?? throw new InvalidOperationException("Missing embedded cook.yaml"); using StreamReader streamReader = new StreamReader(stream); return Parse(streamReader.ReadToEnd()); } public static CookBook Parse(string text) { CookBook book = new CookBook(); CookRow cur = null; CookUse cookUse = null; string text2 = null; string section = null; string[] array = text.Split(new string[2] { "\r\n", "\n" }, StringSplitOptions.None); for (int i = 0; i < array.Length; i++) { string text3 = array[i].TrimEnd(Array.Empty<char>()); if (text3 == "kit:" || text3 == "items:") { Flush(); section = text3.TrimEnd(new char[1] { ':' }); cookUse = null; text2 = null; } else { if (section == null) { continue; } if (text3.StartsWith(" - id:", StringComparison.Ordinal)) { Flush(); cur = new CookRow { Id = Value(text3) }; cookUse = null; text2 = null; } else { if (cur == null) { continue; } if (text3.StartsWith(" feeds:", StringComparison.Ordinal)) { text2 = "feeds"; if (text3.Contains("[]")) { text2 = null; } } else if (text3.StartsWith(" uses:", StringComparison.Ordinal)) { text2 = "uses"; } else if (text2 == "feeds" && text3.StartsWith(" - ", StringComparison.Ordinal)) { cur.Feeds.Add(text3.Substring(text3.IndexOf('-') + 1).Trim()); } else if (text2 == "uses" && text3.StartsWith(" - item:", StringComparison.Ordinal)) { cookUse = new CookUse { Item = Value(text3) }; cur.Uses.Add(cookUse); } else if (text2 == "uses" && cookUse != null && text3.StartsWith(" amount:", StringComparison.Ordinal)) { cookUse.Amount = int.Parse(Value(text3)); } else if (text3.StartsWith(" ", StringComparison.Ordinal) && text3.Contains(":") && !text3.StartsWith(" ", StringComparison.Ordinal)) { text2 = null; int num = text3.IndexOf(':'); string text4 = text3.Substring(0, num).Trim(); string text5 = Unquote(text3.Substring(num + 1).Trim()); switch (text4) { case "name": cur.Name = text5; break; case "kind": cur.Kind = text5; break; case "source": cur.Source = text5; break; case "operation": cur.Operation = text5; break; case "tier": cur.Tier = text5; break; case "prefab": cur.Prefab = text5; break; case "recipe_id": cur.RecipeId = text5; break; case "clone_from": cur.CloneFrom = text5; break; case "food": cur.Food = int.Parse(text5); break; case "food_stamina": cur.FoodStamina = int.Parse(text5); break; case "food_eitr": cur.FoodEitr = int.Parse(text5); break; case "food_regen": cur.FoodRegen = float.Parse(text5, CultureInfo.InvariantCulture); break; case "food_minutes": cur.FoodMinutes = int.Parse(text5); break; case "output_amount": cur.OutputAmount = int.Parse(text5); break; case "station": cur.Station = text5; break; case "station_level": cur.StationLevel = int.Parse(text5); break; } } } } } Flush(); Validate(book.Items); ValidateKit(book.Kit); return book; void Flush() { if (cur != null) { if (section == "kit") { book.Kit.Add(cur); } else if (section == "items") { book.Items.Add(cur); } cur = null; } } } public static void Validate(IReadOnlyList<CookRow> items) { if (items.Count != 81) { throw new InvalidOperationException($"cook.yaml must have 81 rows, got {items.Count}"); } HashSet<string> hashSet = new HashSet<string>(items.Select((CookRow i) => i.Id), StringComparer.Ordinal); if (hashSet.Count != 81) { throw new InvalidOperationException("cook.yaml has duplicate ids"); } foreach (CookRow item in items) { if (item.Uses.Count == 0) { throw new InvalidOperationException(item.Id + ": empty uses[]"); } foreach (string feed in item.Feeds) { if (!hashSet.Contains(feed)) { throw new InvalidOperationException(item.Id + ": feeds unknown id " + feed); } } } Require(Count((CookRow i) => i.IsAdd) == 35, "35 add rows"); Require(Count((CookRow i) => i.IsRewrite) == 16, "16 rewrite rows"); Require(Count((CookRow i) => i.IsReference) == 30, "30 reference rows"); Require(Count((CookRow i) => i.IsAdd || i.IsRewrite) == 51, "51 recipe operations"); Require(Count((CookRow i) => i.IsMeal && i.Source == "custom" && i.IsAdd) == 17, "17 custom meals"); Require(Count((CookRow i) => i.IsFeast && i.Source == "custom" && i.IsAdd) == 16, "16 custom feasts"); Require(Count((CookRow i) => i.IsSideboard && i.IsAdd) == 2, "2 sideboards"); Require(Count((CookRow i) => i.IsMeal && i.IsRewrite) == 14, "14 cooked-first rewrites"); Require(Count((CookRow i) => i.IsFeast && i.IsRewrite) == 2, "2 feast reroutes"); Require(Count((CookRow i) => i.IsMeal && i.IsReference) == 24, "24 meal references"); Require(Count((CookRow i) => i.IsFeast && i.IsReference) == 6, "6 feast references"); foreach (CookRow item2 in items.Where((CookRow i) => i.IsAdd)) { if (string.IsNullOrEmpty(item2.CloneFrom)) { throw new InvalidOperationException(item2.Id + ": add requires clone_from"); } if (string.IsNullOrEmpty(item2.Prefab)) { throw new InvalidOperationException(item2.Id + ": add requires prefab"); } } foreach (CookRow item3 in items.Where((CookRow i) => i.IsAdd && (i.IsMeal || i.IsFeast))) { if (item3.Food == 0 && item3.FoodStamina == 0 && item3.FoodEitr == 0) { throw new InvalidOperationException(item3.Id + ": custom meal/feast needs food stats"); } if (item3.FoodMinutes <= 0) { throw new InvalidOperationException(item3.Id + ": custom meal/feast needs food_minutes"); } if (item3.FoodRegen <= 0f) { throw new InvalidOperationException(item3.Id + ": custom meal/feast needs food_regen"); } } foreach (CookRow item4 in items.Where((CookRow i) => i.IsSideboard)) { if (item4.Food != 0 || item4.FoodStamina != 0 || item4.FoodEitr != 0 || item4.FoodMinutes != 0) { throw new InvalidOperationException(item4.Id + ": sideboard is not edible"); } } foreach (CookRow item5 in items.Where((CookRow i) => i.IsRewrite)) { if (string.IsNullOrEmpty(item5.RecipeId)) { throw new InvalidOperationException(item5.Id + ": rewrite requires recipe_id"); } } Dictionary<string, CookRow> byId = items.ToDictionary<CookRow, string>((CookRow i) => i.Id, StringComparer.Ordinal); foreach (CookRow item6 in items.Where((CookRow i) => i.IsMeal)) { if (!ReachesFeast(item6, byId)) { throw new InvalidOperationException(item6.Id + ": meal has no path to a feast"); } } foreach (CookRow item7 in items.Where((CookRow i) => i.IsFeast && i.Source == "custom" && i.IsAdd && (i.Tier == "meadows" || i.Tier == "blackforest"))) { if (item7.Uses.Any((CookUse u) => u.Item == "SpiceForests")) { throw new InvalidOperationException(item7.Id + ": early custom feast cannot require Bog Witch spices"); } } int Count(Func<CookRow, bool> pred) { return items.Count(pred); } } private static void ValidateKit(IReadOnlyList<CookRow> kit) { if (kit.Count != 2) { throw new InvalidOperationException($"cook.yaml kit must have 2 rows, got {kit.Count}"); } CookRow cookRow = kit.FirstOrDefault((CookRow i) => i.Id == "food_preparation_table"); CookRow cookRow2 = kit.FirstOrDefault((CookRow i) => i.Id == "serving_tray"); if (cookRow == null || !cookRow.IsStation || !cookRow.IsRewrite || cookRow.Prefab != "piece_preptable" || cookRow.Uses.Count == 0) { throw new InvalidOperationException("kit: food_preparation_table must rewrite piece_preptable"); } if (cookRow2 == null || !cookRow2.IsTool || !cookRow2.IsAdd || cookRow2.Prefab != "Feaster" || cookRow2.Uses.Count == 0) { throw new InvalidOperationException("kit: serving_tray must add a Feaster recipe"); } } private static bool ReachesFeast(CookRow start, IReadOnlyDictionary<string, CookRow> byId) { HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); Stack<string> stack = new Stack<string>(); stack.Push(start.Id); while (stack.Count > 0) { string text = stack.Pop(); if (!hashSet.Add(text) || !byId.TryGetValue(text, out CookRow value)) { continue; } if (value.IsFeast && text != start.Id) { return true; } foreach (string feed in value.Feeds) { stack.Push(feed); } } return start.IsFeast; } private static void Require(bool ok, string label) { if (!ok) { throw new InvalidOperationException("cook.yaml failed check: " + label); } } private static string Value(string line) { int num = line.IndexOf(':'); return Unquote(line.Substring(num + 1).Trim()); } private static string Unquote(string val) { if (val.Length >= 2 && ((val[0] == '"' && val[val.Length - 1] == '"') || (val[0] == '\'' && val[val.Length - 1] == '\''))) { return val.Substring(1, val.Length - 2); } return val; } } [BepInPlugin("restless.cook", "RestlessCook", "0.1.9")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "restless.cook"; public const string PluginName = "RestlessCook"; public const string PluginVersion = "0.1.9"; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; CookBook cookBook = CookYaml.LoadEmbedded(); RecipeEngine.Load(cookBook); Log.LogInfo((object)string.Format("{0} {1} loaded ({2} cook.yaml rows, {3} kit).", "RestlessCook", "0.1.9", cookBook.Items.Count, cookBook.Kit.Count)); } } internal static class RecipeEngine { [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] public static class CopyOtherDbPatch { public static void Postfix(ObjectDB __instance) { Rewrite(__instance); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] public static class AwakePatch { public static void Postfix(ObjectDB __instance) { Rewrite(__instance); } } [HarmonyPatch(typeof(Feast), "UpdateVisual")] public static class FeastVisualPatch { public static void Postfix(Feast __instance) { if ((Object)(object)__instance != (Object)null) { ReadyFeast(__instance); CookVisual.KeepPlate(((Component)__instance).gameObject); } } } [HarmonyPatch(typeof(Feast), "Interact")] public static class FeastInteractPatch { public static void Prefix(Feast __instance) { ReadyFeast(__instance); } } [HarmonyPatch(typeof(Player), "AddKnownRecipe")] public static class AddKnownRecipePatch { public static bool Prefix(Recipe recipe) { if (Ours(recipe)) { return ReqsComplete(recipe); } return true; } } [HarmonyPatch(typeof(Player), "UpdateKnownRecipesList")] public static class KnownFeastPatch { public static void Postfix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } TeachOurs(__instance); foreach (CookRow item in _rows.Where((CookRow r) => r.IsAdd && r.IsFeast)) { GameObject prefab = PrefabManager.Instance.GetPrefab(item.Prefab); Piece val = ((prefab != null) ? prefab.GetComponent<Piece>() : null); if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.m_name) && !__instance.m_knownRecipes.Contains(val.m_name) && __instance.HaveRequirements(val, (RequirementMode)1)) { __instance.AddKnownPiece(val); } } } } [HarmonyPatch(typeof(Player), "IsRecipeKnown")] public static class IsRecipeKnownPatch { public static void Postfix(Player __instance, string name, ref bool __result) { if (!__result) { return; } ObjectDB instance = ObjectDB.instance; if (instance?.m_recipes != null) { Recipe val = FindRecipeByKnownName(instance, name); if (!((Object)(object)val == (Object)null) && Ours(val) && !ShouldShow(val)) { __result = false; } } } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")] public static class RecipeListPatch { public static void Prefix(object __0) { HideUnknown(__0); } } private static IReadOnlyList<CookRow> _rows = Array.Empty<CookRow>(); private static IReadOnlyList<CookRow> _kit = Array.Empty<CookRow>(); private static bool _added; private static Harmony? _harmony; public static void Load(CookBook book) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown _rows = book.Items; _kit = book.Kit; PrefabManager.OnVanillaPrefabsAvailable += AddCustom; ItemManager.OnItemsRegistered += RewriteRegistered; ItemManager.OnItemsRegistered += RewriteSoon; PieceManager.OnPiecesRegistered += WireFeasts; _harmony = new Harmony("restless.cook.recipes"); _harmony.PatchAll(typeof(RecipeEngine).Assembly); } private static string StationName(string station) { return station switch { "piece_preptable" => CraftingStations.FoodPreparationTable, "piece_cauldron" => CraftingStations.Cauldron, "piece_workbench" => CraftingStations.Workbench, _ => station, }; } internal static string CloneSource(CookRow row) { string cloneFrom = row.CloneFrom; if (row.IsFeast && cloneFrom.StartsWith("Feast", StringComparison.Ordinal) && !cloneFrom.EndsWith("_Material", StringComparison.Ordinal)) { return cloneFrom + "_Material"; } return cloneFrom; } private static void AddCustom() { PrefabManager.OnVanillaPrefabsAvailable -= AddCustom; if (_added) { return; } _added = true; RewritePrepTable(); GrantTrayRecipe(); foreach (CookRow item in _rows.Where((CookRow r) => r.IsAdd && r.IsMeal)) { RegisterItem(item); } foreach (CookRow item2 in _rows.Where((CookRow r) => r.IsAdd && r.IsSideboard)) { RegisterItem(item2); } foreach (CookRow item3 in _rows.Where((CookRow r) => r.IsAdd && r.IsFeast)) { RegisterFeast(item3); } int num = _rows.Count((CookRow r) => r.IsAdd || r.IsRewrite); Plugin.Log.LogInfo((object)$"RestlessCook registered {_rows.Count((CookRow r) => r.IsAdd)} custom items from cook.yaml ({num} recipe operations)."); } private static void RegisterItem(CookRow row) { //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) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown ItemConfig val = new ItemConfig { Name = row.Name, Description = Description(row), CraftingStation = StationName(row.Station), MinStationLevel = row.StationLevel, Amount = row.OutputAmount }; Sprite val2 = CookIcons.Sprite(row.Id); if ((Object)(object)val2 != (Object)null) { val.Icon = val2; } foreach (CookUse use in row.Uses) { val.AddRequirement(use.Item, use.Amount, 0); } string text = CloneSource(row); GameObject val3 = PrefabManager.Instance.CreateClonedPrefab(row.Prefab, text); CustomItem val4 = ((!((Object)(object)val3 != (Object)null)) ? new CustomItem(row.Prefab, text, val) : new CustomItem(val3, true, val)); ItemManager.Instance.AddItem(val4); CookVisual.Apply(((Object)(object)val3 != (Object)null) ? val3 : val4.ItemPrefab, row); if (row.IsSideboard) { StripFood(val4); } else if (row.IsMeal) { ApplyFood(row, val4); } } private static void RegisterFeast(CookRow row) { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown Sprite val = CookIcons.Sprite(row.Id); string text = row.Prefab + "_Material"; string text2 = (row.CloneFrom.EndsWith("_Material", StringComparison.Ordinal) ? row.CloneFrom : (row.CloneFrom + "_Material")); if ((Object)(object)PrefabManager.Instance.GetPrefab(text2) == (Object)null) { text2 = row.CloneFrom; } GameObject val2 = PrefabManager.Instance.CreateClonedPrefab(text, text2); if ((Object)(object)val2 != (Object)null) { SharedData val3 = val2.GetComponent<ItemDrop>()?.m_itemData?.m_shared; if (val3 != null) { val3.m_name = row.Name; val3.m_description = Description(row); if ((Object)(object)val != (Object)null) { val3.m_icons = (Sprite[])(object)new Sprite[1] { val }; } } ItemManager.Instance.AddItem(new CustomItem(val2, true)); CookVisual.Apply(val2, row); ApplyFood(row, val2.GetComponent<ItemDrop>()); GrantItemRecipe(row, text); } else { Plugin.Log.LogWarning((object)("cook feast missing material " + text2)); } string text3 = (row.CloneFrom.EndsWith("_Material", StringComparison.Ordinal) ? row.CloneFrom.Substring(0, row.CloneFrom.Length - "_Material".Length) : row.CloneFrom); GameObject val4 = PrefabManager.Instance.CreateClonedPrefab(row.Prefab, text3); if ((Object)(object)val4 == (Object)null) { Plugin.Log.LogWarning((object)("cook feast missing piece " + text3)); return; } PieceConfig val5 = new PieceConfig { Name = row.Name, Description = Description(row), PieceTable = PieceTables.ServingTray, CraftingStation = CraftingStations.None }; if ((Object)(object)val != (Object)null) { val5.Icon = val; } val5.AddRequirement(text, 1, true); PieceManager.Instance.AddPiece(new CustomPiece(val4, true, val5)); CookVisual.Apply(val4, row); Plugin.Log.LogInfo((object)("cook feast piece " + row.Prefab)); } private static void GrantTrayRecipe() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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_00dd: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown CookRow cookRow = _kit.FirstOrDefault((CookRow r) => r.IsTool && r.IsAdd); if (cookRow == null) { return; } if ((Object)(object)PrefabManager.Instance.GetPrefab(cookRow.Prefab) == (Object)null) { Plugin.Log.LogWarning((object)("cook kit missing item " + cookRow.Prefab)); return; } RecipeConfig val = new RecipeConfig { Name = "Recipe_Restless_" + cookRow.Id, Item = cookRow.Prefab, Amount = cookRow.OutputAmount, CraftingStation = StationName(string.IsNullOrEmpty(cookRow.Station) ? "piece_workbench" : cookRow.Station), RepairStation = CraftingStations.Workbench, MinStationLevel = ((cookRow.StationLevel < 1) ? 1 : cookRow.StationLevel) }; foreach (CookUse use in cookRow.Uses) { val.AddRequirement(use.Item, use.Amount, 0); } ItemManager.Instance.AddRecipe(new CustomRecipe(val)); Plugin.Log.LogInfo((object)("cook kit recipe " + cookRow.Prefab)); } private static void GrantItemRecipe(CookRow row, string itemName) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown if ((Object)(object)PrefabManager.Instance.GetPrefab(itemName) == (Object)null) { Plugin.Log.LogWarning((object)("cook feast leftover missing " + itemName)); return; } RecipeConfig val = new RecipeConfig { Name = "Recipe_Restless_" + row.Id, Item = itemName, Amount = row.OutputAmount, CraftingStation = StationName(string.IsNullOrEmpty(row.Station) ? "piece_preptable" : row.Station), MinStationLevel = ((row.StationLevel < 1) ? 1 : row.StationLevel) }; foreach (CookUse use in row.Uses) { val.AddRequirement(use.Item, use.Amount, 0); } ItemManager.Instance.AddRecipe(new CustomRecipe(val)); Plugin.Log.LogInfo((object)("cook feast leftover recipe " + itemName)); } private static void RewritePrepTable() { //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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown CookRow cookRow = _kit.FirstOrDefault((CookRow r) => r.IsStation && r.IsRewrite); if (cookRow == null) { return; } GameObject prefab = PrefabManager.Instance.GetPrefab(cookRow.Prefab); Piece val = ((prefab != null) ? prefab.GetComponent<Piece>() : null); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("cook kit missing " + cookRow.Prefab)); return; } List<Requirement> list = new List<Requirement>(); foreach (CookUse use in cookRow.Uses) { GameObject prefab2 = PrefabManager.Instance.GetPrefab(use.Item); ItemDrop val2 = ((prefab2 != null) ? prefab2.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)("cook kit missing ingredient " + use.Item)); continue; } list.Add(new Requirement { m_resItem = val2, m_amount = use.Amount, m_amountPerLevel = 0, m_recover = true }); } if (list.Count != 0) { val.m_resources = list.ToArray(); Plugin.Log.LogInfo((object)("cook kit piece " + cookRow.Prefab)); } } private static string Description(CookRow row) { if (row.IsSideboard) { return "A prepared board for feast assembly. Not edible on its own."; } if (row.IsFeast) { return "A Restless feast assembled from prepared meals."; } return "A Restless prepared meal."; } private static void ApplyFood(CookRow row, CustomItem item) { ApplyFood(row, item.ItemDrop); } private static void ApplyFood(CookRow row, ItemDrop? drop) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) SharedData val = drop?.m_itemData?.m_shared; if (val != null) { val.m_food = row.Food; val.m_foodStamina = row.FoodStamina; val.m_foodEitr = row.FoodEitr; val.m_foodRegen = row.FoodRegen; val.m_foodBurnTime = (float)row.FoodMinutes * 60f; val.m_itemType = (ItemType)2; val.m_consumeStatusEffect = null; } } private static void StripFood(CustomItem item) { StripFood(item.ItemDrop); } private static void StripFood(ItemDrop? drop) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) SharedData val = drop?.m_itemData?.m_shared; if (val != null) { val.m_itemType = (ItemType)1; val.m_food = 0f; val.m_foodStamina = 0f; val.m_foodEitr = 0f; val.m_foodRegen = 0f; val.m_foodBurnTime = 0f; val.m_consumeStatusEffect = null; if (val.m_maxStackSize < 20) { val.m_maxStackSize = 20; } } } private static void RewriteRegistered() { DressRegistered(); if ((Object)(object)ObjectDB.instance != (Object)null) { Rewrite(ObjectDB.instance); } } private static void RewriteSoon() { if ((Object)(object)Plugin.Instance != (Object)null) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(RewriteAfterRecipes()); } } private static IEnumerator RewriteAfterRecipes() { yield return null; yield return null; if ((Object)(object)ObjectDB.instance != (Object)null) { Rewrite(ObjectDB.instance); } } private static void DressRegistered() { int num = 0; foreach (CookRow item in _rows.Where((CookRow r) => r.IsAdd)) { foreach (string item2 in PrefabNames(item)) { object obj = PrefabManager.Instance.GetPrefab(item2); if (obj == null) { ObjectDB instance = ObjectDB.instance; obj = ((instance != null) ? instance.GetItemPrefab(item2) : null); } GameObject val = (GameObject)obj; if (!((Object)(object)val == (Object)null)) { CookVisual.Apply(val, item); ItemDrop component = val.GetComponent<ItemDrop>(); if (item.IsSideboard) { StripFood(component); } else if (item.IsMeal || item.IsFeast) { ApplyFood(item, component); } num++; } } } Plugin.Log.LogInfo((object)$"cook dressed {num} prefabs"); } private static IEnumerable<string> PrefabNames(CookRow row) { yield return row.Prefab; if (row.IsFeast) { yield return row.Prefab + "_Material"; } } private static void WireFeasts() { foreach (CookRow item in _rows.Where((CookRow r) => r.IsAdd && r.IsFeast)) { GameObject prefab = PrefabManager.Instance.GetPrefab(item.Prefab); Feast val = ((prefab != null) ? prefab.GetComponent<Feast>() : null); object obj = PrefabManager.Instance.GetPrefab(item.Prefab + "_Material"); if (obj == null) { ObjectDB instance = ObjectDB.instance; obj = ((instance != null) ? instance.GetItemPrefab(item.Prefab + "_Material") : null); } ItemDrop val2 = ((obj != null) ? ((GameObject)obj).GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)("cook feast leftover missing " + item.Prefab)); continue; } val.m_foodItem = val2; ApplyFood(item, val2); if (val.m_eatStacks < 1) { val.m_eatStacks = 10; } CookVisual.Apply(((Component)val).gameObject, item); BindFeastPiece(item, ((Component)val).GetComponent<Piece>(), ObjectDB.instance); } if ((Object)(object)ObjectDB.instance != (Object)null) { Rewrite(ObjectDB.instance); } } private static void BindFeastPiece(CookRow row, Piece? piece, ObjectDB? db) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown if (!((Object)(object)piece == (Object)null)) { piece.m_craftingStation = null; piece.m_enabled = true; EnsureOnTray(((Component)piece).gameObject); DetachFromOtherTables(((Component)piece).gameObject); string text = row.Prefab + "_Material"; GameObject val = (((Object)(object)db != (Object)null) ? db.GetItemPrefab(text) : null); if ((Object)(object)val == (Object)null) { val = PrefabManager.Instance.GetPrefab(text); } ItemDrop val2 = ((val != null) ? val.GetComponent<ItemDrop>() : null); if (val2?.m_itemData?.m_shared == null) { Plugin.Log.LogWarning((object)("cook feast " + row.Id + " missing leftover " + text)); return; } piece.m_resources = (Requirement[])(object)new Requirement[1] { new Requirement { m_resItem = val2, m_amount = 1, m_amountPerLevel = 0, m_recover = true } }; } } private static void EnsureOnTray(GameObject go) { foreach (PieceTable item in PieceTablesInPlay()) { if (IsServingTray(item) && item.m_pieces != null && !item.m_pieces.Contains(go)) { item.m_pieces.Add(go); Plugin.Log.LogInfo((object)("cook feast added to " + ((Object)item).name)); } } } private static void DetachFromOtherTables(GameObject go) { foreach (PieceTable item in PieceTablesInPlay()) { if (!IsServingTray(item) && item.m_pieces != null && item.m_pieces.Remove(go)) { Plugin.Log.LogInfo((object)("cook feast removed from " + ((Object)item).name)); } } } private static bool IsServingTray(PieceTable table) { string text = (((Object)(object)table != (Object)null) ? ((Object)table).name : ""); if (string.IsNullOrEmpty(text)) { return false; } if (text.IndexOf("Feaster", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (text.IndexOf("ServingTray", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } string text2 = PieceTables.ServingTray ?? ""; if (text2.Length > 0) { return text.IndexOf(text2, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static IEnumerable<PieceTable> PieceTablesInPlay() { HashSet<PieceTable> seen = new HashSet<PieceTable>(); PieceTable[] array = Resources.FindObjectsOfTypeAll<PieceTable>(); foreach (PieceTable val in array) { if ((Object)(object)val != (Object)null && seen.Add(val)) { yield return val; } } } internal static void Rewrite(ObjectDB db) { if (db?.m_recipes == null || (Object)(object)FindItem(db, "Wood") == (Object)null) { return; } CookRow tray = _kit.FirstOrDefault((CookRow r) => r.IsTool && r.IsAdd); if (tray != null && !db.m_recipes.Any((Recipe r) => (Object)(object)r != (Object)null && MatchesKitRecipe(r, tray))) { Plugin.Log.LogWarning((object)("cook kit recipe missing from ObjectDB: Recipe_Restless_" + tray.Id)); } foreach (CookRow row in _rows.Where((CookRow r) => r.IsRewrite)) { List<Requirement> list = BuildReqs(db, row); if (list.Count != 0) { Recipe val = ((IEnumerable<Recipe>)db.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe r) => (Object)(object)r != (Object)null && ((Object)r).name == row.RecipeId)); if ((Object)(object)val != (Object)null) { val.m_resources = list.ToArray(); val.m_amount = row.OutputAmount; } string text = (row.Prefab.EndsWith("_Material", StringComparison.Ordinal) ? row.Prefab.Substring(0, row.Prefab.Length - "_Material".Length) : row.Prefab); GameObject prefab = PrefabManager.Instance.GetPrefab(text); Piece val2 = ((prefab != null) ? prefab.GetComponent<Piece>() : null); if ((Object)(object)val2 != (Object)null) { val2.m_resources = list.ToArray(); } else if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("RestlessCook: missing " + row.RecipeId + " / " + text + " for " + row.Id)); } } } foreach (CookRow item in _rows.Where((CookRow r) => r.IsAdd && r.IsFeast)) { GameObject prefab2 = PrefabManager.Instance.GetPrefab(item.Prefab); Piece piece = ((prefab2 != null) ? prefab2.GetComponent<Piece>() : null); BindFeastPiece(item, piece, db); } foreach (Recipe recipe in db.m_recipes) { CookRow cookRow = RowForRecipe(recipe); if (cookRow != null) { List<Requirement> list2 = BuildReqs(db, cookRow); if (list2.Count != 0) { recipe.m_resources = list2.ToArray(); recipe.m_amount = cookRow.OutputAmount; } } } GateOurs(db); } private static void GateOurs(ObjectDB db) { if (db?.m_recipes == null) { return; } foreach (Recipe recipe in db.m_recipes) { if (Ours(recipe)) { recipe.m_enabled = ReqsComplete(recipe); } } } private static bool MatchesKitRecipe(Recipe recipe, CookRow tray) { if ((Object)(object)recipe == (Object)null) { return false; } if (((Object)recipe).name == "Recipe_Restless_" + tray.Id) { return true; } string text = (((Object)(object)recipe.m_item != (Object)null) ? ((Object)recipe.m_item).name : ""); if (!(text == tray.Prefab)) { return text.IndexOf(tray.Prefab, StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static CookRow? RowForRecipe(Recipe? recipe) { if ((Object)(object)recipe == (Object)null) { return null; } foreach (CookRow row in _rows) { if (row.IsAdd && (row.IsMeal || row.IsSideboard || row.IsFeast) && MatchesAddRecipe(recipe, row)) { return row; } } return null; } private static bool MatchesAddRecipe(Recipe? recipe, CookRow row) { if ((Object)(object)recipe == (Object)null) { return false; } string text = (row.IsFeast ? (row.Prefab + "_Material") : row.Prefab); string text2 = (((Object)(object)recipe.m_item != (Object)null) ? ((Object)recipe.m_item).name : ""); if (text2 == text || text2 == row.Prefab) { return true; } if (text2.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } string text3 = ((Object)recipe).name ?? ""; if (text3 == "Recipe_Restless_" + row.Id) { return true; } if (text3.IndexOf(text, StringComparison.OrdinalIgnoreCase) < 0 && text3.IndexOf(row.Prefab, StringComparison.OrdinalIgnoreCase) < 0) { return text3.IndexOf(row.Id, StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static List<Requirement> BuildReqs(ObjectDB db, CookRow row) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown List<Requirement> list = new List<Requirement>(); foreach (CookUse use in row.Uses) { GameObject val = FindItem(db, use.Item); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)("RestlessCook: " + row.Id + " missing ingredient " + use.Item)); continue; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogWarning((object)("RestlessCook: " + use.Item + " has no ItemDrop")); continue; } list.Add(new Requirement { m_resItem = component, m_amount = use.Amount, m_amountPerLevel = 0, m_recover = row.IsFeast }); } return list; } private static GameObject? FindItem(ObjectDB db, string name) { GameObject itemPrefab = db.GetItemPrefab(name); if ((Object)(object)itemPrefab != (Object)null) { return itemPrefab; } itemPrefab = PrefabManager.Instance.GetPrefab(name); if ((Object)(object)itemPrefab != (Object)null) { return itemPrefab; } if (db.m_items == null) { return null; } foreach (GameObject item in db.m_items) { if ((Object)(object)item != (Object)null && ((Object)item).name.Equals(name, StringComparison.OrdinalIgnoreCase)) { return item; } } return null; } private static bool Ours(Recipe? recipe) { if ((Object)(object)recipe?.m_item == (Object)null) { return false; } string crafted = ((Object)recipe.m_item).name; if (crafted.StartsWith("Restless", StringComparison.Ordinal)) { return true; } if ((((Object)recipe).name ?? "").IndexOf("Restless", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return _rows.Any((CookRow r) => r.IsAdd && (crafted == r.Prefab || crafted == r.Prefab + "_Material")); } private static bool ReqsComplete(Recipe? recipe) { if (recipe?.m_resources == null || recipe.m_resources.Length == 0) { return false; } int num = 0; Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if (val != null && val.m_amount > 0) { num++; ItemDrop resItem = val.m_resItem; if ((Object)(object)resItem == (Object)null || ((Object)resItem).name.IndexOf("Mock", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } if (resItem.m_itemData?.m_shared == null || string.IsNullOrEmpty(resItem.m_itemData.m_shared.m_name)) { return false; } } } return num > 0; } private static bool ShouldShow(Recipe recipe) { return ReqsComplete(recipe); } private static void TeachOurs(Player player) { ObjectDB instance = ObjectDB.instance; if (instance?.m_recipes == null || player.m_knownRecipes == null) { return; } GateOurs(instance); List<string> list = new List<string>(); foreach (string knownRecipe in player.m_knownRecipes) { Recipe val = FindRecipeByKnownName(instance, knownRecipe); if ((Object)(object)val != (Object)null && Ours(val) && !ReqsComplete(val)) { list.Add(knownRecipe); } } foreach (string item in list) { player.m_knownRecipes.Remove(item); } foreach (Recipe recipe in instance.m_recipes) { if (Ours(recipe) && ShouldShow(recipe)) { string text = recipe.m_item.m_itemData?.m_shared?.m_name; if (!string.IsNullOrEmpty(text) && !player.m_knownRecipes.Contains(text)) { player.AddKnownRecipe(recipe); } } } } private static Recipe? FindRecipeByKnownName(ObjectDB db, string name) { foreach (Recipe recipe in db.m_recipes) { if (recipe?.m_item?.m_itemData?.m_shared?.m_name == name) { return recipe; } } return null; } private static void HideUnknown(object? list) { if ((Object)(object)Player.m_localPlayer == (Object)null || list == null) { return; } if (list is List<Recipe> list2) { list2.RemoveAll((Recipe recipe) => Ours(recipe) && !ShouldShow(recipe)); } else { if (!(list is IList list3)) { return; } for (int num = list3.Count - 1; num >= 0; num--) { Recipe val = RecipeOf(list3[num]); if ((Object)(object)val != (Object)null && Ours(val) && !ShouldShow(val)) { list3.RemoveAt(num); } } } } private static Recipe? RecipeOf(object? entry) { Recipe val = (Recipe)((entry is Recipe) ? entry : null); if (val != null) { return val; } if (entry == null) { return null; } object? obj = (AccessTools.Field(entry.GetType(), "Recipe") ?? AccessTools.Field(entry.GetType(), "m_recipe") ?? AccessTools.Field(entry.GetType(), "recipe"))?.GetValue(entry); return (Recipe?)((obj is Recipe) ? obj : null); } internal static void DumpForSizeTest() { //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { Console instance = Console.instance; if (instance != null) { instance.Print("restlesscook: no player"); } return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); List<string> list = new List<string>(); CookRow cookRow = _kit.FirstOrDefault((CookRow r) => r.IsTool && r.IsAdd); if (cookRow != null) { list.Add(cookRow.Prefab); } foreach (CookRow row in _rows) { if (row.IsAdd && (row.IsMeal || row.IsSideboard)) { list.Add(row.Prefab); } else if (row.IsAdd && row.IsFeast) { list.Add(row.Prefab + "_Material"); } else if (row.IsFeast && (row.IsRewrite || row.IsReference)) { list.Add(row.Prefab); } } int num = 0; int num2 = 0; int num3 = 0; Vector3 val = ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward + Vector3.up; foreach (string item in list.Distinct()) { GameObject val2 = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(item) : null); if ((Object)(object)val2 == (Object)null) { val2 = PrefabManager.Instance.GetPrefab(item); } if ((Object)(object)val2 == (Object)null || (Object)(object)val2.GetComponent<ItemDrop>() == (Object)null) { num3++; Plugin.Log.LogWarning((object)("restlesscook dump missing " + item)); continue; } if (inventory.AddItem(val2, 1)) { num++; continue; } ItemData obj = val2.GetComponent<ItemDrop>().m_itemData.Clone(); obj.m_stack = 1; ItemDrop.DropItem(obj, 1, val, Quaternion.identity); num2++; } string text = $"restlesscook: {num} in bag, {num2} at feet" + ((num3 > 0) ? $", {num3} missing" : ""); Console instance2 = Console.instance; if (instance2 != null) { instance2.Print(text); } Plugin.Log.LogInfo((object)text); } private static void ReadyFeast(Feast? feast) { if ((Object)(object)feast == (Object)null) { return; } string name = Utils.GetPrefabName(((Component)feast).gameObject); CookRow cookRow = _rows.FirstOrDefault((CookRow r) => r.IsAdd && r.IsFeast && r.Prefab == name); if (cookRow != null) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(cookRow.Prefab + "_Material") : null); if ((Object)(object)val == (Object)null) { val = PrefabManager.Instance.GetPrefab(cookRow.Prefab + "_Material"); } ItemDrop val2 = ((val != null) ? val.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 != (Object)null) { feast.m_foodItem = val2; ApplyFood(cookRow, val2); } if (feast.m_eatStacks < 1) { feast.m_eatStacks = 10; } CookVisual.EnsureHit(((Component)feast).gameObject); } } } }