using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("DynamicFurniture")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Valheim mod that dynamically loads furniture from OBJ and PNG files at runtime.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DynamicFurniture")] [assembly: AssemblyTitle("DynamicFurniture")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DynamicFurniture { [BepInPlugin("com.woltreks.dynamicfurniture", "DynamicFurniture", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class DynamicFurniture : BaseUnityPlugin { public const string PluginGUID = "com.woltreks.dynamicfurniture"; public const string PluginName = "DynamicFurniture"; public const string PluginVersion = "1.0.0"; private void Awake() { PrefabManager.OnVanillaPrefabsAvailable += LoadCustomFurniture; Logger.LogInfo((object)"DynamicFurniture mod initialized!"); } private void LoadCustomFurniture() { //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: 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_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Expected O, but got Unknown //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Expected O, but got Unknown //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Expected O, but got Unknown //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Expected O, but got Unknown //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Expected O, but got Unknown //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Expected O, but got Unknown PrefabManager.OnVanillaPrefabsAvailable -= LoadCustomFurniture; string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); Logger.LogInfo((object)("Scanning for custom furniture in: " + directoryName)); if (!Directory.Exists(directoryName)) { return; } GameObject prefab = PrefabManager.Instance.GetPrefab("piece_chair"); Material val = null; if ((Object)(object)prefab != (Object)null) { Renderer componentInChildren = prefab.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { val = componentInChildren.sharedMaterial; } } string[] directories = Directory.GetDirectories(directoryName); foreach (string text in directories) { string text2 = Path.Combine(text, "model.obj"); string path = Path.Combine(text, "texture.png"); string path2 = Path.Combine(text, "piece.json"); if (!File.Exists(text2)) { continue; } string fileName = Path.GetFileName(text); Logger.LogInfo((object)("Found model folder: " + fileName)); try { PieceJson pieceJson = new PieceJson(); if (File.Exists(path2)) { pieceJson = PieceJson.Parse(File.ReadAllText(path2)); } else { pieceJson.name = fileName.Replace("_", " "); } Texture2D val2 = null; if (File.Exists(path)) { byte[] array = File.ReadAllBytes(path); val2 = new Texture2D(2, 2); if (!ImageConversion.LoadImage(val2, array)) { Logger.LogWarning((object)("Failed to load image texture for " + fileName)); val2 = null; } } Mesh val3 = ObjLoader.LoadOBJ(text2); if ((Object)(object)val3 == (Object)null) { Logger.LogError((object)("Failed to load OBJ mesh for " + fileName)); continue; } GameObject val4 = new GameObject(fileName); val4.SetActive(false); GameObject val5 = new GameObject("model"); val5.transform.SetParent(val4.transform, false); val5.AddComponent().sharedMesh = val3; MeshRenderer obj = val5.AddComponent(); Material val6; if ((Object)(object)val != (Object)null) { val6 = new Material(val); if ((Object)(object)val2 != (Object)null) { val6.mainTexture = (Texture)(object)val2; if (val6.HasProperty("_BumpMap")) { val6.SetTexture("_BumpMap", (Texture)null); } } } else { val6 = new Material(Shader.Find("Standard")); if ((Object)(object)val2 != (Object)null) { val6.mainTexture = (Texture)(object)val2; } } ((Renderer)obj).sharedMaterial = val6; val5.transform.localPosition = pieceJson.offset; val5.transform.localRotation = Quaternion.Euler(pieceJson.rotation); val5.transform.localScale = pieceJson.scale; MeshCollider obj2 = val5.AddComponent(); obj2.sharedMesh = val3; obj2.convex = false; if (pieceJson.sittingEnabled) { GameObject val7 = new GameObject("AttachPoint"); val7.transform.SetParent(val4.transform, false); val7.transform.localPosition = pieceJson.sittingPosition; val7.transform.localRotation = Quaternion.Euler(pieceJson.sittingRotation); Chair obj3 = val4.AddComponent(); obj3.m_attachPoint = val7.transform; obj3.m_name = "$piece_sit"; } Piece obj4 = val4.AddComponent(); obj4.m_name = pieceJson.name; obj4.m_description = pieceJson.description; obj4.m_comfort = pieceJson.comfort; PieceCategory category = (PieceCategory)4; if (Enum.TryParse(pieceJson.category, ignoreCase: true, out PieceCategory result)) { category = result; } obj4.m_category = category; val4.AddComponent().m_health = 50f; PieceConfig val8 = new PieceConfig(); val8.Name = pieceJson.name; val8.Description = pieceJson.description; val8.PieceTable = PieceTables.Hammer; val8.Category = pieceJson.category; val8.CraftingStation = pieceJson.craftingStation; if (pieceJson.cost.Count > 0) { foreach (KeyValuePair item in pieceJson.cost) { val8.AddRequirement(new RequirementConfig(item.Key, item.Value, 0, false)); } } else { val8.AddRequirement(new RequirementConfig("Wood", 5, 0, false)); } CustomPiece val9 = new CustomPiece(val4, false, val8); PieceManager.Instance.AddPiece(val9); Logger.LogInfo((object)("Successfully registered custom piece: " + pieceJson.name)); } catch (Exception arg) { Logger.LogError((object)$"Error loading custom furniture from folder {fileName}: {arg}"); } } } } public class PieceJson { public string name = "Custom Furniture"; public string description = "Custom building piece."; public string category = "Furniture"; public string craftingStation = "piece_workbench"; public Dictionary cost = new Dictionary(); public Vector3 scale = Vector3.one; public Vector3 rotation = Vector3.zero; public Vector3 offset = Vector3.zero; public int comfort; public bool sittingEnabled; public Vector3 sittingPosition = new Vector3(0f, 0.5f, 0f); public Vector3 sittingRotation = Vector3.zero; public static PieceJson Parse(string jsonText) { //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) PieceJson pieceJson = new PieceJson(); string[] array = jsonText.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); bool flag = false; bool flag2 = false; string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string text = array2[i].Trim(); if (text.Contains("\"cost\":")) { flag = true; continue; } if (text.Contains("\"sitting\":")) { flag2 = true; continue; } if (text == "}," || text == "}") { flag = false; flag2 = false; continue; } int num = text.IndexOf(':'); if (num < 0) { continue; } string text2 = text.Substring(0, num).Replace("\"", "").Trim(); string text3 = text.Substring(num + 1).Replace("\"", "").Trim(); if (text3.EndsWith(",")) { text3 = text3.Substring(0, text3.Length - 1); } if (flag) { if (int.TryParse(text3, out var result)) { pieceJson.cost[text2] = result; } continue; } if (flag2) { switch (text2) { case "enabled": pieceJson.sittingEnabled = text3.ToLower() == "true"; break; case "position": pieceJson.sittingPosition = ParseVector3(text); break; case "rotation": pieceJson.sittingRotation = ParseVector3(text); break; } continue; } switch (text2) { case "name": pieceJson.name = text3; break; case "description": pieceJson.description = text3; break; case "category": pieceJson.category = text3; break; case "crafting_station": pieceJson.craftingStation = text3; break; case "comfort": int.TryParse(text3, out pieceJson.comfort); break; case "scale": pieceJson.scale = ParseVector3(text); break; case "rotation": pieceJson.rotation = ParseVector3(text); break; case "offset": pieceJson.offset = ParseVector3(text); break; } } return pieceJson; } private static Vector3 ParseVector3(string line) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) int num = line.IndexOf('['); int num2 = line.IndexOf(']'); if (num >= 0 && num2 > num) { string[] array = line.Substring(num + 1, num2 - num - 1).Split(','); if (array.Length >= 3) { float.TryParse(array[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result); float.TryParse(array[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2); float.TryParse(array[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result3); return new Vector3(result, result2, result3); } } return Vector3.one; } } public static class ObjLoader { public static Mesh LoadOBJ(string filePath) { //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) if (!File.Exists(filePath)) { return null; } List list = new List(); List list2 = new List(); List list3 = new List(); List list4 = new List(); Dictionary dictionary = new Dictionary(); List list5 = new List(); List list6 = new List(); List list7 = new List(); string[] array = File.ReadAllLines(filePath); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.StartsWith("#") || string.IsNullOrEmpty(text)) { continue; } string[] array2 = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length == 0) { continue; } switch (array2[0]) { case "v": { float num9 = float.Parse(array2[1], CultureInfo.InvariantCulture); float num10 = float.Parse(array2[2], CultureInfo.InvariantCulture); float num11 = float.Parse(array2[3], CultureInfo.InvariantCulture); list.Add(new Vector3(0f - num9, num10, num11)); break; } case "vt": { float num7 = float.Parse(array2[1], CultureInfo.InvariantCulture); float num8 = float.Parse(array2[2], CultureInfo.InvariantCulture); list2.Add(new Vector2(num7, num8)); break; } case "vn": { float num4 = float.Parse(array2[1], CultureInfo.InvariantCulture); float num5 = float.Parse(array2[2], CultureInfo.InvariantCulture); float num6 = float.Parse(array2[3], CultureInfo.InvariantCulture); list3.Add(new Vector3(0f - num4, num5, num6)); break; } case "f": { List list8 = new List(); for (int j = 1; j < array2.Length; j++) { string text2 = array2[j]; if (dictionary.TryGetValue(text2, out var value)) { list8.Add(value); continue; } string[] array3 = text2.Split('/'); int num = int.Parse(array3[0]) - 1; if (num < 0) { num = list.Count + num + 1; } Vector2 item = Vector2.zero; if (array3.Length > 1 && !string.IsNullOrEmpty(array3[1])) { int num2 = int.Parse(array3[1]) - 1; if (num2 < 0) { num2 = list2.Count + num2 + 1; } if (num2 >= 0 && num2 < list2.Count) { item = list2[num2]; } } Vector3 item2 = Vector3.zero; if (array3.Length > 2 && !string.IsNullOrEmpty(array3[2])) { int num3 = int.Parse(array3[2]) - 1; if (num3 < 0) { num3 = list3.Count + num3 + 1; } if (num3 >= 0 && num3 < list3.Count) { item2 = list3[num3]; } } int count = list5.Count; list5.Add(list[num]); list6.Add(item); list7.Add(item2); dictionary[text2] = count; list8.Add(count); } for (int k = 1; k < list8.Count - 1; k++) { list4.Add(list8[0]); list4.Add(list8[k + 1]); list4.Add(list8[k]); } break; } } } Mesh val = new Mesh(); val.vertices = list5.ToArray(); val.uv = list6.ToArray(); if (list7.Count > 0) { val.normals = list7.ToArray(); } else { val.RecalculateNormals(); } val.triangles = list4.ToArray(); val.RecalculateBounds(); val.RecalculateTangents(); return val; } } }